[Distutils] Re: CygwinCCompiler, msvc hack, BCPPCompiler

Rene Liebscher R.Liebscher@gmx.de
Thu, 27 Jul 2000 12:57:15 +0200


This is a multi-part message in MIME format.
--------------09D84941F7DE6AE76370E7A8
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Oops, I forgot to attach the patches.

Here they are.



Kind regards

Rene Liebscher
--------------09D84941F7DE6AE76370E7A8
Content-Type: text/plain; charset=us-ascii;
 name="msvc.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="msvc.patch"

diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/build_ext.py d.px/distutils/command/build_ext.py
--- distutils.orig/distutils/command/build_ext.py	Thu Jul 27 09:52:46 2000
+++ d.px/distutils/command/build_ext.py	Thu Jul 27 12:31:44 2000
@@ -84,7 +84,7 @@
     help_options = [
         ('help-compiler', None,
          "list available compilers", show_compilers),
-	]
+        ]
 
     def initialize_options (self):
         self.extensions = None
@@ -283,6 +283,9 @@
             # 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')
+            if ext.export_symbol_file is not None:
+                self.warn("export_symbol_file is no longer supported, "
+                           "comments and questions to <distutils-sig@python.org>")
 
             # Non-trivial stuff: 'macros' split into 'define_macros'
             # and 'undef_macros'.
@@ -420,16 +423,14 @@
                 objects.extend (ext.extra_objects)
             extra_args = ext.extra_link_args or []
 
-            # Bunch of fixing-up we have to do for Microsoft's linker.
-            if self.compiler.compiler_type == 'msvc':
-                self.msvc_prelink_hack(sources, ext, extra_args)
 
             self.compiler.link_shared_object (
                 objects, ext_filename, 
-                libraries=ext.libraries,
+                libraries=self.get_libraries(ext),
                 library_dirs=ext.library_dirs,
                 runtime_library_dirs=ext.runtime_library_dirs,
                 extra_postargs=extra_args,
+                export_symbols=self.get_export_symbols(ext), 
                 debug=self.debug,
                 build_temp=self.build_temp)
 
@@ -511,44 +512,6 @@
 
     # find_swig ()
     
-
-    # -- Hooks 'n hacks ------------------------------------------------
-
-    def msvc_prelink_hack (self, sources, ext, extra_args):
-
-        # XXX this is a kludge!  Knowledge of specific compilers or
-        # platforms really doesn't belong here; in an ideal world, the
-        # CCompiler interface would provide access to everything in a
-        # compiler/linker system needs to build Python extensions, and
-        # we would just do everything nicely and cleanly through that
-        # interface.  However, this is a not an ideal world and the
-        # CCompiler interface doesn't handle absolutely everything.
-        # Thus, kludges like this slip in occasionally.  (This is no
-        # excuse for committing more platform- and compiler-specific
-        # kludges; they are to be avoided if possible!)
-
-        def_file = ext.export_symbol_file
-
-        if def_file is not None:
-            extra_args.append ('/DEF:' + def_file)
-        else:
-            modname = string.split (ext.name, '.')[-1]
-            extra_args.append('/export:init%s' % modname)
-
-        # The MSVC linker generates .lib and .exp files, which cannot be
-        # suppressed by any linker switches. The .lib files may even be
-        # needed! Make sure they are generated in the temporary build
-        # directory. Since they have different names for debug and release
-        # builds, they can go into the same directory.
-        implib_file = os.path.join (
-            self.implib_dir,
-            self.get_ext_libname (ext.name))
-        extra_args.append ('/IMPLIB:' + implib_file)
-        self.mkpath (os.path.dirname (implib_file))
-
-    # msvc_prelink_hack ()
-
-
     # -- Name generators -----------------------------------------------
     # (extension names, filenames, whatever)
 
@@ -578,5 +541,33 @@
         if os.name == 'nt' and self.debug:
             return apply (os.path.join, ext_path) + '_d.lib'
         return apply (os.path.join, ext_path) + '.lib'
