%PDF- %PDF-
Direktori : /lib/python3/dist-packages/pythran/ |
Current File : //lib/python3/dist-packages/pythran/dist.py |
''' This modules contains a distutils extension mechanism for Pythran * PythranExtension: is used as distutils's Extension ''' import pythran.config as cfg from collections import defaultdict try: from collections.abc import Iterable except ImportError: from collections import Iterable import os.path import os from distutils.command.build_ext import build_ext as LegacyBuildExt from numpy.distutils.extension import Extension class PythranBuildExtMixIn(object): """Subclass of `distutils.command.build_ext.build_ext` which is required to build `PythranExtension` with the configured C++ compiler. It may also be subclassed if you want to combine with another build_ext class (NumPy, Cython implementations). """ def build_extension(self, ext): StringTypes = str, def get_value(obj, key): var = getattr(obj, key) if isinstance(var, Iterable) and not isinstance(var, StringTypes): return var[0] else: return var def set_value(obj, key, value): var = getattr(obj, key) if isinstance(var, Iterable) and not isinstance(var, StringTypes): var[0] = value else: setattr(obj, key, value) prev = { # linux-like 'preprocessor': None, 'compiler_cxx': None, 'compiler_so': None, 'compiler': None, 'linker_exe': None, 'linker_so': None, # Windows-like 'cc': None, } # Backup compiler settings for key in list(prev.keys()): if hasattr(self.compiler, key): prev[key] = get_value(self.compiler, key) else: del prev[key] # try hard to modify the compiler if getattr(ext, 'cxx', None) is not None: for comp in prev: if hasattr(self.compiler, comp): set_value(self.compiler, comp, ext.cxx) find_exe = None if getattr(ext, 'cc', None) is not None: try: import distutils._msvccompiler as msvc # install hook find_exe = msvc._find_exe def _find_exe(exe, *args, **kwargs): if exe == 'cl.exe': exe = ext.cc return find_exe(exe, *args, **kwargs) msvc._find_exe = _find_exe except ImportError: pass # 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. for flag in cfg.cfg.get('compiler', "ignoreflags").split(): for target in ('compiler_so', 'linker_so'): try: while True: getattr(self.compiler, target).remove(flag) except (AttributeError, ValueError): pass # Remove -arch i386 if 'x86_64' is specified, otherwise incorrect # code is generated, at least on OSX if hasattr(self.compiler, 'compiler_so'): archs = defaultdict(list) for i, flag in enumerate(self.compiler.compiler_so[1:]): if self.compiler.compiler_so[i] == '-arch': archs[flag].append(i + 1) if 'x86_64' in archs and 'i386' in archs: for i in archs['i386']: self.compiler.compiler_so[i] = 'x86_64' try: return super(PythranBuildExtMixIn, self).build_extension(ext) finally: # Revert compiler settings for key in prev.keys(): set_value(self.compiler, key, prev[key]) # uninstall hook if find_exe is not None: import distutils._msvccompiler as msvc msvc._find_exe = find_exe class PythranBuildExtMeta(type): def __getitem__(self, base): class PythranBuildExt(PythranBuildExtMixIn, base): pass return PythranBuildExt class PythranBuildExt(PythranBuildExtMixIn, LegacyBuildExt, metaclass=PythranBuildExtMeta): pass class PythranExtension(Extension): ''' Description of a Pythran extension Similar to distutils.core.Extension except that the sources are .py files They must be processable by pythran, of course. The compilation process ends up in a native Python module. ''' def __init__(self, name, sources, *args, **kwargs): cfg_ext = cfg.make_extension(python=True, **kwargs) self.cxx = cfg_ext.pop('cxx', None) self.cc = cfg_ext.pop('cc', None) self._sources = sources Extension.__init__(self, name, sources, *args, **cfg_ext) self.__dict__.pop("sources", None) @property def sources(self): import pythran.toolchain as tc cxx_sources = [] for source in self._sources: base, ext = os.path.splitext(source) if ext != '.py': cxx_sources.append(source) continue output_file = base + '.cpp' # target name if os.path.exists(source) and (not os.path.exists(output_file) or os.path.getmtime(output_file) < os.path.getmtime(source)): # get the last name in the path if '.' in self.name: module_name = os.path.splitext(self.name)[-1][1:] else: module_name = self.name tc.compile_pythranfile(source, output_file, module_name, cpponly=True) cxx_sources.append(output_file) return cxx_sources @sources.setter def sources(self, sources): self._sources = sources