[Distutils] install w/o build, spaces in directory names

Thomas Heller thomas.heller@ion-tof.com
Fri, 11 Feb 2000 14:20:23 +0100


From: David Ascher <DavidA@ActiveState.com>
Sent: Thursday, February 10, 2000 8:50 PM
> 2) Again on Windows, if I do
>
> python setup.py build
> python setup.py install
>
> the second line causes the code to be recompiled, even though the
> compilation is not needed.  Greg assures me that that is not the case on
> Unix.  Anyone have the time to tackle this?

I have patched msvccompiler.py to do this (patch is at the end).
The problem is that this is currently not safe because of the debug
flag recently introduced.
If you do
  setup.py build_ext
  setup.py install
everything will be fine (non-debug extensions will be compiled, linked
and installed), if after that you do
  setup.py build_ext --debug
  setup.py install
the debug extensions mod_d.pyd will be linked from obj-files
compiled with the wrong flags.
The only thing you can do currently is to force a rebuild with:
  setup.py build_ext --debug --force
  setup.py install

This should either be fixed by:
- compiling the debug and non-debug object-files into different
  directories (temp-release, temp-debug)
- naming the object files differently (mod.obj vs mod_d.obj).

Thomas Heller

*** c:\python.org\distutils\distutils\msvccompiler.py Fri Feb 11 11:56:18
2000
--- distutils\msvccompiler.py Fri Feb 11 12:08:54 2000
***************
*** 14,19 ****
--- 14,21 ----
  from distutils.errors import *
  from distutils.ccompiler import \
       CCompiler, gen_preprocess_options, gen_lib_options
+ from util import move_file, newer_pairwise, newer_group
+ from copy import copy


  def get_devstudio_versions ():
***************
*** 222,239 ****
              compile_options = self.compile_options_debug
          else:
              compile_options = self.compile_options
-
-         for srcFile in sources:
-             base,ext = os.path.splitext(srcFile)
-             objFile = base + ".obj"

              if ext in self._c_extensions:
                  fileOpt = "/Tc"
              elif ext in self._cpp_extensions:
                  fileOpt = "/Tp"

!             inputOpt  = fileOpt + srcFile
!             outputOpt = "/Fo"   + objFile

              cc_args = compile_options + \
                        base_pp_opts + \
--- 223,261 ----
              compile_options = self.compile_options_debug
          else:
              compile_options = self.compile_options

+         # So we can mangle 'sources' without hurting the caller's data
+         orig_sources = sources
+         sources = copy (sources)
+
+         # Get the list of expected output (object) files and drop files we
+         # don't have to recompile.  (Simplistic check -- we just compare
the
+         # source and object file, no deep dependency checking involving
+         # header files.  Hmmm.)
+         objects = self.object_filenames (sources, output_dir=output_dir)
+
+         if not self.force:
+             skipped = newer_pairwise (sources, objects)
+             for skipped_pair in skipped:
+                 self.announce ("skipping %s (%s up-to-date)" %
skipped_pair)
+
+         # Build list of (source,object) tuples for convenience
+         srcobj = []
+         for i in range (len (sources)):
+             srcobj.append ((sources[i], objects[i]))
+
+         # Compile all source files that weren't eliminated by
+         # 'newer_pairwise()'.
+
+         for (source,object) in srcobj:
+             base, ext = os.path.splitext (source)
              if ext in self._c_extensions:
                  fileOpt = "/Tc"
              elif ext in self._cpp_extensions:
                  fileOpt = "/Tp"

!             inputOpt = fileOpt + source
!             outputOpt = "/Fo" + object

              cc_args = compile_options + \
                        base_pp_opts + \
***************
*** 245,252 ****
                  cc_args.extend (extra_postargs)

              self.spawn ([self.cc] + cc_args)
!             objectFiles.append( objFile )
!         return objectFiles


      # XXX the signature of this method is different from CCompiler and
--- 267,277 ----
                  cc_args.extend (extra_postargs)

              self.spawn ([self.cc] + cc_args)
!         # Have to re-fetch list of object filenames, because we want to
!         # return *all* of them, including those that weren't recompiled on
!         # this call!
!         return self.object_filenames (orig_sources, output_dir)
! ##        return self.object_filenames (orig_sources)


      # XXX the signature of this method is different from CCompiler and
***************
*** 344,352 ****
          if extra_postargs:
              ld_args.extend (extra_postargs)

!         self.spawn ( [ self.link ] + ld_args )


      # -- Filename mangling methods -------------------------------------

      def _change_extensions( self, filenames, newExtension ):
--- 369,391 ----
          if extra_postargs:
              ld_args.extend (extra_postargs)

!         # If any of the input object files are newer than the output
shared
!         # object, relink.  Again, this is a simplistic dependency check:
!         # doesn't look at any of the libraries we might be linking with.

+         if not self.force:
+             if self.dry_run:
+                 newer = newer_group (objects, output_filename,
missing='newer')
+             else:
+                 newer = newer_group (objects, output_filename)

+         if self.force or newer:
+             self.spawn ( [ self.link ] + ld_args )
+         else:
+             self.announce ("skipping %s (up-to-date)" % output_filename)
+
+
+
      # -- Filename mangling methods -------------------------------------

      def _change_extensions( self, filenames, newExtension ):
***************
*** 359,367 ****

          return object_filenames

!     def object_filenames (self, source_filenames):
          """Return the list of object filenames corresponding to each
             specified source filename."""
          return self._change_extensions( source_filenames, self._obj_ext )

      def shared_object_filename (self, source_filename):
--- 398,407 ----

          return object_filenames

!     def object_filenames (self, source_filenames, output_dir=None):
          """Return the list of object filenames corresponding to each
             specified source filename."""
+         #XXX output_dir currently ignored
          return self._change_extensions( source_filenames, self._obj_ext )

      def shared_object_filename (self, source_filename):