[Distutils] Re: CygwinCCompiler, msvc hack, BCPPCompiler

Rene Liebscher R.Liebscher@gmx.de
Sun, 23 Jul 2000 01:54:53 +0200


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

Rene Liebscher wrote:
> 
> Greg Ward wrote:
> >
> > On 06 July 2000, Rene Liebscher said:
> > > +# * cygwin gcc 2.91 works (after patching some include files)
> > > +# * mingw32 gcc 2.95.2 works (it doesn't support gcc -shared)
> > > +# * cygwin gcc 2.95.2 doesn't work now
> > > +#   - its dllwrap doesn't work at my machine
> > > +#   - target had to be changed to something like i686-cygwin32
> > > +#   - mingw32-mode is specified by -mno-cygwin
> > > +#   - using gcc -shared instead dllwrap didn't work because some problems with
> > > +#     the import library, maybe it needs some additional parameters
> >
> > AAUUGGHH!!!  (What more can I say?)
> gcc 2.91 is no problem for us. People should use a newer compiler.
> But the differences betweeen these two gcc 2.9.5 are a problem,
> mingw32 doesn't support gcc -shared yet, and cygwin's dllwrap
> seems to have a bug (It fails to reallocate 1.7 GByte of Memory.)
> Cygwin's gcc -shared wants other symbols than dlltool creates
> in the import library.
> Is there someone out there who has already successful created a
> extension module with the new cygwin version? If yes, please send me
> the commandlines you used for this.
In the latest cygwin binutils 2.10.90 is a bug in dllwrap.
This new version of my patch tries now to find out the version
numbers of gcc, ld and dllwrap, so we can inform the user 
if he is using a broken version of one of these programs.

(I also found many tabs in distutils which were introduced by 
by my help-option patch. This patch replaces these tabs with 
spaces.)

kind regards
 
Rene Liebscher
--------------7EEEE0777720915A60C3A738
Content-Type: text/plain; charset=us-ascii;
 name="msvc_hack3.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="msvc_hack3.patch"

diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/bcppcompiler.py distutils.patched/distutils/bcppcompiler.py
--- distutils.orig/distutils/bcppcompiler.py	Wed Jun 28 03:20:35 2000
+++ distutils.patched/distutils/bcppcompiler.py	Tue Jul 18 11:20:23 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
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/bdist.py distutils.patched/distutils/command/bdist.py
--- distutils.orig/distutils/command/bdist.py	Wed Jul  5 05:07:18 2000
+++ distutils.patched/distutils/command/bdist.py	Tue Jul 18 11:20:23 2000
@@ -42,7 +42,7 @@
     help_options = [
         ('help-formats', None,
          "lists available distribution formats", show_formats),
-	]
+        ]
 
     # The following commands do not take a format option from bdist
     no_format_option = ('bdist_rpm',)
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/build.py distutils.patched/distutils/command/build.py
--- distutils.orig/distutils/command/build.py	Sat Jun 24 03:23:37 2000
+++ distutils.patched/distutils/command/build.py	Tue Jul 18 11:20:23 2000
@@ -45,7 +45,7 @@
     help_options = [
         ('help-compiler', None,
          "list available compilers", show_compilers),
-	]
+        ]
 
     def initialize_options (self):
         self.build_base = 'build'
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/build_clib.py distutils.patched/distutils/command/build_clib.py
--- distutils.orig/distutils/command/build_clib.py	Sun Jun 25 04:10:58 2000
+++ distutils.patched/distutils/command/build_clib.py	Tue Jul 18 11:20:23 2000
@@ -51,7 +51,7 @@
     help_options = [
         ('help-compiler', None,
          "list available compilers", show_compilers),
-	]
+        ]
 
     def initialize_options (self):
         self.build_clib = None
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/build_ext.py distutils.patched/distutils/command/build_ext.py
--- distutils.orig/distutils/command/build_ext.py	Sun Jul 16 16:10:00 2000
+++ distutils.patched/distutils/command/build_ext.py	Tue Jul 18 11:20:23 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/command/install_data.py distutils.patched/distutils/command/install_data.py
--- distutils.orig/distutils/command/install_data.py	Sat Jun 24 19:36:24 2000
+++ distutils.patched/distutils/command/install_data.py	Tue Jul 18 11:20:23 2000
@@ -32,9 +32,9 @@
 
     def finalize_options (self):
         self.set_undefined_options('install',
-	                           ('install_data', 'install_dir'),
-				   ('root', 'root'),
-				  )
+                                   ('install_data', 'install_dir'),
+                                   ('root', 'root'),
+                                  )
 
     def run (self):
         self.mkpath(self.install_dir)
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/install_lib.py distutils.patched/distutils/command/install_lib.py
--- distutils.orig/distutils/command/install_lib.py	Sat May 27 19:27:23 2000
+++ distutils.patched/distutils/command/install_lib.py	Tue Jul 18 11:20:23 2000
@@ -74,7 +74,7 @@
                     out_fn = f + (__debug__ and "c" or "o")
                     compile_msg = "byte-compiling %s to %s" % \
                                   (f, os.path.basename (out_fn))
-                    skip_msg = "byte-compilation of %s skipped" % f
+                    skip_msg = "skipping byte-compilation of %s" % f
                     self.make_file (f, out_fn, compile, (f,),
                                     compile_msg, skip_msg)
     # run ()
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/command/sdist.py distutils.patched/distutils/command/sdist.py
--- distutils.orig/distutils/command/sdist.py	Wed Jul  5 05:06:46 2000
+++ distutils.patched/distutils/command/sdist.py	Tue Jul 18 11:20:23 2000
@@ -73,7 +73,7 @@
     help_options = [
         ('help-formats', None,
          "list available distribution formats", show_formats),
-	]
+        ]
 
     negative_opt = {'no-defaults': 'use-defaults',
                     'no-prune': 'prune' }
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/cygwinccompiler.py distutils.patched/distutils/cygwinccompiler.py
--- distutils.orig/distutils/cygwinccompiler.py	Fri Jun 30 00:57:55 2000
+++ distutils.patched/distutils/cygwinccompiler.py	Tue Jul 18 11:20:23 2000
@@ -6,53 +6,45 @@
 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
