"""Cython.Distutils.old_build_ext Implements a version of the Distutils 'build_ext' command, for building Cython extension modules. Note that this module is deprecated. Use cythonize() instead. """ __revision__ = "$Id:$" import sys import os from distutils.errors import DistutilsPlatformError from distutils.dep_util import newer, newer_group from distutils import log from distutils.command import build_ext as _build_ext from distutils import sysconfig try: from __builtin__ import basestring except ImportError: basestring = str # FIXME: the below does not work as intended since importing 'Cython.Distutils' already # imports this module through 'Cython/Distutils/build_ext.py', so the condition is # always false and never prints the warning. """ import inspect import warnings def _check_stack(path): try: for frame in inspect.getouterframes(inspect.currentframe(), 0): if path in frame[1].replace(os.sep, '/'): return True except Exception: pass return False if (not _check_stack('setuptools/extensions.py') and not _check_stack('pyximport/pyxbuild.py') and not _check_stack('Cython/Distutils/build_ext.py')): warnings.warn( "Cython.Distutils.old_build_ext does not properly handle dependencies " "and is deprecated.") """ extension_name_re = _build_ext.extension_name_re show_compilers = _build_ext.show_compilers class Optimization(object): def __init__(self): self.flags = ( 'OPT', 'CFLAGS', 'CPPFLAGS', 'EXTRA_CFLAGS', 'BASECFLAGS', 'PY_CFLAGS', ) self.state = sysconfig.get_config_vars(*self.flags) self.config_vars = sysconfig.get_config_vars() def disable_optimization(self): "disable optimization for the C or C++ compiler" badoptions = ('-O1', '-O2', '-O3') for flag, option in zip(self.flags, self.state): if option is not None: L = [opt for opt in option.split() if opt not in badoptions] self.config_vars[flag] = ' '.join(L) def restore_state(self): "restore the original state" for flag, option in zip(self.flags, self.state): if option is not None: self.config_vars[flag] = option optimization = Optimization() class old_build_ext(_build_ext.build_ext): description = "build C/C++ and Cython extensions (compile/link to build directory)" sep_by = _build_ext.build_ext.sep_by user_options = _build_ext.build_ext.user_options[:] boolean_options = _build_ext.build_ext.boolean_options[:] help_options = _build_ext.build_ext.help_options[:] # Add the pyrex specific data. user_options.extend([ ('cython-cplus', None, "generate C++ source files"), ('cython-create-listing', None, "write errors to a listing file"), ('cython-line-directives', None, "emit source line directives"), ('cython-include-dirs=', None, "path to the Cython include files" + sep_by), ('cython-c-in-temp', None, "put generated C files in temp directory"), ('cython-gen-pxi', None, "generate .pxi file for public declarations"), ('cython-directives=', None, "compiler directive overrides"), ('cython-gdb', None, "generate debug information for cygdb"), ('cython-compile-time-env', None, "cython compile time environment"), # For backwards compatibility. ('pyrex-cplus', None, "generate C++ source files"), ('pyrex-create-listing', None, "write errors to a listing file"), ('pyrex-line-directives', None, "emit source line directives"), ('pyrex-include-dirs=', None, "path to the Cython include files" + sep_by), ('pyrex-c-in-temp', None, "put generated C files in temp directory"), ('pyrex-gen-pxi', None, "generate .pxi file for public declarations"), ('pyrex-directives=', None, "compiler directive overrides"), ('pyrex-gdb', None, "generate debug information for cygdb"), ]) boolean_options.extend([ 'cython-cplus', 'cython-create-listing', 'cython-line-directives', 'cython-c-in-temp', 'cython-gdb', # For backwards compatibility. 'pyrex-cplus', 'pyrex-create-listing', 'pyrex-line-directives', 'pyrex-c-in-temp', 'pyrex-gdb', ]) def initialize_options(self): _build_ext.build_ext.initialize_options(self) self.cython_cplus = 0 self.cython_create_listing = 0 self.cython_line_directives = 0 self.cython_include_dirs = None self.cython_directives = None self.cython_c_in_temp = 0 self.cython_gen_pxi = 0 self.cython_gdb = False self.no_c_in_traceback = 0 self.cython_compile_time_env = None def __getattr__(self, name): if name[:6] == 'pyrex_': return getattr(self, 'cython_' + name[6:]) else: return _build_ext.build_ext.__getattr__(self, name) def __setattr__(self, name, value): if name[:6] == 'pyrex_': return setattr(self, 'cython_' + name[6:], value) else: # _build_ext.build_ext.__setattr__(self, name, value) self.__dict__[name] = value def finalize_options(self): _build_ext.build_ext.finalize_options(self) if self.cython_include_dirs is None: self.cython_include_dirs = [] elif isinstance(self.cython_include_dirs, basestring): self.cython_include_dirs = \ self.cython_include_dirs.split(os.pathsep) if self.cython_directives is None: self.cython_directives = {} # finalize_options () def run(self): # We have one shot at this before build_ext initializes the compiler. # If --pyrex-gdb is in effect as a command line option or as option # of any Extension module, disable optimization for the C or C++ # compiler. if self.cython_gdb or [1 for ext in self.extensions if getattr(ext, 'cython_gdb', False)]: optimization.disable_optimization() _build_ext.build_ext.run(self) def check_extensions_list(self, extensions): # Note: might get called multiple times. _build_ext.build_ext.check_extensions_list(self, extensions) for ext in self.extensions: ext.sources = self.cython_sources(ext.sources, ext) def cython_sources(self, sources, extension): """ Walk the list of source files in 'sources', looking for Cython source files (.pyx and .py). Run Cython on all that are found, and return a modified 'sources' list with Cython source files replaced by the generated C (or C++) files. """ new_sources = [] cython_sources = [] cython_targets = {} # Setup create_list and cplus from the extension options if # Cython.Distutils.extension.Extension is used, otherwise just # use what was parsed from the command-line or the configuration file. # cplus will also be set to true is extension.language is equal to # 'C++' or 'c++'. #try: # create_listing = self.cython_create_listing or \ # extension.cython_create_listing # cplus = self.cython_cplus or \ # extension.cython_cplus or \ # (extension.language != None and \ # extension.language.lower() == 'c++') #except AttributeError: # create_listing = self.cython_create_listing # cplus = self.cython_cplus or \ # (extension.language != None and \ # extension.language.lower() == 'c++') create_listing = self.cython_create_listing or \ getattr(extension, 'cython_create_listing', 0) line_directives = self.cython_line_directives or \ getattr(extension, 'cython_line_directives', 0) no_c_in_traceback = self.no_c_in_traceback or \ getattr(extension, 'no_c_in_traceback', 0) cplus = self.cython_cplus or getattr(extension, 'cython_cplus', 0) or \ (extension.language and extension.language.lower() == 'c++') cython_gen_pxi = self.cython_gen_pxi or getattr(extension, 'cython_gen_pxi', 0) cython_gdb = self.cython_gdb or getattr(extension, 'cython_gdb', False) cython_compile_time_env = self.cython_compile_time_env or \ getattr(extension, 'cython_compile_time_env', None) # Set up the include_path for the Cython compiler: # 1. Start with the command line option. # 2. Add in any (unique) paths from the extension # cython_include_dirs (if Cython.Distutils.extension is used). # 3. Add in any (unique) paths from the extension include_dirs includes = list(self.cython_include_dirs) try: for i in extension.cython_include_dirs: if i not in includes: includes.append(i) except AttributeError: pass # In case extension.include_dirs is a generator, evaluate it and keep # result extension.include_dirs = list(extension.include_dirs) for i in extension.include_dirs: if i not in includes: includes.append(i) # Set up Cython compiler directives: # 1. Start with the command line option. # 2. Add in any (unique) entries from the extension # cython_directives (if Cython.Distutils.extension is used). directives = dict(self.cython_directives) if hasattr(extension, "cython_directives"): directives.update(extension.cython_directives) # Set the target file extension for C/C++ mode. if cplus: target_ext = '.cpp' else: target_ext = '.c' # Decide whether to drop the generated C files into the temp dir # or the source tree. if not self.inplace and (self.cython_c_in_temp or getattr(extension, 'cython_c_in_temp', 0)): target_dir = os.path.join(self.build_temp, "pyrex") for package_name in extension.name.split('.')[:-1]: target_dir = os.path.join(target_dir, package_name) else: target_dir = None newest_dependency = None for source in sources: (base, ext) = os.path.splitext(os.path.basename(source)) if ext == ".py": # FIXME: we might want to special case this some more ext = '.pyx' if ext == ".pyx": # Cython source file output_dir = target_dir or os.path.dirname(source) new_sources.append(os.path.join(output_dir, base + target_ext)) cython_sources.append(source) cython_targets[source] = new_sources[-1] elif ext == '.pxi' or ext == '.pxd': if newest_dependency is None \ or newer(source, newest_dependency): newest_dependency = source else: new_sources.append(source) if not cython_sources: return new_sources try: from Cython.Compiler.Main \ import CompilationOptions, \ default_options as cython_default_options, \ compile as cython_compile from Cython.Compiler.Errors import PyrexError except ImportError: e = sys.exc_info()[1] print("failed to import Cython: %s" % e) raise DistutilsPlatformError("Cython does not appear to be installed") module_name = extension.name for source in cython_sources: target = cython_targets[source] depends = [source] + list(extension.depends or ()) if(source[-4:].lower()==".pyx" and os.path.isfile(source[:-3]+"pxd")): depends += [source[:-3]+"pxd"] rebuild = self.force or newer_group(depends, target, 'newer') if not rebuild and newest_dependency is not None: rebuild = newer(newest_dependency, target) if rebuild: log.info("cythoning %s to %s", source, target) self.mkpath(os.path.dirname(target)) if self.inplace: output_dir = os.curdir else: output_dir = self.build_lib options = CompilationOptions(cython_default_options, use_listing_file = create_listing, include_path = includes, compiler_directives = directives, output_file = target, cplus = cplus, emit_linenums = line_directives, c_line_in_traceback = not no_c_in_traceback, generate_pxi = cython_gen_pxi, output_dir = output_dir, gdb_debug = cython_gdb, compile_time_env = cython_compile_time_env) result = cython_compile(source, options=options, full_module_name=module_name) else: log.info("skipping '%s' Cython extension (up-to-date)", target) return new_sources # cython_sources () # class build_ext