[Python-checkins] CVS: distutils/distutils/command build_ext.py,1.40,1.41

Greg Ward python-dev@python.org
Tue, 30 May 2000 18:09:54 -0700


Update of /cvsroot/python/distutils/distutils/command
In directory slayer.i.sourceforge.net:/tmp/cvs-serv7537

Modified Files:
	build_ext.py 
Log Message:
Overhauled to expect 'self.extensions' (taken from 'ext_modules' in the
setup script) to be a list of Extension instances, rather than a list of of
(ext_name, build_info) tuples.  This is mostly a simplification, but
'check_extension_list()' got a lot more complicated because of the need to
convert the old-style tuples to Extension instances.

Temporarily dropped support for defining/undefining macros in the
'extensions' list -- I want to change the interface, but haven't yet made
the required changes in CCompiler and friends to support this nicely.

Also neatened up the code that merges 'extra_compile_flags' and the CFLAGS
environment variable.


Index: build_ext.py
===================================================================
RCS file: /cvsroot/python/distutils/distutils/command/build_ext.py,v
retrieving revision 1.40
retrieving revision 1.41
diff -C2 -r1.40 -r1.41
*** build_ext.py	2000/05/27 17:27:23	1.40
--- build_ext.py	2000/05/31 01:09:52	1.41
***************
*** 7,11 ****
  # created 1999/08/09, Greg Ward
  
! __revision__ = "$Id: build_ext.py,v 1.40 2000/05/27 17:27:23 gward Exp $"
  
  import sys, os, string, re
--- 7,11 ----
  # created 1999/08/09, Greg Ward
  
! __revision__ = "$Id: build_ext.py,v 1.41 2000/05/31 01:09:52 gward Exp $"
  
  import sys, os, string, re
***************
*** 14,17 ****
--- 14,18 ----
  from distutils.errors import *
  from distutils.dep_util import newer_group
+ from distutils.extension import Extension
  
  # An extension name is just a dot-separated list of Python NAMEs (ie.
***************
*** 153,163 ****
          from distutils.ccompiler import new_compiler
  
!         # 'self.extensions', as supplied by setup.py, is a list of 2-tuples.
!         # Each tuple is simple:
          #    (ext_name, build_info)
!         # build_info is a dictionary containing everything specific to
!         # building this extension.  (Info pertaining to all extensions
!         # should be handled by general distutils options passed from
!         # setup.py down to right here, but that's not taken care of yet.)
  
          if not self.extensions:
--- 154,168 ----
          from distutils.ccompiler import new_compiler
  
!         # 'self.extensions', as supplied by setup.py, is a list of
!         # Extension instances.  See the documentation for Extension (in
!         # distutils.core) for details.
!         # 
!         # For backwards compatibility with Distutils 0.8.2 and earlier, we
!         # also allow the 'extensions' list to be a list of tuples:
          #    (ext_name, build_info)
!         # where build_info is a dictionary containing everything that
!         # Extension instances do except the name, with a few things being
!         # differently named.  We convert these 2-tuples to Extension
!         # instances as needed.
  
          if not self.extensions:
***************
*** 209,238 ****
      def check_extensions_list (self, extensions):
          """Ensure that the list of extensions (presumably provided as a
!            command option 'extensions') is valid, i.e. it is a list of
!            2-tuples, where the tuples are (extension_name, build_info_dict).
!            Raise DistutilsSetupError if the structure is invalid anywhere;
!            just returns otherwise."""
! 
!         if type (extensions) is not ListType:
              raise DistutilsSetupError, \
!                   "'ext_modules' option must be a list of tuples"
          
!         for ext in extensions:
!             if type (ext) is not TupleType and len (ext) != 2:
                  raise DistutilsSetupError, \
!                       "each element of 'ext_modules' option must be a 2-tuple"
  
!             if not (type (ext[0]) is StringType and
!                     extension_name_re.match (ext[0])):
                  raise DistutilsSetupError, \
