3 Aug 08:51
Re: [Pyrex] New Distutils implementation for Pyrex.
Billy G. Allie wrote: > Stefan Behnel wrote: >> Billy G. Allie wrote: >> >>> I am re-implementing my PostgreSQL interface (pyPgSQL) using Pyrex to >>> implement an extension for the libpq C-API. When using the supplied >>> build_ext, I notices that I had to have the .pxd files in the same >>> directory as the source .pyx file. Also, the generated c source file >>> was placed in the same directory as the Pyrex source. I also could not >>> specify Pyrex options to create a listing file, etc. I wanted to have >>> the .pxd files in an separate include directory and I also did not want >>> to clean up the generated files from the Pyrex source directory. To >>> correct these (minor) annoyances, I've implemented a new version of >>> buld_ext.py and created a version of core.py and extension.py. >> >> is this an independent implementation or is it based on the old one? If the >> latter, could you provide a patch against Cython and submit it at the >> Cython >> bug tracker? If it's new, could you still provide a single-file patch that >> includes the new files? >> >> https://bugs.launchpad.net/cython >> >> http://www.cython.org >> >> > I am attaching a diff generated by the 'diff -cbN <originale Distutils > directory> <new Distutils directory>' command. > I also changed all references to Pyrex to Cython and pyrex to cython in the > files. > > I used the patched Distutils modules to successfully build my libpq > extension (after I fixed some syntax errors that Pyrex missed) Thanks a lot for the patches! I'm resending them to the Cython list for now. You mentioned that you used distutils in Python 2.4 as a base. Python 2.3 compatibility is currently a requirement for Cython. Would you say there are any 2.4 specifics in there? Thanks again, Stefan
diff -cbN /home/bga/tmp/cython-0.9.6.3/Cython/Distutils/build_ext.py Distutils/build_ext.py *** /home/bga/tmp/cython-0.9.6.3/Cython/Distutils/build_ext.py 2007-07-28 16:41:03.000000000 -0400 --- Distutils/build_ext.py 2007-08-03 00:36:10.000000000 -0400 *************** *** 1,63 **** ! # Subclasses disutils.command.build_ext, ! # replacing it with a Cython version that compiles pyx->c ! # before calling the original build_ext command. ! # July 2002, Graham Fawcett ! # Modified by Darrell Gallion <dgallion1@...> ! # to allow inclusion of .c files along with .pyx files. ! # Pyrex is (c) Greg Ewing. ! ! import distutils.command.build_ext ! #import Cython.Compiler.Main ! from Cython.Compiler.Main import CompilationOptions, default_options, compile ! from Cython.Compiler.Errors import PyrexError ! from distutils.dep_util import newer ! import os ! import sys ! def replace_suffix(path, new_suffix): ! return os.path.splitext(path)[0] + new_suffix ! class build_ext (distutils.command.build_ext.build_ext): ! description = "compile Cython scripts, then build C/C++ extensions (compile/link to build directory)" def finalize_options (self): ! distutils.command.build_ext.build_ext.finalize_options(self) ! # The following hack should no longer be needed. ! if 0: ! # compiling with mingw32 gets an "initializer not a constant" error ! # doesn't appear to happen with MSVC! ! # so if we are compiling with mingw32, ! # switch to C++ mode, to avoid the problem ! if self.compiler == 'mingw32': ! self.swig_cpp = 1 ! ! def swig_sources (self, sources, extension = None): ! if not self.extensions: ! return ! ! # collect the names of the source (.pyx) files ! pyx_sources = [] ! pyx_sources = [source for source in sources if source.endswith('.pyx')] ! other_sources = [source for source in sources if not source.endswith('.pyx')] ! ! #suffix = self.swig_cpp and '.cpp' or '.c' ! suffix = '.c' ! for pyx in pyx_sources: ! # should I raise an exception if it doesn't exist? ! if os.path.exists(pyx): ! source = pyx ! target = replace_suffix(source, suffix) ! if newer(source, target) or self.force: ! self.cython_compile(source) ! ! return [replace_suffix(src, suffix) for src in pyx_sources] + other_sources ! ! def cython_compile(self, source): ! options = CompilationOptions(default_options, ! include_path = self.include_dirs) ! result = compile(source, options) ! if result.num_errors <> 0: ! sys.exit(1) --- 1,159 ---- ! """Cython.Distutils.build_ext ! Implements a version of the Distutils 'build_ext' command, for ! building Cython extension modules.""" ! # This module should be kept compatible with Python 2.1. ! __revision__ = "$Id:$" ! ! import sys, os, string, re ! from types import * ! from Cython.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 Cython.Distutils.extension import Extension ! from distutils import log ! from distutils.dir_util import mkpath ! 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: ! 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 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 cython specific data. ! user_options.extend([ ! ('cython-cplus', None, ! "generate C++ source files"), ! ('cython-create-listing', None, ! "write errors to a listing file"), ! ('cython-include-dirs=', None, ! "path to the Cython include files" + sep_by), ! ]) ! ! boolean_options.extend(['cython-cplus', 'cython-create-listing']) ! ! def initialize_options(self): ! _build_ext.build_ext.initialize_options(self) ! self.cython_cplus = 0 ! self.cython_create_listing = 0 ! self.cython_include_dirs = None def finalize_options (self): ! _build_ext.build_ext.finalize_options(self) ! ! if self.cython_include_dirs is None: ! self.cython_include_dirs = [] ! elif type(self.cython_include_dirs) is StringType: ! self.cython_include_dirs = \ ! string.split(self.cython_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.cython_sources(ext.sources, ext) ! self.build_extension(ext) ! ! def cython_sources (self, sources, extension): ! ! """ ! Walk the list of source files in 'sources', looking for Cython ! source (.pyx) files. 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. ! """ ! ! if PyrexError == None: ! raise DistutilsPlatformError, \ ! ("Cython does not appear to be installed " ! "on platform '%s'") % os.name ! ! new_sources = [] ! cython_sources = [] ! cython_targets = {} ! ! create_listing = self.cython_create_listing or \ ! extension.cython_create_listing ! cplus = self.cython_cplus or extension.cython_cplus ! ! #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 ! # cython_include_dirs. ! # 3. Add in any (unique) paths from the extension include_dirs ! # if and only if there there were no cython_include_dirs defined.. ! includes = self.cython_include_dirs ! for i in extension.cython_include_dirs: ! if not i in includes: ! includes.append(i) ! if len(includes) < 1: ! for i in extension.include_dirs: ! if not i in includes: ! includes.append(i) ! ! # Set the target_ext to '.c'. Cython 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, "cython") ! ! for source in sources: ! (base, ext) = os.path.splitext(source) ! if ext == ".pyx": # Cython source file ! new_sources.append(os.path.join(target_dir, base + target_ext)) ! cython_sources.append(source) ! cython_targets[source] = new_sources[-1] ! else: ! new_sources.append(source) ! ! if not cython_sources: ! return new_sources ! ! for source in cython_sources: ! target = cython_targets[source] ! log.info("cythoning %s to %s", source, target) ! self.mkpath(os.path.dirname(target)) ! options = CompilationOptions(cython_default_options, ! use_listing_file = create_listing, ! include_path = includes, ! output_file = target, ! cplus = cplus) ! result = cython_compile(source, options=options) ! ! return new_sources ! # cython_sources () + # class build_ext diff -cbN /home/bga/tmp/cython-0.9.6.3/Cython/Distutils/core.py Distutils/core.py *** /home/bga/tmp/cython-0.9.6.3/Cython/Distutils/core.py 1969-12-31 19:00:00.000000000 -0500 --- Distutils/core.py 2007-08-03 00:36:10.000000000 -0400 *************** *** 0 **** --- 1,34 ---- + """Cython.Distutils.core + + This module wraps the 'distutils.core' module and extends it to support + Cython extension modules. + + This is the only module that needs to be imported to use the Distutils; + provides the 'setup' function (which is to be called from the setup script). + Also indirectly provides the Distribution and Command classes, although + they are really defined in distutils.dist and distutils.cmd. + """ + + # This module should be kept compatible with Python 2.1. + + __revision__ = "$Id:$" + + import sys, os + from types import * + + from distutils.debug import DEBUG + from distutils.errors import * + from distutils.util import grok_environment_error + + # Mainly import these so setup scripts can "from distutils.core import" them. + from distutils.dist import Distribution + from distutils.cmd import Command + + # Make sure we get Cython's Extension class. + from Cython.Distutils.extension import Extension + + from distutils.core import * + + extension_keywords = extension_keywords + \ + ('cython_include_dirs', 'cython_create_listing', + 'cython_cplus') diff -cbN /home/bga/tmp/cython-0.9.6.3/Cython/Distutils/extension.py Distutils/extension.py *** /home/bga/tmp/cython-0.9.6.3/Cython/Distutils/extension.py 1969-12-31 19:00:00.000000000 -0500 --- Distutils/extension.py 2007-08-03 00:36:10.000000000 -0400 *************** *** 0 **** --- 1,73 ---- + """Cython.Distutils.extension + + Provides a modified Extension class, that understands hou to describe + Cython extension modules in setup scripts.""" + + __revision__ = "$Id:$" + + import os, string, sys + from types import * + import distutils.extension as _Extension + + try: + import warnings + except ImportError: + warnings = None + + class Extension(_Extension.Extension): + _Extension.Extension.__doc__ + \ + """cython_include_dirs : [string] + list of directories to search for Cython header files (.pxd) (in + Unix form for portability) + cython_create_listing_file : boolean + write cython error messages to a listing (.lis) file. + cython_cplus : boolean + use the C++ compiler for compiling and linking. + """ + + # When adding arguments to this constructor, be sure to update + # setup_keywords in core.py. + def __init__ (self, name, sources, + include_dirs=None, + define_macros=None, + undef_macros=None, + library_dirs=None, + libraries=None, + runtime_library_dirs=None, + extra_objects=None, + extra_compile_args=None, + extra_link_args=None, + export_symbols=None, + swig_opts = None, + depends=None, + language=None, + cython_include_dirs=None, + cython_create_listing=0, + cython_cplus=0, + **kw # To catch unknown keywords + ): + + _Extension.Extension.__init__(self, name, sources, + include_dirs, + define_macros, + undef_macros, + library_dirs, + libraries, + runtime_library_dirs, + extra_objects, + extra_compile_args, + extra_link_args, + export_symbols, + swig_opts , + depends, + language, + **kw + ) + + self.cython_include_dirs = cython_include_dirs or [] + self.cython_create_listing = cython_create_listing + self.cython_cplus = cython_cplus + + # class Extension + + read_setup_file = _Extension.read_setup_file diff -cbN /home/bga/tmp/cython-0.9.6.3/Cython/Distutils/__init__.py Distutils/__init__.py *** /home/bga/tmp/cython-0.9.6.3/Cython/Distutils/__init__.py 2007-07-28 15:29:52.000000000 -0400 --- Distutils/__init__.py 2007-08-03 00:36:10.000000000 -0400 *************** *** 1,22 **** # July 2002, Graham Fawcett - # - # this hack was inspired by the way Thomas Heller got py2exe - # to appear as a distutil command - # - # we replace distutils.command.build_ext with our own version - # and keep the old one under the module name _build_ext, - # so that *our* build_ext can make use of it. ! from build_ext import build_ext ! --- 1,16 ---- # July 2002, Graham Fawcett # # this hack was inspired by the way Thomas Heller got py2exe # to appear as a distutil command # # we replace distutils.command.build_ext with our own version # and keep the old one under the module name _build_ext, # so that *our* build_ext can make use of it. + __revision__ = "$Id:$" + __all__ = [ 'core.py', 'build_ext.py', 'extension.py' ] ! import core, build_ext, extension
_______________________________________________ Cython-dev mailing list Cython-dev@... https://lists.berlios.de/mailman/listinfo/cython-dev
)
Thanks a lot for the patches! I'm resending them to the Cython list for now.
You mentioned that you used distutils in Python 2.4 as a base. Python 2.3
compatibility is currently a requirement for Cython. Would you say there are
any 2.4 specifics in there?
Thanks again,
Stefan
RSS Feed