Home | History | Annotate | Download | only in distutils
      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$"
     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 def get_msvcr():
     60     """Include the appropriate MSVC runtime library if Python was built
     61     with MSVC 7.0 or later.
     62     """
     63     # FIXME: next code is from issue870382
     64     # MS C-runtime libraries never support backward compatibility.
     65     # Linking to a different library without to specify correct runtime
     66     # version for the headers will link renamed functions to msvcrt.
     67     # See issue3308: this piece of code is python problem even
     68     # with correct w32api headers.
     69     # Issue: for MSVC compiler we can get the version and from version
     70     # to determine mcvcrt as code below. But what about if python is
     71     # build with GCC compiler?
     72     # Output of sys.version is information for python build on first
     73     # line, on the next line is information for the compiler and the
     74     # output lack information for the C-runtime.
     75     msc_pos = sys.version.find('MSC v.')
     76     if msc_pos != -1:
     77         msc_ver = sys.version[msc_pos+6:msc_pos+10]
     78         if msc_ver == '1300':
     79             # MSVC 7.0
     80             return ['msvcr70']
     81         elif msc_ver == '1310':
     82             # MSVC 7.1
     83             return ['msvcr71']
     84         elif msc_ver == '1400':
     85             # VS2005 / MSVC 8.0
     86             return ['msvcr80']
     87         elif msc_ver == '1500':
     88             # VS2008 / MSVC 9.0
     89             return ['msvcr90']
     90         else:
     91             raise ValueError("Unknown MS Compiler version %s " % msc_ver)
     92     else:
     93         return []
     94 
     95 
     96 class CygwinCCompiler (UnixCCompiler):
     97 
     98     compiler_type = 'cygwin'
     99     obj_extension = ".o"
    100     static_lib_extension = ".a"
    101     shared_lib_extension = ".dll"
    102     # FIXME: dylib_... = ".dll.a" is not enought for binutils
    103     # loader on win32 platform !!!
    104     dylib_lib_extension = ".dll.a"
    105     static_lib_format = "lib%s%s"
    106     shared_lib_format = "%s%s"
    107     exe_extension = ".exe"
    108 
    109     def __init__ (self, verbose=0, dry_run=0, force=0):
    110 
    111         UnixCCompiler.__init__ (self, verbose, dry_run, force)
    112 
    113         (status, details) = check_config_h()
    114         self.debug_print("Python's GCC status: %s (details: %s)" %
    115                          (status, details))
    116         if status is not CONFIG_H_OK:
    117             self.warn(
    118                 "Python's pyconfig.h doesn't seem to support your compiler. "
    119                 "Reason: %s. "
    120                 "Compiling may fail because of undefined preprocessor macros."
    121                 % details)
    122 
    123         # Next line of code is problem for cross-compiled enviroment:
    124         # NOTE: GCC cross-compiler is prefixed by the <hostarch>-<hostos>-
    125         # and by default binaries are installed in same directory
    126         # as native compiler.
    127         self.gcc_version, self.ld_version, self.dllwrap_version = \
    128             get_versions()
    129         self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
    130                          (self.gcc_version,
    131                           self.ld_version,
    132                           self.dllwrap_version) )
    133 
    134         # ld_version >= "2.10.90" and < "2.13" should also be able to use
    135         # gcc -mdll instead of dllwrap
    136         # Older dllwraps had own version numbers, newer ones use the
    137         # same as the rest of binutils ( also ld )
    138         # dllwrap 2.10.90 is buggy
    139         if self.ld_version >= "2.10.90":
    140             self.linker_dll = "gcc"
    141         else:
    142             self.linker_dll = "dllwrap"
    143 
    144         # ld_version >= "2.13" support -shared so use it instead of
    145         # -mdll -static
    146         if self.ld_version >= "2.13":
    147             shared_option = "-shared"
    148         else:
    149             shared_option = "-mdll -static"
    150 
    151         # FIXME:
    152         # Hard-code may override unix-compiler settings and isn't
    153         # possible to use Makefile variables to pass correct flags !
    154         # Hard-code GCC because that's what this is all about.
    155         # XXX optimization, warnings etc. should be customizable.
    156         self.set_executables(compiler='gcc -mcygwin -O -Wall',
    157                              compiler_so='gcc -mcygwin -mdll -O -Wall',
    158                              compiler_cxx='g++ -mcygwin -O -Wall',
    159                              linker_exe='gcc -mcygwin',
    160                              linker_so=('%s -mcygwin %s' %
    161                                         (self.linker_dll, shared_option)))
    162 
    163         # cygwin and mingw32 need different sets of libraries
    164         if self.gcc_version == "2.91.57":
    165             # cygwin shouldn't need msvcrt, but without the dlls will crash
    166             # (gcc version 2.91.57) -- perhaps something about initialization
    167             self.dll_libraries=["msvcrt"]
    168             self.warn(
    169                 "Consider upgrading to a newer version of gcc")
    170         else:
    171             # Include the appropriate MSVC runtime library if Python was built
    172             # with MSVC 7.0 or later.
    173             self.dll_libraries = get_msvcr()
    174 
    175     # __init__ ()
    176 
    177 
    178     def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
    179         if ext == '.rc' or ext == '.res':
    180             # gcc needs '.res' and '.rc' compiled to object files !!!
    181             try:
    182                 self.spawn(["windres", "-i", src, "-o", obj])
    183             except DistutilsExecError, msg:
    184                 raise CompileError, msg
    185         else: # for other files use the C-compiler
    186             try:
    187                 self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
    188                            extra_postargs)
    189             except DistutilsExecError, msg:
    190                 raise CompileError, msg
    191 
    192     def link (self,
    193               target_desc,
    194               objects,
    195               output_filename,
    196               output_dir=None,
    197               libraries=None,
    198               library_dirs=None,
    199               runtime_library_dirs=None,
    200               export_symbols=None,
    201               debug=0,
    202               extra_preargs=None,
    203               extra_postargs=None,
    204               build_temp=None,
    205               target_lang=None):
    206 
    207         # use separate copies, so we can modify the lists
    208         extra_preargs = copy.copy(extra_preargs or [])
    209         libraries = copy.copy(libraries or [])
    210         objects = copy.copy(objects or [])
    211 
    212         # Additional libraries
    213         libraries.extend(self.dll_libraries)
    214 
    215         # handle export symbols by creating a def-file
    216         # with executables this only works with gcc/ld as linker
    217         if ((export_symbols is not None) and
    218             (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
    219             # (The linker doesn't do anything if output is up-to-date.
    220             # So it would probably better to check if we really need this,
    221             # but for this we had to insert some unchanged parts of
    222             # UnixCCompiler, and this is not what we want.)
    223 
    224             # we want to put some files in the same directory as the
    225             # object files are, build_temp doesn't help much
    226             # where are the object files
    227             temp_dir = os.path.dirname(objects[0])
    228             # name of dll to give the helper files the same base name
    229             (dll_name, dll_extension) = os.path.splitext(
    230                 os.path.basename(output_filename))
    231 
    232             # generate the filenames for these files
    233             def_file = os.path.join(temp_dir, dll_name + ".def")
    234             lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
    235 
    236             # Generate .def file
    237             contents = [
    238                 "LIBRARY %s" % os.path.basename(output_filename),
    239                 "EXPORTS"]
    240             for sym in export_symbols:
    241                 contents.append(sym)
    242             self.execute(write_file, (def_file, contents),
    243                          "writing %s" % def_file)
    244 
    245             # next add options for def-file and to creating import libraries
    246 
    247             # dllwrap uses different options than gcc/ld
    248             if self.linker_dll == "dllwrap":
    249                 extra_preargs.extend(["--output-lib", lib_file])
    250                 # for dllwrap we have to use a special option
    251                 extra_preargs.extend(["--def", def_file])
    252             # we use gcc/ld here and can be sure ld is >= 2.9.10
    253             else:
    254                 # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
    255                 #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])
    256                 # for gcc/ld the def-file is specified as any object files
    257                 objects.append(def_file)
    258 
    259         #end: if ((export_symbols is not None) and
    260         #        (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
    261 
    262         # who wants symbols and a many times larger output file
    263         # should explicitly switch the debug mode on
    264         # otherwise we let dllwrap/ld strip the output file
    265         # (On my machine: 10KB < stripped_file < ??100KB
    266         #   unstripped_file = stripped_file + XXX KB
    267         #  ( XXX=254 for a typical python extension))
    268         if not debug:
    269             extra_preargs.append("-s")
    270 
    271         UnixCCompiler.link(self,
    272                            target_desc,
    273                            objects,
    274                            output_filename,
    275                            output_dir,
    276                            libraries,
    277                            library_dirs,
    278                            runtime_library_dirs,
    279                            None, # export_symbols, we do this in our def-file
    280                            debug,
    281                            extra_preargs,
    282                            extra_postargs,
    283                            build_temp,
    284                            target_lang)
    285 
    286     # link ()
    287 
    288     # -- Miscellaneous methods -----------------------------------------
    289 
    290     # overwrite the one from CCompiler to support rc and res-files
    291     def object_filenames (self,
    292                           source_filenames,
    293                           strip_dir=0,
    294                           output_dir=''):
    295         if output_dir is None: output_dir = ''
    296         obj_names = []
    297         for src_name in source_filenames:
    298             # FIXME: "bogus checks for suffix" - as example the commented
    299             # by #BOGUS# code break valid assembler suffix ".S" !
    300             #BOGUS## use normcase to make sure '.rc' is really '.rc' and not '.RC'
    301             #BOGUS#base, ext = os.path.splitext(os.path.normcase(src_name))
    302             base, ext = os.path.splitext (src_name)
    303             ext_normcase = os.path.normcase(ext)
    304             if ext_normcase in ['.rc','.res']:
    305                 ext = ext_normcase
    306             if ext not in (self.src_extensions + ['.rc','.res']):
    307                 raise UnknownFileError, \
    308                       "unknown file type '%s' (from '%s')" % \
    309                       (ext, src_name)
    310             base = os.path.splitdrive(base)[1] # Chop off the drive
    311             base = base[os.path.isabs(base):]  # If abs, chop off leading /
    312             if strip_dir:
    313                 base = os.path.basename (base)
    314             if ext == '.res' or ext == '.rc':
    315                 # these need to be compiled to object files
    316                 obj_names.append (os.path.join (output_dir,
    317                                             base + ext + self.obj_extension))
    318             else:
    319                 obj_names.append (os.path.join (output_dir,
    320                                             base + self.obj_extension))
    321         return obj_names
    322 
    323     # object_filenames ()
    324 
    325 # class CygwinCCompiler
    326 
    327 
    328 # the same as cygwin plus some additional parameters
    329 class Mingw32CCompiler (CygwinCCompiler):
    330 
    331     compiler_type = 'mingw32'
    332 
    333     def __init__ (self,
    334                   verbose=0,
    335                   dry_run=0,
    336                   force=0):
    337 
    338         CygwinCCompiler.__init__ (self, verbose, dry_run, force)
    339 
    340         # ld_version >= "2.13" support -shared so use it instead of
    341         # -mdll -static
    342         if self.ld_version >= "2.13":
    343             shared_option = "-shared"
    344         else:
    345             shared_option = "-mdll -static"
    346 
    347         # A real mingw32 doesn't need to specify a different entry point,
    348         # but cygwin 2.91.57 in no-cygwin-mode needs it.
    349         if self.gcc_version <= "2.91.57":
    350             entry_point = '--entry _DllMain@12'
    351         else:
    352             entry_point = ''
    353 
    354         self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
    355                              compiler_so='gcc -mno-cygwin -mdll -O -Wall',
    356                              compiler_cxx='g++ -mno-cygwin -O -Wall',
    357                              linker_exe='gcc -mno-cygwin',
    358                              linker_so='%s -mno-cygwin %s %s'
    359                                         % (self.linker_dll, shared_option,
    360                                            entry_point))
    361         # Maybe we should also append -mthreads, but then the finished
    362         # dlls need another dll (mingwm10.dll see Mingw32 docs)
    363         # (-mthreads: Support thread-safe exception handling on `Mingw32')
    364 
    365         # no additional libraries needed
    366         self.dll_libraries=[]
    367 
    368         # Include the appropriate MSVC runtime library if Python was built
    369         # with MSVC 7.0 or later.
    370         self.dll_libraries = get_msvcr()
    371 
    372     # __init__ ()
    373 
    374 # class Mingw32CCompiler
    375 
    376 # Because these compilers aren't configured in Python's pyconfig.h file by
    377 # default, we should at least warn the user if he is using a unmodified
    378 # version.
    379 
    380 CONFIG_H_OK = "ok"
    381 CONFIG_H_NOTOK = "not ok"
    382 CONFIG_H_UNCERTAIN = "uncertain"
    383 
    384 def check_config_h():
    385 
    386     """Check if the current Python installation (specifically, pyconfig.h)
    387     appears amenable to building extensions with GCC.  Returns a tuple
    388     (status, details), where 'status' is one of the following constants:
    389       CONFIG_H_OK
    390         all is well, go ahead and compile
    391       CONFIG_H_NOTOK
    392         doesn't look good
    393       CONFIG_H_UNCERTAIN
    394         not sure -- unable to read pyconfig.h
    395     'details' is a human-readable string explaining the situation.
    396 
    397     Note there are two ways to conclude "OK": either 'sys.version' contains
    398     the string "GCC" (implying that this Python was built with GCC), or the
    399     installed "pyconfig.h" contains the string "__GNUC__".
    400     """
    401 
    402     # XXX since this function also checks sys.version, it's not strictly a
    403     # "pyconfig.h" check -- should probably be renamed...
    404 
    405     from distutils import sysconfig
    406     import string
    407     # if sys.version contains GCC then python was compiled with
    408     # GCC, and the pyconfig.h file should be OK
    409     if string.find(sys.version,"GCC") >= 0:
    410         return (CONFIG_H_OK, "sys.version mentions 'GCC'")
    411 
    412     fn = sysconfig.get_config_h_filename()
    413     try:
    414         # It would probably better to read single lines to search.
    415         # But we do this only once, and it is fast enough
    416         f = open(fn)
    417         try:
    418             s = f.read()
    419         finally:
    420             f.close()
    421 
    422     except IOError, exc:
    423         # if we can't read this file, we cannot say it is wrong
    424         # the compiler will complain later about this file as missing
    425         return (CONFIG_H_UNCERTAIN,
    426                 "couldn't read '%s': %s" % (fn, exc.strerror))
    427 
    428     else:
    429         # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
    430         if string.find(s,"__GNUC__") >= 0:
    431             return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
    432         else:
    433             return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
    434 
    435 
    436 
    437 def get_versions():
    438     """ Try to find out the versions of gcc, ld and dllwrap.
    439         If not possible it returns None for it.
    440     """
    441     from distutils.version import LooseVersion
    442     from distutils.spawn import find_executable
    443     import re
    444 
    445     gcc_exe = os.environ.get('CC') or find_executable('gcc')
    446     ld_exe = os.environ.get('LD') or find_executable('ld')
    447     if gcc_exe:
    448         out = os.popen(gcc_exe + ' -dumpversion','r')
    449         out_string = out.read()
    450         out.close()
    451         result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
    452         if result:
    453             gcc_version = LooseVersion(result.group(1))
    454         else:
    455             gcc_version = None
    456         out = os.popen(gcc_exe + ' --print-prog-name ld','r')
    457         ld_exe = out.read().decode('ascii').split()[0]
    458         out.close()
    459     else:
    460         gcc_version = None
    461     if ld_exe:
    462         out = os.popen(ld_exe + ' -v','r')
    463         out_string = out.read()
    464         out.close()
    465         result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
    466         if result:
    467             ld_version = LooseVersion(result.group(1))
    468         else:
    469             ld_version = None
    470     else:
    471         ld_version = None
    472     dllwrap_exe = os.environ.get('DLLWRAP') or find_executable('dllwrap')
    473     if dllwrap_exe:
    474         out = os.popen(dllwrap_exe + ' --version','r')
    475         out_string = out.read()
    476         out.close()
    477         result = re.search(' (\d+\.\d+(\.\d+)*)',out_string)
    478         if result:
    479             dllwrap_version = LooseVersion(result.group(1))
    480         else:
    481             dllwrap_version = None
    482     else:
    483         dllwrap_version = None
    484     return (gcc_version, ld_version, dllwrap_version)
    485