!                       "first element of each tuple in 'ext_modules' " + \
!                       "must be the extension name (a string)"
  
!             if type (ext[1]) is not DictionaryType:
                  raise DistutilsSetupError, \
!                       "second element of each tuple in 'ext_modules' " + \
!                       "must be a dictionary (build info)"
  
!         # end sanity-check for
  
      # check_extensions_list ()
--- 214,293 ----
      def check_extensions_list (self, extensions):
          """Ensure that the list of extensions (presumably provided as a
!         command option 'extensions') is valid, i.e. it is a list of
!         Extension objects.  We also support the old-style list of 2-tuples,
!         where the tuples are (ext_name, build_info), which are converted to
!         Extension instances here.
! 
!         Raise DistutilsSetupError if the structure is invalid anywhere;
!         just returns otherwise.
!         """
!         if type(extensions) is not ListType:
              raise DistutilsSetupError, \
!                   "'ext_modules' option must be a list of Extension instances"
          
!         for i in range(len(extensions)):
!             ext = extensions[i]
!             if isinstance(ext, Extension):
!                 continue                # OK! (assume type-checking done
!                                         # by Extension constructor)
! 
!             (ext_name, build_info) = ext
!             self.warn(("old-style (ext_name, build_info) tuple found in "
!                        "ext_modules for extension '%s'" 
!                        "-- please convert to Extension instance" % ext_name))
!             if type(ext) is not TupleType and len(ext) != 2:
                  raise DistutilsSetupError, \
!                       ("each element of 'ext_modules' option must be an "
!                        "Extension instance or 2-tuple")
  
!             if not (type(ext_name) is StringType and
!                     extension_name_re.match(ext_name)):
                  raise DistutilsSetupError, \
!                       ("first element of each tuple in 'ext_modules' "
!                        "must be the extension name (a string)")
  
!             if type(build_info) is not DictionaryType:
                  raise DistutilsSetupError, \
!                       ("second element of each tuple in 'ext_modules' "
!                        "must be a dictionary (build info)")
! 
!             # OK, the (ext_name, build_info) dict is type-safe: convert it
!             # to an Extension instance.
!             ext = Extension(ext_name, build_info['sources'])
! 
!             # Easy stuff: one-to-one mapping from dict elements to
!             # instance attributes.
!             for key in ('include_dirs',
!                         'library_dirs',
!                         'libraries',
!                         'extra_objects',
!                         'extra_compile_args',
!                         'extra_link_args'):
!                 setattr(ext, key, build_info.get(key))
! 
!             # Medium-easy stuff: same syntax/semantics, different names.
!             ext.runtime_library_dirs = build_info.get('rpath')
!             ext.export_symbol_file = build_info.get('def_file')
! 
!             # Non-trivial stuff: 'macros' split into 'define_macros'
!             # and 'undef_macros'.
!             macros = build_info.get('macros')
!             if macros:
!                 ext.define_macros = []
!                 ext.undef_macros = []
!                 for macro in macros:
!                     if not (type(macro) is TupleType and
!                             1 <= len(macros) <= 2):
!                         raise DistutilsSetupError, \
!                               ("'macros' element of build info dict "
!                                "must be 1- or 2-tuple")
!                     if len(macro) == 1:
!                         ext.undef_macros.append(macro[0])
!                     elif len(macro) == 2:
!                         ext.define_macros.append(macro)
! 
!             extensions[i] = ext
  
!         # for extensions
  
      # check_extensions_list ()
***************
*** 244,251 ****
  
          # Wouldn't it be neat if we knew the names of header files too...
!         for (extension_name, build_info) in self.extensions:
!             sources = build_info.get ('sources')
!             if type (sources) in (ListType, TupleType):
!                 filenames.extend (sources)
  
          return filenames
--- 299,304 ----
  
          # Wouldn't it be neat if we knew the names of header files too...
!         for ext in self.extensions:
!             filenames.extend (ext.sources)
  
          return filenames
***************
*** 263,268 ****
          # "build" tree.
          outputs = []
