0001 """distutils.cygwinccompiler 0002 0003 Provides the CygwinCCompiler class, a subclass of UnixCCompiler that 0004 handles the Cygwin port of the GNU C compiler to Windows. It also contains 0005 the Mingw32CCompiler class which handles the mingw32 port of GCC (same as 0006 cygwin in no-cygwin mode). 0007 """ 0008 0009 # problems: 0010 # 0011 # * if you use a msvc compiled python version (1.5.2) 0012 # 1. you have to insert a __GNUC__ section in its config.h 0013 # 2. you have to generate a import library for its dll 0014 # - create a def-file for python??.dll 0015 # - create a import library using 0016 # dlltool --dllname python15.dll --def python15.def \ 0017 # --output-lib libpython15.a 0018 # 0019 # see also http://starship.python.net/crew/kernr/mingw32/Notes.html 0020 # 0021 # * We put export_symbols in a def-file, and don't use 0022 # --export-all-symbols because it doesn't worked reliable in some 0023 # tested configurations. And because other windows compilers also 0024 # need their symbols specified this no serious problem. 0025 # 0026 # tested configurations: 0027 # 0028 # * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works 0029 # (after patching python's config.h and for C++ some other include files) 0030 # see also http://starship.python.net/crew/kernr/mingw32/Notes.html 0031 # * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works 0032 # (ld doesn't support -shared, so we use dllwrap) 0033 # * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now 0034 # - its dllwrap doesn't work, there is a bug in binutils 2.10.90 0035 # see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html 0036 # - using gcc -mdll instead dllwrap doesn't work without -static because 0037 # it tries to link against dlls instead their import libraries. (If 0038 # it finds the dll first.) 0039 # By specifying -static we force ld to link against the import libraries, 0040 # this is windows standard and there are normally not the necessary symbols 0041 # in the dlls. 0042 # *** only the version of June 2000 shows these problems 0043 # * cygwin gcc 3.2/ld 2.13.90 works 0044 # (ld supports -shared) 0045 # * mingw gcc 3.2/ld 2.13 works 0046 # (ld supports -shared) 0047 0048 # This module should be kept compatible with Python 1.5.2. 0049 0050 __revision__ = "$Id: cygwinccompiler.py,v 1.28 2004/08/04 02:36:18 tim_one Exp $" 0051 0052 import os,sys,copy 0053 from distutils.ccompiler import gen_preprocess_options, gen_lib_options 0054 from distutils.unixccompiler import UnixCCompiler 0055 from distutils.file_util import write_file 0056 from distutils.errors import DistutilsExecError, CompileError, UnknownFileError 0057 from distutils import log 0058 0059 class CygwinCCompiler (UnixCCompiler): 0060 0061 compiler_type = 'cygwin' 0062 obj_extension = ".o" 0063 static_lib_extension = ".a" 0064 shared_lib_extension = ".dll" 0065 static_lib_format = "lib%s%s" 0066 shared_lib_format = "%s%s" 0067 exe_extension = ".exe" 0068 0069 def __init__ (self, verbose=0, dry_run=0, force=0): 0070 0071 UnixCCompiler.__init__ (self, verbose, dry_run, force) 0072 0073 (status, details) = check_config_h() 0074 self.debug_print("Python's GCC status: %s (details: %s)" % 0075 (status, details)) 0076 if status is not CONFIG_H_OK: 0077 self.warn( 0078 "Python's pyconfig.h doesn't seem to support your compiler. " 0079 "Reason: %s. " 0080 "Compiling may fail because of undefined preprocessor macros." 0081 % details) 0082 0083 self.gcc_version, self.ld_version, self.dllwrap_version = \ 0084 get_versions() 0085 self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % 0086 (self.gcc_version, 0087 self.ld_version, 0088 self.dllwrap_version) ) 0089 0090 # ld_version >= "2.10.90" and < "2.13" should also be able to use 0091 # gcc -mdll instead of dllwrap 0092 # Older dllwraps had own version numbers, newer ones use the 0093 # same as the rest of binutils ( also ld ) 0094 # dllwrap 2.10.90 is buggy 0095 if self.ld_version >= "2.10.90": 0096 self.linker_dll = "gcc" 0097 else: 0098 self.linker_dll = "dllwrap" 0099 0100 # ld_version >= "2.13" support -shared so use it instead of 0101 # -mdll -static 0102 if self.ld_version >= "2.13": 0103 shared_option = "-shared" 0104 else: 0105 shared_option = "-mdll -static" 0106 0107 # Hard-code GCC because that's what this is all about. 0108 # XXX optimization, warnings etc. should be customizable. 0109 self.set_executables(compiler='gcc -mcygwin -O -Wall', 0110 compiler_so='gcc -mcygwin -mdll -O -Wall', 0111 compiler_cxx='g++ -mcygwin -O -Wall', 0112 linker_exe='gcc -mcygwin', 0113 linker_so=('%s -mcygwin %s' % 0114 (self.linker_dll, shared_option))) 0115 0116 # cygwin and mingw32 need different sets of libraries 0117 if self.gcc_version == "2.91.57": 0118 # cygwin shouldn't need msvcrt, but without the dlls will crash 0119 # (gcc version 2.91.57) -- perhaps something about initialization 0120 self.dll_libraries=["msvcrt"] 0121 self.warn( 0122 "Consider upgrading to a newer version of gcc") 0123 else: 0124 self.dll_libraries=[] 0125 # Include the appropriate MSVC runtime library if Python was built 0126 # with MSVC 7.0 or 7.1. 0127 msc_pos = sys.version.find('MSC v.') 0128 if msc_pos != -1: 0129 msc_ver = sys.version[msc_pos+6:msc_pos+10] 0130 if msc_ver == '1300': 0131 # MSVC 7.0 0132 self.dll_libraries = ['msvcr70'] 0133 elif msc_ver == '1310': 0134 # MSVC 7.1 0135 self.dll_libraries = ['msvcr71'] 0136 0137 # __init__ () 0138 0139 0140 def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): 0141 if ext == '.rc' or ext == '.res': 0142 # gcc needs '.res' and '.rc' compiled to object files !!! 0143 try: 0144 self.spawn(["windres", "-i", src, "-o", obj]) 0145 except DistutilsExecError, msg: 0146 raise CompileError, msg 0147 else: # for other files use the C-compiler 0148 try: 0149 self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + 0150 extra_postargs) 0151 except DistutilsExecError, msg: 0152 raise CompileError, msg 0153 0154 def link (self, 0155 target_desc, 0156 objects, 0157 output_filename, 0158 output_dir=None, 0159 libraries=None, 0160 library_dirs=None, 0161 runtime_library_dirs=None, 0162 export_symbols=None, 0163 debug=0, 0164 extra_preargs=None, 0165 extra_postargs=None, 0166 build_temp=None, 0167 target_lang=None): 0168 0169 # use separate copies, so we can modify the lists 0170 extra_preargs = copy.copy(extra_preargs or []) 0171 libraries = copy.copy(libraries or []) 0172 objects = copy.copy(objects or []) 0173 0174 # Additional libraries 0175 libraries.extend(self.dll_libraries) 0176 0177 # handle export symbols by creating a def-file 0178 # with executables this only works with gcc/ld as linker 0179 if ((export_symbols is not None) and 0180 (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): 0181 # (The linker doesn't do anything if output is up-to-date. 0182 # So it would probably better to check if we really need this, 0183 # but for this we had to insert some unchanged parts of 0184 # UnixCCompiler, and this is not what we want.) 0185 0186 # we want to put some files in the same directory as the 0187 # object files are, build_temp doesn't help much 0188 # where are the object files 0189 temp_dir = os.path.dirname(objects[0]) 0190 # name of dll to give the helper files the same base name 0191 (dll_name, dll_extension) = os.path.splitext( 0192 os.path.basename(output_filename)) 0193 0194 # generate the filenames for these files 0195 def_file = os.path.join(temp_dir, dll_name + ".def") 0196 lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a") 0197 0198 # Generate .def file 0199 contents = [ 0200 "LIBRARY %s" % os.path.basename(output_filename), 0201 "EXPORTS"] 0202 for sym in export_symbols: 0203 contents.append(sym) 0204 self.execute(write_file, (def_file, contents), 0205 "writing %s" % def_file) 0206 0207 # next add options for def-file and to creating import libraries 0208 0209 # dllwrap uses different options than gcc/ld 0210 if self.linker_dll == "dllwrap": 0211 extra_preargs.extend(["--output-lib", lib_file]) 0212 # for dllwrap we have to use a special option 0213 extra_preargs.extend(["--def", def_file]) 0214 # we use gcc/ld here and can be sure ld is >= 2.9.10 0215 else: 0216 # doesn't work: bfd_close build\...\libfoo.a: Invalid operation 0217 #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file]) 0218 # for gcc/ld the def-file is specified as any object files 0219 objects.append(def_file) 0220 0221 #end: if ((export_symbols is not None) and 0222 # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): 0223 0224 # who wants symbols and a many times larger output file 0225 # should explicitly switch the debug mode on 0226 # otherwise we let dllwrap/ld strip the output file 0227 # (On my machine: 10KB < stripped_file < ??100KB 0228 # unstripped_file = stripped_file + XXX KB 0229 # ( XXX=254 for a typical python extension)) 0230 if not debug: 0231 extra_preargs.append("-s") 0232 0233 UnixCCompiler.link(self, 0234 target_desc, 0235 objects, 0236 output_filename, 0237 output_dir, 0238 libraries, 0239 library_dirs, 0240 runtime_library_dirs, 0241 None, # export_symbols, we do this in our def-file 0242 debug, 0243 extra_preargs, 0244 extra_postargs, 0245 build_temp, 0246 target_lang) 0247 0248 # link () 0249 0250 # -- Miscellaneous methods ----------------------------------------- 0251 0252 # overwrite the one from CCompiler to support rc and res-files 0253 def object_filenames (self, 0254 source_filenames, 0255 strip_dir=0, 0256 output_dir=''): 0257 if output_dir is None: output_dir = '' 0258 obj_names = [] 0259 for src_name in source_filenames: 0260 # use normcase to make sure '.rc' is really '.rc' and not '.RC' 0261 (base, ext) = os.path.splitext (os.path.normcase(src_name)) 0262 if ext not in (self.src_extensions + ['.rc','.res']): 0263 raise UnknownFileError, \ 0264 "unknown file type '%s' (from '%s')" % \ 0265 (ext, src_name) 0266 if strip_dir: 0267 base = os.path.basename (base) 0268 if ext == '.res' or ext == '.rc': 0269 # these need to be compiled to object files 0270 obj_names.append (os.path.join (output_dir, 0271 base + ext + self.obj_extension)) 0272 else: 0273 obj_names.append (os.path.join (output_dir, 0274 base + self.obj_extension)) 0275 return obj_names 0276 0277 # object_filenames () 0278 0279 # class CygwinCCompiler 0280 0281 0282 # the same as cygwin plus some additional parameters 0283 class Mingw32CCompiler (CygwinCCompiler): 0284 0285 compiler_type = 'mingw32' 0286 0287 def __init__ (self, 0288 verbose=0, 0289 dry_run=0, 0290 force=0): 0291 0292 CygwinCCompiler.__init__ (self, verbose, dry_run, force) 0293 0294 # ld_version >= "2.13" support -shared so use it instead of 0295 # -mdll -static 0296 if self.ld_version >= "2.13": 0297 shared_option = "-shared" 0298 else: 0299 shared_option = "-mdll -static" 0300 0301 # A real mingw32 doesn't need to specify a different entry point, 0302 # but cygwin 2.91.57 in no-cygwin-mode needs it. 0303 if self.gcc_version <= "2.91.57": 0304 entry_point = '--entry _DllMain@12' 0305 else: 0306 entry_point = '' 0307 0308 self.set_executables(compiler='gcc -mno-cygwin -O -Wall', 0309 compiler_so='gcc -mno-cygwin -mdll -O -Wall', 0310 compiler_cxx='g++ -mno-cygwin -O -Wall', 0311 linker_exe='gcc -mno-cygwin', 0312 linker_so='%s -mno-cygwin %s %s' 0313 % (self.linker_dll, shared_option, 0314 entry_point)) 0315 # Maybe we should also append -mthreads, but then the finished 0316 # dlls need another dll (mingwm10.dll see Mingw32 docs) 0317 # (-mthreads: Support thread-safe exception handling on `Mingw32') 0318 0319 # no additional libraries needed 0320 self.dll_libraries=[] 0321 0322 # Include the appropriate MSVC runtime library if Python was built 0323 # with MSVC 7.0 or 7.1. 0324 msc_pos = sys.version.find('MSC v.') 0325 if msc_pos != -1: 0326 msc_ver = sys.version[msc_pos+6:msc_pos+10] 0327 if msc_ver == '1300': 0328 # MSVC 7.0 0329 self.dll_libraries = ['msvcr70'] 0330 elif msc_ver == '1310': 0331 # MSVC 7.1 0332 self.dll_libraries = ['msvcr71'] 0333 0334 # __init__ () 0335 0336 # class Mingw32CCompiler 0337 0338 # Because these compilers aren't configured in Python's pyconfig.h file by 0339 # default, we should at least warn the user if he is using a unmodified 0340 # version. 0341 0342 CONFIG_H_OK = "ok" 0343 CONFIG_H_NOTOK = "not ok" 0344 CONFIG_H_UNCERTAIN = "uncertain" 0345 0346 def check_config_h(): 0347 0348 """Check if the current Python installation (specifically, pyconfig.h) 0349 appears amenable to building extensions with GCC. Returns a tuple 0350 (status, details), where 'status' is one of the following constants: 0351 CONFIG_H_OK 0352 all is well, go ahead and compile 0353 CONFIG_H_NOTOK 0354 doesn't look good 0355 CONFIG_H_UNCERTAIN 0356 not sure -- unable to read pyconfig.h 0357 'details' is a human-readable string explaining the situation. 0358 0359 Note there are two ways to conclude "OK": either 'sys.version' contains 0360 the string "GCC" (implying that this Python was built with GCC), or the 0361 installed "pyconfig.h" contains the string "__GNUC__". 0362 """ 0363 0364 # XXX since this function also checks sys.version, it's not strictly a 0365 # "pyconfig.h" check -- should probably be renamed... 0366 0367 from distutils import sysconfig 0368 import string 0369 # if sys.version contains GCC then python was compiled with 0370 # GCC, and the pyconfig.h file should be OK 0371 if string.find(sys.version,"GCC") >= 0: 0372 return (CONFIG_H_OK, "sys.version mentions 'GCC'") 0373 0374 fn = sysconfig.get_config_h_filename() 0375 try: 0376 # It would probably better to read single lines to search. 0377 # But we do this only once, and it is fast enough 0378 f = open(fn) 0379 s = f.read() 0380 f.close() 0381 0382 except IOError, exc: 0383 # if we can't read this file, we cannot say it is wrong 0384 # the compiler will complain later about this file as missing 0385 return (CONFIG_H_UNCERTAIN, 0386 "couldn't read '%s': %s" % (fn, exc.strerror)) 0387 0388 else: 0389 # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar 0390 if string.find(s,"__GNUC__") >= 0: 0391 return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn) 0392 else: 0393 return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn) 0394 0395 0396 0397 def get_versions(): 0398 """ Try to find out the versions of gcc, ld and dllwrap. 0399 If not possible it returns None for it. 0400 """ 0401 from distutils.version import StrictVersion 0402 from distutils.spawn import find_executable 0403 import re 0404 0405 gcc_exe = find_executable('gcc') 0406 if gcc_exe: 0407 out = os.popen(gcc_exe + ' -dumpversion','r') 0408 out_string = out.read() 0409 out.close() 0410 result = re.search('(\d+\.\d+(\.\d+)*)',out_string) 0411 if result: 0412 gcc_version = StrictVersion(result.group(1)) 0413 else: 0414 gcc_version = None 0415 else: 0416 gcc_version = None 0417 ld_exe = find_executable('ld') 0418 if ld_exe: 0419 out = os.popen(ld_exe + ' -v','r') 0420 out_string = out.read() 0421 out.close() 0422 result = re.search('(\d+\.\d+(\.\d+)*)',out_string) 0423 if result: 0424 ld_version = StrictVersion(result.group(1)) 0425 else: 0426 ld_version = None 0427 else: 0428 ld_version = None 0429 dllwrap_exe = find_executable('dllwrap') 0430 if dllwrap_exe: 0431 out = os.popen(dllwrap_exe + ' --version','r') 0432 out_string = out.read() 0433 out.close() 0434 result = re.search(' (\d+\.\d+(\.\d+)*)',out_string) 0435 if result: 0436 dllwrap_version = StrictVersion(result.group(1)) 0437 else: 0438 dllwrap_version = None 0439 else: 0440 dllwrap_version = None 0441 return (gcc_version, ld_version, dllwrap_version) 0442
Generated by PyXR 0.9.4