"""Pyrex.Distutils.build_ext Implements a version of the Distutils 'build_ext' command, for building Pyrex extension modules.""" # This module should be kept compatible with Python 2.1. __revision__ = "$Id:$" import sys, os, string, re from types import * from distutils.core import Command from distutils.errors import * from distutils.sysconfig import customize_compiler, get_python_version from distutils.dep_util import newer_group from distutils import log from distutils.dir_util import mkpath try: from Pyrex.Compiler.Main \ import CompilationOptions, \ default_options as pyrex_default_options, \ compile as pyrex_compile from Pyrex.Compiler.Errors import PyrexError except ImportError: PyrexError = None from distutils.command import build_ext as _build_ext extension_name_re = _build_ext.extension_name_re show_compilers = _build_ext.show_compilers class build_ext(_build_ext.build_ext): description = "build C/C++ and Pyrex 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([ ('pyrex-cplus', None, "generate C++ source files"), ('pyrex-create-listing', None, "write errors to a listing file"), ('pyrex-include-dirs=', None, "path to the Pyrex include files" + sep_by), ]) boolean_options.extend(['pyrex-cplus', 'pyrex-create-listing']) def initialize_options(self): _build_ext.build_ext.initialize_options(self) self.pyrex_cplus = 0 self.pyrex_create_listing = 0 self.pyrex_include_dirs = None def finalize_options (self): _build_ext.build_ext.finalize_options(self) if self.pyrex_include_dirs is None: self.pyrex_include_dirs = [] elif type(self.pyrex_include_dirs) is StringType: self.pyrex_include_dirs = \ string.split(self.pyrex_include_dirs, os.pathsep) # finalize_options () def build_extensions(self): # First, sanity-check the 'extensions' list self.check_extensions_list(self.extensions) for ext in self.extensions: ext.sources = self.pyrex_sources(ext.sources, ext) self.build_extension(ext) def pyrex_sources(self, sources, extension): """ Walk the list of source files in 'sources', looking for Pyrex source (.pyx) files. Run Pyrex on all that are found, and return a modified 'sources' list with Pyrex source files replaced by the generated C (or C++) files. """ if PyrexError == None: raise DistutilsPlatformError, \ ("Pyrex does not appear to be installed " "on platform '%s'") % os.name new_sources = [] pyrex_sources = [] pyrex_targets = {} # Setup create_list and cplus from the extension options if # Pyrex.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.pyrex_create_listing or \ extension.pyrex_create_listing cplus = self.pyrex_cplus or \ extension.pyrex_cplus or \ (extension.language != None and \ extension.language.lower() == 'c++') except AttributeError: create_listing = self.pyrex_create_listing cplus = self.pyrex_cplus or \ (extension.language != None and \ extension.language.lower() == 'c++') # Set up the include_path for the Pyres compiler: # 1. Start with the command line option. # 2. Add in any (unique) paths from the extension # pyrex_include_dirs (if Pyrex.Distutils.extension is used). # 3. Add in any (unique) paths from the extension include_dirs includes = self.pyrex_include_dirs try: for i in extension.pyrex_include_dirs: if not i in includes: includes.append(i) except AttributeError: pass for i in extension.include_dirs: if not i in includes: includes.append(i) # Set the target_ext to '.c'. Pyrex will change this to '.cpp' if # needed. if cplus: target_ext = '.cpp' else: target_ext = '.c' # Drop the generated C files into the temp dir, unless the inplace # option is present. In that case, drop them into the source tree. if self.inplace: target_dir = "" else: target_dir = os.path.join(self.build_temp, "pyrex") for source in sources: (base, ext) = os.path.splitext(source) if ext == ".pyx": # Pyrex source file new_sources.append(os.path.join(target_dir, base + target_ext)) pyrex_sources.append(source) pyrex_targets[source] = new_sources[-1] else: new_sources.append(source) if not pyrex_sources: return new_sources for source in pyrex_sources: target = pyrex_targets[source] log.info("pyrexing %s to %s", source, target) self.mkpath(os.path.dirname(target)) options = CompilationOptions(pyrex_default_options, use_listing_file = create_listing, include_path = includes, output_file = target, cplus = cplus) result = pyrex_compile(source, options=options) return new_sources # pyrex_sources () # class build_ext