!         for (extension_name, build_info) in self.extensions:
!             fullname = self.get_ext_fullname (extension_name)
              outputs.append (os.path.join (self.build_lib,
                                            self.get_ext_filename(fullname)))
--- 316,321 ----
          # "build" tree.
          outputs = []
!         for ext in self.extensions:
!             fullname = self.get_ext_fullname (ext.name)
              outputs.append (os.path.join (self.build_lib,
                                            self.get_ext_filename(fullname)))
***************
*** 277,290 ****
          self.check_extensions_list (self.extensions)
  
!         for (extension_name, build_info) in self.extensions:
!             sources = build_info.get ('sources')
              if sources is None or type (sources) not in (ListType, TupleType):
                  raise DistutilsSetupError, \
                        ("in 'ext_modules' option (extension '%s'), " +
                         "'sources' must be present and must be " +
!                        "a list of source filenames") % extension_name
              sources = list (sources)
  
!             fullname = self.get_ext_fullname (extension_name)
              if self.inplace:
                  # ignore build-lib -- put the compiled extension into
--- 330,343 ----
          self.check_extensions_list (self.extensions)
  
!         for ext in self.extensions:
!             sources = ext.sources
              if sources is None or type (sources) not in (ListType, TupleType):
                  raise DistutilsSetupError, \
                        ("in 'ext_modules' option (extension '%s'), " +
                         "'sources' must be present and must be " +
!                        "a list of source filenames") % ext.name
              sources = list (sources)
  
!             fullname = self.get_ext_fullname (ext.name)
              if self.inplace:
                  # ignore build-lib -- put the compiled extension into
***************
*** 303,312 ****
                                               self.get_ext_filename(fullname))
  
! 	    if not newer_group(sources, ext_filename, 'newer'):
  	    	self.announce ("skipping '%s' extension (up-to-date)" %
!                                extension_name)
  		continue # 'for' loop over all extensions
  	    else:
!         	self.announce ("building '%s' extension" % extension_name)
  
              # First step: compile the source code to object files.  This
--- 356,365 ----
                                               self.get_ext_filename(fullname))
  
! 	    if not (self.force or newer_group(sources, ext_filename, 'newer')):
  	    	self.announce ("skipping '%s' extension (up-to-date)" %
!                                ext.name)
  		continue # 'for' loop over all extensions
  	    else:
!         	self.announce ("building '%s' extension" % ext.name)
  
              # First step: compile the source code to object files.  This
***************
*** 315,333 ****
              # Makefile.pre.in-based system does it, so at least there's a
              # precedent!)
!             macros = build_info.get ('macros')
!             include_dirs = build_info.get ('include_dirs')
!             extra_args = build_info.get ('extra_compile_args')
!             # honor CFLAGS enviroment variable
!             # XXX do we *really* need this? or is it just a hack until
!             # the user can put compiler flags in setup.cfg?
              if os.environ.has_key('CFLAGS'):
!                 if not extra_args:
!                     extra_args = []
!                 extra_args = string.split(os.environ['CFLAGS']) + extra_args
                  
              objects = self.compiler.compile (sources,
                                               output_dir=self.build_temp,
!                                              macros=macros,
!                                              include_dirs=include_dirs,
                                               debug=self.debug,
                                               extra_postargs=extra_args)
--- 368,398 ----
              # Makefile.pre.in-based system does it, so at least there's a
              # precedent!)
! 
!             # XXX not honouring 'define_macros' or 'undef_macros' -- the
!             # CCompiler API needs to change to accomodate this, and I
!             # want to do one thing at a time!
! 
!             # Two possible sources for extra compiler arguments:
!             #   - 'extra_compile_args' in Extension object
!             #   - CFLAGS environment variable (not particularly
!             #     elegant, but people seem to expect it and I
!             #     guess it's useful)
!             # The environment variable should take precedence, and
!             # any sensible compiler will give precendence to later
!             # command line args.  Hence we combine them in order:
!             extra_args = ext.extra_compile_args
! 
!             # XXX and if we support CFLAGS, why not CC (compiler
!             # executable), CPPFLAGS (pre-processor options), and LDFLAGS
!             # (linker options) too?
!             # XXX should we use shlex to properly parse CFLAGS?
! 
              if os.environ.has_key('CFLAGS'):
