[Python-checkins] CVS: distutils/distutils cygwinccompiler.py,1.3,1.4

Greg Ward python-dev@python.org
Tue, 1 Aug 2000 18:31:58 -0700


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

Modified Files:
	cygwinccompiler.py 
Log Message:
Latest version from Rene Liebscher; major changes:
  - added big comment describing possible problems
  - look for and react to versions of gcc, ld, and dlltool; mainly
    this is done by the 'get_versions()' function and the CygwinCCompiler
    and Mingw32CCompiler constructors
  - move 'check_config_h()' to end of file and defer calling it until
    we need to (ie. in the CygwinCCompiler constructor)
  - lots of changes in 'link_shared_object()' -- mostly seems to be
    library and DLL stuff, but I don't follow it entirely


Index: cygwinccompiler.py
===================================================================
RCS file: /cvsroot/python/distutils/distutils/cygwinccompiler.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -r1.3 -r1.4
*** cygwinccompiler.py	2000/07/27 02:13:19	1.3
--- cygwinccompiler.py	2000/08/02 01:31:56	1.4
***************
*** 7,57 ****
  """
  
  # created 2000/05/05, Rene Liebscher
  
  __revision__ = "$Id$"
  
! import os,sys,string
! from distutils import sysconfig
  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'
     
      def __init__ (self,
--- 7,58 ----
  """
  
+ # 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$"
  
! import os,sys
  from distutils.unixccompiler import UnixCCompiler
+ from distutils.file_util import write_file
  
  class CygwinCCompiler (UnixCCompiler):
  
      compiler_type = 'cygwin'
+     gcc_version = None
+     dllwrap_version = None
+     ld_version = None
     
      def __init__ (self,
***************
*** 62,81 ****
          UnixCCompiler.__init__ (self, verbose, dry_run, force)
  
          # 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')
  
          # 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"
!                             ]
          
      # __init__ ()
--- 63,105 ----
          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 -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 
!         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( 
!                 "Consider upgrading to a newer version of gcc")
!         else:
!             self.dll_libraries=[]
          
      # __init__ ()
***************
*** 94,155 ****
                              build_temp=None):
          
!         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
  
!         # XXX WRONG WRONG WRONG
!         # this is NOT the place to make guesses about Python namespaces;
!         # that MUST be done in build_ext.py
! 
!         if not debug:
!             ext_name = os.path.basename(output_filename)[:-len(".pyd")]
!         else:
!             ext_name = os.path.basename(output_filename)[:-len("_d.pyd")]
! 
!         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")    
          else:
!             # if there are more symbols to export write them into f
              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
!                         ]
!         
          # 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
          # (On my machine unstripped_file = stripped_file + 254KB
          #   10KB < stripped_file < ??100KB ) 
          if not debug: 
!             extra_preargs = extra_preargs + ["-s"] 
          
          UnixCCompiler.link_shared_object(self,
--- 118,182 ----
                              build_temp=None):
          
!         # use separate copies, so can modify the lists
!         extra_preargs = list(extra_preargs or [])
!         libraries = list(libraries or [])
          
!         # 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
  
!         # where are the object files
!         temp_dir = os.path.dirname(objects[0])
  
!         # 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))
! 
!         # 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")
! 
!         #extra_preargs.append("--verbose")
!         if self.linker == "dllwrap":
!             extra_preargs.extend([#"--output-exp",exp_file,
!                                   "--output-lib",lib_file,
!                                  ])
          else:
!             # 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")
!             contents = [
!                 "LIBRARY %s" % os.path.basename(output_filename),
!                 "EXPORTS"]
              for sym in export_symbols:
!                 contents.append(sym)
!             self.execute(write_file, (def_file, contents),
!                          "writing %s" % def_file)
! 
!         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/ld strip the output file
          # (On my machine unstripped_file = stripped_file + 254KB
          #   10KB < stripped_file < ??100KB ) 
          if not debug: 
!             extra_preargs.append("-s") 
          
          UnixCCompiler.link_shared_object(self,
***************
*** 160,164 ****
                              library_dirs,
                              runtime_library_dirs,
!                             None, # export_symbols, we do this with our def-file
                              debug,
                              extra_preargs,
--- 187,191 ----
                              library_dirs,
                              runtime_library_dirs,
!                             None, # export_symbols, we do this in our def-file
                              debug,
                              extra_preargs,
***************
*** 182,199 ****
  
          CygwinCCompiler.__init__ (self, verbose, dry_run, force)
  
          self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
!                              compiler_so='gcc -mno-cygwin -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)
! 
      # __init__ ()
!                 
  # class Mingw32CCompiler
--- 209,322 ----
  
          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 -mdll -O -Wall',
                               linker_exe='gcc -mno-cygwin',
!                              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)
+