blob: 7c3ad025bb2863ea45473d722614b50ce58154cf [file] [log] [blame]
Marc-André Lemburg9273ec72002-02-06 18:22:48 +00001"""distutils.emxccompiler
2
3Provides the EMXCCompiler class, a subclass of UnixCCompiler that
4handles the EMX port of the GNU C compiler to OS/2.
5"""
6
7# issues:
8#
9# * OS/2 insists that DLLs can have names no longer than 8 characters
10# We put export_symbols in a def-file, as though the DLL can have
11# an arbitrary length name, but truncate the output filename.
12#
13# * only use OMF objects and use LINK386 as the linker (-Zomf)
14#
15# * always build for multithreading (-Zmt) as the accompanying OS/2 port
16# of Python is only distributed with threads enabled.
17#
18# tested configurations:
Guido van Rossumbffa52f2002-09-29 00:25:51 +000019#
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000020# * EMX gcc 2.81/EMX 0.9d fix03
21
22# created 2001/5/7, Andrew MacIntyre, from Rene Liebscher's cywinccompiler.py
23
24__revision__ = "$Id$"
25
26import os,sys,copy
27from distutils.ccompiler import gen_preprocess_options, gen_lib_options
28from distutils.unixccompiler import UnixCCompiler
29from distutils.file_util import write_file
30from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000031from distutils import log
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000032
33class EMXCCompiler (UnixCCompiler):
34
35 compiler_type = 'emx'
36 obj_extension = ".obj"
37 static_lib_extension = ".lib"
38 shared_lib_extension = ".dll"
39 static_lib_format = "%s%s"
40 shared_lib_format = "%s%s"
41 res_extension = ".res" # compiled resource file
42 exe_extension = ".exe"
Guido van Rossumbffa52f2002-09-29 00:25:51 +000043
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000044 def __init__ (self,
45 verbose=0,
46 dry_run=0,
47 force=0):
48
49 UnixCCompiler.__init__ (self, verbose, dry_run, force)
50
51 (status, details) = check_config_h()
52 self.debug_print("Python's GCC status: %s (details: %s)" %
53 (status, details))
54 if status is not CONFIG_H_OK:
55 self.warn(
56 "Python's pyconfig.h doesn't seem to support your compiler. " +
57 ("Reason: %s." % details) +
58 "Compiling may fail because of undefined preprocessor macros.")
Guido van Rossumbffa52f2002-09-29 00:25:51 +000059
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000060 (self.gcc_version, self.ld_version) = \
61 get_versions()
62 self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" %
Guido van Rossumbffa52f2002-09-29 00:25:51 +000063 (self.gcc_version,
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000064 self.ld_version) )
65
66 # Hard-code GCC because that's what this is all about.
67 # XXX optimization, warnings etc. should be customizable.
68 self.set_executables(compiler='gcc -Zomf -Zmt -O2 -Wall',
69 compiler_so='gcc -Zomf -Zmt -O2 -Wall',
70 linker_exe='gcc -Zomf -Zmt -Zcrtdll',
71 linker_so='gcc -Zomf -Zmt -Zcrtdll -Zdll')
72
73 # want the gcc library statically linked (so that we don't have
74 # to distribute a version dependent on the compiler we have)
75 self.dll_libraries=["gcc"]
Guido van Rossumbffa52f2002-09-29 00:25:51 +000076
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000077 # __init__ ()
78
Andrew MacIntyre428a38c2002-08-04 06:17:08 +000079 def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
Jeremy Hylton1b046e42002-06-18 18:48:55 +000080 if ext == '.rc':
81 # gcc requires '.rc' compiled to binary ('.res') files !!!
82 try:
83 self.spawn(["rc", "-r", src])
84 except DistutilsExecError, msg:
85 raise CompileError, msg
Guido van Rossumbffa52f2002-09-29 00:25:51 +000086 else: # for other files use the C-compiler
Jeremy Hylton1b046e42002-06-18 18:48:55 +000087 try:
88 self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
89 extra_postargs)
90 except DistutilsExecError, msg:
91 raise CompileError, msg
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000092
93 def link (self,
94 target_desc,
95 objects,
96 output_filename,
97 output_dir=None,
98 libraries=None,
99 library_dirs=None,
100 runtime_library_dirs=None,
101 export_symbols=None,
102 debug=0,
103 extra_preargs=None,
104 extra_postargs=None,
105 build_temp=None):
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000106
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000107 # use separate copies, so we can modify the lists
108 extra_preargs = copy.copy(extra_preargs or [])
109 libraries = copy.copy(libraries or [])
110 objects = copy.copy(objects or [])
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000111
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000112 # Additional libraries
113 libraries.extend(self.dll_libraries)
114
115 # handle export symbols by creating a def-file
116 # with executables this only works with gcc/ld as linker
117 if ((export_symbols is not None) and
118 (target_desc != self.EXECUTABLE)):
119 # (The linker doesn't do anything if output is up-to-date.
120 # So it would probably better to check if we really need this,
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000121 # but for this we had to insert some unchanged parts of
122 # UnixCCompiler, and this is not what we want.)
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000123
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000124 # we want to put some files in the same directory as the
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000125 # object files are, build_temp doesn't help much
126 # where are the object files
127 temp_dir = os.path.dirname(objects[0])
128 # name of dll to give the helper files the same base name
129 (dll_name, dll_extension) = os.path.splitext(
130 os.path.basename(output_filename))
131
132 # generate the filenames for these files
133 def_file = os.path.join(temp_dir, dll_name + ".def")
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000134
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000135 # Generate .def file
136 contents = [
Jeremy Hyltona2f99892002-06-04 20:26:44 +0000137 "LIBRARY %s INITINSTANCE TERMINSTANCE" % \
138 os.path.splitext(os.path.basename(output_filename))[0],
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000139 "DATA MULTIPLE NONSHARED",
140 "EXPORTS"]
141 for sym in export_symbols:
142 contents.append(' "%s"' % sym)
143 self.execute(write_file, (def_file, contents),
144 "writing %s" % def_file)
145
146 # next add options for def-file and to creating import libraries
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000147 # for gcc/ld the def-file is specified as any other object files
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000148 objects.append(def_file)
149
150 #end: if ((export_symbols is not None) and
151 # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000152
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000153 # who wants symbols and a many times larger output file
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000154 # should explicitly switch the debug mode on
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000155 # otherwise we let dllwrap/ld strip the output file
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000156 # (On my machine: 10KB < stripped_file < ??100KB
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000157 # unstripped_file = stripped_file + XXX KB
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000158 # ( XXX=254 for a typical python extension))
159 if not debug:
160 extra_preargs.append("-s")
161
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000162 UnixCCompiler.link(self,
163 target_desc,
164 objects,
165 output_filename,
166 output_dir,
167 libraries,
168 library_dirs,
169 runtime_library_dirs,
170 None, # export_symbols, we do this in our def-file
171 debug,
172 extra_preargs,
173 extra_postargs,
174 build_temp)
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000175
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000176 # link ()
177
178 # -- Miscellaneous methods -----------------------------------------
179
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000180 # override the object_filenames method from CCompiler to
181 # support rc and res-files
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000182 def object_filenames (self,
183 source_filenames,
184 strip_dir=0,
185 output_dir=''):
186 if output_dir is None: output_dir = ''
187 obj_names = []
188 for src_name in source_filenames:
189 # use normcase to make sure '.rc' is really '.rc' and not '.RC'
190 (base, ext) = os.path.splitext (os.path.normcase(src_name))
191 if ext not in (self.src_extensions + ['.rc']):
192 raise UnknownFileError, \
193 "unknown file type '%s' (from '%s')" % \
194 (ext, src_name)
195 if strip_dir:
196 base = os.path.basename (base)
197 if ext == '.rc':
198 # these need to be compiled to object files
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000199 obj_names.append (os.path.join (output_dir,
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000200 base + self.res_extension))
201 else:
202 obj_names.append (os.path.join (output_dir,
203 base + self.obj_extension))
204 return obj_names
205
206 # object_filenames ()
207
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000208 # override the find_library_file method from UnixCCompiler
209 # to deal with file naming/searching differences
210 def find_library_file(self, dirs, lib, debug=0):
211 shortlib = '%s.lib' % lib
212 longlib = 'lib%s.lib' % lib # this form very rare
213
214 # get EMX's default library directory search path
215 try:
216 emx_dirs = os.environ['LIBRARY_PATH'].split(';')
217 except KeyError:
218 emx_dirs = []
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000219
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000220 for dir in dirs + emx_dirs:
221 shortlibp = os.path.join(dir, shortlib)
222 longlibp = os.path.join(dir, longlib)
223 if os.path.exists(shortlibp):
224 return shortlibp
225 elif os.path.exists(longlibp):
226 return longlibp
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000227
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000228 # Oops, didn't find it in *any* of 'dirs'
229 return None
230
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000231# class EMXCCompiler
232
233
234# Because these compilers aren't configured in Python's pyconfig.h file by
235# default, we should at least warn the user if he is using a unmodified
236# version.
237
238CONFIG_H_OK = "ok"
239CONFIG_H_NOTOK = "not ok"
240CONFIG_H_UNCERTAIN = "uncertain"
241
242def check_config_h():
243
244 """Check if the current Python installation (specifically, pyconfig.h)
245 appears amenable to building extensions with GCC. Returns a tuple
246 (status, details), where 'status' is one of the following constants:
247 CONFIG_H_OK
248 all is well, go ahead and compile
249 CONFIG_H_NOTOK
250 doesn't look good
251 CONFIG_H_UNCERTAIN
252 not sure -- unable to read pyconfig.h
253 'details' is a human-readable string explaining the situation.
254
255 Note there are two ways to conclude "OK": either 'sys.version' contains
256 the string "GCC" (implying that this Python was built with GCC), or the
257 installed "pyconfig.h" contains the string "__GNUC__".
258 """
259
260 # XXX since this function also checks sys.version, it's not strictly a
261 # "pyconfig.h" check -- should probably be renamed...
262
263 from distutils import sysconfig
264 import string
265 # if sys.version contains GCC then python was compiled with
266 # GCC, and the pyconfig.h file should be OK
267 if string.find(sys.version,"GCC") >= 0:
268 return (CONFIG_H_OK, "sys.version mentions 'GCC'")
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000269
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000270 fn = sysconfig.get_config_h_filename()
271 try:
272 # It would probably better to read single lines to search.
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000273 # But we do this only once, and it is fast enough
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000274 f = open(fn)
275 s = f.read()
276 f.close()
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000277
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000278 except IOError, exc:
279 # if we can't read this file, we cannot say it is wrong
280 # the compiler will complain later about this file as missing
281 return (CONFIG_H_UNCERTAIN,
282 "couldn't read '%s': %s" % (fn, exc.strerror))
283
284 else:
285 # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
286 if string.find(s,"__GNUC__") >= 0:
287 return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
288 else:
289 return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
290
291
292def get_versions():
293 """ Try to find out the versions of gcc and ld.
294 If not possible it returns None for it.
295 """
296 from distutils.version import StrictVersion
297 from distutils.spawn import find_executable
298 import re
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000299
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000300 gcc_exe = find_executable('gcc')
301 if gcc_exe:
302 out = os.popen(gcc_exe + ' -dumpversion','r')
303 out_string = out.read()
304 out.close()
305 result = re.search('(\d+\.\d+\.\d+)',out_string)
306 if result:
307 gcc_version = StrictVersion(result.group(1))
308 else:
309 gcc_version = None
310 else:
311 gcc_version = None
312 # EMX ld has no way of reporting version number, and we use GCC
313 # anyway - so we can link OMF DLLs
314 ld_version = None
315 return (gcc_version, ld_version)