+#   
+# * 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 doesn't work
+#   - its dllwrap doesn't work, there is a bug in binutils 2.10.90
+#     see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html
+#   - using gcc -shared instead dllwrap didn't work because some problems 
+#     with the import library, maybe it needs some additional parameters? 
+#     ( "undefined reference to '_imp__PyErr_SetString'",
+#       dlltool builds import libraries with '__imp__PyErr_SetString' 
+#       and '___imp_PyErr_SetString' )   
+
 # created 2000/05/05, Rene Liebscher
 
 __revision__ = "$Id: cygwinccompiler.py,v 1.2 2000/06/29 22:57:55 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 +53,41 @@
 
         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 -shared instead of dllwrap
+        # Older dllwraps had own version numbers, newer ones use the 
+        # same as the rest of binutils ( also ld )
+        if self.dllwrap_version == "2.10.90": 
+            # only warn, the user could have a patched version
+            self.warn("dllwrap 2.10.90 is buggy please use another version.")
+
         # 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='dllwrap -mcygwin -mdll')
 
         # 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__ ()
 
@@ -96,53 +107,49 @@
         if libraries == None:
             libraries = []
         
-        # 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)
-        libraries.extend(self.dll_libraries)
-
-        # name of extension
+        # Additional libraries
+        # libraries.extend(...) would affect the list we got as parameter
+        # and this can come from anywhere  
+        libraries = libraries + self.dll_libraries
+        
+        # we want to put some files in the same directory as the 
+        # object files are, build_temp doesn't help much
 
-        # 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")]
+        # where are the object files
+        temp_dir = os.path.dirname(objects[0])
 
-        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")
+        # 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")
         
-        # 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")    
-        else:
-            # if there are more symbols to export write them into f
+        #  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("EXPORTS\n") # intro
             for sym in export_symbols:
                 f.write(sym+"\n")                    
-        f.close()
-        
-        if extra_preargs == None:
+            f.close()
+                
+
+        if extra_preargs is None:
                 extra_preargs = []
         
         extra_preargs = extra_preargs + [
                         #"--verbose",
                         #"--output-exp",exp_file,
                         #"--output-lib",lib_file,
-                        "--def",def_file
                         ]
+        if def_file:
+            extra_preargs.extend(["--def",def_file])
         
         # who wants symbols and a many times larger output file
         # should explicitely switch the debug mode on 
@@ -150,7 +157,7 @@
         # (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,
@@ -181,19 +188,112 @@
                   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='dllwrap -mno-cygwin -mdll' 
+                                      + 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():
+    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/dist.py distutils.patched/distutils/dist.py
--- distutils.orig/distutils/dist.py	Fri Jul  7 22:45:21 2000
+++ distutils.patched/distutils/dist.py	Tue Jul 18 11:20:23 2000
@@ -278,7 +278,7 @@
             user_filename = ".pydistutils.cfg"
         else:
             user_filename = "pydistutils.cfg"
-	
+        
         # And look for the user config file
         if os.environ.has_key('HOME'):
             user_file = os.path.join(os.environ.get('HOME'), user_filename)
@@ -437,8 +437,8 @@
             negative_opt = copy (negative_opt)
             negative_opt.update (cmd_class.negative_opt)
 
-	# Check for help_options in command class.  They have a different
-	# format (tuple of four) so we need to preprocess them here.
+        # Check for help_options in command class.  They have a different
+        # format (tuple of four) so we need to preprocess them here.
         if (hasattr(cmd_class, 'help_options') and
             type (cmd_class.help_options) is ListType):
             help_options = fix_help_options(cmd_class.help_options)
@@ -463,7 +463,7 @@
             for (help_option, short, desc, func) in cmd_class.help_options:
                 if hasattr(opts, parser.get_attr_name(help_option)):
                     help_option_found=1
-		    #print "showing help for option %s of command %s" % \
+                    #print "showing help for option %s of command %s" % \
                     #      (help_option[0],cmd_class)
 
                     if callable(func):
@@ -539,7 +539,7 @@
         return
 
     # _show_help ()
-	
+    
 
     def handle_display_options (self, option_order):
         """If there were any non-global "display-only" options
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/extension.py distutils.patched/distutils/extension.py
--- distutils.orig/distutils/extension.py	Sat Jun 24 02:18:24 2000
+++ distutils.patched/distutils/extension.py	Tue Jul 18 11:20:23 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 distutils.patched/distutils/msvccompiler.py
--- distutils.orig/distutils/msvccompiler.py	Fri Jun 30 21:37:59 2000
+++ distutils.patched/distutils/msvccompiler.py	Tue Jul 18 11:20:23 2000
@@ -379,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
diff -BurN --minimal --exclude=*.pyc distutils.orig/distutils/spawn.py distutils.patched/distutils/spawn.py
--- distutils.orig/distutils/spawn.py	Sun Mar 26 23:47:00 2000
+++ distutils.patched/distutils/spawn.py	Tue Jul 18 11:20:23 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 distutils.patched/distutils/sysconfig.py
--- distutils.orig/distutils/sysconfig.py	Tue Jun 27 03:59:43 2000
+++ distutils.patched/distutils/sysconfig.py	Tue Jul 18 11:20:24 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():

--------------7EEEE0777720915A60C3A738--