diff options
author | xoviat <xoviat@users.noreply.github.com> | 2017-07-22 15:30:07 -0500 |
---|---|---|
committer | Pauli Virtanen <pav@iki.fi> | 2017-09-02 16:56:22 +0300 |
commit | f3c8a0ab23966cae9992dae74da96807a44bc0d8 (patch) | |
tree | 8d00247115affdcb9d8f5b1b8c88586946b9143b /numpy/distutils/command | |
parent | 11593aa176d491beb0cc5ffcc393956a5435a2bf (diff) | |
download | numpy-f3c8a0ab23966cae9992dae74da96807a44bc0d8.tar.gz |
distutils: gnu: patch fcompile
This allows mingw's gfortran to work with MSVC. DLLs are
autogenerated using heuristics that should work with most
cases. In addition, a libopenblas DLL is compiled from
the static lib for use with MSVC.
All generated DLLs have randomized names so that no clashes
will occur.
Diffstat (limited to 'numpy/distutils/command')
-rw-r--r-- | numpy/distutils/command/build_clib.py | 78 | ||||
-rw-r--r-- | numpy/distutils/command/build_ext.py | 120 |
2 files changed, 117 insertions, 81 deletions
diff --git a/numpy/distutils/command/build_clib.py b/numpy/distutils/command/build_clib.py index 1c868cf6c..594c3f67f 100644 --- a/numpy/distutils/command/build_clib.py +++ b/numpy/distutils/command/build_clib.py @@ -7,21 +7,22 @@ from glob import glob import shutil from distutils.command.build_clib import build_clib as old_build_clib from distutils.errors import DistutilsSetupError, DistutilsError, \ - DistutilsFileError + DistutilsFileError 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, \ - get_numpy_include_dirs + has_cxx_sources, all_strings, get_lib_source_files, is_sequence, \ + get_numpy_include_dirs, get_library_names # Fix Python distutils bug sf #1718574: _l = old_build_clib.user_options for _i in range(len(_l)): if _l[_i][0] in ['build-clib', 'build-temp']: - _l[_i] = (_l[_i][0]+'=',)+_l[_i][1:] + _l[_i] = (_l[_i][0] + '=',) + _l[_i][1:] # + class build_clib(old_build_clib): description = "build C/C++/F libraries used by Python extensions" @@ -32,7 +33,7 @@ class build_clib(old_build_clib): ('inplace', 'i', 'Build in-place'), ('parallel=', 'j', "number of parallel jobs"), - ] + ] boolean_options = old_build_clib.boolean_options + ['inplace'] @@ -75,7 +76,8 @@ class build_clib(old_build_clib): for (lib_name, build_info) in self.libraries: l = build_info.get('language', None) - if l and l not in languages: languages.append(l) + if l and l not in languages: + languages.append(l) from distutils.ccompiler import new_compiler self.compiler = new_compiler(compiler=self.compiler, @@ -94,11 +96,11 @@ class build_clib(old_build_clib): if self.have_f_sources(): from numpy.distutils.fcompiler import new_fcompiler self._f_compiler = new_fcompiler(compiler=self.fcompiler, - verbose=self.verbose, - dry_run=self.dry_run, - force=self.force, - requiref90='f90' in languages, - c_compiler=self.compiler) + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90='f90' in languages, + c_compiler=self.compiler) if self._f_compiler is not None: self._f_compiler.customize(self.distribution) @@ -114,10 +116,10 @@ class build_clib(old_build_clib): self.build_libraries(self.libraries) if self.inplace: - for l in self.distribution.installed_libraries: + for l in self.distribution.installed_libraries: libname = self.compiler.library_filename(l.name) source = os.path.join(self.build_clib, libname) - target = os.path.join(l.target_dir, libname) + target = os.path.join(l.target_dir, libname) self.mkpath(l.target_dir) shutil.copy(source, target) @@ -129,6 +131,11 @@ class build_clib(old_build_clib): return filenames def build_libraries(self, libraries): + library_names = get_library_names() + library_order = {v: k for k, v in enumerate(library_names)} + libraries = sorted( + libraries, key=lambda library: library_order[library[0]]) + for (lib_name, build_info) in libraries: self.build_a_library(build_info, lib_name, libraries) @@ -140,21 +147,25 @@ class build_clib(old_build_clib): sources = build_info.get('sources') if sources is None or not is_sequence(sources): raise DistutilsSetupError(("in 'libraries' option (library '%s'), " + - "'sources' must be present and must be " + - "a list of source filenames") % lib_name) + "'sources' must be present and must be " + + "a list of source filenames") % lib_name) sources = list(sources) c_sources, cxx_sources, f_sources, fmodule_sources \ - = filter_sources(sources) + = filter_sources(sources) requiref90 = not not fmodule_sources or \ - build_info.get('language', 'c')=='f90' + 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') + 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, @@ -168,8 +179,8 @@ class build_clib(old_build_clib): 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' \ + 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, @@ -186,12 +197,14 @@ class build_clib(old_build_clib): # 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)) + raise DistutilsError("library %s has Fortran sources" + " but no Fortran compiler found" % (lib_name)) if fcompiler is not None: - fcompiler.extra_f77_compile_args = build_info.get('extra_f77_compile_args') or [] - fcompiler.extra_f90_compile_args = build_info.get('extra_f90_compile_args') or [] + fcompiler.extra_f77_compile_args = build_info.get( + 'extra_f77_compile_args') or [] + fcompiler.extra_f90_compile_args = build_info.get( + 'extra_f90_compile_args') or [] macros = build_info.get('macros') include_dirs = build_info.get('include_dirs') @@ -203,9 +216,10 @@ class build_clib(old_build_clib): # 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 requiref90: + self.mkpath(module_build_dir) - if 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 @@ -239,7 +253,7 @@ class build_clib(old_build_clib): if requiref90: if fcompiler.module_dir_switch is None: existing_modules = glob('*.mod') - extra_postargs += fcompiler.module_options(\ + extra_postargs += fcompiler.module_options( module_dirs, module_build_dir) if fmodule_sources: @@ -257,14 +271,14 @@ class build_clib(old_build_clib): if f in existing_modules: continue t = os.path.join(module_build_dir, f) - if os.path.abspath(f)==os.path.abspath(t): + 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' \ + log.warn('failed to move %r to %r' % (f, module_build_dir)) if f_sources: diff --git a/numpy/distutils/command/build_ext.py b/numpy/distutils/command/build_ext.py index cf5bfa04f..cf0747d2f 100644 --- a/numpy/distutils/command/build_ext.py +++ b/numpy/distutils/command/build_ext.py @@ -5,24 +5,26 @@ from __future__ import division, absolute_import, print_function import os import sys +import shutil 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,\ - DistutilsError + 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.system_info import combine_paths, system_info from numpy.distutils.misc_util import filter_sources, has_f_sources, \ - has_cxx_sources, get_ext_source_files, \ - get_numpy_include_dirs, is_sequence, get_build_architecture, \ - msvc_version + has_cxx_sources, get_ext_source_files, \ + get_numpy_include_dirs, is_sequence, get_build_architecture, \ + msvc_version from numpy.distutils.command.config_compiler import show_fortran_compilers + class build_ext (old_build_ext): description = "build C/C++/F extensions (compile/link to build directory)" @@ -32,12 +34,12 @@ class build_ext (old_build_ext): "specify the Fortran compiler type"), ('parallel=', 'j', "number of parallel jobs"), - ] + ] 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) @@ -80,11 +82,13 @@ class build_ext (old_build_ext): if self.distribution.has_c_libraries(): if self.inplace: if self.distribution.have_run.get('build_clib'): - log.warn('build_clib already run, it is too late to ' \ - 'ensure in-place build of build_clib') - build_clib = self.distribution.get_command_obj('build_clib') + log.warn('build_clib already run, it is too late to ' + 'ensure in-place build of build_clib') + build_clib = self.distribution.get_command_obj( + 'build_clib') else: - build_clib = self.distribution.get_command_obj('build_clib') + build_clib = self.distribution.get_command_obj( + 'build_clib') build_clib.inplace = 1 build_clib.ensure_finalized() build_clib.run() @@ -120,8 +124,8 @@ class build_ext (old_build_ext): if build_clib is not None: for libname, build_info in build_clib.libraries or []: if libname in clibs and clibs[libname] != build_info: - log.warn('library %r defined more than once,'\ - ' overwriting build_info\n%s... \nwith\n%s...' \ + log.warn('library %r defined more than once,' + ' overwriting build_info\n%s... \nwith\n%s...' % (libname, repr(clibs[libname])[:300], repr(build_info)[:300])) clibs[libname] = build_info # .. and distribution libraries: @@ -177,7 +181,7 @@ class build_ext (old_build_ext): elif 'f77' in ext_languages: ext_language = 'f77' else: - ext_language = 'c' # default + 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)) @@ -192,9 +196,9 @@ class build_ext (old_build_ext): # 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) + 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) @@ -234,7 +238,7 @@ class build_ext (old_build_ext): dry_run=self.dry_run, force=self.force, requiref90=True, - c_compiler = self.compiler) + c_compiler=self.compiler) fcompiler = self._f90_compiler if fcompiler: ctype = fcompiler.compiler_type @@ -252,6 +256,18 @@ class build_ext (old_build_ext): # Build extensions self.build_extensions() + shared_libs = system_info.shared_libs + if shared_libs: + runtime_lib_dir = os.path.join( + self.build_lib, self.distribution.get_name(), '_lib') + try: + os.makedirs(runtime_lib_dir) + except OSError: + pass + + for runtime_lib in shared_libs: + if runtime_lib: + copy_file(runtime_lib, runtime_lib_dir) def swig_sources(self, sources): # Do nothing. Swig sources have beed handled in build_src command. @@ -295,11 +311,9 @@ class build_ext (old_build_ext): macros.append((undef,)) c_sources, cxx_sources, f_sources, fmodule_sources = \ - filter_sources(ext.sources) - + filter_sources(ext.sources) - - if self.compiler.compiler_type=='msvc': + if self.compiler.compiler_type == 'msvc': if cxx_sources: # Needed to compile kiva.agg._agg extension. extra_args.append('/Zm1000') @@ -309,32 +323,34 @@ class build_ext (old_build_ext): cxx_sources = [] # Set Fortran/C++ compilers for compilation and linking. - if ext.language=='f90': + if ext.language == 'f90': fcompiler = self._f90_compiler - elif ext.language=='f77': + elif ext.language == 'f77': fcompiler = self._f77_compiler - else: # in case ext.language is c++, for instance + else: # in case ext.language is c++, for instance fcompiler = self._f90_compiler or self._f77_compiler if fcompiler is not None: - fcompiler.extra_f77_compile_args = (ext.extra_f77_compile_args or []) if hasattr(ext, 'extra_f77_compile_args') else [] - fcompiler.extra_f90_compile_args = (ext.extra_f90_compile_args or []) if hasattr(ext, 'extra_f90_compile_args') else [] + fcompiler.extra_f77_compile_args = (ext.extra_f77_compile_args or []) if hasattr( + ext, 'extra_f77_compile_args') else [] + fcompiler.extra_f90_compile_args = (ext.extra_f90_compile_args or []) if hasattr( + ext, 'extra_f90_compile_args') else [] 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)) + 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)) + 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)) + 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} + kws = {'depends': ext.depends} output_dir = self.build_temp include_dirs = ext.include_dirs + get_numpy_include_dirs() @@ -387,7 +403,7 @@ class build_ext (old_build_ext): if f in existing_modules: continue t = os.path.join(module_build_dir, f) - if os.path.abspath(f)==os.path.abspath(t): + if os.path.abspath(f) == os.path.abspath(t): continue if os.path.isfile(t): os.remove(t) @@ -419,11 +435,12 @@ class build_ext (old_build_ext): if self.compiler.compiler_type in ('msvc', 'intelw', 'intelemw'): # expand libraries with fcompiler libraries as we are # not using fcompiler linker - self._libs_with_msvc_and_fortran(fcompiler, libraries, library_dirs) + 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 - if ext.language=='c++' and cxx_compiler is not None: + if ext.language == 'c++' and cxx_compiler is not None: linker = cxx_compiler.link_shared_object linker(objects, ext_filename, @@ -440,23 +457,27 @@ class build_ext (old_build_ext): build_src = self.get_finalized_command("build_src").build_src build_clib = self.get_finalized_command("build_clib").build_clib objects = self.compiler.compile([os.path.join(build_src, - "gfortran_vs2003_hack.c")], - output_dir=self.build_temp) - self.compiler.create_static_lib(objects, "_gfortran_workaround", output_dir=build_clib, debug=self.debug) + "gfortran_vs2003_hack.c")], + output_dir=self.build_temp) + self.compiler.create_static_lib( + objects, "_gfortran_workaround", output_dir=build_clib, debug=self.debug) def _libs_with_msvc_and_fortran(self, fcompiler, c_libraries, c_library_dirs): - if fcompiler is None: return + if fcompiler is None: + return for libname in c_libraries: - if libname.startswith('msvc'): continue + 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 + if fileexists: + continue # make g77-compiled static libs available to MSVC fileexists = False for libdir in c_library_dirs: @@ -470,7 +491,8 @@ class build_ext (old_build_ext): c_library_dirs.append(self.build_temp) fileexists = True break - if fileexists: continue + if fileexists: + continue log.warn('could not find library %r in directories %s' % (libname, c_library_dirs)) @@ -498,14 +520,14 @@ class build_ext (old_build_ext): if self.build_temp not in c_library_dirs: c_library_dirs.append(self.build_temp) - def get_source_files (self): + 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): + def get_outputs(self): self.check_extensions_list(self.extensions) outputs = [] |