blob: 3f9a5bd58566dc41f44224219326a5fcb4c80450 [file] [log] [blame]
Greg Ward7c6395a2000-06-21 03:33:03 +00001"""distutils.cygwinccompiler
2
Greg Wardf34506a2000-06-29 22:57:55 +00003Provides 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).
Greg Ward7c6395a2000-06-21 03:33:03 +00007"""
8
Greg Wardbf5c7092000-08-02 01:31:56 +00009# 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 use 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 .....
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
Greg Ward7c6395a2000-06-21 03:33:03 +000043# created 2000/05/05, Rene Liebscher
44
45__revision__ = "$Id$"
46
Greg Wardbf5c7092000-08-02 01:31:56 +000047import os,sys
Greg Ward7c6395a2000-06-21 03:33:03 +000048from distutils.unixccompiler import UnixCCompiler
Greg Wardbf5c7092000-08-02 01:31:56 +000049from distutils.file_util import write_file
Greg Ward7c6395a2000-06-21 03:33:03 +000050
Greg Ward7c6395a2000-06-21 03:33:03 +000051class CygwinCCompiler (UnixCCompiler):
52
53 compiler_type = 'cygwin'
Greg Wardbf5c7092000-08-02 01:31:56 +000054 gcc_version = None
55 dllwrap_version = None
56 ld_version = None
Greg Ward7c6395a2000-06-21 03:33:03 +000057
58 def __init__ (self,
59 verbose=0,
60 dry_run=0,
61 force=0):
62
63 UnixCCompiler.__init__ (self, verbose, dry_run, force)
64
Greg Wardbf5c7092000-08-02 01:31:56 +000065 if check_config_h()<=0:
66 self.warn(
67 "Python's config.h doesn't seem to support your compiler. "
68 "Compiling may fail because of undefined preprocessor macros.")
69
70 (self.gcc_version, self.ld_version, self.dllwrap_version) = \
71 get_versions()
72 sys.stderr.write(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
73 (self.gcc_version,
74 self.ld_version,
75 self.dllwrap_version) )
76
77 # ld_version >= "2.10.90" should also be able to use
78 # gcc -mdll instead of dllwrap
79 # Older dllwraps had own version numbers, newer ones use the
80 # same as the rest of binutils ( also ld )
81 # dllwrap 2.10.90 is buggy
82 if self.ld_version >= "2.10.90":
83 self.linker = "gcc"
84 else:
85 self.linker = "dllwrap"
86
Greg Wardf34506a2000-06-29 22:57:55 +000087 # Hard-code GCC because that's what this is all about.
88 # XXX optimization, warnings etc. should be customizable.
Greg Wardbf5c7092000-08-02 01:31:56 +000089 self.set_executables(compiler='gcc -mcygwin -O -Wall',
90 compiler_so='gcc -mcygwin -mdll -O -Wall',
91 linker_exe='gcc -mcygwin',
92 linker_so=('%s -mcygwin -mdll -static' %
93 self.linker))
Greg Ward7c6395a2000-06-21 03:33:03 +000094
Greg Wardf34506a2000-06-29 22:57:55 +000095 # cygwin and mingw32 need different sets of libraries
Greg Wardbf5c7092000-08-02 01:31:56 +000096 if self.gcc_version == "2.91.57":
97 # cygwin shouldn't need msvcrt, but without the dlls will crash
98 # (gcc version 2.91.57) -- perhaps something about initialization
99 self.dll_libraries=["msvcrt"]
100 self.warn(
101 "Consider upgrading to a newer version of gcc")
102 else:
103 self.dll_libraries=[]
Greg Ward7c6395a2000-06-21 03:33:03 +0000104
105 # __init__ ()
106
107 def link_shared_object (self,
108 objects,
109 output_filename,
110 output_dir=None,
111 libraries=None,
112 library_dirs=None,
113 runtime_library_dirs=None,
114 export_symbols=None,
Greg Wardf34506a2000-06-29 22:57:55 +0000115 debug=0,
Greg Ward7c6395a2000-06-21 03:33:03 +0000116 extra_preargs=None,
Greg Wardf34506a2000-06-29 22:57:55 +0000117 extra_postargs=None,
118 build_temp=None):
Greg Ward7c6395a2000-06-21 03:33:03 +0000119
Greg Wardbf5c7092000-08-02 01:31:56 +0000120 # use separate copies, so can modify the lists
121 extra_preargs = list(extra_preargs or [])
122 libraries = list(libraries or [])
Greg Ward7c6395a2000-06-21 03:33:03 +0000123
Greg Wardbf5c7092000-08-02 01:31:56 +0000124 # Additional libraries
Greg Wardf34506a2000-06-29 22:57:55 +0000125 libraries.extend(self.dll_libraries)
Greg Ward7c6395a2000-06-21 03:33:03 +0000126
Greg Wardbf5c7092000-08-02 01:31:56 +0000127 # we want to put some files in the same directory as the
128 # object files are, build_temp doesn't help much
129
130 # where are the object files
131 temp_dir = os.path.dirname(objects[0])
132
133 # name of dll to give the helper files (def, lib, exp) the same name
134 (dll_name, dll_extension) = os.path.splitext(
135 os.path.basename(output_filename))
136
137 # generate the filenames for these files
138 def_file = None # this will be done later, if necessary
139 exp_file = os.path.join(temp_dir, dll_name + ".exp")
140 lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
141
142 #extra_preargs.append("--verbose")
143 if self.linker == "dllwrap":
144 extra_preargs.extend([#"--output-exp",exp_file,
145 "--output-lib",lib_file,
146 ])
Greg Wardf34506a2000-06-29 22:57:55 +0000147 else:
Greg Wardbf5c7092000-08-02 01:31:56 +0000148 # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
149 extra_preargs.extend([#"-Wl,--out-implib,%s" % lib_file,
150 ])
151
152 # check what we got in export_symbols
153 if export_symbols is not None:
154 # Make .def file
155 # (It would probably better to check if we really need this,
156 # but for this we had to insert some unchanged parts of
157 # UnixCCompiler, and this is not what we want.)
158 def_file = os.path.join(temp_dir, dll_name + ".def")
159 contents = [
160 "LIBRARY %s" % os.path.basename(output_filename),
161 "EXPORTS"]
Greg Ward7c6395a2000-06-21 03:33:03 +0000162 for sym in export_symbols:
Greg Wardbf5c7092000-08-02 01:31:56 +0000163 contents.append(sym)
164 self.execute(write_file, (def_file, contents),
165 "writing %s" % def_file)
166
167 if def_file:
168 if self.linker == "dllwrap":
169 # for dllwrap we have to use a special option
170 extra_preargs.append("--def")
171 # for gcc/ld it is specified as any other object file
172 extra_preargs.append(def_file)
173
Greg Wardf34506a2000-06-29 22:57:55 +0000174 # who wants symbols and a many times larger output file
Greg Ward612eb9f2000-07-27 02:13:20 +0000175 # should explicitly switch the debug mode on
Greg Wardbf5c7092000-08-02 01:31:56 +0000176 # otherwise we let dllwrap/ld strip the output file
Greg Wardf34506a2000-06-29 22:57:55 +0000177 # (On my machine unstripped_file = stripped_file + 254KB
Greg Ward7c6395a2000-06-21 03:33:03 +0000178 # 10KB < stripped_file < ??100KB )
179 if not debug:
Greg Wardbf5c7092000-08-02 01:31:56 +0000180 extra_preargs.append("-s")
Greg Wardf34506a2000-06-29 22:57:55 +0000181
182 UnixCCompiler.link_shared_object(self,
Greg Ward7c6395a2000-06-21 03:33:03 +0000183 objects,
184 output_filename,
185 output_dir,
186 libraries,
187 library_dirs,
188 runtime_library_dirs,
Greg Wardbf5c7092000-08-02 01:31:56 +0000189 None, # export_symbols, we do this in our def-file
Greg Ward7c6395a2000-06-21 03:33:03 +0000190 debug,
191 extra_preargs,
Greg Wardf34506a2000-06-29 22:57:55 +0000192 extra_postargs,
193 build_temp)
Greg Ward7c6395a2000-06-21 03:33:03 +0000194
195 # link_shared_object ()
196
197# class CygwinCCompiler
198
Greg Wardf34506a2000-06-29 22:57:55 +0000199
Greg Ward7c6395a2000-06-21 03:33:03 +0000200# the same as cygwin plus some additional parameters
201class Mingw32CCompiler (CygwinCCompiler):
202
203 compiler_type = 'mingw32'
204
205 def __init__ (self,
206 verbose=0,
207 dry_run=0,
208 force=0):
209
210 CygwinCCompiler.__init__ (self, verbose, dry_run, force)
Greg Wardbf5c7092000-08-02 01:31:56 +0000211
212 # A real mingw32 doesn't need to specify a different entry point,
213 # but cygwin 2.91.57 in no-cygwin-mode needs it.
214 if self.gcc_version <= "2.91.57":
215 entry_point = '--entry _DllMain@12'
216 else:
217 entry_point = ''
Greg Ward7c6395a2000-06-21 03:33:03 +0000218
Greg Wardf34506a2000-06-29 22:57:55 +0000219 self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
Greg Wardbf5c7092000-08-02 01:31:56 +0000220 compiler_so='gcc -mno-cygwin -mdll -O -Wall',
Greg Wardf34506a2000-06-29 22:57:55 +0000221 linker_exe='gcc -mno-cygwin',
Greg Wardbf5c7092000-08-02 01:31:56 +0000222 linker_so='%s -mno-cygwin -mdll -static %s'
223 % (self.linker, entry_point))
224 # Maybe we should also append -mthreads, but then the finished
225 # dlls need another dll (mingwm10.dll see Mingw32 docs)
226 # (-mthreads: Support thread-safe exception handling on `Mingw32')
227
228 # no additional libraries needed
229 self.dll_libraries=[]
230
Greg Ward7c6395a2000-06-21 03:33:03 +0000231 # __init__ ()
Greg Wardbf5c7092000-08-02 01:31:56 +0000232
Greg Ward7c6395a2000-06-21 03:33:03 +0000233# class Mingw32CCompiler
Greg Wardbf5c7092000-08-02 01:31:56 +0000234
235# Because these compilers aren't configured in Python's config.h file by
236# default, we should at least warn the user if he is using a unmodified
237# version.
238
239def check_config_h():
240 """Checks if the GCC compiler is mentioned in config.h. If it is not,
241 compiling probably doesn't work.
242 """
243 # return values
244 # 2: OK, python was compiled with GCC
245 # 1: OK, python's config.h mentions __GCC__
246 # 0: uncertain, because we couldn't check it
247 # -1: probably not OK, because we didn't found it in config.h
248 # You could check check_config_h()>0 => OK
249
250 from distutils import sysconfig
251 import string,sys
252 # if sys.version contains GCC then python was compiled with
253 # GCC, and the config.h file should be OK
254 if -1 == string.find(sys.version,"GCC"):
255 pass # go to the next test
256 else:
257 return 2
258
259 try:
260 # It would probably better to read single lines to search.
261 # But we do this only once, and it is fast enough
262 f=open(sysconfig.get_config_h_filename())
263 s=f.read()
264 f.close()
265
266 # is somewhere a #ifdef __GNUC__ or something similar
267 if -1 == string.find(s,"__GNUC__"):
268 return -1
269 else:
270 return 1
271 except IOError:
272 # if we can't read this file, we cannot say it is wrong
273 # the compiler will complain later about this file as missing
274 pass
275 return 0
276
277def get_versions():
278 """ Try to find out the versions of gcc, ld and dllwrap.
279 If not possible it returns None for it.
280 """
281 from distutils.version import StrictVersion
282 from distutils.spawn import find_executable
283 import re
284
285 gcc_exe = find_executable('gcc')
286 if gcc_exe:
287 out = os.popen(gcc_exe + ' -dumpversion','r')
288 out_string = out.read()
289 out.close()
290 result = re.search('(\d+\.\d+\.\d+)',out_string)
291 if result:
292 gcc_version = StrictVersion(result.group(1))
293 else:
294 gcc_version = None
295 else:
296 gcc_version = None
297 ld_exe = find_executable('ld')
298 if ld_exe:
299 out = os.popen(ld_exe + ' -v','r')
300 out_string = out.read()
301 out.close()
302 result = re.search('(\d+\.\d+\.\d+)',out_string)
303 if result:
304 ld_version = StrictVersion(result.group(1))
305 else:
306 ld_version = None
307 else:
308 ld_version = None
309 dllwrap_exe = find_executable('dllwrap')
310 if dllwrap_exe:
311 out = os.popen(dllwrap_exe + ' --version','r')
312 out_string = out.read()
313 out.close()
314 result = re.search(' (\d+\.\d+\.\d+)',out_string)
315 if result:
316 dllwrap_version = StrictVersion(result.group(1))
317 else:
318 dllwrap_version = None
319 else:
320 dllwrap_version = None
321 return (gcc_version, ld_version, dllwrap_version)
322