summaryrefslogtreecommitdiff
path: root/numpy/distutils/command/scons.py
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/distutils/command/scons.py')
-rw-r--r--numpy/distutils/command/scons.py589
1 files changed, 0 insertions, 589 deletions
diff --git a/numpy/distutils/command/scons.py b/numpy/distutils/command/scons.py
deleted file mode 100644
index d7bbec35e..000000000
--- a/numpy/distutils/command/scons.py
+++ /dev/null
@@ -1,589 +0,0 @@
-import os
-import sys
-import os.path
-from os.path import join as pjoin, dirname as pdirname
-
-from distutils.errors import DistutilsPlatformError
-from distutils.errors import DistutilsExecError, DistutilsSetupError
-
-from numpy.distutils.command.build_ext import build_ext as old_build_ext
-from numpy.distutils.ccompiler import CCompiler, new_compiler
-from numpy.distutils.fcompiler import FCompiler, new_fcompiler
-from numpy.distutils.exec_command import find_executable
-from numpy.distutils import log
-from numpy.distutils.misc_util import is_bootstrapping, get_cmd
-from numpy.distutils.misc_util import get_numpy_include_dirs as _incdir
-from numpy.distutils.compat import get_exception
-
-# A few notes:
-# - numscons is not mandatory to build numpy, so we cannot import it here.
-# Any numscons import has to happen once we check numscons is available and
-# is required for the build (call through setupscons.py or native numscons
-# build).
-def get_scons_build_dir():
- """Return the top path where everything produced by scons will be put.
-
- The path is relative to the top setup.py"""
- from numscons import get_scons_build_dir
- return get_scons_build_dir()
-
-def get_scons_pkg_build_dir(pkg):
- """Return the build directory for the given package (foo.bar).
-
- The path is relative to the top setup.py"""
- from numscons.core.utils import pkg_to_path
- return pjoin(get_scons_build_dir(), pkg_to_path(pkg))
-
-def get_scons_configres_dir():
- """Return the top path where everything produced by scons will be put.
-
- The path is relative to the top setup.py"""
- from numscons import get_scons_configres_dir
- return get_scons_configres_dir()
-
-def get_scons_configres_filename():
- """Return the top path where everything produced by scons will be put.
-
- The path is relative to the top setup.py"""
- from numscons import get_scons_configres_filename
- return get_scons_configres_filename()
-
-def get_scons_local_path():
- """This returns the full path where scons.py for scons-local is located."""
- from numscons import get_scons_path
- return get_scons_path()
-
-def _get_top_dir(pkg):
- # XXX: this mess is necessary because scons is launched per package, and
- # has no knowledge outside its build dir, which is package dependent. If
- # one day numscons does not launch one process/package, this will be
- # unnecessary.
- from numscons import get_scons_build_dir
- from numscons.core.utils import pkg_to_path
- scdir = pjoin(get_scons_build_dir(), pkg_to_path(pkg))
- n = scdir.count(os.sep)
- return os.sep.join([os.pardir for i in range(n+1)])
-
-def get_distutils_libdir(cmd, pkg):
- """Returns the path where distutils install libraries, relatively to the
- scons build directory."""
- return pjoin(_get_top_dir(pkg), cmd.build_lib)
-
-def get_distutils_clibdir(cmd, pkg):
- """Returns the path where distutils put pure C libraries."""
- return pjoin(_get_top_dir(pkg), cmd.build_clib)
-
-def get_distutils_install_prefix(pkg, inplace):
- """Returns the installation path for the current package."""
- from numscons.core.utils import pkg_to_path
- if inplace == 1:
- return pkg_to_path(pkg)
- else:
- install_cmd = get_cmd('install').get_finalized_command('install')
- return pjoin(install_cmd.install_libbase, pkg_to_path(pkg))
-
-def get_python_exec_invoc():
- """This returns the python executable from which this file is invocated."""
- # Do we need to take into account the PYTHONPATH, in a cross platform way,
- # that is the string returned can be executed directly on supported
- # platforms, and the sys.path of the executed python should be the same
- # than the caller ? This may not be necessary, since os.system is said to
- # take into accound os.environ. This actually also works for my way of
- # using "local python", using the alias facility of bash.
- return sys.executable
-
-def get_numpy_include_dirs(sconscript_path):
- """Return include dirs for numpy.
-
- The paths are relatively to the setup.py script path."""
- from numscons import get_scons_build_dir
- scdir = pjoin(get_scons_build_dir(), pdirname(sconscript_path))
- n = scdir.count(os.sep)
-
- dirs = _incdir()
- rdirs = []
- for d in dirs:
- rdirs.append(pjoin(os.sep.join([os.pardir for i in range(n+1)]), d))
- return rdirs
-
-def dirl_to_str(dirlist):
- """Given a list of directories, returns a string where the paths are
- concatenated by the path separator.
-
- example: ['foo/bar', 'bar/foo'] will return 'foo/bar:bar/foo'."""
- return os.pathsep.join(dirlist)
-
-def dist2sconscc(compiler):
- """This converts the name passed to distutils to scons name convention (C
- compiler). compiler should be a CCompiler instance.
-
- Example:
- --compiler=intel -> intelc"""
- compiler_type = compiler.compiler_type
- if compiler_type == 'msvc':
- return 'msvc'
- elif compiler_type == 'intel':
- return 'intelc'
- else:
- return compiler.compiler[0]
-
-def dist2sconsfc(compiler):
- """This converts the name passed to distutils to scons name convention
- (Fortran compiler). The argument should be a FCompiler instance.
-
- Example:
- --fcompiler=intel -> ifort on linux, ifl on windows"""
- if compiler.compiler_type == 'intel':
- #raise NotImplementedError('FIXME: intel fortran compiler name ?')
- return 'ifort'
- elif compiler.compiler_type == 'gnu':
- return 'g77'
- elif compiler.compiler_type == 'gnu95':
- return 'gfortran'
- elif compiler.compiler_type == 'sun':
- return 'sunf77'
- else:
- # XXX: Just give up for now, and use generic fortran compiler
- return 'fortran'
-
-def dist2sconscxx(compiler):
- """This converts the name passed to distutils to scons name convention
- (C++ compiler). The argument should be a Compiler instance."""
- if compiler.compiler_type == 'msvc':
- return compiler.compiler_type
-
- return compiler.compiler_cxx[0]
-
-def get_compiler_executable(compiler):
- """For any give CCompiler instance, this gives us the name of C compiler
- (the actual executable).
-
- NOTE: does NOT work with FCompiler instances."""
- # Geez, why does distutils has no common way to get the compiler name...
- if compiler.compiler_type == 'msvc':
- # this is harcoded in distutils... A bit cleaner way would be to
- # initialize the compiler instance and then get compiler.cc, but this
- # may be costly: we really just want a string.
- # XXX: we need to initialize the compiler anyway, so do not use
- # hardcoded string
- #compiler.initialize()
- #print compiler.cc
- return 'cl.exe'
- else:
- return compiler.compiler[0]
-
-def get_f77_compiler_executable(compiler):
- """For any give FCompiler instance, this gives us the name of F77 compiler
- (the actual executable)."""
- return compiler.compiler_f77[0]
-
-def get_cxxcompiler_executable(compiler):
- """For any give CCompiler instance, this gives us the name of CXX compiler
- (the actual executable).
-
- NOTE: does NOT work with FCompiler instances."""
- # Geez, why does distutils has no common way to get the compiler name...
- if compiler.compiler_type == 'msvc':
- # this is harcoded in distutils... A bit cleaner way would be to
- # initialize the compiler instance and then get compiler.cc, but this
- # may be costly: we really just want a string.
- # XXX: we need to initialize the compiler anyway, so do not use
- # hardcoded string
- #compiler.initialize()
- #print compiler.cc
- return 'cl.exe'
- else:
- return compiler.compiler_cxx[0]
-
-def get_tool_path(compiler):
- """Given a distutils.ccompiler.CCompiler class, returns the path of the
- toolset related to C compilation."""
- fullpath_exec = find_executable(get_compiler_executable(compiler))
- if fullpath_exec:
- fullpath = pdirname(fullpath_exec)
- else:
- raise DistutilsSetupError("Could not find compiler executable info for scons")
- return fullpath
-
-def get_f77_tool_path(compiler):
- """Given a distutils.ccompiler.FCompiler class, returns the path of the
- toolset related to F77 compilation."""
- fullpath_exec = find_executable(get_f77_compiler_executable(compiler))
- if fullpath_exec:
- fullpath = pdirname(fullpath_exec)
- else:
- raise DistutilsSetupError("Could not find F77 compiler executable "\
- "info for scons")
- return fullpath
-
-def get_cxx_tool_path(compiler):
- """Given a distutils.ccompiler.CCompiler class, returns the path of the
- toolset related to C compilation."""
- fullpath_exec = find_executable(get_cxxcompiler_executable(compiler))
- if fullpath_exec:
- fullpath = pdirname(fullpath_exec)
- else:
- raise DistutilsSetupError("Could not find compiler executable info for scons")
- return fullpath
-
-def protect_path(path):
- """Convert path (given as a string) to something the shell will have no
- problem to understand (space, etc... problems)."""
- if path:
- # XXX: to this correctly, this is totally bogus for now (does not check for
- # already quoted path, for example).
- return '"' + path + '"'
- else:
- return '""'
-
-def parse_package_list(pkglist):
- return pkglist.split(",")
-
-def find_common(seq1, seq2):
- """Given two list, return the index of the common items.
-
- The index are relative to seq1.
-
- Note: do not handle duplicate items."""
- dict2 = dict([(i, None) for i in seq2])
-
- return [i for i in range(len(seq1)) if dict2.has_key(seq1[i])]
-
-def select_packages(sconspkg, pkglist):
- """Given a list of packages in pkglist, return the list of packages which
- match this list."""
- common = find_common(sconspkg, pkglist)
- if not len(common) == len(pkglist):
- msg = "the package list contains a package not found in "\
- "the current list. The current list is %s" % sconspkg
- raise ValueError(msg)
- return common
-
-def check_numscons(minver):
- """Check that we can use numscons.
-
- minver is a 3 integers tuple which defines the min version."""
- try:
- import numscons
- except ImportError:
- e = get_exception()
- raise RuntimeError("importing numscons failed (error was %s), using " \
- "scons within distutils is not possible without "
- "this package " % str(e))
-
- try:
- # version_info was added in 0.10.0
- from numscons import version_info
- # Stupid me used string instead of numbers in version_info in
- # dev versions of 0.10.0
- if isinstance(version_info[0], str):
- raise ValueError("Numscons %s or above expected " \
- "(detected 0.10.0)" % str(minver))
- # Stupid me used list instead of tuple in numscons
- version_info = tuple(version_info)
- if version_info[:3] < minver:
- raise ValueError("Numscons %s or above expected (got %s) "
- % (str(minver), str(version_info[:3])))
- except ImportError:
- raise RuntimeError("You need numscons >= %s to build numpy "\
- "with numscons (imported numscons path " \
- "is %s)." % (minver, numscons.__file__))
-
-# XXX: this is a giantic mess. Refactor this at some point.
-class scons(old_build_ext):
- # XXX: add an option to the scons command for configuration (auto/force/cache).
- description = "Scons builder"
-
- library_options = [
- ('with-perflib=', None,
- 'Specify which performance library to use for BLAS/LAPACK/etc...' \
- 'Examples: mkl/atlas/sunper/accelerate'),
- ('with-mkl-lib=', None, 'TODO'),
- ('with-mkl-include=', None, 'TODO'),
- ('with-mkl-libraries=', None, 'TODO'),
- ('with-atlas-lib=', None, 'TODO'),
- ('with-atlas-include=', None, 'TODO'),
- ('with-atlas-libraries=', None, 'TODO')
- ]
- user_options = [
- ('jobs=', 'j', "specify number of worker threads when executing" \
- "scons"),
- ('inplace', 'i', 'If specified, build in place.'),
- ('import-env', 'e', 'If specified, import user environment into scons env["ENV"].'),
- ('bypass', 'b', 'Bypass distutils compiler detection (experimental).'),
- ('scons-tool-path=', None, 'specify additional path '\
- '(absolute) to look for scons tools'),
- ('silent=', None, 'specify whether scons output should less verbose'\
- '(1), silent (2), super silent (3) or not (0, default)'),
- ('log-level=', None, 'specify log level for numscons. Any value ' \
- 'valid for the logging python module is valid'),
- ('package-list=', None,
- 'If specified, only run scons on the given '\
- 'packages (example: --package-list=scipy.cluster). If empty, '\
- 'no package is built'),
- ('fcompiler=', None, "specify the Fortran compiler type"),
- ('compiler=', None, "specify the C compiler type"),
- ('cxxcompiler=', None,
- "specify the C++ compiler type (same as C by default)"),
- ('debug', 'g',
- "compile/link with debugging information"),
- ] + library_options
-
- def initialize_options(self):
- old_build_ext.initialize_options(self)
- self.build_clib = None
-
- self.debug = 0
-
- self.compiler = None
- self.cxxcompiler = None
- self.fcompiler = None
-
- self.jobs = None
- self.silent = 0
- self.import_env = 0
- self.scons_tool_path = ''
- # If true, we bypass distutils to find the c compiler altogether. This
- # is to be used in desperate cases (like incompatible visual studio
- # version).
- self._bypass_distutils_cc = False
-
- # scons compilers
- self.scons_compiler = None
- self.scons_compiler_path = None
- self.scons_fcompiler = None
- self.scons_fcompiler_path = None
- self.scons_cxxcompiler = None
- self.scons_cxxcompiler_path = None
-
- self.package_list = None
- self.inplace = 0
- self.bypass = 0
-
- # Only critical things
- self.log_level = 50
-
- # library options
- self.with_perflib = []
- self.with_mkl_lib = []
- self.with_mkl_include = []
- self.with_mkl_libraries = []
- self.with_atlas_lib = []
- self.with_atlas_include = []
- self.with_atlas_libraries = []
-
- def _init_ccompiler(self, compiler_type):
- # XXX: The logic to bypass distutils is ... not so logic.
- if compiler_type == 'msvc':
- self._bypass_distutils_cc = True
- try:
- distutils_compiler = new_compiler(compiler=compiler_type,
- verbose=self.verbose,
- dry_run=self.dry_run,
- force=self.force)
- distutils_compiler.customize(self.distribution)
- # This initialization seems necessary, sometimes, for find_executable to work...
- if hasattr(distutils_compiler, 'initialize'):
- distutils_compiler.initialize()
- self.scons_compiler = dist2sconscc(distutils_compiler)
- self.scons_compiler_path = protect_path(get_tool_path(distutils_compiler))
- except DistutilsPlatformError:
- e = get_exception()
- if not self._bypass_distutils_cc:
- raise e
- else:
- self.scons_compiler = compiler_type
-
- def _init_fcompiler(self, compiler_type):
- self.fcompiler = new_fcompiler(compiler = compiler_type,
- verbose = self.verbose,
- dry_run = self.dry_run,
- force = self.force)
-
- if self.fcompiler is not None:
- self.fcompiler.customize(self.distribution)
- self.scons_fcompiler = dist2sconsfc(self.fcompiler)
- self.scons_fcompiler_path = protect_path(get_f77_tool_path(self.fcompiler))
-
- def _init_cxxcompiler(self, compiler_type):
- cxxcompiler = new_compiler(compiler = compiler_type,
- verbose = self.verbose,
- dry_run = self.dry_run,
- force = self.force)
- if cxxcompiler is not None:
- cxxcompiler.customize(self.distribution, need_cxx = 1)
- cxxcompiler.customize_cmd(self)
- self.cxxcompiler = cxxcompiler.cxx_compiler()
- try:
- get_cxx_tool_path(self.cxxcompiler)
- except DistutilsSetupError:
- self.cxxcompiler = None
-
- if self.cxxcompiler:
- self.scons_cxxcompiler = dist2sconscxx(self.cxxcompiler)
- self.scons_cxxcompiler_path = protect_path(get_cxx_tool_path(self.cxxcompiler))
-
- def finalize_options(self):
- old_build_ext.finalize_options(self)
-
- self.sconscripts = []
- self.pre_hooks = []
- self.post_hooks = []
- self.pkg_names = []
- self.pkg_paths = []
-
- if self.distribution.has_scons_scripts():
- for i in self.distribution.scons_data:
- self.sconscripts.append(i.scons_path)
- self.pre_hooks.append(i.pre_hook)
- self.post_hooks.append(i.post_hook)
- self.pkg_names.append(i.parent_name)
- self.pkg_paths.append(i.pkg_path)
- # This crap is needed to get the build_clib
- # directory
- build_clib_cmd = get_cmd("build_clib").get_finalized_command("build_clib")
- self.build_clib = build_clib_cmd.build_clib
-
- if not self.cxxcompiler:
- self.cxxcompiler = self.compiler
-
- # To avoid trouble, just don't do anything if no sconscripts are used.
- # This is useful when for example f2py uses numpy.distutils, because
- # f2py does not pass compiler information to scons command, and the
- # compilation setup below can crash in some situation.
- if len(self.sconscripts) > 0:
- if self.bypass:
- self.scons_compiler = self.compiler
- self.scons_fcompiler = self.fcompiler
- self.scons_cxxcompiler = self.cxxcompiler
- else:
- # Try to get the same compiler than the ones used by distutils: this is
- # non trivial because distutils and scons have totally different
- # conventions on this one (distutils uses PATH from user's environment,
- # whereas scons uses standard locations). The way we do it is once we
- # got the c compiler used, we use numpy.distutils function to get the
- # full path, and add the path to the env['PATH'] variable in env
- # instance (this is done in numpy.distutils.scons module).
-
- self._init_ccompiler(self.compiler)
- self._init_fcompiler(self.fcompiler)
- self._init_cxxcompiler(self.cxxcompiler)
-
- if self.package_list:
- self.package_list = parse_package_list(self.package_list)
-
- def _call_scons(self, scons_exec, sconscript, pkg_name, pkg_path, bootstrapping):
- # XXX: when a scons script is missing, scons only prints warnings, and
- # does not return a failure (status is 0). We have to detect this from
- # distutils (this cannot work for recursive scons builds...)
-
- # XXX: passing everything at command line may cause some trouble where
- # there is a size limitation ? What is the standard solution in thise
- # case ?
-
- cmd = [scons_exec, "-f", sconscript, '-I.']
- if self.jobs:
- cmd.append(" --jobs=%d" % int(self.jobs))
- if self.inplace:
- cmd.append("inplace=1")
- cmd.append('scons_tool_path="%s"' % self.scons_tool_path)
- cmd.append('src_dir="%s"' % pdirname(sconscript))
- cmd.append('pkg_path="%s"' % pkg_path)
- cmd.append('pkg_name="%s"' % pkg_name)
- cmd.append('log_level=%s' % self.log_level)
- #cmd.append('distutils_libdir=%s' % protect_path(pjoin(self.build_lib,
- # pdirname(sconscript))))
- cmd.append('distutils_libdir=%s' %
- protect_path(get_distutils_libdir(self, pkg_name)))
- cmd.append('distutils_clibdir=%s' %
- protect_path(get_distutils_clibdir(self, pkg_name)))
- prefix = get_distutils_install_prefix(pkg_name, self.inplace)
- cmd.append('distutils_install_prefix=%s' % protect_path(prefix))
-
- if not self._bypass_distutils_cc:
- cmd.append('cc_opt=%s' % self.scons_compiler)
- if self.scons_compiler_path:
- cmd.append('cc_opt_path=%s' % self.scons_compiler_path)
- else:
- cmd.append('cc_opt=%s' % self.scons_compiler)
-
- cmd.append('debug=%s' % self.debug)
-
- if self.scons_fcompiler:
- cmd.append('f77_opt=%s' % self.scons_fcompiler)
- if self.scons_fcompiler_path:
- cmd.append('f77_opt_path=%s' % self.scons_fcompiler_path)
-
- if self.scons_cxxcompiler:
- cmd.append('cxx_opt=%s' % self.scons_cxxcompiler)
- if self.scons_cxxcompiler_path:
- cmd.append('cxx_opt_path=%s' % self.scons_cxxcompiler_path)
-
- cmd.append('include_bootstrap=%s' % dirl_to_str(get_numpy_include_dirs(sconscript)))
- cmd.append('bypass=%s' % self.bypass)
- cmd.append('import_env=%s' % self.import_env)
- if self.silent:
- if int(self.silent) == 2:
- cmd.append('-Q')
- elif int(self.silent) == 3:
- cmd.append('-s')
- cmd.append('silent=%d' % int(self.silent))
- cmd.append('bootstrapping=%d' % bootstrapping)
- cmdstr = ' '.join(cmd)
- if int(self.silent) < 1:
- log.info("Executing scons command (pkg is %s): %s ", pkg_name, cmdstr)
- else:
- log.info("======== Executing scons command for pkg %s =========", pkg_name)
- st = os.system(cmdstr)
- if st:
- #print "status is %d" % st
- msg = "Error while executing scons command."
- msg += " See above for more information.\n"
- msg += """\
-If you think it is a problem in numscons, you can also try executing the scons
-command with --log-level option for more detailed output of what numscons is
-doing, for example --log-level=0; the lowest the level is, the more detailed
-the output it."""
- raise DistutilsExecError(msg)
-
- def run(self):
- if len(self.sconscripts) < 1:
- # nothing to do, just leave it here.
- return
-
- check_numscons(minver=(0, 11, 0))
-
- if self.package_list is not None:
- id = select_packages(self.pkg_names, self.package_list)
- sconscripts = [self.sconscripts[i] for i in id]
- pre_hooks = [self.pre_hooks[i] for i in id]
- post_hooks = [self.post_hooks[i] for i in id]
- pkg_names = [self.pkg_names[i] for i in id]
- pkg_paths = [self.pkg_paths[i] for i in id]
- else:
- sconscripts = self.sconscripts
- pre_hooks = self.pre_hooks
- post_hooks = self.post_hooks
- pkg_names = self.pkg_names
- pkg_paths = self.pkg_paths
-
- if is_bootstrapping():
- bootstrapping = 1
- else:
- bootstrapping = 0
-
- scons_exec = get_python_exec_invoc()
- scons_exec += ' ' + protect_path(pjoin(get_scons_local_path(), 'scons.py'))
-
- for sconscript, pre_hook, post_hook, pkg_name, pkg_path in zip(sconscripts,
- pre_hooks, post_hooks,
- pkg_names, pkg_paths):
- if pre_hook:
- pre_hook()
-
- if sconscript:
- self._call_scons(scons_exec, sconscript, pkg_name, pkg_path, bootstrapping)
-
- if post_hook:
- post_hook(**{'pkg_name': pkg_name, 'scons_cmd' : self})
-