summaryrefslogtreecommitdiff
path: root/numpy/distutils/command/build_ext.py
diff options
context:
space:
mode:
authorTravis Oliphant <oliphant@enthought.com>2006-01-04 17:26:31 +0000
committerTravis Oliphant <oliphant@enthought.com>2006-01-04 17:26:31 +0000
commit8e2654541c6eae0f308908f501cccbc86b2f9101 (patch)
treebfcfe3b282c8fb659832bf86a841ce76852094ad /numpy/distutils/command/build_ext.py
parentddaed649c23bbd0ad36cdafdfe9cd92397ce69e3 (diff)
downloadnumpy-8e2654541c6eae0f308908f501cccbc86b2f9101.tar.gz
Moved scipy directory to numpy
Diffstat (limited to 'numpy/distutils/command/build_ext.py')
-rw-r--r--numpy/distutils/command/build_ext.py349
1 files changed, 349 insertions, 0 deletions
diff --git a/numpy/distutils/command/build_ext.py b/numpy/distutils/command/build_ext.py
new file mode 100644
index 000000000..7a2318b70
--- /dev/null
+++ b/numpy/distutils/command/build_ext.py
@@ -0,0 +1,349 @@
+""" Modified version of build_ext that handles fortran source files.
+"""
+
+import os
+import string
+import sys
+from glob import glob
+from types import *
+
+from distutils.dep_util import newer_group, newer
+from distutils.command.build_ext import build_ext as old_build_ext
+
+from scipy.distutils import log
+from scipy.distutils.misc_util import filter_sources, has_f_sources, \
+ has_cxx_sources, get_ext_source_files, all_strings, \
+ get_scipy_include_dirs
+from distutils.errors import DistutilsFileError
+
+class build_ext (old_build_ext):
+
+ description = "build C/C++/F extensions (compile/link to build directory)"
+
+ user_options = old_build_ext.user_options + [
+ ('fcompiler=', None,
+ "specify the Fortran compiler type"),
+ ]
+
+ def initialize_options(self):
+ old_build_ext.initialize_options(self)
+ self.fcompiler = None
+ return
+
+ def finalize_options(self):
+ old_build_ext.finalize_options(self)
+ self.set_undefined_options('config_fc',
+ ('fcompiler', 'fcompiler'))
+ return
+
+ def run(self):
+ if not self.extensions:
+ return
+
+ # Make sure that extension sources are complete.
+ for ext in self.extensions:
+ if not all_strings(ext.sources):
+ self.run_command('build_src')
+
+ if self.distribution.has_c_libraries():
+ build_clib = self.get_finalized_command('build_clib')
+ self.library_dirs.append(build_clib.build_clib)
+ else:
+ build_clib = None
+
+ # Not including C libraries to the list of
+ # extension libraries automatically to prevent
+ # bogus linking commands. Extensions must
+ # explicitly specify the C libraries that they use.
+
+ # Determine if Fortran compiler is needed.
+ if build_clib and build_clib.fcompiler is not None:
+ need_f_compiler = 1
+ else:
+ need_f_compiler = 0
+ for ext in self.extensions:
+ if has_f_sources(ext.sources):
+ need_f_compiler = 1
+ break
+ if getattr(ext,'language','c') in ['f77','f90']:
+ need_f_compiler = 1
+ break
+
+ # Determine if C++ compiler is needed.
+ need_cxx_compiler = 0
+ for ext in self.extensions:
+ if has_cxx_sources(ext.sources):
+ need_cxx_compiler = 1
+ break
+ if getattr(ext,'language','c')=='c++':
+ need_cxx_compiler = 1
+ break
+
+ from distutils.ccompiler import new_compiler
+ self.compiler = new_compiler(compiler=self.compiler,
+ verbose=self.verbose,
+ dry_run=self.dry_run,
+ force=self.force)
+ self.compiler.customize(self.distribution,need_cxx=need_cxx_compiler)
+ self.compiler.customize_cmd(self)
+ self.compiler.show_customization()
+
+ # Initialize Fortran/C++ compilers if needed.
+ if need_f_compiler:
+ from scipy.distutils.fcompiler import new_fcompiler
+ self.fcompiler = new_fcompiler(compiler=self.fcompiler,
+ verbose=self.verbose,
+ dry_run=self.dry_run,
+ force=self.force)
+ if self.fcompiler.get_version():
+ self.fcompiler.customize(self.distribution)
+ self.fcompiler.customize_cmd(self)
+ self.fcompiler.show_customization()
+ else:
+ self.warn('fcompiler=%s is not available.' % (self.fcompiler.compiler_type))
+ self.fcompiler = None
+
+ # Build extensions
+ self.build_extensions()
+ return
+
+ def swig_sources(self, sources):
+ # Do nothing. Swig sources have beed handled in build_src command.
+ return sources
+
+ def build_extension(self, ext):
+ sources = ext.sources
+ if sources is None or type(sources) not in (ListType, TupleType):
+ raise DistutilsSetupError, \
+ ("in 'ext_modules' option (extension '%s'), " +
+ "'sources' must be present and must be " +
+ "a list of source filenames") % ext.name
+ sources = list(sources)
+
+ if not sources:
+ return
+
+ fullname = self.get_ext_fullname(ext.name)
+ if self.inplace:
+ modpath = string.split(fullname, '.')
+ package = string.join(modpath[0:-1], '.')
+ base = modpath[-1]
+
+ build_py = self.get_finalized_command('build_py')
+ package_dir = build_py.get_package_dir(package)
+ ext_filename = os.path.join(package_dir,
+ self.get_ext_filename(base))
+ else:
+ ext_filename = os.path.join(self.build_lib,
+ self.get_ext_filename(fullname))
+ depends = sources + ext.depends
+
+ if not (self.force or newer_group(depends, ext_filename, 'newer')):
+ log.debug("skipping '%s' extension (up-to-date)", ext.name)
+ return
+ else:
+ log.info("building '%s' extension", ext.name)
+
+ extra_args = ext.extra_compile_args or []
+ macros = ext.define_macros[:]
+ for undef in ext.undef_macros:
+ macros.append((undef,))
+
+ clib_libraries = []
+ clib_library_dirs = []
+ if self.distribution.libraries:
+ for libname,build_info in self.distribution.libraries:
+ if libname in ext.libraries:
+ macros.extend(build_info.get('macros',[]))
+ clib_libraries.extend(build_info.get('libraries',[]))
+ clib_library_dirs.extend(build_info.get('library_dirs',[]))
+
+ c_sources, cxx_sources, f_sources, fmodule_sources = \
+ filter_sources(ext.sources)
+ if self.compiler.compiler_type=='msvc':
+ if cxx_sources:
+ # Needed to compile kiva.agg._agg extension.
+ extra_args.append('/Zm1000')
+ # this hack works around the msvc compiler attributes
+ # problem, msvc uses its own convention :(
+ c_sources += cxx_sources
+ cxx_sources = []
+
+
+ kws = {'depends':ext.depends}
+ output_dir = self.build_temp
+
+ include_dirs = ext.include_dirs + get_scipy_include_dirs()
+
+ c_objects = []
+ if c_sources:
+ log.info("compiling C sources")
+ c_objects = self.compiler.compile(c_sources,
+ output_dir=output_dir,
+ macros=macros,
+ include_dirs=include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_args,
+ **kws)
+ if cxx_sources:
+ log.info("compiling C++ sources")
+
+ old_compiler = self.compiler.compiler_so[0]
+ self.compiler.compiler_so[0] = self.compiler.compiler_cxx[0]
+
+ c_objects += self.compiler.compile(cxx_sources,
+ output_dir=output_dir,
+ macros=macros,
+ include_dirs=include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_args,
+ **kws)
+ self.compiler.compiler_so[0] = old_compiler
+
+ check_for_f90_modules = not not fmodule_sources
+
+ if f_sources or fmodule_sources:
+ extra_postargs = []
+ module_dirs = ext.module_dirs[:]
+
+ #if self.fcompiler.compiler_type=='ibm':
+ macros = []
+
+ if check_for_f90_modules:
+ module_build_dir = os.path.join(\
+ self.build_temp,os.path.dirname(\
+ self.get_ext_filename(fullname)))
+
+ self.mkpath(module_build_dir)
+ if self.fcompiler.module_dir_switch is None:
+ existing_modules = glob('*.mod')
+ extra_postargs += self.fcompiler.module_options(\
+ module_dirs,module_build_dir)
+
+ f_objects = []
+ if fmodule_sources:
+ log.info("compiling Fortran 90 module sources")
+ f_objects = self.fcompiler.compile(fmodule_sources,
+ output_dir=self.build_temp,
+ macros=macros,
+ include_dirs=include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_postargs,
+ depends=ext.depends)
+
+ if check_for_f90_modules \
+ and self.fcompiler.module_dir_switch is None:
+ for f in glob('*.mod'):
+ if f in existing_modules:
+ continue
+ try:
+ self.move_file(f, module_build_dir)
+ except DistutilsFileError: # already exists in destination
+ os.remove(f)
+
+ if f_sources:
+ log.info("compiling Fortran sources")
+ f_objects += self.fcompiler.compile(f_sources,
+ output_dir=self.build_temp,
+ macros=macros,
+ include_dirs=include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_postargs,
+ depends=ext.depends)
+ else:
+ f_objects = []
+
+ objects = c_objects + f_objects
+
+ if ext.extra_objects:
+ objects.extend(ext.extra_objects)
+ extra_args = ext.extra_link_args or []
+
+ try:
+ old_linker_so_0 = self.compiler.linker_so[0]
+ except:
+ pass
+
+ use_fortran_linker = getattr(ext,'language','c') in ['f77','f90'] \
+ and self.fcompiler is not None
+ c_libraries = []
+ c_library_dirs = []
+ if use_fortran_linker or f_sources:
+ use_fortran_linker = 1
+ elif self.distribution.has_c_libraries():
+ build_clib = self.get_finalized_command('build_clib')
+ f_libs = []
+ for (lib_name, build_info) in build_clib.libraries:
+ if has_f_sources(build_info.get('sources',[])):
+ f_libs.append(lib_name)
+ if lib_name in ext.libraries:
+ # XXX: how to determine if c_libraries contain
+ # fortran compiled sources?
+ c_libraries.extend(build_info.get('libraries',[]))
+ c_library_dirs.extend(build_info.get('library_dirs',[]))
+ for l in ext.libraries:
+ if l in f_libs:
+ use_fortran_linker = 1
+ break
+
+ # Always use system linker when using MSVC compiler.
+ if self.compiler.compiler_type=='msvc' and use_fortran_linker:
+ c_libraries.extend(self.fcompiler.libraries)
+ c_library_dirs.extend(self.fcompiler.library_dirs)
+ use_fortran_linker = 0
+
+ if use_fortran_linker:
+ if cxx_sources:
+ # XXX: Which linker should be used, Fortran or C++?
+ log.warn('mixing Fortran and C++ is untested')
+ link = self.fcompiler.link_shared_object
+ language = ext.language or self.fcompiler.detect_language(f_sources)
+ else:
+ link = self.compiler.link_shared_object
+ if sys.version[:3]>='2.3':
+ language = ext.language or self.compiler.detect_language(sources)
+ else:
+ language = ext.language
+ if cxx_sources:
+ self.compiler.linker_so[0] = self.compiler.compiler_cxx[0]
+
+ if sys.version[:3]>='2.3':
+ kws = {'target_lang':language}
+ else:
+ kws = {}
+
+ link(objects, ext_filename,
+ libraries=self.get_libraries(ext) + c_libraries + clib_libraries,
+ library_dirs=ext.library_dirs + c_library_dirs + clib_library_dirs,
+ runtime_library_dirs=ext.runtime_library_dirs,
+ extra_postargs=extra_args,
+ export_symbols=self.get_export_symbols(ext),
+ debug=self.debug,
+ build_temp=self.build_temp,**kws)
+
+ try:
+ self.compiler.linker_so[0] = old_linker_so_0
+ except:
+ pass
+
+ return
+
+ def get_source_files (self):
+ self.check_extensions_list(self.extensions)
+ filenames = []
+ for ext in self.extensions:
+ filenames.extend(get_ext_source_files(ext))
+ return filenames
+
+ def get_outputs (self):
+ self.check_extensions_list(self.extensions)
+
+ outputs = []
+ for ext in self.extensions:
+ if not ext.sources:
+ continue
+ fullname = self.get_ext_fullname(ext.name)
+ outputs.append(os.path.join(self.build_lib,
+ self.get_ext_filename(fullname)))
+ return outputs
+