def generate_numpyconfig_h(ext, build_dir): """Depends on config.h: generate_config_h has to be called before !""" target = join(build_dir,'numpyconfig.h') if newer(__file__,target): config_cmd = config.get_config_cmd() log.info('Generating %s',target) testcode = generate_numpyconfig_code(target) from distutils import sysconfig python_include = sysconfig.get_python_inc() python_h = join(python_include, 'Python.h') if not os.path.isfile(python_h): raise SystemError,\ "Non-existing %s. Perhaps you need to install"\ " python-dev|python-devel." % (python_h) config.numpy_include_dirs result = config_cmd.try_run(testcode, include_dirs = [python_include] + \ config.numpy_include_dirs, library_dirs = default_lib_dirs) if not result: raise SystemError,"Failed to generate numpy configuration. "\ "See previous error messages for more information." print 'File: %s' % target target_f = open(target) print target_f.read() target_f.close() print 'EOF' config.add_data_files((header_dir, target)) return target
def generate_a_pyrex_source(self, base, ext_name, source, extension): ''' Monkey patch for numpy build_src.build_src method Uses Cython instead of Pyrex. Assumes Cython is present ''' if self.inplace: target_dir = dirname(base) else: target_dir = appendpath(self.build_src, dirname(base)) target_file = pjoin(target_dir, ext_name + '.c') depends = [source] + extension.depends # add distribution (package-wide) include directories, in order to # pick up needed .pxd files for cython compilation incl_dirs = extension.include_dirs[:] dist_incl_dirs = self.distribution.include_dirs if not dist_incl_dirs is None: incl_dirs += dist_incl_dirs if self.force or newer_group(depends, target_file, 'newer'): import Cython.Compiler.Main log.info("cythonc:> %s" % (target_file)) self.mkpath(target_dir) options = Cython.Compiler.Main.CompilationOptions( defaults=Cython.Compiler.Main.default_options, include_path=incl_dirs, output_file=target_file) cython_result = Cython.Compiler.Main.compile(source, options=options) if cython_result.num_errors != 0: raise DistutilsError("%d errors while compiling %r with Cython" \ % (cython_result.num_errors, source)) return target_file
def configuration(parent_package='',top_path=None): config = Configuration('f2py', parent_package, top_path) config.add_subpackage('lib') config.add_data_dir('docs') config.add_data_files('src/fortranobject.c', 'src/fortranobject.h', 'f2py.1' ) config.make_svn_version_py() def generate_f2py_py(build_dir): f2py_exe = 'f2py'+os.path.basename(sys.executable)[6:] if f2py_exe[-4:]=='.exe': f2py_exe = f2py_exe[:-4] + '.py' if 'bdist_wininst' in sys.argv and f2py_exe[-3:] != '.py': f2py_exe = f2py_exe + '.py' target = os.path.join(build_dir,f2py_exe) if newer(__file__,target): log.info('Creating %s', target) f = open(target,'w') f.write('''\ #!/usr/bin/env %s # See http://cens.ioc.ee/projects/f2py2e/ import os, sys for mode in ["g3-numpy", "2e-numeric", "2e-numarray", "2e-numpy"]: try: i=sys.argv.index("--"+mode) del sys.argv[i] break except ValueError: pass os.environ["NO_SCIPY_IMPORT"]="f2py" if mode=="g3-numpy": try: from main import main except ImportError: from numpy.f2py.lib.api import main elif mode=="2e-numeric": from f2py2e import main elif mode=="2e-numarray": sys.argv.append("-DNUMARRAY") from f2py2e import main elif mode=="2e-numpy": from numpy.f2py import main else: print >> sys.stderr, "Unknown mode:",`mode` sys.exit(1) main() '''%(os.path.basename(sys.executable))) f.close() return target config.add_scripts(generate_f2py_py) log.info('F2PY Version %s', config.get_version()) return config
def finalize_options(self): 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 CCompiler_show_customization(self): """ Print the compiler customizations to stdout. Parameters ---------- None Returns ------- None Notes ----- Printing is only done if the distutils log threshold is < 2. """ if 0: for attrname in ['include_dirs','define','undef', 'libraries','library_dirs', 'rpath','link_objects']: attr = getattr(self,attrname,None) if not attr: continue log.info("compiler '%s' is set to %s" % (attrname,attr)) try: self.get_version() except: pass if log._global_log.threshold<2: print(('*'*80)) print((self.__class__)) print((_compiler_to_string(self))) print(('*'*80))
def configuration(parent_package="", top_path=None): config = Configuration("f2py", parent_package, top_path) config.add_data_dir("tests") config.add_data_files("src/fortranobject.c", "src/fortranobject.h") config.make_svn_version_py() def generate_f2py_py(build_dir): f2py_exe = "f2py" + os.path.basename(sys.executable)[6:] if f2py_exe[-4:] == ".exe": f2py_exe = f2py_exe[:-4] + ".py" if "bdist_wininst" in sys.argv and f2py_exe[-3:] != ".py": f2py_exe = f2py_exe + ".py" target = os.path.join(build_dir, f2py_exe) if newer(__file__, target): log.info("Creating %s", target) f = open(target, "w") f.write(_get_f2py_shebang() + "\n") mainloc = os.path.join(os.path.dirname(__file__), "__main__.py") with open(mainloc) as mf: f.write(mf.read()) f.close() return target config.add_scripts(generate_f2py_py) log.info("F2PY Version %s", config.get_version()) return config
def build_data_files_sources(self): if not self.data_files: return log.info("building data_files sources") from numpy.distutils.misc_util import get_data_files new_data_files = [] for data in self.data_files: if isinstance(data, str): new_data_files.append(data) elif isinstance(data, tuple): d, files = data if self.inplace: build_dir = self.get_package_dir(".".join(d.split(os.sep))) else: build_dir = os.path.join(self.build_src, d) funcs = filter(lambda f: hasattr(f, "__call__"), files) files = filter(lambda f: not hasattr(f, "__call__"), files) for f in funcs: if f.func_code.co_argcount == 1: s = f(build_dir) else: s = f() if s is not None: if isinstance(s, list): files.extend(s) elif isinstance(s, str): files.append(s) else: raise TypeError(repr(s)) filenames = get_data_files((d, files)) new_data_files.append((d, filenames)) else: raise TypeError(repr(data)) self.data_files[:] = new_data_files
def generate_a_pyrex_source(self, base, ext_name, source, extension): if self.inplace or not have_pyrex(): target_dir = os.path.dirname(base) else: target_dir = appendpath(self.build_src, os.path.dirname(base)) target_file = os.path.join(target_dir, ext_name + ".c") depends = [source] + extension.depends if self.force or newer_group(depends, target_file, "newer"): if have_pyrex(): import Pyrex.Compiler.Main log.info("pyrexc:> %s" % (target_file)) self.mkpath(target_dir) options = Pyrex.Compiler.Main.CompilationOptions( defaults=Pyrex.Compiler.Main.default_options, include_path=extension.include_dirs, output_file=target_file, ) pyrex_result = Pyrex.Compiler.Main.compile(source, options=options) if pyrex_result.num_errors != 0: raise DistutilsError("%d errors while compiling %r with Pyrex" % (pyrex_result.num_errors, source)) elif os.path.isfile(target_file): log.warn( "Pyrex required for compiling %r but not available," " using old target %r" % (source, target_file) ) else: raise DistutilsError("Pyrex required for compiling %r" " but notavailable" % (source,)) return target_file
def build_npy_pkg_config(self): log.info("build_src: building npy-pkg config files") # XXX: another ugly workaround to circumvent distutils brain damage. We # need the install prefix here, but finalizing the options of the # install command when only building sources cause error. Instead, we # copy the install command instance, and finalize the copy so that it # does not disrupt how distutils want to do things when with the # original install command instance. install_cmd = copy.copy(get_cmd("install")) if not install_cmd.finalized == 1: install_cmd.finalize_options() build_npkg = False gd = {} if self.inplace == 1: top_prefix = "." build_npkg = True elif hasattr(install_cmd, "install_libbase"): top_prefix = install_cmd.install_libbase build_npkg = True if build_npkg: for pkg, infos in self.distribution.installed_pkg_config.items(): pkg_path = os.path.join(*pkg.split(".")) prefix = os.path.join(os.path.abspath(top_prefix), pkg_path) d = {"prefix": prefix} for info in infos: install_dir, generated = self._build_npy_pkg_config(info, d, prefix) self.distribution.data_files.append((install_dir, [generated]))
def build_py_modules_sources(self): if not self.py_modules: return log.info('building py_modules sources') new_py_modules = [] for source in self.py_modules: if is_sequence(source) and len(source)==3: package, module_base, source = source if self.inplace: build_dir = self.get_package_dir(package) else: build_dir = os.path.join(self.build_src, os.path.join(*package.split('.'))) if hasattr(source, '__call__'): target = os.path.join(build_dir, module_base + '.py') source = source(target) if source is None: continue modules = [(package, module_base, source)] if package not in self.py_modules_dict: self.py_modules_dict[package] = [] self.py_modules_dict[package] += modules else: new_py_modules.append(source) self.py_modules[:] = new_py_modules
def generate_a_cython_source(self, base, ext_name, source, extension): if self.inplace or not have_cython(): target_dir = os.path.dirname(base) else: target_dir = appendpath(self.build_src, os.path.dirname(base)) target_file = os.path.join(target_dir, ext_name + '.c') depends = [source] + extension.depends if self.force or newer_group(depends, target_file, 'newer'): if have_cython(): import Cython.Compiler.Main log.info("cythonc:> %s: %s " % (target_dir, target_file)) log.info("cwd %s " % (os.getcwd())) self.mkpath(target_dir) options = Cython.Compiler.Main.CompilationOptions( defaults=Cython.Compiler.Main.default_options, include_path=extension.include_dirs, output_file=target_file ) #log.info('\n'.join([s + ' ' + str(getattr(options, s)) for s in dir(options)])) # avoid calling compile_single, because it will give wrong module names. cython_result = Cython.Compiler.Main.compile([source], options=options) if cython_result.num_errors != 0: raise DistutilsError("%d errors while compiling %r with Cython" \ % (cython_result.num_errors, source)) elif os.path.isfile(target_file): log.warn("Cython required for compiling %r but not available,"\ " using old target %r"\ % (source, target_file)) else: raise DistutilsError("Cython required for compiling %r"\ " but notavailable" % (source,)) return target_file
def CCompiler_customize(self, dist, need_cxx=0): # See FCompiler.customize for suggested usage. log.info('customize %s' % (self.__class__.__name__)) customize_compiler(self) if need_cxx: # In general, distutils uses -Wstrict-prototypes, but this option is # not valid for C++ code, only for C. Remove it if it's there to # avoid a spurious warning on every compilation. All the default # options used by distutils can be extracted with: # from distutils import sysconfig # sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', # 'CCSHARED', 'LDSHARED', 'SO') print "compiler options1:", self.compiler_so try: self.compiler_so.remove('-Wstrict-prototypes') except (AttributeError, ValueError): pass print "compiler options2:", self.compiler_so if hasattr(self,'compiler') and self.compiler[0].find('cc')>=0: if not self.compiler_cxx: if self.compiler[0].startswith('gcc'): a, b = 'gcc', 'g++' else: a, b = 'cc', 'c++' self.compiler_cxx = [self.compiler[0].replace(a,b)]\ + self.compiler[1:] else: if hasattr(self,'compiler'): log.warn("#### %s #######" % (self.compiler,)) log.warn('Missing compiler_cxx fix for '+self.__class__.__name__) return
def _build_import_library_amd64(): dll_file = find_python_dll() out_name = "libpython%d%d.a" % tuple(sys.version_info[:2]) out_file = os.path.join(sys.prefix, 'libs', out_name) if os.path.isfile(out_file): log.debug('Skip building import library: "%s" exists' % (out_file)) return # didn't exist in virtualenv, maybe in base distribution? base_file = os.path.join(sys.base_prefix, 'libs', out_name) if os.path.isfile(base_file): log.debug('Skip building import library: "%s" exists', base_file) return def_name = "python%d%d.def" % tuple(sys.version_info[:2]) def_file = os.path.join(sys.prefix, 'libs', def_name) log.info('Building import library (arch=AMD64): "%s" (from %s)' % (out_file, dll_file)) generate_def(dll_file, def_file) cmd = ['dlltool', '-d', def_file, '-l', out_file] subprocess.Popen(cmd)
def generate_a_pyrex_source(self, base, ext_name, source, extension): ''' Monkey patch for numpy build_src.build_src method Uses Cython instead of Pyrex, iff source contains 'pymor' Assumes Cython is present ''' if 'pymor' not in source: return _orig_generate_a_pyrex_source(self, base, ext_name, source, extension) if self.inplace: target_dir = dirname(base) else: target_dir = appendpath(self.build_src, dirname(base)) target_file = pjoin(target_dir, ext_name + '.c') depends = [source] + extension.depends if self.force or newer_group(depends, target_file, 'newer'): import Cython.Compiler.Main log.info("cythonc:> %s" % (target_file)) self.mkpath(target_dir) options = Cython.Compiler.Main.CompilationOptions( defaults=Cython.Compiler.Main.default_options, include_path=extension.include_dirs, output_file=target_file) cython_result = Cython.Compiler.Main.compile(source, options=options) if cython_result.num_errors != 0: raise DistutilsError("%d errors while compiling %r with Cython" % (cython_result.num_errors, source)) return target_file
def configuration(parent_package='',top_path=None): config = Configuration('f2py', parent_package, top_path) config.add_data_dir('tests') config.add_data_files('src/fortranobject.c', 'src/fortranobject.h', ) config.make_svn_version_py() def generate_f2py_py(build_dir): f2py_exe = 'f2py'+os.path.basename(sys.executable)[6:] if f2py_exe[-4:]=='.exe': f2py_exe = f2py_exe[:-4] + '.py' if 'bdist_wininst' in sys.argv and f2py_exe[-3:] != '.py': f2py_exe = f2py_exe + '.py' target = os.path.join(build_dir, f2py_exe) if newer(__file__, target): log.info('Creating %s', target) f = open(target, 'w') f.write('#!%s\n' % (sys.executable)) mainloc = os.path.join(os.path.dirname(__file__), "__main__.py") with open(mainloc) as mf: f.write(mf.read()) f.close() return target config.add_scripts(generate_f2py_py) log.info('F2PY Version %s', config.get_version()) return config
def CCompiler_customize(self, dist, need_cxx=0): """ Do any platform-specific customization of a compiler instance. This method calls `distutils.sysconfig.customize_compiler` for platform-specific customization, as well as optionally remove a flag to suppress spurious warnings in case C++ code is being compiled. Parameters ---------- dist : object This parameter is not used for anything. need_cxx : bool, optional Whether or not C++ has to be compiled. If so (True), the ``"-Wstrict-prototypes"`` option is removed to prevent spurious warnings. Default is False. Returns ------- None Notes ----- All the default options used by distutils can be extracted with:: from distutils import sysconfig sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', 'CCSHARED', 'LDSHARED', 'SO') """ # See FCompiler.customize for suggested usage. log.info('customize %s' % (self.__class__.__name__)) customize_compiler(self) if need_cxx: # In general, distutils uses -Wstrict-prototypes, but this option is # not valid for C++ code, only for C. Remove it if it's there to # avoid a spurious warning on every compilation. All the default # options used by distutils can be extracted with: # from distutils import sysconfig # sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', # 'CCSHARED', 'LDSHARED', 'SO') try: self.compiler_so.remove('-Wstrict-prototypes') except (AttributeError, ValueError): pass if hasattr(self,'compiler') and 'cc' in self.compiler[0]: if not self.compiler_cxx: if self.compiler[0].startswith('gcc'): a, b = 'gcc', 'g++' else: a, b = 'cc', 'c++' self.compiler_cxx = [self.compiler[0].replace(a,b)]\ + self.compiler[1:] else: if hasattr(self,'compiler'): log.warn("#### %s #######" % (self.compiler,)) log.warn('Missing compiler_cxx fix for '+self.__class__.__name__) return
def new_compiler (plat=None, compiler=None, verbose=0, dry_run=0, force=0): # Try first C compilers from numpy.distutils. if plat is None: plat = os.name try: if compiler is None: compiler = get_default_compiler(plat) (module_name, class_name, long_description) = compiler_class[compiler] except KeyError: msg = "don't know how to compile C/C++ code on platform '%s'" % plat if compiler is not None: msg = msg + " with '%s' compiler" % compiler raise DistutilsPlatformError, msg module_name = "numpy.distutils." + module_name try: __import__ (module_name) except ImportError, msg: log.info('%s in numpy.distutils; trying from distutils', str(msg)) module_name = module_name[6:] try: __import__(module_name) except ImportError, msg: raise DistutilsModuleError, \ "can't compile C/C++ code: unable to load module '%s'" % \ module_name
def _build_import_library_x86(): """ Build the import libraries for Mingw32-gcc on Windows """ lib_name = "python%d%d.lib" % tuple(sys.version_info[:2]) lib_file = os.path.join(sys.prefix, 'libs', lib_name) out_name = "libpython%d%d.a" % tuple(sys.version_info[:2]) out_file = os.path.join(sys.prefix, 'libs', out_name) if not os.path.isfile(lib_file): log.warn('Cannot build import library: "%s" not found' % (lib_file)) return if os.path.isfile(out_file): log.debug('Skip building import library: "%s" exists' % (out_file)) return log.info('Building import library (ARCH=x86): "%s"' % (out_file)) from numpy.distutils import lib2def def_name = "python%d%d.def" % tuple(sys.version_info[:2]) def_file = os.path.join(sys.prefix, 'libs', def_name) nm_cmd = '%s %s' % (lib2def.DEFAULT_NM, lib_file) nm_output = lib2def.getnm(nm_cmd) dlist, flist = lib2def.parse_nm(nm_output) lib2def.output_def(dlist, flist, lib2def.DEF_HEADER, open(def_file, 'w')) dll_name = "python%d%d.dll" % tuple(sys.version_info[:2]) args = (dll_name, def_file, out_file) cmd = 'dlltool --dllname %s --def %s --output-lib %s' % args status = os.system(cmd) # for now, fail silently if status: log.warn('Failed to build import library for gcc. Linking will fail.') return
def generate_numpyconfig_h(ext, build_dir): """Depends on config.h: generate_config_h has to be called before !""" target = join(build_dir,header_dir,'numpyconfig.h') d = os.path.dirname(target) if not os.path.exists(d): os.makedirs(d) if newer(__file__,target): config_cmd = config.get_config_cmd() log.info('Generating %s',target) # Check sizeof ignored, moredefs = cocache.check_types(config_cmd, ext, build_dir) if is_npy_no_signal(): moredefs.append(('NPY_NO_SIGNAL', 1)) if is_npy_no_smp(): moredefs.append(('NPY_NO_SMP', 1)) else: moredefs.append(('NPY_NO_SMP', 0)) moredefs.extend(cocache.check_ieee_macros(config_cmd)[1]) # Check wether we can use inttypes (C99) formats if config_cmd.check_decl('PRIdPTR', headers = ['inttypes.h']): moredefs.append(('NPY_USE_C99_FORMATS', 1)) else: moredefs.append(('NPY_USE_C99_FORMATS', 0)) # Inline check inline = config_cmd.check_inline() # Add moredefs to header target_f = open(target,'a') for d in moredefs: if isinstance(d,str): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0],d[1])) # define NPY_INLINE to recognized keyword target_f.write('#define NPY_INLINE %s\n' % inline) # Define __STDC_FORMAT_MACROS target_f.write(""" #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS 1 #endif """) target_f.close() # Dump the numpyconfig.h header to stdout print 'File: %s' % target target_f = open(target) print target_f.read() target_f.close() print 'EOF' config.add_data_files((header_dir, target)) return target
def finalize_options(self): self.set_undefined_options('build', ('build_base', 'build_base'), ('build_lib', 'build_lib'), ('force', 'force')) if self.package is None: self.package = self.distribution.ext_package self.extensions = self.distribution.ext_modules self.libraries = self.distribution.libraries or [] self.shared_libraries = self.distribution.shared_libraries or [] self.py_modules = self.distribution.py_modules or [] self.data_files = self.distribution.data_files or [] 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) # py_modules_dict is used in build_py.find_package_modules self.py_modules_dict = {} 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.f2py_opts = shlex.split(self.f2py_opts) 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.swig_opts = shlex.split(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 CCompiler_spawn(self, cmd, display=None): """ Execute a command in a sub-process. Parameters ---------- cmd : str The command to execute. display : str or sequence of str, optional The text to add to the log file kept by `numpy.distutils`. If not given, `display` is equal to `cmd`. Returns ------- None Raises ------ DistutilsExecError If the command failed, i.e. the exit status was not 0. """ if display is None: display = cmd if is_sequence(display): display = ' '.join(list(display)) log.info(display) try: subprocess.check_output(cmd) except subprocess.CalledProcessError as exc: o = exc.output s = exc.returncode except OSError: # OSError doesn't have the same hooks for the exception # output, but exec_command() historically would use an # empty string for EnvironmentError (base class for # OSError) o = b'' # status previously used by exec_command() for parent # of OSError s = 127 else: # use a convenience return here so that any kind of # caught exception will execute the default code after the # try / except block, which handles various exceptions return None if is_sequence(cmd): cmd = ' '.join(list(cmd)) forward_bytes_to_stdout(o) if re.search(b'Too many open files', o): msg = '\nTry rerunning setup command until build succeeds.' else: msg = '' raise DistutilsExecError('Command "%s" failed with exit status %d%s' % (cmd, s, msg))
def build_msvcr_library(debug=False): if os.name != 'nt': return False # If the version number is None, then we couldn't find the MSVC runtime at # all, because we are running on a Python distribution which is customed # compiled; trust that the compiler is the same as the one available to us # now, and that it is capable of linking with the correct runtime without # any extra options. msvcr_ver = msvc_runtime_major() if msvcr_ver is None: log.debug('Skip building import library: ' 'Runtime is not compiled with MSVC') return False # Skip using a custom library for versions < MSVC 8.0 if msvcr_ver < 80: log.debug('Skip building msvcr library:' ' custom functionality not present') return False msvcr_name = msvc_runtime_library() if debug: msvcr_name += 'd' # Skip if custom library already exists out_name = "lib%s.a" % msvcr_name out_file = os.path.join(sys.prefix, 'libs', out_name) if os.path.isfile(out_file): log.debug('Skip building msvcr library: "%s" exists' % (out_file,)) return True # Find the msvcr dll msvcr_dll_name = msvcr_name + '.dll' dll_file = find_dll(msvcr_dll_name) if not dll_file: log.warn('Cannot build msvcr library: "%s" not found' % msvcr_dll_name) return False def_name = "lib%s.def" % msvcr_name def_file = os.path.join(sys.prefix, 'libs', def_name) log.info('Building msvcr library: "%s" (from %s)' \ % (out_file, dll_file)) # Generate a symbol definition file from the msvcr dll generate_def(dll_file, def_file) # Create a custom mingw library for the given symbol definitions cmd = ['dlltool', '-d', def_file, '-l', out_file] retcode = subprocess.call(cmd) # Clean up symbol definitions os.remove(def_file) return (not retcode)
def configuration(parent_package='',top_path=None): config = Configuration('f2py', parent_package, top_path) config.add_data_dir('docs') config.add_data_dir('tests') config.add_data_files('src/fortranobject.c', 'src/fortranobject.h', 'f2py.1' ) config.make_svn_version_py() def generate_f2py_py(build_dir): f2py_exe = 'f2py' if f2py_exe[-4:]=='.exe': f2py_exe = f2py_exe[:-4] + '.py' if 'bdist_wininst' in sys.argv and f2py_exe[-3:] != '.py': f2py_exe = f2py_exe + '.py' target = os.path.join(build_dir, f2py_exe) if newer(__file__, target): log.info('Creating %s', target) f = open(target, 'w') f.write('''\ #!/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 # See http://cens.ioc.ee/projects/f2py2e/ import os, sys for mode in ["g3-numpy", "2e-numeric", "2e-numarray", "2e-numpy"]: try: i=sys.argv.index("--"+mode) del sys.argv[i] break except ValueError: pass os.environ["NO_SCIPY_IMPORT"]="f2py" if mode=="g3-numpy": sys.stderr.write("G3 f2py support is not implemented, yet.\\n") sys.exit(1) elif mode=="2e-numeric": from f2py2e import main elif mode=="2e-numarray": sys.argv.append("-DNUMARRAY") from f2py2e import main elif mode=="2e-numpy": from numpy.f2py import main else: sys.stderr.write("Unknown mode: " + repr(mode) + "\\n") sys.exit(1) main() ''') f.close() return target config.add_scripts(generate_f2py_py) log.info('F2PY Version %s', config.get_version()) return config
def generate_numpyconfig_h(ext, build_dir): """Depends on config.h: generate_config_h has to be called before !""" target = join(build_dir,header_dir,'_numpyconfig.h') d = dirname(target) if not exists(d): os.makedirs(d) if newer(__file__,target): config_cmd = config.get_config_cmd() log.info('Generating %s',target) moredefs = [] if is_npy_no_signal(): moredefs.append(('NPY_NO_SIGNAL', 1)) if is_npy_no_smp(): moredefs.append(('NPY_NO_SMP', 1)) else: moredefs.append(('NPY_NO_SMP', 0)) mathlibs = check_mathlib(config_cmd) # Check wether we can use inttypes (C99) formats if config_cmd.check_decl('PRIdPTR', headers = ['inttypes.h']): moredefs.append(('NPY_USE_C99_FORMATS', 1)) # visibility check hidden_visibility = visibility_define(config_cmd) moredefs.append(('NPY_VISIBILITY_HIDDEN', hidden_visibility)) # Add the C API/ABI versions moredefs.append(('NUMPY_ABI_VERSION', '2.0.0')) moredefs.append(('NUMPY_API_VERSION', '2.0.0')) # Add moredefs to header target_f = open(target, 'w') for d in moredefs: if isinstance(d,str): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0],d[1])) # Define __STDC_FORMAT_MACROS target_f.write(""" #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS 1 #endif """) target_f.close() # Dump the numpyconfig.h header to stdout print('File: %s' % target) target_f = open(target) print(target_f.read()) target_f.close() print('EOF') config.add_data_files((header_dir, target)) return target
def finalize_options(self): self.set_undefined_options( "build", ("build_base", "build_base"), ("build_lib", "build_lib"), ("force", "force") ) if self.package is None: self.package = self.distribution.ext_package self.extensions = self.distribution.ext_modules self.libraries = self.distribution.libraries or [] self.py_modules = self.distribution.py_modules or [] self.data_files = self.distribution.data_files or [] 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) # py_modules_dict is used in build_py.find_package_modules self.py_modules_dict = {} 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.f2py_opts = shlex.split(self.f2py_opts) 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.swig_opts = shlex.split(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 generate_api(ext, build_dir): script = join(codegen_dir, module_name + ".py") sys.path.insert(0, codegen_dir) try: m = __import__(module_name) log.info("executing %s", script) h_file, c_file, doc_file = m.generate_api(os.path.join(build_dir, header_dir)) finally: del sys.path[0] config.add_data_files((header_dir, h_file), (header_dir, doc_file)) return (h_file,)
def get_default_fcompiler(osname=None, platform=None, requiref90=False, c_compiler=None): """Determine the default Fortran compiler to use for the given platform.""" matching_compiler_types = available_fcompilers_for_platform(osname, platform) log.info("get_default_fcompiler: matching types: '%s'", matching_compiler_types) compiler_type = _find_existing_fcompiler(matching_compiler_types, osname=osname, platform=platform, requiref90=requiref90, c_compiler=c_compiler) return compiler_type
def build_msvcr_library(debug=False): if os.name != 'nt': return False msvcr_name = msvc_runtime_library() # Skip using a custom library for versions < MSVC 8.0 msvcr_ver = msvc_runtime_major() if msvcr_ver and msvcr_ver < 80: log.debug('Skip building msvcr library:' ' custom functionality not present') return False if debug: msvcr_name += 'd' # Skip if custom library already exists out_name = "lib%s.a" % msvcr_name out_file = os.path.join(sys.prefix, 'libs', out_name) if os.path.isfile(out_file): log.debug('Skip building msvcr library: "%s" exists' % (out_file,)) return True # Find the msvcr dll msvcr_dll_name = msvcr_name + '.dll' dll_file = find_dll(msvcr_dll_name) if not dll_file: log.warn('Cannot build msvcr library: "%s" not found' % msvcr_dll_name) return False def_name = "lib%s.def" % msvcr_name def_file = os.path.join(sys.prefix, 'libs', def_name) log.info('Building msvcr library: "%s" (from %s)' \ % (out_file, dll_file)) # Generate a symbol definition file from the msvcr dll generate_def(dll_file, def_file) # Create a custom mingw library for the given symbol definitions cmd = ['dlltool', '-d', def_file, '-l', out_file] retcode = subprocess.call(cmd) # Clean up symbol definitions os.remove(def_file) return (not retcode)
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): """Compile 'src' to product 'obj'.""" src_flags = {} if is_f_file(src) and not has_f90_header(src): flavor = ':f77' compiler = self.compiler_f77 src_flags = get_f77flags(src) extra_compile_args = self.extra_f77_compile_args or [] elif is_free_format(src): flavor = ':f90' compiler = self.compiler_f90 if compiler is None: raise DistutilsExecError('f90 not supported by %s needed for %s'\ % (self.__class__.__name__, src)) extra_compile_args = self.extra_f90_compile_args or [] else: flavor = ':fix' compiler = self.compiler_fix if compiler is None: raise DistutilsExecError('f90 (fixed) not supported by %s needed for %s'\ % (self.__class__.__name__, src)) extra_compile_args = self.extra_f90_compile_args or [] if self.object_switch[-1]==' ': o_args = [self.object_switch.strip(), obj] else: o_args = [self.object_switch.strip()+obj] assert self.compile_switch.strip() s_args = [self.compile_switch, src] if extra_compile_args: log.info('extra %s options: %r' \ % (flavor[1:], ' '.join(extra_compile_args))) extra_flags = src_flags.get(self.compiler_type, []) if extra_flags: log.info('using compile options from source: %r' \ % ' '.join(extra_flags)) command = compiler + cc_args + extra_flags + s_args + o_args \ + extra_postargs + extra_compile_args display = '%s: %s' % (os.path.basename(compiler[0]) + flavor, src) try: self.spawn(command, display=display) except DistutilsExecError: msg = str(get_exception()) raise CompileError(msg)
def generate_a_script(build_dir, script=script, config=config): dist = config.get_distribution() install_lib = dist.get_command_obj('install_lib') if not install_lib.finalized: install_lib.finalize_options() script_replace_text = '' install_lib = install_lib.install_dir if install_lib is not None: script_replace_text = ''' import sys if %(d)r not in sys.path: sys.path.insert(0, %(d)r) ''' % dict(d=install_lib) if multiprocessing is not None: mp_install_lib = dirname(dirname(multiprocessing.__file__)) script_replace_text += ''' if %(d)r not in sys.path: sys.path.insert(0, %(d)r) ''' % dict(d=mp_install_lib) start_mark = '### START UPDATE SYS.PATH ###' end_mark = '### END UPDATE SYS.PATH ###' name = basename(script) if name.startswith (script_prefix): target_name = name elif wininst: target_name = script_prefix + '_' + name else: target_name = script_prefix + '.' + splitext(name)[0] target = join(build_dir, target_name) if newer(script, target) or 1: log.info('Creating %r', target) f = open (script, 'r') text = f.read() f.close() i = text.find(start_mark) if i != -1: j = text.find (end_mark) if j == -1: log.warn ("%r missing %r line", script, start_mark) new_text = text[:i+len (start_mark)] + script_replace_text + text[j:] else: new_text = text f = open(target, 'w') f.write(new_text) f.close()
def swig_sources(self, sources, extension): # Assuming SWIG 1.3.14 or later. See compatibility note in # http://www.swig.org/Doc1.3/Python.html#Python_nn6 new_sources = [] swig_sources = [] swig_targets = {} target_dirs = [] py_files = [] # swig generated .py files target_ext = '.c' if '-c++' in extension.swig_opts: typ = 'c++' is_cpp = True extension.swig_opts.remove('-c++') elif self.swig_cpp: typ = 'c++' is_cpp = True else: typ = None is_cpp = False skip_swig = 0 ext_name = extension.name.split('.')[-1] for source in sources: (base, ext) = os.path.splitext(source) if ext == '.i': # SWIG interface file # the code below assumes that the sources list # contains not more than one .i SWIG interface file if self.inplace: target_dir = os.path.dirname(base) py_target_dir = self.ext_target_dir else: target_dir = appendpath(self.build_src, os.path.dirname(base)) py_target_dir = target_dir if os.path.isfile(source): name = get_swig_modulename(source) if name != ext_name[1:]: 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++' else: typ2 = get_swig_target(source) if typ2 is None: log.warn('source %r does not define swig target, assuming %s swig target' \ % (source, typ)) elif 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 else: log.warn( 'assuming that %r has c++ swig target' % (source)) if is_cpp: target_ext = '.cpp' target_file = os.path.join(target_dir, '%s_wrap%s' \ % (name, target_ext)) else: 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.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 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')) swig_sources.append(source) swig_targets[source] = new_sources[-1] else: new_sources.append(source) if not swig_sources: return new_sources if skip_swig: return new_sources + py_files for d in target_dirs: self.mkpath(d) swig = self.swig or self.find_swig() swig_cmd = [swig, "-python"] + extension.swig_opts if is_cpp: swig_cmd.append('-c++') for d in extension.include_dirs: swig_cmd.append('-I' + d) for source in swig_sources: target = swig_targets[source] depends = [source] + extension.depends 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.swig_opts \ + ["-o", target, '-outdir', py_target_dir, source]) else: log.debug(" skipping '%s' swig interface (up-to-date)" \ % (source)) return new_sources + py_files
def swig_sources(self, sources, extension): # Assuming SWIG 1.3.14 or later. See compatibility note in # http://www.swig.org/Doc1.3/Python.html#Python_nn6 new_sources = [] swig_sources = [] swig_targets = {} target_dirs = [] py_files = [] # swig generated .py files target_ext = ".c" if self.swig_cpp: typ = "c++" is_cpp = True else: typ = None is_cpp = False skip_swig = 0 ext_name = extension.name.split(".")[-1] for source in sources: (base, ext) = os.path.splitext(source) if ext == ".i": # SWIG interface file if self.inplace: target_dir = os.path.dirname(base) py_target_dir = self.ext_target_dir else: target_dir = appendpath(self.build_src, os.path.dirname(base)) py_target_dir = target_dir if os.path.isfile(source): name = get_swig_modulename(source) # if name != ext_name: # raise DistutilsSetupError( # 'mismatch of extension names: %s provides %r' # ' but expected %r' % (source, name, ext_name)) if typ is None: typ = get_swig_target(source) is_cpp = typ == "c++" if is_cpp: target_ext = ".cpp" else: 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.warn(" source %s does not exist: skipping swig'ing." % (source)) name = ext_name skip_swig = 1 target_file = _find_swig_target(target_dir, name) if not os.path.isfile(target_file): log.warn(( "target {} does not exist:\n" + "Assuming {}_wrap.{c,cpp} was generated with 'build_src --inplace' command." ).format(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 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')) swig_sources.append(source) swig_targets[source] = new_sources[-1] else: new_sources.append(source) if not swig_sources: return new_sources if skip_swig: return new_sources + py_files for d in target_dirs: self.mkpath(d) swig = self.swig or self.find_swig() swig_cmd = [swig, "-python"] + extension.swig_opts if is_cpp: swig_cmd.append("-c++") for d in extension.include_dirs: swig_cmd.append("-I" + d) for source in swig_sources: target = swig_targets[source] depends = [source] + extension.depends 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.swig_opts + ["-o", target, "-outdir", py_target_dir, source]) else: log.debug(" skipping '%s' swig interface (up-to-date)" % (source)) return new_sources + py_files
def run(self): if not self.extensions: return # Make sure that extension sources are complete. self.run_command('build_src') 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') else: build_clib = self.distribution.get_command_obj( 'build_clib') build_clib.inplace = 1 build_clib.ensure_finalized() build_clib.run() self.distribution.have_run['build_clib'] = 1 else: self.run_command('build_clib') 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. from distutils.ccompiler import new_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) self.compiler.customize_cmd(self) if self.warn_error: self.compiler.compiler.append('-Werror') self.compiler.compiler_so.append('-Werror') self.compiler.show_customization() # Setup directory for storing generated extra DLL files on Windows self.extra_dll_dir = os.path.join(self.build_temp, '.libs') if not os.path.isdir(self.extra_dll_dir): os.makedirs(self.extra_dll_dir) # 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 libname in clibs and clibs[libname] != build_info: 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: for libname, build_info in self.distribution.libraries or []: if libname in clibs: # 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 libname in clibs: 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: ctype = self.fcompiler self._f77_compiler = new_fcompiler(compiler=self.fcompiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force, requiref90=False, c_compiler=self.compiler) fcompiler = self._f77_compiler if fcompiler: ctype = fcompiler.compiler_type fcompiler.customize(self.distribution) if fcompiler and fcompiler.get_version(): fcompiler.customize_cmd(self) fcompiler.show_customization() else: self.warn('f77_compiler=%s is not available.' % (ctype)) self._f77_compiler = None else: self._f77_compiler = None # Initialize Fortran 90 compiler: if need_f90_compiler: ctype = self.fcompiler self._f90_compiler = new_fcompiler(compiler=self.fcompiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force, requiref90=True, c_compiler=self.compiler) fcompiler = self._f90_compiler if fcompiler: ctype = fcompiler.compiler_type fcompiler.customize(self.distribution) if fcompiler and fcompiler.get_version(): fcompiler.customize_cmd(self) fcompiler.show_customization() else: self.warn('f90_compiler=%s is not available.' % (ctype)) self._f90_compiler = None else: self._f90_compiler = None # Build extensions self.build_extensions() # Copy over any extra DLL files # FIXME: In the case where there are more than two packages, # we blindly assume that both packages need all of the libraries, # resulting in a larger wheel than is required. This should be fixed, # but it's so rare that I won't bother to handle it. pkg_roots = { self.get_ext_fullname(ext.name).split('.')[0] for ext in self.extensions } for pkg_root in pkg_roots: shared_lib_dir = os.path.join(pkg_root, '.libs') if not self.inplace: shared_lib_dir = os.path.join(self.build_lib, shared_lib_dir) for fn in os.listdir(self.extra_dll_dir): if not os.path.isdir(shared_lib_dir): os.makedirs(shared_lib_dir) if not fn.lower().endswith('.dll'): continue runtime_lib = os.path.join(self.extra_dll_dir, fn) copy_file(runtime_lib, shared_lib_dir)
def exec_command( command, execute_in='', use_shell=None, use_tee = None, _with_python = 1, **env ): """ Return (status,output) of executed command. command is a concatenated string of executable and arguments. The output contains both stdout and stderr messages. The following special keyword arguments can be used: use_shell - execute `sh -c command` use_tee - pipe the output of command through tee execute_in - before run command `cd execute_in` and after `cd -`. On NT, DOS systems the returned status is correct for external commands. Wild cards will not work for non-posix systems or when use_shell=0. """ if isinstance(command, str): log.info(command) else: log.info(' '.join(command)) log.debug('exec_command(%r,%s)' % (command, ','.join(['%s=%r'%kv for kv in env.items()]))) if use_tee is None: use_tee = os.name=='posix' if use_shell is None: use_shell = os.name=='posix' execute_in = os.path.abspath(execute_in) oldcwd = os.path.abspath(os.getcwd()) if __name__[-12:] == 'exec_command': exec_dir = os.path.dirname(os.path.abspath(__file__)) elif os.path.isfile('exec_command.py'): exec_dir = os.path.abspath('.') else: exec_dir = os.path.abspath(sys.argv[0]) if os.path.isfile(exec_dir): exec_dir = os.path.dirname(exec_dir) if oldcwd!=execute_in: os.chdir(execute_in) log.debug('New cwd: %s' % execute_in) else: log.debug('Retaining cwd: %s' % oldcwd) oldenv = _preserve_environment( env.keys() ) _update_environment( **env ) try: # _exec_command is robust but slow, it relies on # usable sys.std*.fileno() descriptors. If they # are bad (like in win32 Idle, PyCrust environments) # then _exec_command_python (even slower) # will be used as a last resort. # # _exec_command_posix uses os.system and is faster # but not on all platforms os.system will return # a correct status. if _with_python and (0 or sys.__stdout__.fileno()==-1): st = _exec_command_python(command, exec_command_dir = exec_dir, **env) elif os.name=='posix': st = _exec_command_posix(command, use_shell=use_shell, use_tee=use_tee, **env) else: st = _exec_command(command, use_shell=use_shell, use_tee=use_tee,**env) finally: if oldcwd!=execute_in: os.chdir(oldcwd) log.debug('Restored cwd to %s' % oldcwd) _update_environment(**oldenv) return st
("linux.*", "pathcc"), ("nt", "intelw"), ("nt", "intelemw"), ) if sys.platform == "win32": compiler_class["mingw32"] = ( "mingw32ccompiler", "Mingw32CCompiler", "Mingw32 port of GNU C Compiler for Win32" "(for MSC built Python)", ) if mingw32(): # On windows platforms, we want to default to mingw32 (gcc) # because msvc can't build blitz stuff. log.info("Setting mingw32 as default compiler for nt.") ccompiler._default_compilers = ( ("nt", "mingw32"), ) + ccompiler._default_compilers _distutils_new_compiler = new_compiler def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0): # Try first C compilers from numpy.distutils. if plat is None: plat = os.name try: if compiler is None: compiler = get_default_compiler(plat) (module_name, class_name, long_description) = compiler_class[compiler] except KeyError:
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) sources = list(sources) if not sources: return fullname = self.get_ext_fullname(ext.name) if self.inplace: 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, 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, )) 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 = [] # 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 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 [] 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 include_dirs = ext.include_dirs + get_numpy_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") c_objects += cxx_compiler.compile(cxx_sources, output_dir=output_dir, macros=macros, include_dirs=include_dirs, debug=self.debug, extra_postargs=extra_args, **kws) 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 # Always use system linker when using MSVC compiler. 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 if ext.language == 'c++' and cxx_compiler is not None: linker = cxx_compiler.link_shared_object linker(objects, ext_filename, 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, target_lang=ext.language)
def run(self): if not self.extensions: return # Make sure that extension sources are complete. self.run_command('build_src') 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') else: build_clib = self.distribution.get_command_obj( 'build_clib') build_clib.inplace = 1 build_clib.ensure_finalized() build_clib.run() self.distribution.have_run['build_clib'] = 1 else: self.run_command('build_clib') 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. from distutils.ccompiler import new_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) self.compiler.customize_cmd(self) self.compiler.show_customization() # 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 libname in clibs and clibs[libname] != build_info: 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: for libname, build_info in self.distribution.libraries or []: if libname in clibs: # 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 libname in clibs: 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: ctype = self.fcompiler self._f77_compiler = new_fcompiler(compiler=self.fcompiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force, requiref90=False, c_compiler=self.compiler) fcompiler = self._f77_compiler if fcompiler: ctype = fcompiler.compiler_type fcompiler.customize(self.distribution) if fcompiler and fcompiler.get_version(): fcompiler.customize_cmd(self) fcompiler.show_customization() else: self.warn('f77_compiler=%s is not available.' % (ctype)) self._f77_compiler = None else: self._f77_compiler = None # Initialize Fortran 90 compiler: if need_f90_compiler: ctype = self.fcompiler self._f90_compiler = new_fcompiler(compiler=self.fcompiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force, requiref90=True, c_compiler=self.compiler) fcompiler = self._f90_compiler if fcompiler: ctype = fcompiler.compiler_type fcompiler.customize(self.distribution) if fcompiler and fcompiler.get_version(): fcompiler.customize_cmd(self) fcompiler.show_customization() else: self.warn('f90_compiler=%s is not available.' % (ctype)) self._f90_compiler = None else: self._f90_compiler = None # Build extensions self.build_extensions()
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) sources = list(sources) if not sources: return fullname = self.get_ext_fullname(ext.name) if self.inplace: 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, 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, )) 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 = [] # 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 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 []) 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 include_dirs = ext.include_dirs + get_numpy_include_dirs() # filtering C dispatch-table sources when optimization is not disabled, # otherwise treated as normal sources. copt_c_sources = [] copt_baseline_flags = [] copt_macros = [] if not self.disable_optimization: bsrc_dir = self.get_finalized_command("build_src").build_src dispatch_hpath = os.path.join("numpy", "distutils", "include") dispatch_hpath = os.path.join(bsrc_dir, dispatch_hpath) include_dirs.append(dispatch_hpath) copt_build_src = None if self.inplace else bsrc_dir copt_c_sources = [ c_sources.pop(c_sources.index(src)) for src in c_sources[:] if src.endswith(".dispatch.c") ] copt_baseline_flags = self.compiler_opt.cpu_baseline_flags() else: copt_macros.append(("NPY_DISABLE_OPTIMIZATION", 1)) c_objects = [] if copt_c_sources: log.info("compiling C dispatch-able sources") c_objects += self.compiler_opt.try_dispatch( copt_c_sources, output_dir=output_dir, src_dir=copt_build_src, macros=macros + copt_macros, include_dirs=include_dirs, debug=self.debug, extra_postargs=extra_args, **kws) if c_sources: log.info("compiling C sources") c_objects += self.compiler.compile(c_sources, output_dir=output_dir, macros=macros + copt_macros, include_dirs=include_dirs, debug=self.debug, extra_postargs=extra_args + copt_baseline_flags, **kws) if cxx_sources: log.info("compiling C++ sources") c_objects += cxx_compiler.compile(cxx_sources, output_dir=output_dir, macros=macros + copt_macros, include_dirs=include_dirs, debug=self.debug, extra_postargs=extra_args + copt_baseline_flags, **kws) 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, ) if f_objects and not fcompiler.can_ccompiler_link(self.compiler): unlinkable_fobjects = f_objects objects = c_objects else: unlinkable_fobjects = [] 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 # Always use system linker when using MSVC compiler. 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) 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: linker = cxx_compiler.link_shared_object if fcompiler is not None: objects, libraries = self._process_unlinkable_fobjects( objects, libraries, fcompiler, library_dirs, unlinkable_fobjects) linker( objects, ext_filename, 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, target_lang=ext.language, )
def report(): log.info("\n########### EXT COMPILER OPTIMIZATION ###########") log.info(self.compiler_opt.report(full=True))
def generate_config_h(ext, build_dir): target = join(build_dir, header_dir, 'config.h') d = os.path.dirname(target) if not os.path.exists(d): os.makedirs(d) if newer(__file__, target): config_cmd = config.get_config_cmd() log.info('Generating %s', target) # Check that the toolchain works, to fail early if it doesn't # (avoid late errors with MATHLIB which are confusing if the # compiler does not work). config_cmd.try_link('int main(void) { return 0;}') # Check sizeof moredefs, ignored = cocache.check_types(config_cmd, ext, build_dir) # Check math library and C99 math funcs availability mathlibs = check_mathlib(config_cmd) moredefs.append(('MATHLIB', ','.join(mathlibs))) check_math_capabilities(config_cmd, moredefs, mathlibs) moredefs.extend(cocache.check_ieee_macros(config_cmd)[0]) # Signal check if is_npy_no_signal(): moredefs.append('__NPY_PRIVATE_NO_SIGNAL') # Windows checks if sys.platform == 'win32' or os.name == 'nt': win32_checks(moredefs) # Inline check inline = config_cmd.check_inline() # Check whether we need our own wide character support if not config_cmd.check_decl('Py_UNICODE_WIDE', headers=['Python.h']): PYTHON_HAS_UNICODE_WIDE = True else: PYTHON_HAS_UNICODE_WIDE = False if ENABLE_SEPARATE_COMPILATION: moredefs.append(('ENABLE_SEPARATE_COMPILATION', 1)) # Generate the config.h file from moredefs target_f = open(target, 'w') for d in moredefs: if isinstance(d, str): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0], d[1])) # define inline to our keyword, or nothing target_f.write('#ifndef __cplusplus\n') if inline == 'inline': target_f.write('/* #undef inline */\n') else: target_f.write('#define inline %s\n' % inline) target_f.write('#endif\n') target_f.close() print 'File:', target target_f = open(target) print target_f.read() target_f.close() print 'EOF' else: mathlibs = [] target_f = open(target) for line in target_f.readlines(): s = '#define MATHLIB' if line.startswith(s): value = line[len(s):].strip() if value: mathlibs.extend(value.split(',')) target_f.close() # Ugly: this can be called within a library and not an extension, # in which case there is no libraries attributes (and none is # needed). if hasattr(ext, 'libraries'): ext.libraries.extend(mathlibs) incl_dir = os.path.dirname(target) if incl_dir not in config.numpy_include_dirs: config.numpy_include_dirs.append(incl_dir) return target
def CCompiler_spawn(self, cmd, display=None): """ Execute a command in a sub-process. Parameters ---------- cmd : str The command to execute. display : str or sequence of str, optional The text to add to the log file kept by `numpy.distutils`. If not given, `display` is equal to `cmd`. Returns ------- None Raises ------ DistutilsExecError If the command failed, i.e. the exit status was not 0. """ if display is None: display = cmd if is_sequence(display): display = ' '.join(list(display)) log.info(display) try: if self.verbose: subprocess.check_output(cmd) else: subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: o = exc.output s = exc.returncode except OSError: # OSError doesn't have the same hooks for the exception # output, but exec_command() historically would use an # empty string for EnvironmentError (base class for # OSError) o = b'' # status previously used by exec_command() for parent # of OSError s = 127 else: # use a convenience return here so that any kind of # caught exception will execute the default code after the # try / except block, which handles various exceptions return None if is_sequence(cmd): cmd = ' '.join(list(cmd)) if self.verbose: forward_bytes_to_stdout(o) if re.search(b'Too many open files', o): msg = '\nTry rerunning setup command until build succeeds.' else: msg = '' raise DistutilsExecError('Command "%s" failed with exit status %d%s' % (cmd, s, msg))
def CCompiler_compile(self, sources, output_dir=None, macros=None, include_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, depends=None): """ Compile one or more source files. Please refer to the Python distutils API reference for more details. Parameters ---------- sources : list of str A list of filenames output_dir : str, optional Path to the output directory. macros : list of tuples A list of macro definitions. include_dirs : list of str, optional The directories to add to the default include file search path for this compilation only. debug : bool, optional Whether or not to output debug symbols in or alongside the object file(s). extra_preargs, extra_postargs : ? Extra pre- and post-arguments. depends : list of str, optional A list of file names that all targets depend on. Returns ------- objects : list of str A list of object file names, one per source file `sources`. Raises ------ CompileError If compilation fails. """ # This method is effective only with Python >=2.3 distutils. # Any changes here should be applied also to fcompiler.compile # method to support pre Python 2.3 distutils. global _job_semaphore jobs = get_num_build_jobs() # setup semaphore to not exceed number of compile jobs when parallelized at # extension level (python >= 3.5) with _global_lock: if _job_semaphore is None: _job_semaphore = threading.Semaphore(jobs) if not sources: return [] # FIXME:RELATIVE_IMPORT if sys.version_info[0] < 3: from .fcompiler import FCompiler, is_f_file, has_f90_header else: from numpy.distutils.fcompiler import (FCompiler, is_f_file, has_f90_header) if isinstance(self, FCompiler): display = [] for fc in ['f77', 'f90', 'fix']: fcomp = getattr(self, 'compiler_' + fc) if fcomp is None: continue display.append("Fortran %s compiler: %s" % (fc, ' '.join(fcomp))) display = '\n'.join(display) else: ccomp = self.compiler_so display = "C compiler: %s\n" % (' '.join(ccomp), ) log.info(display) macros, objects, extra_postargs, pp_opts, build = \ self._setup_compile(output_dir, macros, include_dirs, sources, depends, extra_postargs) cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) display = "compile options: '%s'" % (' '.join(cc_args)) if extra_postargs: display += "\nextra options: '%s'" % (' '.join(extra_postargs)) log.info(display) def single_compile(args): obj, (src, ext) = args if not _needs_build(obj, cc_args, extra_postargs, pp_opts): return # check if we are currently already processing the same object # happens when using the same source in multiple extensions while True: # need explicit lock as there is no atomic check and add with GIL with _global_lock: # file not being worked on, start working if obj not in _processing_files: _processing_files.add(obj) break # wait for the processing to end time.sleep(0.1) try: # retrieve slot from our #job semaphore and build with _job_semaphore: self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) finally: # register being done processing with _global_lock: _processing_files.remove(obj) if isinstance(self, FCompiler): objects_to_build = list(build.keys()) f77_objects, other_objects = [], [] for obj in objects: if obj in objects_to_build: src, ext = build[obj] if self.compiler_type == 'absoft': obj = cyg2win32(obj) src = cyg2win32(src) if is_f_file(src) and not has_f90_header(src): f77_objects.append((obj, (src, ext))) else: other_objects.append((obj, (src, ext))) # f77 objects can be built in parallel build_items = f77_objects # build f90 modules serial, module files are generated during # compilation and may be used by files later in the list so the # ordering is important for o in other_objects: single_compile(o) else: build_items = build.items() if len(build) > 1 and jobs > 1: # build parallel import multiprocessing.pool pool = multiprocessing.pool.ThreadPool(jobs) pool.map(single_compile, build_items) pool.close() else: # build serial for o in build_items: single_compile(o) # Return *all* object filenames, not just the ones we just built. return objects
def generate_config_h(ext, build_dir): target = join(build_dir, header_dir, 'config.h') d = os.path.dirname(target) if not os.path.exists(d): os.makedirs(d) if newer(__file__, target): config_cmd = config.get_config_cmd() log.info('Generating %s', target) # Check sizeof moredefs, ignored = cocache.check_types(config_cmd, ext, build_dir) # Check math library and C99 math funcs availability mathlibs = check_mathlib(config_cmd) moredefs.append(('MATHLIB', ','.join(mathlibs))) check_math_capabilities(config_cmd, moredefs, mathlibs) moredefs.extend(cocache.check_ieee_macros(config_cmd)[0]) moredefs.extend(cocache.check_complex(config_cmd, mathlibs)[0]) # Signal check if is_npy_no_signal(): moredefs.append('__NPY_PRIVATE_NO_SIGNAL') # Windows checks if sys.platform == 'win32' or os.name == 'nt': win32_checks(moredefs) # C99 restrict keyword moredefs.append(('NPY_RESTRICT', config_cmd.check_restrict())) # Inline check inline = config_cmd.check_inline() # Use relaxed stride checking if NPY_RELAXED_STRIDES_CHECKING: moredefs.append(('NPY_RELAXED_STRIDES_CHECKING', 1)) # Use bogus stride debug aid when relaxed strides are enabled if NPY_RELAXED_STRIDES_DEBUG: moredefs.append(('NPY_RELAXED_STRIDES_DEBUG', 1)) # Get long double representation rep = check_long_double_representation(config_cmd) moredefs.append(('HAVE_LDOUBLE_%s' % rep, 1)) if check_for_right_shift_internal_compiler_error(config_cmd): moredefs.append('NPY_DO_NOT_OPTIMIZE_LONG_right_shift') moredefs.append('NPY_DO_NOT_OPTIMIZE_ULONG_right_shift') moredefs.append('NPY_DO_NOT_OPTIMIZE_LONGLONG_right_shift') moredefs.append('NPY_DO_NOT_OPTIMIZE_ULONGLONG_right_shift') # Py3K check if sys.version_info[0] >= 3: moredefs.append(('NPY_PY3K', 1)) # Generate the config.h file from moredefs with open(target, 'w') as target_f: for d in moredefs: if isinstance(d, str): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0], d[1])) # define inline to our keyword, or nothing target_f.write('#ifndef __cplusplus\n') if inline == 'inline': target_f.write('/* #undef inline */\n') else: target_f.write('#define inline %s\n' % inline) target_f.write('#endif\n') # add the guard to make sure config.h is never included directly, # but always through npy_config.h target_f.write( textwrap.dedent(""" #ifndef _NPY_NPY_CONFIG_H_ #error config.h should never be included directly, include npy_config.h instead #endif """)) print('File:', target) with open(target) as target_f: print(target_f.read()) print('EOF') else: mathlibs = [] with open(target) as target_f: for line in target_f: s = '#define MATHLIB' if line.startswith(s): value = line[len(s):].strip() if value: mathlibs.extend(value.split(',')) # Ugly: this can be called within a library and not an extension, # in which case there is no libraries attributes (and none is # needed). if hasattr(ext, 'libraries'): ext.libraries.extend(mathlibs) incl_dir = os.path.dirname(target) if incl_dir not in config.numpy_include_dirs: config.numpy_include_dirs.append(incl_dir) return target
def build_a_library(self, build_info, lib_name, libraries): # default compilers compiler = self.compiler fcompiler = self._f_compiler 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 = 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) return 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, c_compiler=self.compiler) if fcompiler is not None: 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)) 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 [] macros = build_info.get('macros') include_dirs = build_info.get('include_dirs') if include_dirs is None: include_dirs = [] extra_postargs = build_info.get('extra_compiler_args') or [] include_dirs.extend(get_numpy_include_dirs()) # 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 compiler.compiler_type == 'msvc': # this hack works around the msvc compiler attributes # problem, msvc uses its own convention :( c_sources += cxx_sources cxx_sources = [] objects = [] if c_sources: log.info("compiling C sources") objects = compiler.compile(c_sources, output_dir=self.build_temp, macros=macros, include_dirs=include_dirs, debug=self.debug, extra_postargs=extra_postargs) if cxx_sources: log.info("compiling C++ sources") cxx_compiler = compiler.cxx_compiler() cxx_objects = cxx_compiler.compile(cxx_sources, output_dir=self.build_temp, macros=macros, include_dirs=include_dirs, debug=self.debug, extra_postargs=extra_postargs) objects.extend(cxx_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._f_compiler.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 = [] if f_objects and not fcompiler.can_ccompiler_link(compiler): # Default linker cannot link Fortran object files, and results # need to be wrapped later. Instead of creating a real static # library, just keep track of the object files. listfn = os.path.join(self.build_clib, lib_name + '.fobjects') with open(listfn, 'w') as f: f.write("\n".join(os.path.abspath(obj) for obj in f_objects)) listfn = os.path.join(self.build_clib, lib_name + '.cobjects') with open(listfn, 'w') as f: f.write("\n".join(os.path.abspath(obj) for obj in objects)) # create empty "library" file for dependency tracking lib_fname = os.path.join(self.build_clib, lib_name + compiler.static_lib_extension) with open(lib_fname, 'wb') as f: pass else: # assume that default linker is suitable for # linking Fortran object files objects.extend(f_objects) 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: clib_libraries.extend(binfo.get('libraries', [])) if clib_libraries: build_info['libraries'] = clib_libraries
def generate_config_h(ext, build_dir): target = join(build_dir,header_dir,'config.h') d = os.path.dirname(target) if not os.path.exists(d): os.makedirs(d) if newer(__file__,target): config_cmd = config.get_config_cmd() log.info('Generating %s',target) # Check sizeof moredefs, ignored = cocache.check_types(config_cmd, ext, build_dir) # Check math library and C99 math funcs availability mathlibs = check_mathlib(config_cmd) moredefs.append(('MATHLIB',','.join(mathlibs))) check_math_capabilities(config_cmd, moredefs, mathlibs) moredefs.extend(cocache.check_ieee_macros(config_cmd)[0]) # Signal check if is_npy_no_signal(): moredefs.append('__NPY_PRIVATE_NO_SIGNAL') # Windows checks if sys.platform=='win32' or os.name=='nt': win32_checks(moredefs) # Inline check inline = config_cmd.check_inline() # Generate the config.h file from moredefs target_f = open(target,'a') for d in moredefs: if isinstance(d,str): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0],d[1])) # define inline to our keyword, or nothing target_f.write('#ifndef __cplusplus\n') if inline == 'inline': target_f.write('/* #undef inline */\n') else: target_f.write('#define inline %s\n' % inline) target_f.write('#endif\n') target_f.close() print 'File:',target target_f = open(target) print target_f.read() target_f.close() print 'EOF' else: mathlibs = [] target_f = open(target) for line in target_f.readlines(): s = '#define MATHLIB' if line.startswith(s): value = line[len(s):].strip() if value: mathlibs.extend(value.split(',')) target_f.close() # Ugly: this can be called within a library and not an extension, # in which case there is no libraries attributes (and none is # needed). if hasattr(ext, 'libraries'): ext.libraries.extend(mathlibs) incl_dir = os.path.dirname(target) if incl_dir not in config.numpy_include_dirs: config.numpy_include_dirs.append(incl_dir) return target
def generate_config_h(ext, build_dir): target = join(build_dir, header_dir, 'config.h') d = os.path.dirname(target) if not os.path.exists(d): os.makedirs(d) if newer(__file__, target): config_cmd = config.get_config_cmd() log.info('Generating %s', target) # Check sizeof moredefs, ignored = cocache.check_types(config_cmd, ext, build_dir) # Check math library and C99 math funcs availability mathlibs = check_mathlib(config_cmd) moredefs.append(('MATHLIB', ','.join(mathlibs))) check_math_capabilities(config_cmd, moredefs, mathlibs) moredefs.extend(cocache.check_ieee_macros(config_cmd)[0]) moredefs.extend(cocache.check_complex(config_cmd, mathlibs)[0]) # Signal check if is_npy_no_signal(): moredefs.append('__NPY_PRIVATE_NO_SIGNAL') # Windows checks if sys.platform=='win32' or os.name=='nt': win32_checks(moredefs) # C99 restrict keyword moredefs.append(('NPY_RESTRICT', config_cmd.check_restrict())) # Inline check inline = config_cmd.check_inline() # Check whether we need our own wide character support if not config_cmd.check_decl('Py_UNICODE_WIDE', headers=['Python.h']): PYTHON_HAS_UNICODE_WIDE = True else: PYTHON_HAS_UNICODE_WIDE = False if ENABLE_SEPARATE_COMPILATION: moredefs.append(('ENABLE_SEPARATE_COMPILATION', 1)) if NPY_RELAXED_STRIDES_CHECKING: moredefs.append(('NPY_RELAXED_STRIDES_CHECKING', 1)) # Get long double representation if sys.platform != 'darwin': rep = check_long_double_representation(config_cmd) if rep in ['INTEL_EXTENDED_12_BYTES_LE', 'INTEL_EXTENDED_16_BYTES_LE', 'MOTOROLA_EXTENDED_12_BYTES_BE', 'IEEE_QUAD_LE', 'IEEE_QUAD_BE', 'IEEE_DOUBLE_LE', 'IEEE_DOUBLE_BE', 'DOUBLE_DOUBLE_BE', 'DOUBLE_DOUBLE_LE']: moredefs.append(('HAVE_LDOUBLE_%s' % rep, 1)) else: raise ValueError("Unrecognized long double format: %s" % rep) # Py3K check if sys.version_info[0] == 3: moredefs.append(('NPY_PY3K', 1)) # Generate the config.h file from moredefs target_f = open(target, 'w') for d in moredefs: if isinstance(d, str): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0], d[1])) # define inline to our keyword, or nothing target_f.write('#ifndef __cplusplus\n') if inline == 'inline': target_f.write('/* #undef inline */\n') else: target_f.write('#define inline %s\n' % inline) target_f.write('#endif\n') # add the guard to make sure config.h is never included directly, # but always through npy_config.h target_f.write(""" #ifndef _NPY_NPY_CONFIG_H_ #error config.h should never be included directly, include npy_config.h instead #endif """) target_f.close() print('File:', target) target_f = open(target) print(target_f.read()) target_f.close() print('EOF') else: mathlibs = [] target_f = open(target) for line in target_f: s = '#define MATHLIB' if line.startswith(s): value = line[len(s):].strip() if value: mathlibs.extend(value.split(',')) target_f.close() # Ugly: this can be called within a library and not an extension, # in which case there is no libraries attributes (and none is # needed). if hasattr(ext, 'libraries'): ext.libraries.extend(mathlibs) incl_dir = os.path.dirname(target) if incl_dir not in config.numpy_include_dirs: config.numpy_include_dirs.append(incl_dir) return target
def finalize_options(self): self.set_undefined_options( "build", ("build_base", "build_base"), ("build_lib", "build_lib"), ("force", "force"), ) if self.package is None: self.package = self.distribution.ext_package self.extensions = self.distribution.ext_modules self.libraries = self.distribution.libraries or [] self.py_modules = self.distribution.py_modules or [] self.data_files = self.distribution.data_files or [] 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) # py_modules_dict is used in build_py.find_package_modules self.py_modules_dict = {} 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.f2py_opts = shlex.split(self.f2py_opts) 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.swig_opts = shlex.split(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 generate_numpyconfig_h(ext, build_dir): """Depends on config.h: generate_config_h has to be called before !""" # put private include directory in build_dir on search path # allows using code generation in headers headers config.add_include_dirs(join(build_dir, "src", "private")) target = join(build_dir, header_dir, '_numpyconfig.h') d = os.path.dirname(target) if not os.path.exists(d): os.makedirs(d) if newer(__file__, target): config_cmd = config.get_config_cmd() log.info('Generating %s', target) # Check sizeof ignored, moredefs = cocache.check_types(config_cmd, ext, build_dir) if is_npy_no_signal(): moredefs.append(('NPY_NO_SIGNAL', 1)) if is_npy_no_smp(): moredefs.append(('NPY_NO_SMP', 1)) else: moredefs.append(('NPY_NO_SMP', 0)) mathlibs = check_mathlib(config_cmd) moredefs.extend(cocache.check_ieee_macros(config_cmd)[1]) moredefs.extend(cocache.check_complex(config_cmd, mathlibs)[1]) if ENABLE_SEPARATE_COMPILATION: moredefs.append(('NPY_ENABLE_SEPARATE_COMPILATION', 1)) if NPY_RELAXED_STRIDES_CHECKING: moredefs.append(('NPY_RELAXED_STRIDES_CHECKING', 1)) # Check wether we can use inttypes (C99) formats if config_cmd.check_decl('PRIdPTR', headers = ['inttypes.h']): moredefs.append(('NPY_USE_C99_FORMATS', 1)) # visibility check hidden_visibility = visibility_define(config_cmd) moredefs.append(('NPY_VISIBILITY_HIDDEN', hidden_visibility)) # Add the C API/ABI versions moredefs.append(('NPY_ABI_VERSION', '0x%.8X' % C_ABI_VERSION)) moredefs.append(('NPY_API_VERSION', '0x%.8X' % C_API_VERSION)) # Add moredefs to header target_f = open(target, 'w') for d in moredefs: if isinstance(d, str): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0], d[1])) # Define __STDC_FORMAT_MACROS target_f.write(""" #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS 1 #endif """) target_f.close() # Dump the numpyconfig.h header to stdout print('File: %s' % target) target_f = open(target) print(target_f.read()) target_f.close() print('EOF') config.add_data_files((header_dir, target)) return target
def generate_numpyconfig_h(ext, build_dir): """Depends on config.h: generate_config_h has to be called before !""" target = join(build_dir, header_dir, 'numpyconfig.h') d = os.path.dirname(target) if not os.path.exists(d): os.makedirs(d) if newer(__file__, target): config_cmd = config.get_config_cmd() log.info('Generating %s', target) # Check sizeof ignored, moredefs = cocache.check_types(config_cmd, ext, build_dir) if is_npy_no_signal(): moredefs.append(('NPY_NO_SIGNAL', 1)) if is_npy_no_smp(): moredefs.append(('NPY_NO_SMP', 1)) else: moredefs.append(('NPY_NO_SMP', 0)) moredefs.extend(cocache.check_ieee_macros(config_cmd)[1]) if ENABLE_SEPARATE_COMPILATION: moredefs.append(('NPY_ENABLE_SEPARATE_COMPILATION', 1)) # Check wether we can use inttypes (C99) formats if config_cmd.check_decl('PRIdPTR', headers=['inttypes.h']): moredefs.append(('NPY_USE_C99_FORMATS', 1)) # Inline check inline = config_cmd.check_inline() # visibility check hidden_visibility = visibility_define(config_cmd) moredefs.append(('NPY_VISIBILITY_HIDDEN', hidden_visibility)) # Add the C API/ABI versions moredefs.append(('NPY_ABI_VERSION', '0x%.8X' % C_ABI_VERSION)) moredefs.append(('NPY_API_VERSION', '0x%.8X' % C_API_VERSION)) # Add moredefs to header target_f = open(target, 'w') for d in moredefs: if isinstance(d, str): target_f.write('#define %s\n' % (d)) else: target_f.write('#define %s %s\n' % (d[0], d[1])) # define NPY_INLINE to recognized keyword target_f.write('#define NPY_INLINE %s\n' % inline) # Define __STDC_FORMAT_MACROS target_f.write(""" #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS 1 #endif """) target_f.close() # Dump the numpyconfig.h header to stdout print 'File: %s' % target target_f = open(target) print target_f.read() target_f.close() print 'EOF' config.add_data_files((header_dir, target)) return target
def CCompiler_compile(self, sources, output_dir=None, macros=None, include_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, depends=None): """ Compile one or more source files. Please refer to the Python distutils API reference for more details. Parameters ---------- sources : list of str A list of filenames output_dir : str, optional Path to the output directory. macros : list of tuples A list of macro definitions. include_dirs : list of str, optional The directories to add to the default include file search path for this compilation only. debug : bool, optional Whether or not to output debug symbols in or alongside the object file(s). extra_preargs, extra_postargs : ? Extra pre- and post-arguments. depends : list of str, optional A list of file names that all targets depend on. Returns ------- objects : list of str A list of object file names, one per source file `sources`. Raises ------ CompileError If compilation fails. """ # This method is effective only with Python >=2.3 distutils. # Any changes here should be applied also to fcompiler.compile # method to support pre Python 2.3 distutils. if not sources: return [] # FIXME:RELATIVE_IMPORT if sys.version_info[0] < 3: from fcompiler import FCompiler else: from numpy.distutils.fcompiler import FCompiler if isinstance(self, FCompiler): display = [] for fc in ['f77','f90','fix']: fcomp = getattr(self,'compiler_'+fc) if fcomp is None: continue display.append("Fortran %s compiler: %s" % (fc, ' '.join(fcomp))) display = '\n'.join(display) else: ccomp = self.compiler_so display = "C compiler: %s\n" % (' '.join(ccomp),) log.info(display) macros, objects, extra_postargs, pp_opts, build = \ self._setup_compile(output_dir, macros, include_dirs, sources, depends, extra_postargs) cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) display = "compile options: '%s'" % (' '.join(cc_args)) if extra_postargs: display += "\nextra options: '%s'" % (' '.join(extra_postargs)) log.info(display) # build any sources in same order as they were originally specified # especially important for fortran .f90 files using modules if isinstance(self, FCompiler): objects_to_build = build.keys() for obj in objects: if obj in objects_to_build: src, ext = build[obj] if self.compiler_type=='absoft': obj = cyg2win32(obj) src = cyg2win32(src) self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) else: for obj, (src, ext) in build.items(): self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) # Return *all* object filenames, not just the ones we just built. return objects
'pathccompiler', 'PathScaleCCompiler', "PathScale Compiler for SiCortex-based applications") compiler_class['arm'] = ('armccompiler', 'ArmCCompiler', "Arm C Compiler") ccompiler._default_compilers += (('linux.*', 'intel'), ('linux.*', 'intele'), ('linux.*', 'intelem'), ('linux.*', 'pathcc'), ('nt', 'intelw'), ('nt', 'intelemw')) if sys.platform == 'win32': compiler_class['mingw32'] = ('mingw32ccompiler', 'Mingw32CCompiler', "Mingw32 port of GNU C Compiler for Win32"\ "(for MSC built Python)") if mingw32(): # On windows platforms, we want to default to mingw32 (gcc) # because msvc can't build blitz stuff. log.info('Setting mingw32 as default compiler for nt.') ccompiler._default_compilers = (('nt', 'mingw32'),) \ + ccompiler._default_compilers _distutils_new_compiler = new_compiler def new_compiler(plat=None, compiler=None, verbose=None, dry_run=0, force=0): # Try first C compilers from numpy.distutils. if verbose is None: verbose = log.get_threshold() <= log.INFO if plat is None: plat = os.name try: if compiler is None: compiler = get_default_compiler(plat)
def CCompiler_customize(self, dist, need_cxx=0): """ Do any platform-specific customization of a compiler instance. This method calls `distutils.sysconfig.customize_compiler` for platform-specific customization, as well as optionally remove a flag to suppress spurious warnings in case C++ code is being compiled. Parameters ---------- dist : object This parameter is not used for anything. need_cxx : bool, optional Whether or not C++ has to be compiled. If so (True), the ``"-Wstrict-prototypes"`` option is removed to prevent spurious warnings. Default is False. Returns ------- None Notes ----- All the default options used by distutils can be extracted with:: from distutils import sysconfig sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', 'CCSHARED', 'LDSHARED', 'SO') """ # See FCompiler.customize for suggested usage. log.info('customize %s' % (self.__class__.__name__)) customize_compiler(self) if need_cxx: # In general, distutils uses -Wstrict-prototypes, but this option is # not valid for C++ code, only for C. Remove it if it's there to # avoid a spurious warning on every compilation. try: self.compiler_so.remove('-Wstrict-prototypes') except (AttributeError, ValueError): pass if hasattr(self, 'compiler') and 'cc' in self.compiler[0]: if not self.compiler_cxx: if self.compiler[0].startswith('gcc'): a, b = 'gcc', 'g++' else: a, b = 'cc', 'c++' self.compiler_cxx = [self.compiler[0].replace(a, b)]\ + self.compiler[1:] else: if hasattr(self, 'compiler'): log.warn("#### %s #######" % (self.compiler, )) if not hasattr(self, 'compiler_cxx'): log.warn('Missing compiler_cxx fix for ' + self.__class__.__name__) # check if compiler supports gcc style automatic dependencies # run on every extension so skip for known good compilers if hasattr(self, 'compiler') and ('gcc' in self.compiler[0] or 'g++' in self.compiler[0] or 'clang' in self.compiler[0]): self._auto_depends = True elif os.name == 'posix': import tempfile import shutil tmpdir = tempfile.mkdtemp() try: fn = os.path.join(tmpdir, "file.c") with open(fn, "w") as f: f.write("int a;\n") self.compile([fn], output_dir=tmpdir, extra_preargs=['-MMD', '-MF', fn + '.d']) self._auto_depends = True except CompileError: self._auto_depends = False finally: shutil.rmtree(tmpdir) return
def run(self): if not self.libraries: return # Make sure that library sources are complete. languages = [] # Make sure that extension sources are complete. self.run_command('build_src') for (lib_name, build_info) in self.libraries: 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, dry_run=self.dry_run, force=self.force) self.compiler.customize(self.distribution, need_cxx=self.have_cxx_sources()) if self.warn_error: self.compiler.compiler.append('-Werror') self.compiler.compiler_so.append('-Werror') libraries = self.libraries self.libraries = None self.compiler.customize_cmd(self) self.libraries = libraries self.compiler.show_customization() if not self.disable_optimization: dispatch_hpath = os.path.join("numpy", "distutils", "include", "npy_cpu_dispatch_config.h") dispatch_hpath = os.path.join( self.get_finalized_command("build_src").build_src, dispatch_hpath) opt_cache_path = os.path.abspath( os.path.join(self.build_temp, 'ccompiler_opt_cache_clib.py')) self.compiler_opt = new_ccompiler_opt( compiler=self.compiler, dispatch_hpath=dispatch_hpath, cpu_baseline=self.cpu_baseline, cpu_dispatch=self.cpu_dispatch, cache_path=opt_cache_path) if not self.compiler_opt.is_cached(): log.info( "Detected changes on compiler optimizations, force rebuilding" ) self.force = True def report(copt): log.info( "\n########### CLIB COMPILER OPTIMIZATION ###########") log.info(copt.report(full=True)) import atexit atexit.register(report, self.compiler_opt) 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) if self._f_compiler is not None: self._f_compiler.customize(self.distribution) libraries = self.libraries self.libraries = None self._f_compiler.customize_cmd(self) self.libraries = libraries self._f_compiler.show_customization() else: self._f_compiler = None self.build_libraries(self.libraries) if self.inplace: 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) self.mkpath(l.target_dir) shutil.copy(source, target)
def customize(self, dist=None): """Customize Fortran compiler. This method gets Fortran compiler specific information from (i) class definition, (ii) environment, (iii) distutils config files, and (iv) command line (later overrides earlier). This method should be always called after constructing a compiler instance. But not in __init__ because Distribution instance is needed for (iii) and (iv). """ log.info("customize %s" % (self.__class__.__name__)) self._is_customised = True self.distutils_vars.use_distribution(dist) self.command_vars.use_distribution(dist) self.flag_vars.use_distribution(dist) self.update_executables() # find_executables takes care of setting the compiler commands, # version_cmd, linker_so, linker_exe, ar, and ranlib self.find_executables() noopt = self.distutils_vars.get("noopt", False) noarch = self.distutils_vars.get("noarch", noopt) debug = self.distutils_vars.get("debug", False) f77 = self.command_vars.compiler_f77 f90 = self.command_vars.compiler_f90 f77flags = [] f90flags = [] freeflags = [] fixflags = [] if f77: f77 = _shell_utils.NativeParser.split(f77) f77flags = self.flag_vars.f77 if f90: f90 = _shell_utils.NativeParser.split(f90) f90flags = self.flag_vars.f90 freeflags = self.flag_vars.free # XXX Assuming that free format is default for f90 compiler. fix = self.command_vars.compiler_fix # NOTE: this and similar examples are probably just # exluding --coverage flag when F90 = gfortran --coverage # instead of putting that flag somewhere more appropriate # this and similar examples where a Fortran compiler # environment variable has been customized by CI or a user # should perhaps eventually be more throughly tested and more # robustly handled if fix: fix = _shell_utils.NativeParser.split(fix) fixflags = self.flag_vars.fix + f90flags oflags, aflags, dflags = [], [], [] # examine get_flags_<tag>_<compiler> for extra flags # only add them if the method is different from get_flags_<tag> def get_flags(tag, flags): # note that self.flag_vars.<tag> calls self.get_flags_<tag>() flags.extend(getattr(self.flag_vars, tag)) this_get = getattr(self, "get_flags_" + tag) for name, c, flagvar in [ ("f77", f77, f77flags), ("f90", f90, f90flags), ("f90", fix, fixflags), ]: t = "%s_%s" % (tag, name) if c and this_get is not getattr(self, "get_flags_" + t): flagvar.extend(getattr(self.flag_vars, t)) if not noopt: get_flags("opt", oflags) if not noarch: get_flags("arch", aflags) if debug: get_flags("debug", dflags) fflags = self.flag_vars.flags + dflags + oflags + aflags if f77: self.set_commands(compiler_f77=f77 + f77flags + fflags) if f90: self.set_commands(compiler_f90=f90 + freeflags + f90flags + fflags) if fix: self.set_commands(compiler_fix=fix + fixflags + fflags) # XXX: Do we need LDSHARED->SOSHARED, LDFLAGS->SOFLAGS linker_so = self.linker_so if linker_so: linker_so_flags = self.flag_vars.linker_so if sys.platform.startswith("aix"): python_lib = get_python_lib(standard_lib=1) ld_so_aix = os.path.join(python_lib, "config", "ld_so_aix") python_exp = os.path.join(python_lib, "config", "python.exp") linker_so = [ld_so_aix] + linker_so + ["-bI:" + python_exp] self.set_commands(linker_so=linker_so + linker_so_flags) linker_exe = self.linker_exe if linker_exe: linker_exe_flags = self.flag_vars.linker_exe self.set_commands(linker_exe=linker_exe + linker_exe_flags) ar = self.command_vars.archiver if ar: arflags = self.flag_vars.ar self.set_commands(archiver=[ar] + arflags) self.set_library_dirs(self.get_library_dirs()) self.set_libraries(self.get_libraries())
def package_check(pkg_name, version=None, optional=False, checker=LooseVersion, version_getter=None, messages=None, show_only=False): """ Check if package `pkg_name` is present, and in correct version. Parameters ---------- pkg_name : str or sequence of str The name of the package as imported into python. Alternative names (e.g. for different versions) may be given in a list. version : str, optional The minimum version of the package that is required. If not given, the version is not checked. optional : bool, optional If False, raise error for absent package or wrong version; otherwise warn checker : callable, optional If given, the callable with which to return a comparable thing from a version string. The default is ``distutils.version.LooseVersion``. version_getter : callable, optional: If given, the callable that takes `pkg_name` as argument, and returns the package version string - as in:: ``version = version_getter(pkg_name)`` The default is equivalent to:: mod = __import__(pkg_name); version = mod.__version__`` messages : dict, optional If given, the dictionary providing (some of) output messages. show_only : bool If True, do not raise exceptions, only show the package name and version information. """ if version_getter is None: def version_getter(pkg_name): mod = __import__(pkg_name) return mod.__version__ if messages is None: messages = {} msgs = { 'available': '%s is available', 'missing': '%s is missing', 'opt suffix': '; you may get run-time errors', 'version': '%s is available in version %s', 'version old': '%s is available in version %s, but >= %s is needed', 'no version': '%s is available, cannot determine version', } msgs.update(messages) if isinstance(pkg_name, str): names = [pkg_name] else: names = pkg_name import_ok = False for pkg_name in names: try: __import__(pkg_name) except ImportError: pass else: import_ok = True pkg_info = pkg_name + (' (optional)' if optional else '') if not import_ok: if not (optional or show_only): raise RuntimeError(msgs['missing'] % pkg_name) log.warn(msgs['missing'] % pkg_info + msgs['opt suffix']) return if not version: if show_only: log.info(msgs['available'] % pkg_info) return try: have_version = version_getter(pkg_name) except AttributeError: raise RuntimeError(msgs['no version'] % pkg_info) if not have_version: if optional or show_only: log.warn(msgs['no version'] % pkg_info) else: raise RuntimeError(msgs['no version'] % pkg_info) elif checker(have_version) < checker(version): if optional or show_only: log.warn(msgs['version old'] % (pkg_info, have_version, version) + msgs['opt suffix']) else: raise RuntimeError(msgs['version old'] % (pkg_info, have_version, version)) elif show_only: log.info(msgs['version'] % (pkg_info, have_version))
def report(copt): log.info( "\n########### CLIB COMPILER OPTIMIZATION ###########") log.info(copt.report(full=True))
def run(self): log.info("build_src") if not (self.extensions or self.libraries): return self.build_sources()
def f2py_sources(self, sources, extension): new_sources = [] f2py_sources = [] f_sources = [] f2py_targets = {} target_dirs = [] ext_name = extension.name.split('.')[-1] skip_f2py = 0 for source in sources: (base, ext) = os.path.splitext(source) if ext == '.pyf': # F2PY interface file if self.inplace: target_dir = os.path.dirname(base) else: target_dir = appendpath(self.build_src, os.path.dirname(base)) if os.path.isfile(source): name = get_f2py_modulename(source) if 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.' \ % (source)) name = ext_name skip_f2py = 1 target_file = os.path.join(target_dir, name + 'module.c') if not os.path.isfile(target_file): 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 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 new_sources.append(target_file) elif fortran_ext_match(ext): f_sources.append(source) else: new_sources.append(source) if not (f2py_sources or f_sources): return new_sources for d in target_dirs: self.mkpath(d) f2py_options = extension.f2py_options + self.f2py_opts if self.distribution.libraries: for name, build_info in self.distribution.libraries: if name in extension.libraries: f2py_options.extend(build_info.get('f2py_options', [])) log.info("f2py options: %s" % (f2py_options)) if f2py_sources: if len(f2py_sources) != 1: raise DistutilsSetupError( 'only one .pyf file is allowed per extension module but got' \ ' more: %r' % (f2py_sources,)) source = f2py_sources[0] target_file = f2py_targets[source] target_dir = os.path.dirname(target_file) or '.' depends = [source] + extension.depends if (self.force or newer_group(depends, target_file, 'newer')) \ and not skip_f2py: log.info("f2py: %s" % (source)) import numpy.f2py numpy.f2py.run_main(f2py_options + ['--build-dir', target_dir, source]) else: log.debug(" skipping '%s' f2py interface (up-to-date)" % (source)) else: #XXX TODO: --inplace support for sdist command if is_sequence(extension): name = extension[0] else: name = extension.name target_dir = os.path.join(*([self.build_src] + name.split('.')[:-1])) target_file = os.path.join(target_dir, ext_name + 'module.c') new_sources.append(target_file) depends = f_sources + extension.depends if (self.force or newer_group(depends, target_file, 'newer')) \ and not skip_f2py: log.info("f2py:> %s" % (target_file)) self.mkpath(target_dir) import numpy.f2py numpy.f2py.run_main(f2py_options + ['--lower', '--build-dir', target_dir] + \ ['-m', ext_name] + f_sources) else: log.debug(" skipping f2py fortran files for '%s' (up-to-date)" \ % (target_file)) if not os.path.isfile(target_file): raise DistutilsError("f2py target file %r not generated" % (target_file, )) build_dir = os.path.join(self.build_src, target_dir) target_c = os.path.join(build_dir, 'fortranobject.c') target_h = os.path.join(build_dir, 'fortranobject.h') log.info(" adding '%s' to sources." % (target_c)) new_sources.append(target_c) if build_dir not in extension.include_dirs: log.info(" adding '%s' to include_dirs." % (build_dir)) extension.include_dirs.append(build_dir) if not skip_f2py: import numpy.f2py d = os.path.dirname(numpy.f2py.__file__) source_c = os.path.join(d, 'src', 'fortranobject.c') source_h = os.path.join(d, 'src', 'fortranobject.h') if newer(source_c, target_c) or newer(source_h, target_h): self.mkpath(os.path.dirname(target_c)) self.copy_file(source_c, target_c) self.copy_file(source_h, target_h) else: if not os.path.isfile(target_c): raise DistutilsSetupError("f2py target_c file %r not found" % (target_c, )) if not os.path.isfile(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) if os.path.isfile(filename): log.info(" adding '%s' to sources." % (filename)) f_sources.append(filename) return new_sources + f_sources
def customize(self, dist=None): """Customize Fortran compiler. This method gets Fortran compiler specific information from (i) class definition, (ii) environment, (iii) distutils config files, and (iv) command line (later overrides earlier). This method should be always called after constructing a compiler instance. But not in __init__ because Distribution instance is needed for (iii) and (iv). """ log.info('customize %s' % (self.__class__.__name__)) self._is_customised = True self.distutils_vars.use_distribution(dist) self.command_vars.use_distribution(dist) self.flag_vars.use_distribution(dist) self.update_executables() # find_executables takes care of setting the compiler commands, # version_cmd, linker_so, linker_exe, ar, and ranlib self.find_executables() noopt = self.distutils_vars.get('noopt', False) noarch = self.distutils_vars.get('noarch', noopt) debug = self.distutils_vars.get('debug', False) f77 = self.command_vars.compiler_f77 f90 = self.command_vars.compiler_f90 f77flags = [] f90flags = [] freeflags = [] fixflags = [] if f77: f77flags = self.flag_vars.f77 if f90: f90flags = self.flag_vars.f90 freeflags = self.flag_vars.free # XXX Assuming that free format is default for f90 compiler. fix = self.command_vars.compiler_fix if fix: fixflags = self.flag_vars.fix + f90flags oflags, aflags, dflags = [], [], [] # examine get_flags_<tag>_<compiler> for extra flags # only add them if the method is different from get_flags_<tag> def get_flags(tag, flags): # note that self.flag_vars.<tag> calls self.get_flags_<tag>() flags.extend(getattr(self.flag_vars, tag)) this_get = getattr(self, 'get_flags_' + tag) for name, c, flagvar in [('f77', f77, f77flags), ('f90', f90, f90flags), ('f90', fix, fixflags)]: t = '%s_%s' % (tag, name) if c and this_get is not getattr(self, 'get_flags_' + t): flagvar.extend(getattr(self.flag_vars, t)) if not noopt: get_flags('opt', oflags) if not noarch: get_flags('arch', aflags) if debug: get_flags('debug', dflags) fflags = self.flag_vars.flags + dflags + oflags + aflags if f77: self.set_commands(compiler_f77=[f77] + f77flags + fflags) if f90: self.set_commands(compiler_f90=[f90] + freeflags + f90flags + fflags) if fix: self.set_commands(compiler_fix=[fix] + fixflags + fflags) #XXX: Do we need LDSHARED->SOSHARED, LDFLAGS->SOFLAGS linker_so = self.linker_so if linker_so: linker_so_flags = self.flag_vars.linker_so if sys.platform.startswith('aix'): python_lib = get_python_lib(standard_lib=1) ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix') python_exp = os.path.join(python_lib, 'config', 'python.exp') linker_so = [ld_so_aix] + linker_so + ['-bI:' + python_exp] self.set_commands(linker_so=linker_so + linker_so_flags) linker_exe = self.linker_exe if linker_exe: linker_exe_flags = self.flag_vars.linker_exe self.set_commands(linker_exe=linker_exe + linker_exe_flags) ar = self.command_vars.archiver if ar: arflags = self.flag_vars.ar self.set_commands(archiver=[ar] + arflags) self.set_library_dirs(self.get_library_dirs()) self.set_libraries(self.get_libraries())
def run(self): if not self.extensions: return # Make sure that extension sources are complete. self.run_command("build_src") 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") else: build_clib = self.distribution.get_command_obj( "build_clib") build_clib.inplace = 1 build_clib.ensure_finalized() build_clib.run() self.distribution.have_run["build_clib"] = 1 else: self.run_command("build_clib") 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. from distutils.ccompiler import new_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) self.compiler.customize_cmd(self) if self.warn_error: self.compiler.compiler.append("-Werror") self.compiler.compiler_so.append("-Werror") self.compiler.show_customization() if not self.disable_optimization: dispatch_hpath = os.path.join("numpy", "distutils", "include", "npy_cpu_dispatch_config.h") dispatch_hpath = os.path.join( self.get_finalized_command("build_src").build_src, dispatch_hpath) opt_cache_path = os.path.abspath( os.path.join(self.build_temp, "ccompiler_opt_cache_ext.py")) self.compiler_opt = new_ccompiler_opt( compiler=self.compiler, dispatch_hpath=dispatch_hpath, cpu_baseline=self.cpu_baseline, cpu_dispatch=self.cpu_dispatch, cache_path=opt_cache_path, ) if not self.compiler_opt.is_cached(): log.info( "Detected changes on compiler optimizations, force rebuilding" ) self.force = True import atexit def report(): log.info("\n########### EXT COMPILER OPTIMIZATION ###########") log.info(self.compiler_opt.report(full=True)) atexit.register(report) # Setup directory for storing generated extra DLL files on Windows self.extra_dll_dir = os.path.join(self.build_temp, ".libs") if not os.path.isdir(self.extra_dll_dir): os.makedirs(self.extra_dll_dir) # 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 libname in clibs and clibs[libname] != build_info: 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: for libname, build_info in self.distribution.libraries or []: if libname in clibs: # 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 libname in clibs: 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: ctype = self.fcompiler self._f77_compiler = new_fcompiler( compiler=self.fcompiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force, requiref90=False, c_compiler=self.compiler, ) fcompiler = self._f77_compiler if fcompiler: ctype = fcompiler.compiler_type fcompiler.customize(self.distribution) if fcompiler and fcompiler.get_version(): fcompiler.customize_cmd(self) fcompiler.show_customization() else: self.warn("f77_compiler=%s is not available." % (ctype)) self._f77_compiler = None else: self._f77_compiler = None # Initialize Fortran 90 compiler: if need_f90_compiler: ctype = self.fcompiler self._f90_compiler = new_fcompiler( compiler=self.fcompiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force, requiref90=True, c_compiler=self.compiler, ) fcompiler = self._f90_compiler if fcompiler: ctype = fcompiler.compiler_type fcompiler.customize(self.distribution) if fcompiler and fcompiler.get_version(): fcompiler.customize_cmd(self) fcompiler.show_customization() else: self.warn("f90_compiler=%s is not available." % (ctype)) self._f90_compiler = None else: self._f90_compiler = None # Build extensions self.build_extensions() # Copy over any extra DLL files # FIXME: In the case where there are more than two packages, # we blindly assume that both packages need all of the libraries, # resulting in a larger wheel than is required. This should be fixed, # but it's so rare that I won't bother to handle it. pkg_roots = { self.get_ext_fullname(ext.name).split(".")[0] for ext in self.extensions } for pkg_root in pkg_roots: shared_lib_dir = os.path.join(pkg_root, ".libs") if not self.inplace: shared_lib_dir = os.path.join(self.build_lib, shared_lib_dir) for fn in os.listdir(self.extra_dll_dir): if not os.path.isdir(shared_lib_dir): os.makedirs(shared_lib_dir) if not fn.lower().endswith(".dll"): continue runtime_lib = os.path.join(self.extra_dll_dir, fn) copy_file(runtime_lib, shared_lib_dir)