Stefan Behnel | 3 Aug 08:51
Picon
Favicon

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

Gmane