python-2.5.2/win32/Lib/distutils/cygwinccompiler.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """distutils.cygwinccompiler
       
     2 
       
     3 Provides the CygwinCCompiler class, a subclass of UnixCCompiler that
       
     4 handles the Cygwin port of the GNU C compiler to Windows.  It also contains
       
     5 the Mingw32CCompiler class which handles the mingw32 port of GCC (same as
       
     6 cygwin in no-cygwin mode).
       
     7 """
       
     8 
       
     9 # problems:
       
    10 #
       
    11 # * if you use a msvc compiled python version (1.5.2)
       
    12 #   1. you have to insert a __GNUC__ section in its config.h
       
    13 #   2. you have to generate a import library for its dll
       
    14 #      - create a def-file for python??.dll
       
    15 #      - create a import library using
       
    16 #             dlltool --dllname python15.dll --def python15.def \
       
    17 #                       --output-lib libpython15.a
       
    18 #
       
    19 #   see also http://starship.python.net/crew/kernr/mingw32/Notes.html
       
    20 #
       
    21 # * We put export_symbols in a def-file, and don't use
       
    22 #   --export-all-symbols because it doesn't worked reliable in some
       
    23 #   tested configurations. And because other windows compilers also
       
    24 #   need their symbols specified this no serious problem.
       
    25 #
       
    26 # tested configurations:
       
    27 #
       
    28 # * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works
       
    29 #   (after patching python's config.h and for C++ some other include files)
       
    30 #   see also http://starship.python.net/crew/kernr/mingw32/Notes.html
       
    31 # * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works
       
    32 #   (ld doesn't support -shared, so we use dllwrap)
       
    33 # * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now
       
    34 #   - its dllwrap doesn't work, there is a bug in binutils 2.10.90
       
    35 #     see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html
       
    36 #   - using gcc -mdll instead dllwrap doesn't work without -static because
       
    37 #     it tries to link against dlls instead their import libraries. (If
       
    38 #     it finds the dll first.)
       
    39 #     By specifying -static we force ld to link against the import libraries,
       
    40 #     this is windows standard and there are normally not the necessary symbols
       
    41 #     in the dlls.
       
    42 #   *** only the version of June 2000 shows these problems
       
    43 # * cygwin gcc 3.2/ld 2.13.90 works
       
    44 #   (ld supports -shared)
       
    45 # * mingw gcc 3.2/ld 2.13 works
       
    46 #   (ld supports -shared)
       
    47 
       
    48 # This module should be kept compatible with Python 2.1.
       
    49 
       
    50 __revision__ = "$Id: cygwinccompiler.py 37828 2004-11-10 22:23:15Z loewis $"
       
    51 
       
    52 import os,sys,copy
       
    53 from distutils.ccompiler import gen_preprocess_options, gen_lib_options
       
    54 from distutils.unixccompiler import UnixCCompiler
       
    55 from distutils.file_util import write_file
       
    56 from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
       
    57 from distutils import log
       
    58 
       
    59 class CygwinCCompiler (UnixCCompiler):
       
    60 
       
    61     compiler_type = 'cygwin'
       
    62     obj_extension = ".o"
       
    63     static_lib_extension = ".a"
       
    64     shared_lib_extension = ".dll"
       
    65     static_lib_format = "lib%s%s"
       
    66     shared_lib_format = "%s%s"
       
    67     exe_extension = ".exe"
       
    68 
       
    69     def __init__ (self, verbose=0, dry_run=0, force=0):
       
    70 
       
    71         UnixCCompiler.__init__ (self, verbose, dry_run, force)
       
    72 
       
    73         (status, details) = check_config_h()
       
    74         self.debug_print("Python's GCC status: %s (details: %s)" %
       
    75                          (status, details))
       
    76         if status is not CONFIG_H_OK:
       
    77             self.warn(
       
    78                 "Python's pyconfig.h doesn't seem to support your compiler. "
       
    79                 "Reason: %s. "
       
    80                 "Compiling may fail because of undefined preprocessor macros."
       
    81                 % details)
       
    82 
       
    83         self.gcc_version, self.ld_version, self.dllwrap_version = \
       
    84             get_versions()
       
    85         self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
       
    86                          (self.gcc_version,
       
    87                           self.ld_version,
       
    88                           self.dllwrap_version) )
       
    89 
       
    90         # ld_version >= "2.10.90" and < "2.13" should also be able to use
       
    91         # gcc -mdll instead of dllwrap
       
    92         # Older dllwraps had own version numbers, newer ones use the
       
    93         # same as the rest of binutils ( also ld )
       
    94         # dllwrap 2.10.90 is buggy
       
    95         if self.ld_version >= "2.10.90":
       
    96             self.linker_dll = "gcc"
       
    97         else:
       
    98             self.linker_dll = "dllwrap"
       
    99 
       
   100         # ld_version >= "2.13" support -shared so use it instead of
       
   101         # -mdll -static
       
   102         if self.ld_version >= "2.13":
       
   103             shared_option = "-shared"
       
   104         else:
       
   105             shared_option = "-mdll -static"
       
   106 
       
   107         # Hard-code GCC because that's what this is all about.
       
   108         # XXX optimization, warnings etc. should be customizable.
       
   109         self.set_executables(compiler='gcc -mcygwin -O -Wall',
       
   110                              compiler_so='gcc -mcygwin -mdll -O -Wall',
       
   111                              compiler_cxx='g++ -mcygwin -O -Wall',
       
   112                              linker_exe='gcc -mcygwin',
       
   113                              linker_so=('%s -mcygwin %s' %
       
   114                                         (self.linker_dll, shared_option)))
       
   115 
       
   116         # cygwin and mingw32 need different sets of libraries
       
   117         if self.gcc_version == "2.91.57":
       
   118             # cygwin shouldn't need msvcrt, but without the dlls will crash
       
   119             # (gcc version 2.91.57) -- perhaps something about initialization
       
   120             self.dll_libraries=["msvcrt"]
       
   121             self.warn(
       
   122                 "Consider upgrading to a newer version of gcc")
       
   123         else:
       
   124             self.dll_libraries=[]
       
   125             # Include the appropriate MSVC runtime library if Python was built
       
   126             # with MSVC 7.0 or 7.1.
       
   127             msc_pos = sys.version.find('MSC v.')
       
   128             if msc_pos != -1:
       
   129                 msc_ver = sys.version[msc_pos+6:msc_pos+10]
       
   130                 if msc_ver == '1300':
       
   131                     # MSVC 7.0
       
   132                     self.dll_libraries = ['msvcr70']
       
   133                 elif msc_ver == '1310':
       
   134                     # MSVC 7.1
       
   135                     self.dll_libraries = ['msvcr71']
       
   136 
       
   137     # __init__ ()
       
   138 
       
   139 
       
   140     def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
       
   141         if ext == '.rc' or ext == '.res':
       
   142             # gcc needs '.res' and '.rc' compiled to object files !!!
       
   143             try:
       
   144                 self.spawn(["windres", "-i", src, "-o", obj])
       
   145             except DistutilsExecError, msg:
       
   146                 raise CompileError, msg
       
   147         else: # for other files use the C-compiler
       
   148             try:
       
   149                 self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
       
   150                            extra_postargs)
       
   151             except DistutilsExecError, msg:
       
   152                 raise CompileError, msg
       
   153 
       
   154     def link (self,
       
   155               target_desc,
       
   156               objects,
       
   157               output_filename,
       
   158               output_dir=None,
       
   159               libraries=None,
       
   160               library_dirs=None,
       
   161               runtime_library_dirs=None,
       
   162               export_symbols=None,
       
   163               debug=0,
       
   164               extra_preargs=None,
       
   165               extra_postargs=None,
       
   166               build_temp=None,
       
   167               target_lang=None):
       
   168 
       
   169         # use separate copies, so we can modify the lists
       
   170         extra_preargs = copy.copy(extra_preargs or [])
       
   171         libraries = copy.copy(libraries or [])
       
   172         objects = copy.copy(objects or [])
       
   173 
       
   174         # Additional libraries
       
   175         libraries.extend(self.dll_libraries)
       
   176 
       
   177         # handle export symbols by creating a def-file
       
   178         # with executables this only works with gcc/ld as linker
       
   179         if ((export_symbols is not None) and
       
   180             (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
       
   181             # (The linker doesn't do anything if output is up-to-date.
       
   182             # So it would probably better to check if we really need this,
       
   183             # but for this we had to insert some unchanged parts of
       
   184             # UnixCCompiler, and this is not what we want.)
       
   185 
       
   186             # we want to put some files in the same directory as the
       
   187             # object files are, build_temp doesn't help much
       
   188             # where are the object files
       
   189             temp_dir = os.path.dirname(objects[0])
       
   190             # name of dll to give the helper files the same base name
       
   191             (dll_name, dll_extension) = os.path.splitext(
       
   192                 os.path.basename(output_filename))
       
   193 
       
   194             # generate the filenames for these files
       
   195             def_file = os.path.join(temp_dir, dll_name + ".def")
       
   196             lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
       
   197 
       
   198             # Generate .def file
       
   199             contents = [
       
   200                 "LIBRARY %s" % os.path.basename(output_filename),
       
   201                 "EXPORTS"]
       
   202             for sym in export_symbols:
       
   203                 contents.append(sym)
       
   204             self.execute(write_file, (def_file, contents),
       
   205                          "writing %s" % def_file)
       
   206 
       
   207             # next add options for def-file and to creating import libraries
       
   208 
       
   209             # dllwrap uses different options than gcc/ld
       
   210             if self.linker_dll == "dllwrap":
       
   211                 extra_preargs.extend(["--output-lib", lib_file])
       
   212                 # for dllwrap we have to use a special option
       
   213                 extra_preargs.extend(["--def", def_file])
       
   214             # we use gcc/ld here and can be sure ld is >= 2.9.10
       
   215             else:
       
   216                 # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
       
   217                 #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])
       
   218                 # for gcc/ld the def-file is specified as any object files
       
   219                 objects.append(def_file)
       
   220 
       
   221         #end: if ((export_symbols is not None) and
       
   222         #        (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
       
   223 
       
   224         # who wants symbols and a many times larger output file
       
   225         # should explicitly switch the debug mode on
       
   226         # otherwise we let dllwrap/ld strip the output file
       
   227         # (On my machine: 10KB < stripped_file < ??100KB
       
   228         #   unstripped_file = stripped_file + XXX KB
       
   229         #  ( XXX=254 for a typical python extension))
       
   230         if not debug:
       
   231             extra_preargs.append("-s")
       
   232 
       
   233         UnixCCompiler.link(self,
       
   234                            target_desc,
       
   235                            objects,
       
   236                            output_filename,
       
   237                            output_dir,
       
   238                            libraries,
       
   239                            library_dirs,
       
   240                            runtime_library_dirs,
       
   241                            None, # export_symbols, we do this in our def-file
       
   242                            debug,
       
   243                            extra_preargs,
       
   244                            extra_postargs,
       
   245                            build_temp,
       
   246                            target_lang)
       
   247 
       
   248     # link ()
       
   249 
       
   250     # -- Miscellaneous methods -----------------------------------------
       
   251 
       
   252     # overwrite the one from CCompiler to support rc and res-files
       
   253     def object_filenames (self,
       
   254                           source_filenames,
       
   255                           strip_dir=0,
       
   256                           output_dir=''):
       
   257         if output_dir is None: output_dir = ''
       
   258         obj_names = []
       
   259         for src_name in source_filenames:
       
   260             # use normcase to make sure '.rc' is really '.rc' and not '.RC'
       
   261             (base, ext) = os.path.splitext (os.path.normcase(src_name))
       
   262             if ext not in (self.src_extensions + ['.rc','.res']):
       
   263                 raise UnknownFileError, \
       
   264                       "unknown file type '%s' (from '%s')" % \
       
   265                       (ext, src_name)
       
   266             if strip_dir:
       
   267                 base = os.path.basename (base)
       
   268             if ext == '.res' or ext == '.rc':
       
   269                 # these need to be compiled to object files
       
   270                 obj_names.append (os.path.join (output_dir,
       
   271                                             base + ext + self.obj_extension))
       
   272             else:
       
   273                 obj_names.append (os.path.join (output_dir,
       
   274                                             base + self.obj_extension))
       
   275         return obj_names
       
   276 
       
   277     # object_filenames ()
       
   278 
       
   279 # class CygwinCCompiler
       
   280 
       
   281 
       
   282 # the same as cygwin plus some additional parameters
       
   283 class Mingw32CCompiler (CygwinCCompiler):
       
   284 
       
   285     compiler_type = 'mingw32'
       
   286 
       
   287     def __init__ (self,
       
   288                   verbose=0,
       
   289                   dry_run=0,
       
   290                   force=0):
       
   291 
       
   292         CygwinCCompiler.__init__ (self, verbose, dry_run, force)
       
   293 
       
   294         # ld_version >= "2.13" support -shared so use it instead of
       
   295         # -mdll -static
       
   296         if self.ld_version >= "2.13":
       
   297             shared_option = "-shared"
       
   298         else:
       
   299             shared_option = "-mdll -static"
       
   300 
       
   301         # A real mingw32 doesn't need to specify a different entry point,
       
   302         # but cygwin 2.91.57 in no-cygwin-mode needs it.
       
   303         if self.gcc_version <= "2.91.57":
       
   304             entry_point = '--entry _DllMain@12'
       
   305         else:
       
   306             entry_point = ''
       
   307 
       
   308         self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
       
   309                              compiler_so='gcc -mno-cygwin -mdll -O -Wall',
       
   310                              compiler_cxx='g++ -mno-cygwin -O -Wall',
       
   311                              linker_exe='gcc -mno-cygwin',
       
   312                              linker_so='%s -mno-cygwin %s %s'
       
   313                                         % (self.linker_dll, shared_option,
       
   314                                            entry_point))
       
   315         # Maybe we should also append -mthreads, but then the finished
       
   316         # dlls need another dll (mingwm10.dll see Mingw32 docs)
       
   317         # (-mthreads: Support thread-safe exception handling on `Mingw32')
       
   318 
       
   319         # no additional libraries needed
       
   320         self.dll_libraries=[]
       
   321 
       
   322         # Include the appropriate MSVC runtime library if Python was built
       
   323         # with MSVC 7.0 or 7.1.
       
   324         msc_pos = sys.version.find('MSC v.')
       
   325         if msc_pos != -1:
       
   326             msc_ver = sys.version[msc_pos+6:msc_pos+10]
       
   327             if msc_ver == '1300':
       
   328                 # MSVC 7.0
       
   329                 self.dll_libraries = ['msvcr70']
       
   330             elif msc_ver == '1310':
       
   331                 # MSVC 7.1
       
   332                 self.dll_libraries = ['msvcr71']
       
   333 
       
   334     # __init__ ()
       
   335 
       
   336 # class Mingw32CCompiler
       
   337 
       
   338 # Because these compilers aren't configured in Python's pyconfig.h file by
       
   339 # default, we should at least warn the user if he is using a unmodified
       
   340 # version.
       
   341 
       
   342 CONFIG_H_OK = "ok"
       
   343 CONFIG_H_NOTOK = "not ok"
       
   344 CONFIG_H_UNCERTAIN = "uncertain"
       
   345 
       
   346 def check_config_h():
       
   347 
       
   348     """Check if the current Python installation (specifically, pyconfig.h)
       
   349     appears amenable to building extensions with GCC.  Returns a tuple
       
   350     (status, details), where 'status' is one of the following constants:
       
   351       CONFIG_H_OK
       
   352         all is well, go ahead and compile
       
   353       CONFIG_H_NOTOK
       
   354         doesn't look good
       
   355       CONFIG_H_UNCERTAIN
       
   356         not sure -- unable to read pyconfig.h
       
   357     'details' is a human-readable string explaining the situation.
       
   358 
       
   359     Note there are two ways to conclude "OK": either 'sys.version' contains
       
   360     the string "GCC" (implying that this Python was built with GCC), or the
       
   361     installed "pyconfig.h" contains the string "__GNUC__".
       
   362     """
       
   363 
       
   364     # XXX since this function also checks sys.version, it's not strictly a
       
   365     # "pyconfig.h" check -- should probably be renamed...
       
   366 
       
   367     from distutils import sysconfig
       
   368     import string
       
   369     # if sys.version contains GCC then python was compiled with
       
   370     # GCC, and the pyconfig.h file should be OK
       
   371     if string.find(sys.version,"GCC") >= 0:
       
   372         return (CONFIG_H_OK, "sys.version mentions 'GCC'")
       
   373 
       
   374     fn = sysconfig.get_config_h_filename()
       
   375     try:
       
   376         # It would probably better to read single lines to search.
       
   377         # But we do this only once, and it is fast enough
       
   378         f = open(fn)
       
   379         s = f.read()
       
   380         f.close()
       
   381 
       
   382     except IOError, exc:
       
   383         # if we can't read this file, we cannot say it is wrong
       
   384         # the compiler will complain later about this file as missing
       
   385         return (CONFIG_H_UNCERTAIN,
       
   386                 "couldn't read '%s': %s" % (fn, exc.strerror))
       
   387 
       
   388     else:
       
   389         # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
       
   390         if string.find(s,"__GNUC__") >= 0:
       
   391             return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
       
   392         else:
       
   393             return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
       
   394 
       
   395 
       
   396 
       
   397 def get_versions():
       
   398     """ Try to find out the versions of gcc, ld and dllwrap.
       
   399         If not possible it returns None for it.
       
   400     """
       
   401     from distutils.version import StrictVersion
       
   402     from distutils.spawn import find_executable
       
   403     import re
       
   404 
       
   405     gcc_exe = find_executable('gcc')
       
   406     if gcc_exe:
       
   407         out = os.popen(gcc_exe + ' -dumpversion','r')
       
   408         out_string = out.read()
       
   409         out.close()
       
   410         result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
       
   411         if result:
       
   412             gcc_version = StrictVersion(result.group(1))
       
   413         else:
       
   414             gcc_version = None
       
   415     else:
       
   416         gcc_version = None
       
   417     ld_exe = find_executable('ld')
       
   418     if ld_exe:
       
   419         out = os.popen(ld_exe + ' -v','r')
       
   420         out_string = out.read()
       
   421         out.close()
       
   422         result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
       
   423         if result:
       
   424             ld_version = StrictVersion(result.group(1))
       
   425         else:
       
   426             ld_version = None
       
   427     else:
       
   428         ld_version = None
       
   429     dllwrap_exe = find_executable('dllwrap')
       
   430     if dllwrap_exe:
       
   431         out = os.popen(dllwrap_exe + ' --version','r')
       
   432         out_string = out.read()
       
   433         out.close()
       
   434         result = re.search(' (\d+\.\d+(\.\d+)*)',out_string)
       
   435         if result:
       
   436             dllwrap_version = StrictVersion(result.group(1))
       
   437         else:
       
   438             dllwrap_version = None
       
   439     else:
       
   440         dllwrap_version = None
       
   441     return (gcc_version, ld_version, dllwrap_version)