1"""distutils.cygwinccompiler 2 3Provides the CygwinCCompiler class, a subclass of UnixCCompiler that 4handles the Cygwin port of the GNU C compiler to Windows. It also contains 5the Mingw32CCompiler class which handles the mingw32 port of GCC (same as 6cygwin 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 an import library for its dll 14# - create a def-file for python??.dll 15# - create an 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 48import sys 49from subprocess import Popen, PIPE, check_output 50import re 51 52from distutils.unixccompiler import UnixCCompiler 53from distutils.errors import CCompilerError 54from distutils.version import LooseVersion 55from distutils.spawn import find_executable 56 57def get_msvcr(): 58 """Include the appropriate MSVC runtime library if Python was built 59 with MSVC 7.0 or later. 60 """ 61 msc_pos = sys.version.find('MSC v.') 62 if msc_pos != -1: 63 msc_ver = sys.version[msc_pos+6:msc_pos+10] 64 if msc_ver == '1300': 65 # MSVC 7.0 66 return ['msvcr70'] 67 elif msc_ver == '1310': 68 # MSVC 7.1 69 return ['msvcr71'] 70 elif msc_ver == '1400': 71 # VS2005 / MSVC 8.0 72 return ['msvcr80'] 73 elif msc_ver == '1500': 74 # VS2008 / MSVC 9.0 75 return ['msvcr90'] 76 elif msc_ver == '1600': 77 # VS2010 / MSVC 10.0 78 return ['msvcr100'] 79 else: 80 raise ValueError("Unknown MS Compiler version %s " % msc_ver) 81 82 83class CygwinCCompiler(UnixCCompiler): 84 """ Handles the Cygwin port of the GNU C compiler to Windows. 85 """ 86 compiler_type = 'cygwin' 87 obj_extension = ".o" 88 static_lib_extension = ".a" 89 shared_lib_extension = ".dll" 90 static_lib_format = "lib%s%s" 91 shared_lib_format = "%s%s" 92 exe_extension = ".exe" 93 94 def __init__(self, verbose=0, dry_run=0, force=0): 95 96 UnixCCompiler.__init__(self, verbose, dry_run, force) 97 98 status, details = check_config_h() 99 self.debug_print("Python's GCC status: %s (details: %s)" % 100 (status, details)) 101 if status is not CONFIG_H_OK: 102 self.warn( 103 "Python's pyconfig.h doesn't seem to support your compiler. " 104 "Reason: %s. " 105 "Compiling may fail because of undefined preprocessor macros." 106 % details) 107 108 self.gcc_version, self.ld_version, self.dllwrap_version = \ 109 get_versions() 110 self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % 111 (self.gcc_version, 112 self.ld_version, 113 self.dllwrap_version) ) 114 115 # ld_version >= "2.10.90" and < "2.13" should also be able to use 116 # gcc -mdll instead of dllwrap 117 # Older dllwraps had own version numbers, newer ones use the 118 # same as the rest of binutils ( also ld ) 119 # dllwrap 2.10.90 is buggy 120 if self.ld_version >= "2.10.90": 121 self.linker_dll = "gcc" 122 else: 123 self.linker_dll = "dllwrap" 124 125 # ld_version >= "2.13" support -shared so use it instead of 126 # -mdll -static 127 if self.ld_version >= "2.13": 128 shared_option = "-shared" 129 else: 130 shared_option = "-mdll -static" 131 132 # Hard-code GCC because that's what this is all about. 133 # XXX optimization, warnings etc. should be customizable. 134 self.set_executables(compiler='gcc -mcygwin -O -Wall', 135 compiler_so='gcc -mcygwin -mdll -O -Wall', 136 compiler_cxx='g++ -mcygwin -O -Wall', 137 linker_exe='gcc -mcygwin', 138 linker_so=('%s -mcygwin %s' % 139 (self.linker_dll, shared_option))) 140 141 # cygwin and mingw32 need different sets of libraries 142 if self.gcc_version == "2.91.57": 143 # cygwin shouldn't need msvcrt, but without the dlls will crash 144 # (gcc version 2.91.57) -- perhaps something about initialization 145 self.dll_libraries=["msvcrt"] 146 self.warn( 147 "Consider upgrading to a newer version of gcc") 148 else: 149 # Include the appropriate MSVC runtime library if Python was built 150 # with MSVC 7.0 or later. 151 self.dll_libraries = get_msvcr() 152 153 154# the same as cygwin plus some additional parameters 155class Mingw32CCompiler(CygwinCCompiler): 156 """ Handles the Mingw32 port of the GNU C compiler to Windows. 157 """ 158 compiler_type = 'mingw32' 159 160 def __init__(self, verbose=0, dry_run=0, force=0): 161 162 CygwinCCompiler.__init__ (self, verbose, dry_run, force) 163 164 # ld_version >= "2.13" support -shared so use it instead of 165 # -mdll -static 166 if self.ld_version >= "2.13": 167 shared_option = "-shared" 168 else: 169 shared_option = "-mdll -static" 170 171 # A real mingw32 doesn't need to specify a different entry point, 172 # but cygwin 2.91.57 in no-cygwin-mode needs it. 173 if self.gcc_version <= "2.91.57": 174 entry_point = '--entry _DllMain@12' 175 else: 176 entry_point = '' 177 178 if is_cygwingcc(): 179 raise CCompilerError( 180 'Cygwin gcc cannot be used with --compiler=mingw32') 181 182 self.set_executables(compiler='gcc -O -Wall', 183 compiler_so='gcc -mdll -O -Wall', 184 compiler_cxx='g++ -O -Wall', 185 linker_exe='gcc', 186 linker_so='%s %s %s' 187 % (self.linker_dll, shared_option, 188 entry_point)) 189 # Maybe we should also append -mthreads, but then the finished 190 # dlls need another dll (mingwm10.dll see Mingw32 docs) 191 # (-mthreads: Support thread-safe exception handling on `Mingw32') 192 193 # no additional libraries needed 194 self.dll_libraries=[] 195 196 # Include the appropriate MSVC runtime library if Python was built 197 # with MSVC 7.0 or later. 198 self.dll_libraries = get_msvcr() 199 200# Because these compilers aren't configured in Python's pyconfig.h file by 201# default, we should at least warn the user if he is using an unmodified 202# version. 203 204CONFIG_H_OK = "ok" 205CONFIG_H_NOTOK = "not ok" 206CONFIG_H_UNCERTAIN = "uncertain" 207 208def check_config_h(): 209 """Check if the current Python installation appears amenable to building 210 extensions with GCC. 211 212 Returns a tuple (status, details), where 'status' is one of the following 213 constants: 214 215 - CONFIG_H_OK: all is well, go ahead and compile 216 - CONFIG_H_NOTOK: doesn't look good 217 - CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h 218 219 'details' is a human-readable string explaining the situation. 220 221 Note there are two ways to conclude "OK": either 'sys.version' contains 222 the string "GCC" (implying that this Python was built with GCC), or the 223 installed "pyconfig.h" contains the string "__GNUC__". 224 """ 225 226 # XXX since this function also checks sys.version, it's not strictly a 227 # "pyconfig.h" check -- should probably be renamed... 228 229 import sysconfig 230 231 # if sys.version contains GCC then python was compiled with GCC, and the 232 # pyconfig.h file should be OK 233 if "GCC" in sys.version: 234 return CONFIG_H_OK, "sys.version mentions 'GCC'" 235 236 # let's see if __GNUC__ is mentioned in python.h 237 fn = sysconfig.get_config_h_filename() 238 try: 239 config_h = open(fn) 240 try: 241 if "__GNUC__" in config_h.read(): 242 return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn 243 else: 244 return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn 245 finally: 246 config_h.close() 247 except OSError as exc: 248 return (CONFIG_H_UNCERTAIN, 249 "couldn't read '%s': %s" % (fn, exc.strerror)) 250 251RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)') 252 253def _find_exe_version(cmd): 254 """Find the version of an executable by running `cmd` in the shell. 255 256 If the command is not found, or the output does not match 257 `RE_VERSION`, returns None. 258 """ 259 executable = cmd.split()[0] 260 if find_executable(executable) is None: 261 return None 262 out = Popen(cmd, shell=True, stdout=PIPE).stdout 263 try: 264 out_string = out.read() 265 finally: 266 out.close() 267 result = RE_VERSION.search(out_string) 268 if result is None: 269 return None 270 # LooseVersion works with strings 271 # so we need to decode our bytes 272 return LooseVersion(result.group(1).decode()) 273 274def get_versions(): 275 """ Try to find out the versions of gcc, ld and dllwrap. 276 277 If not possible it returns None for it. 278 """ 279 commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version'] 280 return tuple([_find_exe_version(cmd) for cmd in commands]) 281 282def is_cygwingcc(): 283 '''Try to determine if the gcc that would be used is from cygwin.''' 284 out_string = check_output(['gcc', '-dumpmachine']) 285 return out_string.strip().endswith(b'cygwin') 286