!                 extra_args.extend(string.split(os.environ['CFLAGS']))
                  
              objects = self.compiler.compile (sources,
                                               output_dir=self.build_temp,
!                                              #macros=macros,
!                                              include_dirs=ext.include_dirs,
                                               debug=self.debug,
                                               extra_postargs=extra_args)
***************
*** 336,346 ****
              # of course, first we have to figure out all the other things
              # that go into the mix.
!             extra_objects = build_info.get ('extra_objects')
!             if extra_objects:
!                 objects.extend (extra_objects)
!             libraries = build_info.get ('libraries')
!             library_dirs = build_info.get ('library_dirs')
!             rpath = build_info.get ('rpath')
!             extra_args = build_info.get ('extra_link_args') or []
  
              # XXX this is a kludge!  Knowledge of specific compilers or
--- 401,407 ----
              # of course, first we have to figure out all the other things
              # that go into the mix.
!             if ext.extra_objects:
!                 objects.extend (ext.extra_objects)
!             extra_args = ext.extra_link_args
  
              # XXX this is a kludge!  Knowledge of specific compilers or
***************
*** 355,362 ****
              # kludges; they are to be avoided if possible!)
              if self.compiler.compiler_type == 'msvc':
!                 def_file = build_info.get ('def_file')
                  if def_file is None:
                      source_dir = os.path.dirname (sources[0])
!                     ext_base = (string.split (extension_name, '.'))[-1]
                      def_file = os.path.join (source_dir, "%s.def" % ext_base)
                      if not os.path.exists (def_file):
--- 416,423 ----
              # kludges; they are to be avoided if possible!)
              if self.compiler.compiler_type == 'msvc':
!                 def_file = ext.export_symbol_file
                  if def_file is None:
                      source_dir = os.path.dirname (sources[0])
!                     ext_base = (string.split (ext.name, '.'))[-1]
                      def_file = os.path.join (source_dir, "%s.def" % ext_base)
                      if not os.path.exists (def_file):
***************
*** 366,370 ****
                      extra_args.append ('/DEF:' + def_file)
                  else:
!                     modname = string.split (extension_name, '.')[-1]
                      extra_args.append('/export:init%s'%modname)
  
--- 427,431 ----
                      extra_args.append ('/DEF:' + def_file)
                  else:
!                     modname = string.split (ext.name, '.')[-1]
                      extra_args.append('/export:init%s'%modname)
  
***************
*** 375,389 ****
                  implib_file = os.path.join (
                      self.build_temp,
!                     self.get_ext_libname (extension_name))
                  extra_args.append ('/IMPLIB:' + implib_file)
                  self.mkpath (os.path.dirname (implib_file))
              # if MSVC
  
!             self.compiler.link_shared_object (objects, ext_filename, 
!                                               libraries=libraries,
!                                               library_dirs=library_dirs,
!                                               runtime_library_dirs=rpath,
!                                               extra_postargs=extra_args,
!                                               debug=self.debug)
  
      # build_extensions ()
--- 436,451 ----
                  implib_file = os.path.join (
                      self.build_temp,
!                     self.get_ext_libname (ext.name))
                  extra_args.append ('/IMPLIB:' + implib_file)
                  self.mkpath (os.path.dirname (implib_file))
              # if MSVC
  
!             self.compiler.link_shared_object (
!                 objects, ext_filename, 
!                 libraries=ext.libraries,
!                 library_dirs=ext.library_dirs,
!                 runtime_library_dirs=ext.runtime_library_dirs,
!                 extra_postargs=extra_args,
!                 debug=self.debug)
  
      # build_extensions ()