+
+
+    def get_export_symbols (self, ext):
+        # For all platforms and compiler doesn't export all symbols
+        # by default, we have to specify the module's init function
+        # if the user doesn't provide any export information.
+        # All other platforms and compilers should ignore such
+        # export information.
+        if ext.export_symbols is None:
+            # if no exports are specified we can't build a working
+            # python module.
+            # so let us export the module's init function
+            return ["init" + string.split(ext.name,'.')[-1]]
+        else:
+            return ext.export_symbols
+
+    def get_libraries (self, ext):
+            # The python library is always needed on Windows. 
+            # We need the python version without the dot, eg. '15'
+            # MSVC doesn't really need this, because the pragma in config.h 
+            if sys.platform == "win32": 
+                pythonlib = ("python%d%d" %
+                     (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
+                # don't extend ext.libraries, it may be shared with other
+                # extensions, it is a reference to the original list
+                return ext.libraries + [pythonlib]
+            else:
+                return ext.libraries
 
 # class build_ext
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/extension.py d.px/distutils/extension.py
--- distutils.orig/distutils/extension.py	Sat Jun 24 02:18:24 2000
+++ d.px/distutils/extension.py	Thu Jul 27 12:31:44 2000
@@ -111,7 +111,7 @@
         self.extra_objects = extra_objects or []
         self.extra_compile_args = extra_compile_args or []
         self.extra_link_args = extra_link_args or []
-        self.export_symbols = export_symbols or []
+        self.export_symbols = export_symbols
         self.export_symbol_file = export_symbol_file
 
 # class Extension
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/msvccompiler.py d.px/distutils/msvccompiler.py
--- distutils.orig/distutils/msvccompiler.py	Fri Jun 30 21:37:59 2000
+++ d.px/distutils/msvccompiler.py	Thu Jul 27 12:31:44 2000
@@ -380,6 +380,17 @@
             ld_args = (ldflags + lib_opts + export_opts + 
                        objects + ['/OUT:' + output_filename])
 
+            # The MSVC linker generates .lib and .exp files, which cannot be
+            # suppressed by any linker switches. The .lib files may even be
+            # needed! Make sure they are generated in the temporary build
+            # directory. Since they have different names for debug and release
+            # builds, they can go into the same directory.
+            dll_name, dll_ext = os.path.splitext(os.path.basename(output_filename))
+            implib_file = os.path.join (
+                os.path.dirname(objects[0]),
+                self.static_lib_format % (dll_name, self.static_lib_extension))
+            ld_args.append ('/IMPLIB:' + implib_file)
+
             if extra_preargs:
                 ld_args[:0] = extra_preargs
             if extra_postargs:

--------------09D84941F7DE6AE76370E7A8
Content-Type: text/plain; charset=us-ascii;
 name="bcpp.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="bcpp.patch"

diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/bcppcompiler.py d.px/distutils/bcppcompiler.py
--- distutils.orig/distutils/bcppcompiler.py	Wed Jun 28 03:20:35 2000
+++ d.px/distutils/bcppcompiler.py	Thu Jul 27 12:35:21 2000
@@ -11,17 +11,6 @@
 # someone should sit down and factor out the common code as
 # WindowsCCompiler!  --GPW
 
-# XXX Lyle reports that this doesn't quite work yet:
-# """...but this is what I've got so far. The compile step works fine but
-# when it runs the link step I get an "out of memory" failure.  Since
-# spawn() echoes the command it's trying to spawn, I can type the link line
-# verbatim at the DOS prompt and it links the Windows DLL correctly -- so
-# the syntax is correct. There's just some weird interaction going on when
-# it tries to "spawn" the link process from within the setup.py script. I'm
-# not really sure how to debug this one right off-hand; obviously there's
-# nothing wrong with the "spawn()" function since it's working properly for
-# the compile stage."""
-
 __revision__ = "$Id: bcppcompiler.py,v 1.1 2000/06/28 01:20:35 gward Exp $"
 
 
@@ -123,6 +112,9 @@
                 elif ext in self._cpp_extensions:
                     input_opt = "-P"
 
+                src = os.path.normpath(src)
+                obj = os.path.normpath(obj)
+                
                 output_opt = "-o" + obj
 
                 self.mkpath (os.path.dirname (obj))
@@ -230,24 +222,56 @@
             else:
                 ldflags = self.ldflags_shared
 
+            # Borland C++ has problems with '/' in paths
+            objects = map(os.path.normpath,objects)
+
             startup_obj = 'c0d32'
 
-            libraries.append ('mypylib')
+            # either exchange python15.lib in the python libs directory against
+            # a Borland-like one, or create one with name bcpp_python15.lib 
+            # there and remove the pragmas from config.h  
+            #libraries.append ('mypylib')            
             libraries.append ('import32')
             libraries.append ('cw32mt')
 
             # Create a temporary exports file for use by the linker
             head, tail = os.path.split (output_filename)
             modname, ext = os.path.splitext (tail)
-            def_file = os.path.join (build_temp, '%s.def' % modname)
+            temp_dir = os.path.dirname(objects[0]) # preserve tree structure
+            def_file = os.path.join (temp_dir, '%s.def' % modname)
             f = open (def_file, 'w')
             f.write ('EXPORTS\n')
             for sym in (export_symbols or []):
                 f.write ('  %s=_%s\n' % (sym, sym))
+            f.close()
 
-            ld_args = ldflags + [startup_obj] + objects + \
-                [',%s,,' % output_filename] + \
-                libraries + [',' + def_file]
+            # start building command line
+            # flags and options
+            ld_args = list(ldflags) # don't use a reference, use a separate copy
+            for l in library_dirs:
+                ld_args.append("/L%s" % os.path.normpath(l)) 
+            # objects list
+            ld_args.extend([startup_obj])
+            ld_args.extend(objects)
+            # name of dll file
+            ld_args.extend([',',output_filename])
+            # no map file
+            ld_args.extend([','])
+            # start libraries 
+            ld_args.extend([','])
+            for lib in libraries:
+                # see if we find it and if there is a bcpp specific lib 
+                # (bcpp_xxx.lib)
+                l = self.find_library_file(library_dirs,lib,debug)
+                if l == None:
+                    ld_args.append(lib)
+                    # probably an bcpp internal library
+                    #    self.warn('library %s not found.' % lib)
+                else:
+                    # full name which prefers bcpp_xxx.lib over xxx.lib
+                    ld_args.append(l)
+            # def file for export symbols
+            ld_args.extend([',',def_file])
             
             if extra_preargs:
                 ld_args[:0] = extra_preargs
@@ -325,15 +349,28 @@
 
     def runtime_library_dir_option (self, dir):
         raise DistutilsPlatformError, \
-              "don't know how to set runtime library search path for MSVC++"
+              "don't know how to set runtime library search path for Borland C++"
 
     def library_option (self, lib):
         return self.library_filename (lib)
 
 
-    def find_library_file (self, dirs, lib):
-
+    def find_library_file (self, dirs, lib, debug=0):
+        # find library file
+        # bcpp_xxx.lib is better than xxx.lib
+        # and xxx_d.lib is better than xxx.lib if debug is set
         for dir in dirs:
+            if debug:
+                libfile = os.path.join (dir, self.library_filename ("bcpp_" + lib + "_d"))
+                if os.path.exists (libfile):
+                    return libfile
+            libfile = os.path.join (dir, self.library_filename ("bcpp_" + lib))
+            if os.path.exists (libfile):
+                return libfile
+            if debug:
+                libfile = os.path.join (dir, self.library_filename (lib + '_d'))
+                if os.path.exists (libfile):
+                    return libfile
             libfile = os.path.join (dir, self.library_filename (lib))
             if os.path.exists (libfile):
                 return libfile

--------------09D84941F7DE6AE76370E7A8
Content-Type: text/plain; charset=us-ascii;
 name="cygwin.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="cygwin.patch"

diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/cygwinccompiler.py d.px/distutils/cygwinccompiler.py
--- distutils.orig/distutils/cygwinccompiler.py	Thu Jul 27 09:52:42 2000
+++ d.px/distutils/cygwinccompiler.py	Thu Jul 27 12:19:55 2000
@@ -6,53 +6,53 @@
 cygwin in no-cygwin mode).
 """
 
+# problems:
+#
+# * if you use a msvc compiled python version (1.5.2)
+#   1. you have to insert a __GNUC__ section in its config.h
+#   2. you have to generate a import library for its dll
+#      - create a def-file for python??.dll
+#      - create a import library using
+#             dlltool --dllname python15.dll --def python15.def \
+#                       --output-lib libpython15.a
+#
+#   see also http://starship.python.net/crew/kernr/mingw32/Notes.html
+#
+# * We use put export_symbols in a def-file, and don't use 
+#   --export-all-symbols because it doesn't worked reliable in some
+#   tested configurations. And because other windows compilers also
+#   need their symbols specified this no serious problem.
+#
+# tested configurations:
+#   
+# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works 
+#   (after patching python's config.h and for C++ some other include files)
+#   see also http://starship.python.net/crew/kernr/mingw32/Notes.html
+# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works 
+#   (ld doesn't support -shared, so we use dllwrap)   
+# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now
+#   - its dllwrap doesn't work, there is a bug in binutils 2.10.90
+#     see also .....
+#   - using gcc -mdll instead dllwrap doesn't work without -static because 
+#     it tries to link against dlls instead their import libraries. (If
+#     it finds the dll first.)
+#     By specifying -static we force ld to link against the import libraries, 
+#     this is windows standard and there are normally not the necessary symbols 
+#     in the dlls.
+
 # created 2000/05/05, Rene Liebscher
 
 __revision__ = "$Id: cygwinccompiler.py,v 1.3 2000/07/27 02:13:19 gward Exp $"
 
-import os,sys,string
-from distutils import sysconfig
+import os,sys
 from distutils.unixccompiler import UnixCCompiler
 
-# Because these compilers aren't configured in Python's config.h file by
-# default we should at least warn the user if he is using a unmodified
-# version.
-
-def check_config_h():
-    """Checks if the GCC compiler is mentioned in config.h.  If it is not,
-    compiling probably doesn't work, so print a warning to stderr.
-    """
-
-    # XXX the result of the check should be returned!
-
-    from distutils import sysconfig
-    import string,sys
-    try:
-        # It would probably better to read single lines to search.
-        # But we do this only once, and it is fast enough 
-        f=open(sysconfig.get_config_h_filename())
-        s=f.read()
-        f.close()
-        try:
-            # is somewhere a #ifdef __GNUC__ or something similar
-            string.index(s,"__GNUC__") 
-        except ValueError:
-            sys.stderr.write ("warning: "+
-                "Python's config.h doesn't seem to support your compiler.\n")
-    except IOError:
-        # if we can't read this file, we cannot say it is wrong
-        # the compiler will complain later about this file as missing
-        pass
-
-
-# This is called when the module is imported, so we make this check only once
-# XXX why not make it only when the compiler is needed?
-check_config_h()
-
-
 class CygwinCCompiler (UnixCCompiler):
 
     compiler_type = 'cygwin'
+    gcc_version = None
+    dllwrap_version = None
+    ld_version = None
    
     def __init__ (self,
                   verbose=0,
@@ -61,22 +61,43 @@
 
         UnixCCompiler.__init__ (self, verbose, dry_run, force)
 
+        if check_config_h()<=0:
+            self.warn(
+                "Python's config.h doesn't seem to support your compiler. "
+                "Compiling may fail because of undefined preprocessor macros.")
+        
+        self.gcc_version, self.ld_version, self.dllwrap_version = get_versions()
+        sys.stderr.write(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % 
+                                (self.gcc_version, 
+                                 self.ld_version, 
+                                 self.dllwrap_version) )
+
+        # ld_version >= "2.10.90" should also be able to use 
+        # gcc -mdll instead of dllwrap
+        # Older dllwraps had own version numbers, newer ones use the 
+        # same as the rest of binutils ( also ld )
+        # dllwrap 2.10.90 is buggy
+        if self.ld_version >= "2.10.90": 
+            self.linker = "gcc"
+        else:
+            self.linker = "dllwrap"
+
         # Hard-code GCC because that's what this is all about.
         # XXX optimization, warnings etc. should be customizable.
-        self.set_executables(compiler='gcc -O -Wall',
-                             compiler_so='gcc -O -Wall',
-                             linker_exe='gcc',
-                             linker_so='dllwrap --target=i386-cygwin32')
+        self.set_executables(compiler='gcc -mcygwin -O -Wall',
+                             compiler_so='gcc -mcygwin -mdll -O -Wall',
+                             linker_exe='gcc -mcygwin',
+                             linker_so=('%s -mcygwin -mdll -static' % self.linker))
 
         # cygwin and mingw32 need different sets of libraries 
-        self.dll_libraries=[
-               # cygwin shouldn't need msvcrt, 
-               # but without the dll's will crash
-               # ( gcc version 2.91.57 )
-               # perhaps something about initialization
-               # mingw32 needs it in all cases
-                            "msvcrt"
-                            ]
+        if self.gcc_version == "2.91.57":
+            # cygwin shouldn't need msvcrt, but without the dlls will crash
+            # ( gcc version 2.91.57 ) perhaps something about initialization
+            self.dll_libraries=["msvcrt"]
+            self.warn( 
+                "You should think over switching to a newer version of gcc")
+        else:
+            self.dll_libraries=[]
         
     # __init__ ()
 
@@ -93,64 +114,65 @@
                             extra_postargs=None,
                             build_temp=None):
         
-        if libraries == None:
-            libraries = []
+        # use seperate copies, so can modify the lists
+        extra_preargs = list(extra_preargs or [])
+        libraries = list(libraries or [])
         
-        # Additional libraries: the python library is always needed on
-        # Windows we need the python version without the dot, eg. '15'
-
-        pythonlib = ("python%d%d" %
-                     (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
-        libraries.append(pythonlib)
+        # Additional libraries
         libraries.extend(self.dll_libraries)
+        
+        # we want to put some files in the same directory as the 
+        # object files are, build_temp doesn't help much
 
-        # name of extension
+        # where are the object files
+        temp_dir = os.path.dirname(objects[0])
 
-        # XXX WRONG WRONG WRONG
-        # this is NOT the place to make guesses about Python namespaces;
-        # that MUST be done in build_ext.py
+        # name of dll to give the helper files (def, lib, exp) the same name
+        dll_name,dll_extension = os.path.splitext(os.path.basename(output_filename))
 
-        if not debug:
-            ext_name = os.path.basename(output_filename)[:-len(".pyd")]
-        else:
-            ext_name = os.path.basename(output_filename)[:-len("_d.pyd")]
+        # generate the filenames for these files
+        def_file = None # this will be done later, if necessary
+        exp_file = os.path.join(temp_dir, dll_name + ".exp")
+        lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
 
-        def_file = os.path.join(build_temp, ext_name + ".def")
-        #exp_file = os.path.join(build_temp, ext_name + ".exp")
-        #lib_file = os.path.join(build_temp, 'lib' + ext_name + ".a")
-        
-        # Make .def file
-        # (It would probably better to check if we really need this, 
-        # but for this we had to insert some unchanged parts of 
-        # UnixCCompiler, and this is not what we want.) 
-        f = open(def_file,"w")
-        f.write("EXPORTS\n") # intro
-        if export_symbols == None: 
-            # export a function "init" + ext_name
-            f.write("init" + ext_name + "\n")    
+        #extra_preargs.append("--verbose")
+        if self.linker == "dllwrap":
+            extra_preargs.extend([#"--output-exp",exp_file,
+                                  "--output-lib",lib_file,
+                                 ])
         else:
-            # if there are more symbols to export write them into f
+            # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
+            extra_preargs.extend([#"-Wl,--out-implib,%s" % lib_file,
+                                 ])
+       
+        #  check what we got in export_symbols
+        if export_symbols is not None:
+            # Make .def file
+            # (It would probably better to check if we really need this, 
+            # but for this we had to insert some unchanged parts of 
+            # UnixCCompiler, and this is not what we want.) 
+            def_file = os.path.join(temp_dir, dll_name + ".def")
+            f = open(def_file,"w")
+            f.write("LIBRARY %s\n" % os.path.basename(output_filename))
+            f.write("EXPORTS\n") # intro
             for sym in export_symbols:
                 f.write(sym+"\n")                    
-        f.close()
-        
-        if extra_preargs == None:
-                extra_preargs = []
-        
-        extra_preargs = extra_preargs + [
-                        #"--verbose",
-                        #"--output-exp",exp_file,
-                        #"--output-lib",lib_file,
-                        "--def",def_file
-                        ]
-        
+            f.close()
+                
+        if def_file:
+            if self.linker == "dllwrap":
+                # for dllwrap we have to use a special option
+                extra_preargs.append("--def")
+            # for gcc/ld it is specified as any other object file    
+            extra_preargs.append(def_file)
+                                                 
         # who wants symbols and a many times larger output file
         # should explicitly switch the debug mode on 
-        # otherwise we let dllwrap strip the output file
+        # otherwise we let dllwrap/ld strip the output file
         # (On my machine unstripped_file = stripped_file + 254KB
         #   10KB < stripped_file < ??100KB ) 
         if not debug: 
-            extra_preargs = extra_preargs + ["-s"] 
+            extra_preargs.append("-s") 
         
         UnixCCompiler.link_shared_object(self,
                             objects,
@@ -159,7 +181,7 @@
                             libraries,
                             library_dirs,
                             runtime_library_dirs,
-                            None, # export_symbols, we do this with our def-file
+                            None, # export_symbols, we do this in our def-file
                             debug,
                             extra_preargs,
                             extra_postargs,
@@ -181,19 +203,115 @@
                   force=0):
 
         CygwinCCompiler.__init__ (self, verbose, dry_run, force)
+        
+        # a real mingw32 doesn't need to specify a different entry point                
+        # but cygwin 2.91.57 in no-cygwin-mode needs it
+        if self.gcc_version <= "2.91.57":
+            entry_point = '--entry _DllMain@12'
+        else:
+            entry_point = ''
 
         self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
-                             compiler_so='gcc -mno-cygwin -O -Wall',
+                             compiler_so='gcc -mno-cygwin -mdll -O -Wall',
                              linker_exe='gcc -mno-cygwin',
-                             linker_so='dllwrap' 
-                                    + ' --target=i386-mingw32'
-                                    + ' --entry _DllMain@12')
-        # mingw32 doesn't really need 'target' and cygwin too (it seems, 
-        # it is enough to specify a different entry point)                
-
-        # no additional libraries need 
-        # (only msvcrt, which is already added by CygwinCCompiler)
-
+                             linker_so='%s -mno-cygwin -mdll -static %s' 
+                                        % (self.linker, entry_point))
+        # Maybe we should also append -mthreads, but then the finished
+        # dlls need another dll (mingwm10.dll see Mingw32 docs)
+        # (-mthreads: Support thread-safe exception handling on `Mingw32')       
+        
+        # no additional libraries needed 
+        self.dll_libraries=[]
+        
     # __init__ ()
-                
+
 # class Mingw32CCompiler
+
+# Because these compilers aren't configured in Python's config.h file by
+# default, we should at least warn the user if he is using a unmodified
+# version.
+
+def check_config_h():
+    """Checks if the GCC compiler is mentioned in config.h.  If it is not,
+       compiling probably doesn't work.
+    """
+    # return values
+    #  2: OK, python was compiled with GCC
+    #  1: OK, python's config.h mentions __GCC__
+    #  0: uncertain, because we couldn't check it
+    # -1: probably not OK, because we didn't found it in config.h
+    # You could check check_config_h()>0 => OK
+
+    from distutils import sysconfig
+    import string,sys
+    # if sys.version contains GCC then python was compiled with
+    # GCC, and the config.h file should be OK
+    if -1 == string.find(sys.version,"GCC"):
+        pass # go to the next test
+    else:
+        return 2
+    
+    try:
+        # It would probably better to read single lines to search.
+        # But we do this only once, and it is fast enough 
+        f=open(sysconfig.get_config_h_filename())
+        s=f.read()
+        f.close()
+        
+        # is somewhere a #ifdef __GNUC__ or something similar
+        if -1 == string.find(s,"__GNUC__"):
+            return -1  
+        else:
+            return 1
+    except IOError:
+        # if we can't read this file, we cannot say it is wrong
+        # the compiler will complain later about this file as missing
+        pass
+    return 0
+
+def get_versions():
+    """ Try to find out the versions of gcc, ld and dllwrap.
+        If not possible it returns None for it.
+    """
+    from distutils.version import StrictVersion
+    from distutils.spawn import find_executable
+    import re
+        
+    gcc_exe = find_executable('gcc')
+    if gcc_exe:
+        out = os.popen(gcc_exe + ' -dumpversion','r')
+        out_string = out.read()
+        out.close()
+        result = re.search('(\d+\.\d+\.\d+)',out_string)
+        if result:
+            gcc_version = StrictVersion(result.group(1))
+        else:
+            gcc_version = None
+    else:
+        gcc_version = None
+    ld_exe = find_executable('ld')
+    if ld_exe:
+        out = os.popen(ld_exe + ' -v','r')
+        out_string = out.read()
+        out.close()
+        result = re.search('(\d+\.\d+\.\d+)',out_string)
+        if result:
+            ld_version = StrictVersion(result.group(1))
+        else:
+            ld_version = None
+    else:
+        ld_version = None
+    dllwrap_exe = find_executable('dllwrap')
+    if dllwrap_exe:
+        out = os.popen(dllwrap_exe + ' --version','r')
+        out_string = out.read()
+        out.close()
+        result = re.search(' (\d+\.\d+\.\d+)',out_string)
+        if result:
+            dllwrap_version = StrictVersion(result.group(1))
+        else:
+            dllwrap_version = None
+    else:
+        dllwrap_version = None
+    return (gcc_version, ld_version, dllwrap_version)
+
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/spawn.py d.px/distutils/spawn.py
--- distutils.orig/distutils/spawn.py	Sun Mar 26 23:47:00 2000
+++ d.px/distutils/spawn.py	Thu Jul 27 12:29:03 2000
@@ -1,7 +1,9 @@
 """distutils.spawn
 
 Provides the 'spawn()' function, a front-end to various platform-
-specific functions for launching another program in a sub-process."""
+specific functions for launching another program in a sub-process.
+Also provides the 'find_executable()' to search the path for a given
+executable name. """
 
 # created 1999/07/24, Greg Ward
 
@@ -65,17 +67,8 @@
     executable = cmd[0]
     cmd = _nt_quote_args (cmd)
     if search_path:
-        paths = string.split( os.environ['PATH'], os.pathsep)
-        base,ext = os.path.splitext(executable)
-        if (ext != '.exe'):
-            executable = executable + '.exe'
-        if not os.path.isfile(executable):
-            paths.reverse()         # go over the paths and keep the last one
-            for p in paths:
-                f = os.path.join( p, executable )
-                if os.path.isfile ( f ):
-                    # the file exists, we have a shot at spawn working
-                    executable = f
+        # either we find one or it stays the same
+        executable = find_executable(executable) or executable 
     if verbose:
         print string.join ([executable] + cmd[1:], ' ')
     if not dry_run:
@@ -91,7 +84,6 @@
             raise DistutilsExecError, \
                   "command '%s' failed with exit status %d" % (cmd[0], rc)
 
-    
                 
 def _spawn_posix (cmd,
                   search_path=1,
@@ -147,3 +139,24 @@
                       "unknown error executing '%s': termination status %d" % \
                       (cmd[0], status)
 # _spawn_posix ()
+
+
+def find_executable(executable):
+    """ Tries to find executable in the directories listed in PATH.
+        Returns the complete filename or None if not found. """
+
+    paths = string.split( os.environ['PATH'], os.pathsep)
+    base,ext = os.path.splitext(executable)
+    if (sys.platform == 'win32') and (ext != '.exe'):
+        executable = executable + '.exe'
+    if not os.path.isfile(executable):
+        for p in paths:
+            f = os.path.join( p, executable )
+            if os.path.isfile ( f ):
+                # the file exists, we have a shot at spawn working
+                return f
+        return None
+    else:
+        return executable
+
+# find_executable()    
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/sysconfig.py d.px/distutils/sysconfig.py
--- distutils.orig/distutils/sysconfig.py	Tue Jun 27 03:59:43 2000
+++ d.px/distutils/sysconfig.py	Thu Jul 27 12:29:03 2000
@@ -267,24 +267,8 @@
     g['INCLUDEPY'] = get_python_inc(plat_specific=0)
 
     g['SO'] = '.pyd'
-    g['exec_prefix'] = EXEC_PREFIX
-
-    # These are needed for the CygwinCCompiler and Mingw32CCompiler
-    # classes, which are just UnixCCompiler classes that happen to work on
-    # Windows.  UnixCCompiler expects to find these values in sysconfig, so
-    # here they are.  The fact that other Windows compilers don't need
-    # these values is pure luck (hmmm).
-
-    # XXX I think these are now unnecessary...
-
-    g['CC'] = "cc"                      # not gcc?
-    g['RANLIB'] = "ranlib"
-    g['AR'] = "ar"
-    g['OPT'] = "-O2"
-    g['SO'] = ".pyd"
-    g['LDSHARED'] = "ld"
-    g['CCSHARED'] = ""
     g['EXE'] = ".exe"
+    g['exec_prefix'] = EXEC_PREFIX
 
 
 def _init_mac():

--------------09D84941F7DE6AE76370E7A8--