diff options
author | cookedm <cookedm@localhost> | 2007-05-21 13:15:45 +0000 |
---|---|---|
committer | cookedm <cookedm@localhost> | 2007-05-21 13:15:45 +0000 |
commit | 6ac33ee4e12b78b164a05046f7e029681f0e09a3 (patch) | |
tree | d5a4b6f27ff9e3d596bafdb4c93953d5431d0a40 | |
parent | b93a94b5e15d229e253353289c571c7a3142a642 (diff) | |
download | numpy-6ac33ee4e12b78b164a05046f7e029681f0e09a3.tar.gz |
[distutils-revamp] Merged revisions 3769-3794 via svnmerge from
http://svn.scipy.org/svn/numpy/trunk/numpy/distutils
........
r3775 | pearu | 2007-05-18 10:32:33 -0400 (Fri, 18 May 2007) | 1 line
build_src: introduced --swig and other related options (as in std distutils build_ext command), use --f2py-opts instead of --f2pyflags, improved error messages.
........
r3776 | pearu | 2007-05-18 12:41:44 -0400 (Fri, 18 May 2007) | 1 line
Extension modules and libraries are built with suitable compilers/linkers. Improved failure handling.
........
r3779 | pearu | 2007-05-18 13:33:15 -0400 (Fri, 18 May 2007) | 1 line
Fixed warnings on language changes.
........
r3780 | pearu | 2007-05-18 16:17:48 -0400 (Fri, 18 May 2007) | 1 line
unify config_fc, build_clib, build_ext commands --fcompiler options so that --fcompiler can be specified only once in a command line
........
r3781 | pearu | 2007-05-18 16:41:10 -0400 (Fri, 18 May 2007) | 1 line
added config to --fcompiler option unification method. introduced config_cc for unifying --compiler options.
........
r3782 | pearu | 2007-05-18 16:49:09 -0400 (Fri, 18 May 2007) | 1 line
Added --help-fcompiler option to build_ext command.
........
r3783 | pearu | 2007-05-18 17:00:17 -0400 (Fri, 18 May 2007) | 1 line
show less messages in --help-fcompiler
........
r3784 | pearu | 2007-05-18 17:25:23 -0400 (Fri, 18 May 2007) | 1 line
Added --fcompiler,--help-fcompiler options to build command parallel to --compiler,--help-compiler options.
........
r3785 | pearu | 2007-05-18 17:33:07 -0400 (Fri, 18 May 2007) | 1 line
Add descriptions to config_fc and config_cc commands.
........
r3786 | pearu | 2007-05-19 05:54:00 -0400 (Sat, 19 May 2007) | 1 line
Fix for win32 platform.
........
r3787 | pearu | 2007-05-19 06:23:16 -0400 (Sat, 19 May 2007) | 1 line
Fix fcompiler/compiler unification warning.
........
r3788 | pearu | 2007-05-19 11:20:48 -0400 (Sat, 19 May 2007) | 1 line
Fix atlas version detection when using MSVC compiler
........
r3789 | pearu | 2007-05-19 11:21:41 -0400 (Sat, 19 May 2007) | 1 line
Fix typo.
........
r3790 | pearu | 2007-05-19 11:24:20 -0400 (Sat, 19 May 2007) | 1 line
More typo fixes.
........
r3791 | pearu | 2007-05-19 13:01:39 -0400 (Sat, 19 May 2007) | 1 line
win32: fix install when build has been carried out earlier.
........
r3792 | pearu | 2007-05-19 15:44:42 -0400 (Sat, 19 May 2007) | 1 line
Clean up and completed (hopefully) MSVC support.
........
r3794 | cookedm | 2007-05-21 09:01:20 -0400 (Mon, 21 May 2007) | 1 line
minor cleanups in numpy.distutils (style mostly)
........
-rw-r--r-- | ccompiler.py | 1 | ||||
-rw-r--r-- | command/build.py | 18 | ||||
-rw-r--r-- | command/build_clib.py | 178 | ||||
-rw-r--r-- | command/build_ext.py | 459 | ||||
-rw-r--r-- | command/build_src.py | 148 | ||||
-rw-r--r-- | command/config.py | 86 | ||||
-rw-r--r-- | command/config_compiler.py | 158 | ||||
-rw-r--r-- | core.py | 1 | ||||
-rw-r--r-- | fcompiler/__init__.py | 3 | ||||
-rw-r--r-- | misc_util.py | 13 | ||||
-rw-r--r-- | system_info.py | 2 |
11 files changed, 633 insertions, 434 deletions
diff --git a/ccompiler.py b/ccompiler.py index ca3da7f24..bf077bacc 100644 --- a/ccompiler.py +++ b/ccompiler.py @@ -288,6 +288,7 @@ def CCompiler_get_version(self, force=0, ok_status=[0]): replace_method(CCompiler, 'get_version', CCompiler_get_version) def CCompiler_cxx_compiler(self): + if self.compiler_type=='msvc': return self cxx = copy(self) cxx.compiler_so = [cxx.compiler_cxx[0]] + cxx.compiler_so[1:] if sys.platform.startswith('aix') and 'ld_so_aix' in cxx.linker_so[0]: diff --git a/command/build.py b/command/build.py index d30d9f9ca..1f5c08205 100644 --- a/command/build.py +++ b/command/build.py @@ -2,13 +2,29 @@ import os import sys from distutils.command.build import build as old_build from distutils.util import get_platform +from numpy.distutils.command.config_compiler import show_fortran_compilers class build(old_build): - sub_commands = [('config_fc', lambda *args: 1), + sub_commands = [('config_cc', lambda *args: True), + ('config_fc', lambda *args: True), ('build_src', old_build.has_ext_modules), ] + old_build.sub_commands + user_options = old_build.user_options + [ + ('fcompiler=', None, + "specify the Fortran compiler type"), + ] + + help_options = old_build.help_options + [ + ('help-fcompiler',None, "list available Fortran compilers", + show_fortran_compilers), + ] + + def initialize_options(self): + old_build.initialize_options(self) + self.fcompiler = None + def finalize_options(self): build_scripts = self.build_scripts old_build.finalize_options(self) diff --git a/command/build_clib.py b/command/build_clib.py index 2aff51e08..02e88a204 100644 --- a/command/build_clib.py +++ b/command/build_clib.py @@ -1,19 +1,15 @@ """ Modified version of build_clib that handles fortran source files. """ +import os from distutils.command.build_clib import build_clib as old_build_clib -from distutils.errors import DistutilsSetupError +from distutils.errors import DistutilsSetupError, DistutilsError from numpy.distutils import log from distutils.dep_util import newer_group from numpy.distutils.misc_util import filter_sources, has_f_sources,\ has_cxx_sources, all_strings, get_lib_source_files, is_sequence -try: - set -except NameError: - from sets import Set as set - # Fix Python distutils bug sf #1718574: _l = old_build_clib.user_options for _i in range(len(_l)): @@ -33,45 +29,31 @@ class build_clib(old_build_clib): def initialize_options(self): old_build_clib.initialize_options(self) self.fcompiler = None - - def finalize_options(self): - old_build_clib.finalize_options(self) - self._languages = None - self.set_undefined_options('config_fc', - ('fcompiler', 'fcompiler')) - # we set this to the appropiate Fortran compiler object - # (f77 or f90) in the .run() method - self._fcompiler = None - - def languages(self): - """Return a set of language names used in this library. - Valid language names are 'c', 'f77', and 'f90'. - """ - if self._languages is None: - languages = set() - for (lib_name, build_info) in self.libraries: - l = build_info.get('language',None) - if l: - languages.add(l) - self._languages = languages - return self._languages + return def have_f_sources(self): - l = self.languages() - return 'f90' in l or 'f77' in l + for (lib_name, build_info) in self.libraries: + if has_f_sources(build_info.get('sources',[])): + return True + return False def have_cxx_sources(self): - l = self.languages() - return 'c++' in l + for (lib_name, build_info) in self.libraries: + if has_cxx_sources(build_info.get('sources',[])): + return True + return False def run(self): if not self.libraries: return # Make sure that library sources are complete. - self.run_command('build_src') - - languages = self.languages() + languages = [] + for (lib_name, build_info) in self.libraries: + if not all_strings(build_info.get('sources',[])): + self.run_command('build_src') + l = build_info.get('language',None) + if l and l not in languages: languages.append(l) from distutils.ccompiler import new_compiler self.compiler = new_compiler(compiler=self.compiler, @@ -88,17 +70,20 @@ class build_clib(old_build_clib): self.compiler.show_customization() if self.have_f_sources(): - if 'f90' in languages: - fc = self.fcompiler.f90() - else: - fc = self.fcompiler.f77() + from numpy.distutils.fcompiler import new_fcompiler + self.fcompiler = new_fcompiler(compiler=self.fcompiler, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90='f90' in languages) + self.fcompiler.customize(self.distribution) + libraries = self.libraries self.libraries = None - fc.customize_cmd(self) + self.fcompiler.customize_cmd(self) self.libraries = libraries - fc.show_customization() - self._fcompiler = fc + self.fcompiler.show_customization() self.build_libraries(self.libraries) @@ -110,10 +95,10 @@ class build_clib(old_build_clib): return filenames def build_libraries(self, libraries): - fcompiler = self._fcompiler - compiler = self.compiler - for (lib_name, build_info) in libraries: + # default compilers + compiler = self.compiler + fcompiler = self.fcompiler sources = build_info.get('sources') if sources is None or not is_sequence(sources): @@ -123,9 +108,21 @@ class build_clib(old_build_clib): "a list of source filenames") % lib_name sources = list(sources) + c_sources, cxx_sources, f_sources, fmodule_sources \ + = filter_sources(sources) + requiref90 = not not fmodule_sources or \ + build_info.get('language','c')=='f90' + + # save source type information so that build_ext can use it. + source_languages = [] + if c_sources: source_languages.append('c') + if cxx_sources: source_languages.append('c++') + if requiref90: source_languages.append('f90') + elif f_sources: source_languages.append('f77') + build_info['source_languages'] = source_languages + lib_file = compiler.library_filename(lib_name, output_dir=self.build_clib) - depends = sources + build_info.get('depends',[]) if not (self.force or newer_group(depends, lib_file, 'newer')): log.debug("skipping '%s' library (up-to-date)", lib_name) @@ -133,34 +130,42 @@ class build_clib(old_build_clib): else: log.info("building '%s' library", lib_name) - config_fc = build_info.get('config_fc',{}) if fcompiler is not None and config_fc: log.info('using additional config_fc from setup script '\ 'for fortran compiler: %s' \ % (config_fc,)) + from numpy.distutils.fcompiler import new_fcompiler + fcompiler = new_fcompiler(compiler=fcompiler.compiler_type, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90=requiref90) dist = self.distribution base_config_fc = dist.get_option_dict('config_fc').copy() base_config_fc.update(config_fc) fcompiler.customize(base_config_fc) + # check availability of Fortran compilers + if (f_sources or fmodule_sources) and fcompiler is None: + raise DistutilsError, "library %s has Fortran sources"\ + " but no Fortran compiler found" % (lib_name) + macros = build_info.get('macros') include_dirs = build_info.get('include_dirs') extra_postargs = build_info.get('extra_compiler_args') or [] - c_sources, cxx_sources, f_sources, fmodule_sources \ - = filter_sources(sources) + # where compiled F90 module files are: + module_dirs = build_info.get('module_dirs') or [] + module_build_dir = os.path.dirname(lib_file) + if requiref90: self.mkpath(module_build_dir) - if self.compiler.compiler_type=='msvc': + if compiler.compiler_type=='msvc': # this hack works around the msvc compiler attributes # problem, msvc uses its own convention :( c_sources += cxx_sources cxx_sources = [] - if fmodule_sources: - print 'XXX: Fortran 90 module support not implemented or tested' - f_sources.extend(fmodule_sources) - objects = [] if c_sources: log.info("compiling C sources") @@ -182,20 +187,61 @@ class build_clib(old_build_clib): extra_postargs=extra_postargs) objects.extend(cxx_objects) - if f_sources: - log.info("compiling Fortran sources") - f_objects = fcompiler.compile(f_sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=include_dirs, - debug=self.debug, - extra_postargs=[]) - objects.extend(f_objects) + if f_sources or fmodule_sources: + extra_postargs = [] + f_objects = [] + + if requiref90: + if fcompiler.module_dir_switch is None: + existing_modules = glob('*.mod') + extra_postargs += fcompiler.module_options(\ + module_dirs,module_build_dir) + + if fmodule_sources: + log.info("compiling Fortran 90 module sources") + f_objects += fcompiler.compile(fmodule_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs) + + if requiref90 and self.fcompiler.module_dir_switch is None: + # move new compiled F90 module files to module_build_dir + for f in glob('*.mod'): + if f in existing_modules: + continue + t = os.path.join(module_build_dir, f) + if os.path.abspath(f)==os.path.abspath(t): + continue + if os.path.isfile(t): + os.remove(t) + try: + self.move_file(f, module_build_dir) + except DistutilsFileError: + log.warn('failed to move %r to %r' \ + % (f, module_build_dir)) + + if f_sources: + log.info("compiling Fortran sources") + f_objects += fcompiler.compile(f_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs) + else: + f_objects = [] + + objects.extend(f_objects) - self.compiler.create_static_lib(objects, lib_name, - output_dir=self.build_clib, - debug=self.debug) + # assume that default linker is suitable for + # linking Fortran object files + compiler.create_static_lib(objects, lib_name, + output_dir=self.build_clib, + debug=self.debug) + # fix library dependencies clib_libraries = build_info.get('libraries',[]) for lname, binfo in libraries: if lname in clib_libraries: diff --git a/command/build_ext.py b/command/build_ext.py index 729f383c6..6febe9124 100644 --- a/command/build_ext.py +++ b/command/build_ext.py @@ -2,25 +2,27 @@ """ import os -import string import sys from glob import glob from distutils.dep_util import newer_group from distutils.command.build_ext import build_ext as old_build_ext -from distutils.errors import DistutilsFileError, DistutilsSetupError +from distutils.errors import DistutilsFileError, DistutilsSetupError,\ + DistutilsError from distutils.file_util import copy_file from numpy.distutils import log from numpy.distutils.exec_command import exec_command from numpy.distutils.system_info import combine_paths from numpy.distutils.misc_util import filter_sources, has_f_sources, \ - has_cxx_sources, get_ext_source_files, all_strings, \ + has_cxx_sources, get_ext_source_files, \ get_numpy_include_dirs, is_sequence +from numpy.distutils.command.config_compiler import show_fortran_compilers - -def ext_language(ext): - return getattr(ext, 'language', 'c') +try: + set +except NameError: + from sets import Set as set class build_ext (old_build_ext): @@ -31,6 +33,11 @@ class build_ext (old_build_ext): "specify the Fortran compiler type"), ] + help_options = old_build_ext.help_options + [ + ('help-fcompiler',None, "list available Fortran compilers", + show_fortran_compilers), + ] + def initialize_options(self): old_build_ext.initialize_options(self) self.fcompiler = None @@ -40,44 +47,6 @@ class build_ext (old_build_ext): old_build_ext.finalize_options(self) if incl_dirs is not None: self.include_dirs.extend(self.distribution.include_dirs or []) - self.set_undefined_options('config_fc', - ('fcompiler', 'fcompiler')) - self._fcompiler = None - - def initialize_fcompiler(self, build_clib): - # Determine if Fortran compiler is needed. - requiref77 = requiref90 = False - if build_clib: - lang = build_clib.languages() - requiref77 = 'f77' in lang - requiref90 = 'f90' in lang - else: - for ext in self.extensions: - language = ext_language(ext) - if language == 'f77': - requiref77 = True - elif language == 'f90': - requiref90 = True - elif has_f_sources(ext.sources): - # because we don't know any better, assume F77 - requiref77 = True - - if not (requiref77 or requiref90): - return - - if requiref90: - self.fcompiler.need_f90() - if requiref77: - self.fcompiler.need_f77() - - fc = self.fcompiler.fortran(requiref90) - if fc.get_version(): - fc.customize_cmd(self) - fc.show_customization() - else: - self.warn('fcompiler=%s is not available.' % ( - fc.compiler_type,)) - self._fcompiler = fc def run(self): if not self.extensions: @@ -86,10 +55,6 @@ class build_ext (old_build_ext): # Make sure that extension sources are complete. self.run_command('build_src') - # 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. if self.distribution.has_c_libraries(): self.run_command('build_clib') build_clib = self.get_finalized_command('build_clib') @@ -97,26 +62,148 @@ class build_ext (old_build_ext): else: build_clib = None - # Determine if C++ compiler is needed. - need_cxx_compiler = False - for ext in self.extensions: - if has_cxx_sources(ext.sources): - need_cxx_compiler = True - break - if getattr(ext,'language','c') == 'c++': - need_cxx_compiler = True - break + # 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. from distutils.ccompiler import new_compiler - self.compiler = new_compiler(compiler=self.compiler, + from numpy.distutils.fcompiler import new_fcompiler + + compiler_type = self.compiler + # Initialize C compiler: + self.compiler = new_compiler(compiler=compiler_type, verbose=self.verbose, dry_run=self.dry_run, force=self.force) - self.compiler.customize(self.distribution,need_cxx=need_cxx_compiler) + self.compiler.customize(self.distribution) self.compiler.customize_cmd(self) self.compiler.show_customization() - self.initialize_fcompiler(build_clib) + # Create mapping of libraries built by build_clib: + clibs = {} + if build_clib is not None: + for libname,build_info in build_clib.libraries or []: + if clibs.has_key(libname): + log.warn('library %r defined more than once,'\ + ' overwriting build_info %r with %r.' \ + % (libname, clibs[libname], build_info)) + clibs[libname] = build_info + # .. and distribution libraries: + for libname,build_info in self.distribution.libraries or []: + if clibs.has_key(libname): + # build_clib libraries have a precedence before distribution ones + continue + clibs[libname] = build_info + + # Determine if C++/Fortran 77/Fortran 90 compilers are needed. + # Update extension libraries, library_dirs, and macros. + all_languages = set() + for ext in self.extensions: + ext_languages = set() + c_libs = [] + c_lib_dirs = [] + macros = [] + for libname in ext.libraries: + if clibs.has_key(libname): + binfo = clibs[libname] + c_libs += binfo.get('libraries',[]) + c_lib_dirs += binfo.get('library_dirs',[]) + for m in binfo.get('macros',[]): + if m not in macros: + macros.append(m) + for l in clibs.get(libname,{}).get('source_languages',[]): + ext_languages.add(l) + if c_libs: + new_c_libs = ext.libraries + c_libs + log.info('updating extension %r libraries from %r to %r' + % (ext.name, ext.libraries, new_c_libs)) + ext.libraries = new_c_libs + ext.library_dirs = ext.library_dirs + c_lib_dirs + if macros: + log.info('extending extension %r defined_macros with %r' + % (ext.name, macros)) + ext.define_macros = ext.define_macros + macros + + # determine extension languages + if has_f_sources(ext.sources): + ext_languages.add('f77') + if has_cxx_sources(ext.sources): + ext_languages.add('c++') + l = ext.language or self.compiler.detect_language(ext.sources) + if l: + ext_languages.add(l) + # reset language attribute for choosing proper linker + if 'c++' in ext_languages: + ext_language = 'c++' + elif 'f90' in ext_languages: + ext_language = 'f90' + elif 'f77' in ext_languages: + ext_language = 'f77' + else: + ext_language = 'c' # default + if l and l != ext_language and ext.language: + log.warn('resetting extension %r language from %r to %r.' % + (ext.name,l,ext_language)) + ext.language = ext_language + # global language + all_languages.update(ext_languages) + + need_f90_compiler = 'f90' in all_languages + need_f77_compiler = 'f77' in all_languages + need_cxx_compiler = 'c++' in all_languages + + # Initialize C++ compiler: + if need_cxx_compiler: + self._cxx_compiler = new_compiler(compiler=compiler_type, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force) + compiler = self._cxx_compiler + compiler.customize(self.distribution,need_cxx=need_cxx_compiler) + compiler.customize_cmd(self) + compiler.show_customization() + self._cxx_compiler = compiler.cxx_compiler() + else: + self._cxx_compiler = None + + # Initialize Fortran 77 compiler: + if need_f77_compiler: + self._f77_compiler = new_fcompiler(compiler=self.fcompiler, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90=False) + fcompiler = self._f77_compiler + if fcompiler.get_version(): + fcompiler.customize(self.distribution) + fcompiler.customize_cmd(self) + fcompiler.show_customization() + else: + self.warn('f77_compiler=%s is not available.' % + (fcompiler.compiler_type)) + self._f77_compiler = None + else: + self._f77_compiler = None + + # Initialize Fortran 90 compiler: + if need_f90_compiler: + self._f90_compiler = new_fcompiler(compiler=self.fcompiler, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90=True) + fcompiler = self._f90_compiler + if fcompiler.get_version(): + fcompiler.customize(self.distribution) + fcompiler.customize_cmd(self) + fcompiler.show_customization() + else: + self.warn('f90_compiler=%s is not available.' % + (fcompiler.compiler_type)) + self._f90_compiler = None + else: + self._f90_compiler = None # Build extensions self.build_extensions() @@ -125,68 +212,13 @@ class build_ext (old_build_ext): # Do nothing. Swig sources have beed handled in build_src command. return sources - def get_fortran_objects(self, ext, f_sources, fmodule_sources, - macros, include_dirs): - if not f_sources and not fmodule_sources: - return None, [] - - fcompiler = self._fcompiler - - extra_postargs = [] - module_dirs = ext.module_dirs[:] - - macros = [] - - if fmodule_sources: - module_build_dir = os.path.join( - self.build_temp,os.path.dirname( - self.get_ext_filename(fullname))) - - self.mkpath(module_build_dir) - if fcompiler.module_dir_switch is None: - existing_modules = glob('*.mod') - extra_postargs += fcompiler.module_options(\ - module_dirs,module_build_dir) - - f_objects = [] - if fmodule_sources: - log.info("compiling Fortran 90 module sources") - f_objects = 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 fmodule_sources and 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 += 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) - - return fcompiler, f_objects - def build_extension(self, ext): sources = ext.sources if sources is None or not is_sequence(sources): - raise DistutilsSetupError, \ - ("in 'ext_modules' option (extension '%s'), " + - "'sources' must be present and must be " + - "a list of source filenames") % ext.name + 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: @@ -194,10 +226,9 @@ class build_ext (old_build_ext): fullname = self.get_ext_fullname(ext.name) if self.inplace: - modpath = string.split(fullname, '.') - package = string.join(modpath[0:-1], '.') + modpath = fullname.split('.') + package = '.'.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, @@ -218,17 +249,11 @@ class build_ext (old_build_ext): 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. @@ -238,6 +263,28 @@ class build_ext (old_build_ext): c_sources += cxx_sources cxx_sources = [] + # Set Fortran/C++ compilers for compilation and linking. + if ext.language=='f90': + fcompiler = self._f90_compiler + elif ext.language=='f77': + fcompiler = self._f77_compiler + else: # in case ext.language is c++, for instance + fcompiler = self._f90_compiler or self._f77_compiler + cxx_compiler = self._cxx_compiler + + # check for the availability of required compilers + if cxx_sources and cxx_compiler is None: + raise DistutilsError, "extension %r has C++ sources" \ + "but no C++ compiler found" % (ext.name) + if (f_sources or fmodule_sources) and fcompiler is None: + raise DistutilsError, "extension %r has Fortran sources " \ + "but no Fortran compiler found" % (ext.name) + if ext.language in ['f77','f90'] and fcompiler is None: + self.warn("extension %r has Fortran libraries " \ + "but no Fortran linker found, using default linker" % (ext.name)) + if ext.language=='c++' and cxx_compiler is None: + self.warn("extension %r has C++ libraries " \ + "but no C++ linker found, using default linker" % (ext.name)) kws = {'depends':ext.depends} output_dir = self.build_temp @@ -254,11 +301,9 @@ class build_ext (old_build_ext): debug=self.debug, extra_postargs=extra_args, **kws) + if cxx_sources: log.info("compiling C++ sources") - - cxx_compiler = self.compiler.cxx_compiler() - c_objects += cxx_compiler.compile(cxx_sources, output_dir=output_dir, macros=macros, @@ -267,80 +312,117 @@ class build_ext (old_build_ext): extra_postargs=extra_args, **kws) - fcompiler, f_objects = self.get_fortran_objects(ext, - f_sources, - fmodule_sources, - macros, include_dirs) + extra_postargs = [] + f_objects = [] + if fmodule_sources: + log.info("compiling Fortran 90 module sources") + module_dirs = ext.module_dirs[:] + module_build_dir = os.path.join( + self.build_temp,os.path.dirname( + self.get_ext_filename(fullname))) + + self.mkpath(module_build_dir) + if fcompiler.module_dir_switch is None: + existing_modules = glob('*.mod') + extra_postargs += fcompiler.module_options( + module_dirs,module_build_dir) + f_objects += 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 fcompiler.module_dir_switch is None: + for f in glob('*.mod'): + if f in existing_modules: + continue + t = os.path.join(module_build_dir, f) + if os.path.abspath(f)==os.path.abspath(t): + continue + if os.path.isfile(t): + os.remove(t) + try: + self.move_file(f, module_build_dir) + except DistutilsFileError: + log.warn('failed to move %r to %r' % + (f, module_build_dir)) + if f_sources: + log.info("compiling Fortran sources") + f_objects += 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) objects = c_objects + f_objects if ext.extra_objects: objects.extend(ext.extra_objects) extra_args = ext.extra_link_args or [] + libraries = self.get_libraries(ext)[:] + library_dirs = ext.library_dirs[:] linker = self.compiler.link_shared_object - - use_fortran_linker = getattr(ext,'language','c') in ['f77','f90'] - c_libraries = [] - c_library_dirs = [] - if not use_fortran_linker and 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 = True - fcompiler = self.fcompiler.fortran() - break - - if use_fortran_linker and not fcompiler: - fcompiler = self.fcompiler.fortran() - # Always use system linker when using MSVC compiler. - if self.compiler.compiler_type=='msvc' and use_fortran_linker: - self._libs_with_msvc_and_fortran(c_libraries, c_library_dirs) - use_fortran_linker = False - - if use_fortran_linker: - if cxx_sources: - # XXX: Which linker should be used, Fortran or C++? - log.warn('mixing Fortran and C++ is untested') + if self.compiler.compiler_type=='msvc': + # expand libraries with fcompiler libraries as we are + # not using fcompiler linker + self._libs_with_msvc_and_fortran(fcompiler, libraries, library_dirs) + elif ext.language in ['f77','f90'] and fcompiler is not None: linker = fcompiler.link_shared_object - language = ext.language or fcompiler.detect_language(f_sources) - else: - linker = 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: - linker = self.compiler.cxx_compiler().link_shared_object + if ext.language=='c++' and cxx_compiler is not None: + linker = cxx_compiler.link_shared_object if sys.version[:3]>='2.3': - kws = {'target_lang':language} + kws = {'target_lang':ext.language} else: kws = {} linker(objects, ext_filename, - libraries=self.get_libraries(ext) + c_libraries + clib_libraries, - library_dirs=ext.library_dirs+c_library_dirs+clib_library_dirs, + libraries=libraries, + library_dirs=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) - def _libs_with_msvc_and_fortran(self, c_libraries, c_library_dirs): + def _libs_with_msvc_and_fortran(self, fcompiler, c_libraries, + c_library_dirs): + if fcompiler is None: return + + for libname in c_libraries: + if libname.startswith('msvc'): continue + fileexists = False + for libdir in c_library_dirs or []: + libfile = os.path.join(libdir,'%s.lib' % (libname)) + if os.path.isfile(libfile): + fileexists = True + break + if fileexists: continue + # make g77-compiled static libs available to MSVC + fileexists = False + for libdir in c_library_dirs: + libfile = os.path.join(libdir,'lib%s.a' % (libname)) + if os.path.isfile(libfile): + # copy libname.a file to name.lib so that MSVC linker + # can find it + libfile2 = os.path.join(self.build_temp, libname + '.lib') + copy_file(libfile, libfile2) + if self.build_temp not in c_library_dirs: + c_library_dirs.append(self.build_temp) + fileexists = True + break + if fileexists: continue + log.warn('could not find library %r in directories %s' + % (libname, c_library_dirs)) + # Always use system linker when using MSVC compiler. f_lib_dirs = [] - fcompiler = self.fcompiler.fortran() for dir in fcompiler.library_dirs: # correct path when compiling in Cygwin but with normal Win # Python @@ -352,17 +434,16 @@ class build_ext (old_build_ext): c_library_dirs.extend(f_lib_dirs) # make g77-compiled static libs available to MSVC - lib_added = False for lib in fcompiler.libraries: - if not lib.startswith('msvcr'): + if not lib.startswith('msvc'): c_libraries.append(lib) p = combine_paths(f_lib_dirs, 'lib' + lib + '.a') if p: dst_name = os.path.join(self.build_temp, lib + '.lib') - copy_file(p[0], dst_name) - if not lib_added: + if not os.path.isfile(dst_name): + copy_file(p[0], dst_name) + if self.build_temp not in c_library_dirs: c_library_dirs.append(self.build_temp) - lib_added = True def get_source_files (self): self.check_extensions_list(self.extensions) diff --git a/command/build_src.py b/command/build_src.py index 3f534c825..519116ad3 100644 --- a/command/build_src.py +++ b/command/build_src.py @@ -8,6 +8,7 @@ import sys from distutils.command import build_ext from distutils.dep_util import newer_group, newer from distutils.util import get_platform +from distutils.errors import DistutilsError, DistutilsSetupError try: from Pyrex.Compiler import Main @@ -23,6 +24,7 @@ from numpy.distutils.misc_util import fortran_ext_match, \ appendpath, is_string, is_sequence from numpy.distutils.from_template import process_file as process_f_file from numpy.distutils.conv_template import process_file as process_c_file +from numpy.distutils.exec_command import splitcmdline class build_src(build_ext.build_ext): @@ -30,8 +32,12 @@ class build_src(build_ext.build_ext): user_options = [ ('build-src=', 'd', "directory to \"build\" sources to"), - ('f2pyflags=', None, "additonal flags to f2py"), - ('swigflags=', None, "additional flags to swig"), + ('f2py-opts=', None, "list of f2py command line options"), + ('swig=', None, "path to the SWIG executable"), + ('swig-opts=', None, "list of SWIG command line options"), + ('swig-cpp', None, "make SWIG create C++ files (default is autodetected from sources)"), + ('f2pyflags=', None, "additional flags to f2py (use --f2py-opts= instead)"), # obsolete + ('swigflags=', None, "additional flags to swig (use --swig-opts= instead)"), # obsolete ('force', 'f', "forcibly build everything (ignore file timestamps)"), ('inplace', 'i', "ignore build-lib and put compiled extensions into the source " + @@ -53,8 +59,12 @@ class build_src(build_ext.build_ext): self.force = None self.inplace = None self.package_dir = None - self.f2pyflags = None - self.swigflags = None + self.f2pyflags = None # obsolete + self.f2py_opts = None + self.swigflags = None # obsolete + self.swig_opts = None + self.swig_cpp = None + self.swig = None def finalize_options(self): self.set_undefined_options('build', @@ -71,22 +81,48 @@ class build_src(build_ext.build_ext): if self.build_src is None: plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3]) self.build_src = os.path.join(self.build_base, 'src'+plat_specifier) - if self.inplace is None: - build_ext = self.get_finalized_command('build_ext') - self.inplace = build_ext.inplace # py_modules_dict is used in build_py.find_package_modules self.py_modules_dict = {} - if self.f2pyflags is None: - self.f2pyflags = [] + if self.f2pyflags: + if self.f2py_opts: + log.warn('ignoring --f2pyflags as --f2py-opts already used') + else: + self.f2py_opts = self.f2pyflags + self.f2pyflags = None + if self.f2py_opts is None: + self.f2py_opts = [] else: - self.f2pyflags = self.f2pyflags.split() # XXX spaces?? + self.f2py_opts = splitcmdline(self.f2py_opts) - if self.swigflags is None: - self.swigflags = [] + if self.swigflags: + if self.swig_opts: + log.warn('ignoring --swigflags as --swig-opts already used') + else: + self.swig_opts = self.swigflags + self.swigflags = None + + if self.swig_opts is None: + self.swig_opts = [] else: - self.swigflags = self.swigflags.split() # XXX spaces?? + self.swig_opts = splitcmdline(self.swig_opts) + + # use options from build_ext command + build_ext = self.get_finalized_command('build_ext') + if self.inplace is None: + self.inplace = build_ext.inplace + if self.swig_cpp is None: + self.swig_cpp = build_ext.swig_cpp + for c in ['swig','swig_opt']: + o = '--'+c.replace('_','-') + v = getattr(build_ext,c,None) + if v: + if getattr(self,c): + log.warn('both build_src and build_ext define %s option' % (o)) + else: + log.info('using "%s=%s" option from build_ext command' % (o,v)) + setattr(self, c, v) def run(self): if not (self.extensions or self.libraries): @@ -144,7 +180,7 @@ class build_src(build_ext.build_ext): filenames = get_data_files((d,files)) new_data_files.append((d, filenames)) else: - raise + raise TypeError(repr(data)) self.data_files[:] = new_data_files def build_py_modules_sources(self): @@ -354,16 +390,14 @@ class build_src(build_ext.build_ext): output_file=target_file) pyrex_result = Main.compile(source, options=options) if pyrex_result.num_errors != 0: - raise RuntimeError("%d errors in Pyrex compile" % - pyrex_result.num_errors) + raise DistutilsError,"%d errors while compiling %r with Pyrex" \ + % (pyrex_result.num_errors, source) elif os.path.isfile(target_file): - log.warn("Pyrex needed to compile %s but not available."\ - " Using old target %s"\ + log.warn("Pyrex required for compiling %r but not available,"\ + " using old target %r"\ % (source, target_file)) else: - raise SystemError,"Non-existing target %r. "\ - "Perhaps you need to install Pyrex."\ - % (target_file) + raise DistutilsError,"Pyrex required for compiling %r but not available" % (source) new_sources.append(target_file) else: new_sources.append(source) @@ -388,9 +422,9 @@ class build_src(build_ext.build_ext): if os.path.isfile(source): name = get_f2py_modulename(source) if name != ext_name: - raise ValueError('mismatch of extension names: %s ' - 'provides %r but expected %r' % ( - source, name, ext_name)) + raise DistutilsSetupError('mismatch of extension names: %s ' + 'provides %r but expected %r' % ( + source, name, ext_name)) target_file = os.path.join(target_dir,name+'module.c') else: log.debug(' source %s does not exist: skipping f2py\'ing.' \ @@ -399,16 +433,16 @@ class build_src(build_ext.build_ext): skip_f2py = 1 target_file = os.path.join(target_dir,name+'module.c') if not os.path.isfile(target_file): - log.debug(' target %s does not exist:\n '\ - 'Assuming %smodule.c was generated with '\ - '"build_src --inplace" command.' \ - % (target_file, name)) + log.warn(' target %s does not exist:\n '\ + 'Assuming %smodule.c was generated with '\ + '"build_src --inplace" command.' \ + % (target_file, name)) target_dir = os.path.dirname(base) target_file = os.path.join(target_dir,name+'module.c') if not os.path.isfile(target_file): - raise ValueError("%r missing" % (target_file,)) - log.debug(' Yes! Using %s as up-to-date target.' \ - % (target_file)) + raise DistutilsSetupError("%r missing" % (target_file,)) + log.info(' Yes! Using %r as up-to-date target.' \ + % (target_file)) target_dirs.append(target_dir) f2py_sources.append(source) f2py_targets[source] = target_file @@ -423,7 +457,7 @@ class build_src(build_ext.build_ext): map(self.mkpath, target_dirs) - f2py_options = extension.f2py_options + self.f2pyflags + f2py_options = extension.f2py_options + self.f2py_opts if self.distribution.libraries: for name,build_info in self.distribution.libraries: @@ -434,7 +468,7 @@ class build_src(build_ext.build_ext): if f2py_sources: if len(f2py_sources) != 1: - raise ValueError( + raise DistutilsSetupError( 'only one .pyf file is allowed per extension module but got'\ ' more: %r' % (f2py_sources,)) source = f2py_sources[0] @@ -472,7 +506,7 @@ class build_src(build_ext.build_ext): % (target_file)) if not os.path.isfile(target_file): - raise ValueError("%r missing" % (target_file,)) + raise DistutilsError("f2py target file %r not generated" % (target_file,)) target_c = os.path.join(self.build_src,'fortranobject.c') target_h = os.path.join(self.build_src,'fortranobject.h') @@ -494,9 +528,9 @@ class build_src(build_ext.build_ext): self.copy_file(source_h,target_h) else: if not os.path.isfile(target_c): - raise ValueError("%r missing" % (target_c,)) + raise DistutilsSetupError("f2py target_c file %r not found" % (target_c,)) if not os.path.isfile(target_h): - raise ValueError("%r missing" % (target_h,)) + raise DistutilsSetupError("f2py target_h file %r not found" % (target_h,)) for name_ext in ['-f2pywrappers.f','-f2pywrappers2.f90']: filename = os.path.join(target_dir,ext_name + name_ext) @@ -516,8 +550,12 @@ class build_src(build_ext.build_ext): target_dirs = [] py_files = [] # swig generated .py files target_ext = '.c' - typ = None - is_cpp = 0 + if self.swig_cpp: + typ = 'c++' + is_cpp = True + else: + typ = None + is_cpp = False skip_swig = 0 ext_name = extension.name.split('.')[-1] @@ -533,35 +571,43 @@ class build_src(build_ext.build_ext): if os.path.isfile(source): name = get_swig_modulename(source) if name != ext_name[1:]: - raise ValueError( + raise DistutilsSetupError( 'mismatch of extension names: %s provides %r' ' but expected %r' % (source, name, ext_name[1:])) if typ is None: typ = get_swig_target(source) is_cpp = typ=='c++' - if is_cpp: - target_ext = '.cpp' + if is_cpp: target_ext = '.cpp' else: - assert typ == get_swig_target(source), repr(typ) + typ2 = get_swig_target(source) + if typ!=typ2: + log.warn('expected %r but source %r defines %r swig target' \ + % (typ, source, typ2)) + if typ2=='c++': + log.warn('resetting swig target to c++ (some targets may have .c extension)') + is_cpp = True + target_ext = '.cpp' + else: + log.warn('assuming that %r has c++ swig target' % (source)) target_file = os.path.join(target_dir,'%s_wrap%s' \ % (name, target_ext)) else: - log.debug(' source %s does not exist: skipping swig\'ing.' \ + log.warn(' source %s does not exist: skipping swig\'ing.' \ % (source)) name = ext_name[1:] skip_swig = 1 target_file = _find_swig_target(target_dir, name) if not os.path.isfile(target_file): - log.debug(' target %s does not exist:\n '\ - 'Assuming %s_wrap.{c,cpp} was generated with '\ - '"build_src --inplace" command.' \ + log.warn(' target %s does not exist:\n '\ + 'Assuming %s_wrap.{c,cpp} was generated with '\ + '"build_src --inplace" command.' \ % (target_file, name)) target_dir = os.path.dirname(base) target_file = _find_swig_target(target_dir, name) if not os.path.isfile(target_file): - raise ValueError("%r missing" % (target_file,)) - log.debug(' Yes! Using %s as up-to-date target.' \ - % (target_file)) + raise DistutilsSetupError("%r missing" % (target_file,)) + log.warn(' Yes! Using %r as up-to-date target.' \ + % (target_file)) target_dirs.append(target_dir) new_sources.append(target_file) py_files.append(os.path.join(py_target_dir, name+'.py')) @@ -577,7 +623,7 @@ class build_src(build_ext.build_ext): return new_sources + py_files map(self.mkpath, target_dirs) - swig = self.find_swig() + swig = self.swig or self.find_swig() swig_cmd = [swig, "-python"] if is_cpp: swig_cmd.append('-c++') @@ -589,7 +635,7 @@ class build_src(build_ext.build_ext): if self.force or newer_group(depends, target, 'newer'): log.info("%s: %s" % (os.path.basename(swig) \ + (is_cpp and '++' or ''), source)) - self.spawn(swig_cmd + self.swigflags \ + self.spawn(swig_cmd + self.swig_opts \ + ["-o", target, '-outdir', py_target_dir, source]) else: log.debug(" skipping '%s' swig interface (up-to-date)" \ diff --git a/command/config.py b/command/config.py index 2a015e400..f4e96664c 100644 --- a/command/config.py +++ b/command/config.py @@ -3,56 +3,41 @@ # compilers (they must define linker_exe first). # Pearu Peterson -import os, signal, copy +import os, signal from distutils.command.config import config as old_config from distutils.command.config import LANG_EXT from distutils import log +from distutils.file_util import copy_file from numpy.distutils.exec_command import exec_command -from numpy.distutils.fcompiler import FCompiler, new_fcompiler LANG_EXT['f77'] = '.f' LANG_EXT['f90'] = '.f90' class config(old_config): old_config.user_options += [ - ('fcompiler=', None, - "specify the Fortran compiler type"), + ('fcompiler=', None, "specify the Fortran compiler type"), ] def initialize_options(self): self.fcompiler = None old_config.initialize_options(self) - def finalize_options(self): - old_config.finalize_options(self) - f = self.distribution.get_command_obj('config_fc') - self.set_undefined_options('config_fc', - ('fcompiler', 'fcompiler')) - self._fcompiler = None - - def run(self): - self._check_compiler() - - def _check_compiler(self): + def _check_compiler (self): old_config._check_compiler(self) - - def get_fcompiler(self): - if self._fcompiler is None: - fc = self.fcompiler.fortran() - fc.force = 1 - fc.dry_run = self.dry_run - fc.customize(self.distribution) - fc.customize_cmd(self) - fc.show_customization() - self._fcompiler = fc - return self._fcompiler - - def _wrap_method(self, mth, lang, args): + from numpy.distutils.fcompiler import FCompiler, new_fcompiler + if not isinstance(self.fcompiler, FCompiler): + self.fcompiler = new_fcompiler(compiler=self.fcompiler, + dry_run=self.dry_run, force=1) + self.fcompiler.customize(self.distribution) + self.fcompiler.customize_cmd(self) + self.fcompiler.show_customization() + + def _wrap_method(self,mth,lang,args): from distutils.ccompiler import CompileError from distutils.errors import DistutilsExecError save_compiler = self.compiler - if lang in ('f77', 'f90'): - self.compiler = self.get_fcompiler() + if lang in ['f77','f90']: + self.compiler = self.fcompiler try: ret = mth(*((self,)+args)) except (DistutilsExecError,CompileError),msg: @@ -68,6 +53,47 @@ class config(old_config): def _link (self, body, headers, include_dirs, libraries, library_dirs, lang): + if self.compiler.compiler_type=='msvc': + libraries = (libraries or [])[:] + library_dirs = (library_dirs or [])[:] + if lang in ['f77','f90']: + lang = 'c' # always use system linker when using MSVC compiler + if self.fcompiler: + for d in self.fcompiler.library_dirs or []: + # correct path when compiling in Cygwin but with + # normal Win Python + if d.startswith('/usr/lib'): + s,o = exec_command(['cygpath', '-w', d], + use_tee=False) + if not s: d = o + library_dirs.append(d) + for libname in self.fcompiler.libraries or []: + if libname not in libraries: + libraries.append(libname) + for libname in libraries: + if libname.startswith('msvc'): continue + fileexists = False + for libdir in library_dirs or []: + libfile = os.path.join(libdir,'%s.lib' % (libname)) + if os.path.isfile(libfile): + fileexists = True + break + if fileexists: continue + # make g77-compiled static libs available to MSVC + fileexists = False + for libdir in library_dirs: + libfile = os.path.join(libdir,'lib%s.a' % (libname)) + if os.path.isfile(libfile): + # copy libname.a file to name.lib so that MSVC linker + # can find it + libfile2 = os.path.join(libdir,'%s.lib' % (libname)) + copy_file(libfile, libfile2) + self.temp_files.append(libfile2) + fileexists = True + break + if fileexists: continue + log.warn('could not find library %r in directories %s' \ + % (libname, library_dirs)) return self._wrap_method(old_config._link,lang, (body, headers, include_dirs, libraries, library_dirs, lang)) diff --git a/command/config_compiler.py b/command/config_compiler.py index 611527dea..af99dbd32 100644 --- a/command/config_compiler.py +++ b/command/config_compiler.py @@ -1,80 +1,17 @@ import sys -import copy -import distutils.core from distutils.core import Command -from distutils.errors import DistutilsSetupError -from distutils import log -from numpy.distutils.fcompiler import show_fcompilers, new_fcompiler +from numpy.distutils import log -#XXX: Implement confic_cc for enhancing C/C++ compiler options. #XXX: Linker flags def show_fortran_compilers(_cache=[]): # Using cache to prevent infinite recursion - if _cache: - return + if _cache: return _cache.append(1) - show_fcompilers() - -class FCompilerProxy(object): - """ - A layer of indirection to simplify choosing the correct Fortran compiler. - - If need_f90(), f90(), or fortran(requiref90=True) is called at any time, - a Fortran 90 compiler is found and used for *all* Fortran sources, - including Fortran 77 sources. - """ - #XXX The ability to use a separate F77 compiler is likely not - # necessary: of all the compilers we support, only the 'gnu' - # compiler (g77) doesn't support F90, and everything else supports - # both. - - def __init__(self, compiler_type, distribution): - self._fcompiler = None - self._have_f77 = None - self._have_f90 = None - self._compiler_type = compiler_type - self.distribution = distribution - - def _set_fcompiler(self, requiref90=False): - fc = new_fcompiler(compiler=self._compiler_type, - dry_run=self.distribution.dry_run, - verbose=self.distribution.verbose, - requiref90=requiref90) - if fc is None: - raise DistutilsSetupError("could not find a Fortran compiler") - fc.customize(self.distribution) - self._fcompiler = fc - self._have_f77 = fc.compiler_f77 is not None - if requiref90: - self._have_f90 = fc.compiler_f90 is not None - log.info('%s (%s)' % (fc.description, fc.get_version())) - - def need_f77(self): - if self._fcompiler is None: - self._set_fcompiler(requiref90=False) - if not self._have_f77: - raise DistutilsSetupError("could not find a Fortran 77 compiler") - - def need_f90(self): - if self._fcompiler is None or self._have_f90 is None: - self._set_fcompiler(requiref90=True) - if not self._have_f90: - raise DistutilsSetupError("could not find a Fortran 90 compiler") - - def f77(self): - self.need_f77() - return copy.copy(self._fcompiler) - - def f90(self): - self.need_f90() - return copy.copy(self._fcompiler) - - def fortran(self, requiref90=False): - if requiref90: - return self.f90() - else: - return self.f77() + from numpy.distutils.fcompiler import show_fcompilers + import distutils.core + dist = distutils.core._setup_distribution + show_fcompilers(dist) class config_fc(Command): """ Distutils command to hold user specified options @@ -83,24 +20,19 @@ class config_fc(Command): config_fc command is used by the FCompiler.customize() method. """ + description = "specify Fortran 77/Fortran 90 compiler information" + user_options = [ ('fcompiler=',None,"specify Fortran compiler type"), ('f77exec=', None, "specify F77 compiler command"), ('f90exec=', None, "specify F90 compiler command"), ('f77flags=',None,"specify F77 compiler flags"), ('f90flags=',None,"specify F90 compiler flags"), - ('ldshared=',None,"shared-library linker command"), - ('ld=',None,"static library linker command"), - ('ar=',None,"archiver command (ar)"), - ('ranlib=',None,"ranlib command"), ('opt=',None,"specify optimization flags"), ('arch=',None,"specify architecture specific optimization flags"), ('debug','g',"compile with debugging information"), ('noopt',None,"compile without optimization"), ('noarch',None,"compile without arch-dependent optimization"), - ('fflags=',None,"extra flags for Fortran compiler"), - ('ldflags=',None,"linker flags"), - ('arflags=',None,"flags for ar"), ] help_options = [ @@ -116,21 +48,77 @@ class config_fc(Command): self.f90exec = None self.f77flags = None self.f90flags = None - self.ldshared = None - self.ld = None - self.ar = None - self.ranlib = None self.opt = None self.arch = None self.debug = None self.noopt = None self.noarch = None - self.fflags = None - self.ldflags = None - self.arflags = None def finalize_options(self): - self.fcompiler = FCompilerProxy(self.fcompiler, self.distribution) + log.info('unifing config_fc, config, build_clib, build_ext, build commands --fcompiler options') + build_clib = self.get_finalized_command('build_clib') + build_ext = self.get_finalized_command('build_ext') + config = self.get_finalized_command('config') + build = self.get_finalized_command('build') + cmd_list = [self, config, build_clib, build_ext, build] + for a in ['fcompiler']: + l = [] + for c in cmd_list: + v = getattr(c,a) + if v is not None: + if not isinstance(v, str): v = v.compiler_type + if v not in l: l.append(v) + if not l: v1 = None + else: v1 = l[0] + if len(l)>1: + log.warn(' commands have different --%s options: %s'\ + ', using first in list as default' % (a, l)) + if v1: + for c in cmd_list: + if getattr(c,a) is None: setattr(c, a, v1) + + def run(self): + # Do nothing. + return + +class config_cc(Command): + """ Distutils command to hold user specified options + to C/C++ compilers. + """ + + description = "specify C/C++ compiler information" + + user_options = [ + ('compiler=',None,"specify C/C++ compiler type"), + ] + + def initialize_options(self): + self.compiler = None + + def finalize_options(self): + log.info('unifing config_cc, config, build_clib, build_ext, build commands --compiler options') + build_clib = self.get_finalized_command('build_clib') + build_ext = self.get_finalized_command('build_ext') + config = self.get_finalized_command('config') + build = self.get_finalized_command('build') + cmd_list = [self, config, build_clib, build_ext, build] + for a in ['compiler']: + l = [] + for c in cmd_list: + v = getattr(c,a) + if v is not None: + if not isinstance(v, str): v = v.compiler_type + if v not in l: l.append(v) + if not l: v1 = None + else: v1 = l[0] + if len(l)>1: + log.warn(' commands have different --%s options: %s'\ + ', using first in list as default' % (a, l)) + if v1: + for c in cmd_list: + if getattr(c,a) is None: setattr(c, a, v1) + return def run(self): - pass + # Do nothing. + return @@ -39,6 +39,7 @@ from numpy.distutils.misc_util import get_data_files, is_sequence, is_string numpy_cmdclass = {'build': build.build, 'build_src': build_src.build_src, 'build_scripts': build_scripts.build_scripts, + 'config_cc': config_compiler.config_cc, 'config_fc': config_compiler.config_fc, 'config': config.config, 'build_ext': build_ext.build_ext, diff --git a/fcompiler/__init__.py b/fcompiler/__init__.py index 78e58f823..ab59372b7 100644 --- a/fcompiler/__init__.py +++ b/fcompiler/__init__.py @@ -770,7 +770,6 @@ def show_fcompilers(dist=None): dist.cmdclass['config_fc'] = config_fc dist.parse_config_files() dist.parse_command_line() - compilers = [] compilers_na = [] compilers_ni = [] @@ -779,12 +778,14 @@ def show_fcompilers(dist=None): platform_compilers = available_fcompilers_for_platform() for compiler in platform_compilers: v = None + log.set_verbosity(-2) try: c = new_fcompiler(compiler=compiler, verbose=dist.verbose) c.customize(dist) v = c.get_version() except (DistutilsModuleError, CompilerNotFound): pass + if v is None: compilers_na.append(("fcompiler="+compiler, None, fcompiler_class[compiler][2])) diff --git a/misc_util.py b/misc_util.py index fd771429e..bc3a9b8ad 100644 --- a/misc_util.py +++ b/misc_util.py @@ -309,8 +309,9 @@ def as_list(seq): return [seq] def get_language(sources): + # not used in numpy/scipy packages, use build_ext.detect_language instead """ Determine language value (c,f77,f90) from sources """ - language = 'c' + language = None for source in sources: if isinstance(source, str): if f90_ext_match(source): @@ -1020,11 +1021,7 @@ class Configuration(object): ext_args = copy.copy(kw) ext_args['name'] = dot_join(self.name,name) ext_args['sources'] = sources - - language = ext_args.get('language',None) - if language is None: - ext_args['language'] = get_language(sources) - + if ext_args.has_key('extra_info'): extra_info = ext_args['extra_info'] del ext_args['extra_info'] @@ -1089,10 +1086,6 @@ class Configuration(object): name = name #+ '__OF__' + self.name build_info['sources'] = sources - language = build_info.get('language',None) - if language is None: - build_info['language'] = get_language(sources) - self._fix_paths_dict(build_info) self.libraries.append((name,build_info)) diff --git a/system_info.py b/system_info.py index 3e53b3a18..a3a037e2a 100644 --- a/system_info.py +++ b/system_info.py @@ -1107,7 +1107,7 @@ class lapack_src_info(system_info): self.set_info(**info) atlas_version_c_text = r''' -/* This file is generated from numpy_distutils/system_info.py */ +/* This file is generated from numpy/distutils/system_info.py */ void ATL_buildinfo(void); int main(void) { ATL_buildinfo(); |