blob: 624c0fecbdc6806d57121d81a386a404befaf1b2 [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,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000105 build_temp=None,
106 target_lang=None):
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000107
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000108 # use separate copies, so we can modify the lists
109 extra_preargs = copy.copy(extra_preargs or [])
110 libraries = copy.copy(libraries or [])
111 objects = copy.copy(objects or [])
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000112
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000113 # Additional libraries
114 libraries.extend(self.dll_libraries)
115
116 # handle export symbols by creating a def-file
117 # with executables this only works with gcc/ld as linker
118 if ((export_symbols is not None) and
119 (target_desc != self.EXECUTABLE)):
120 # (The linker doesn't do anything if output is up-to-date.
121 # So it would probably better to check if we really need this,
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000122 # but for this we had to insert some unchanged parts of
123 # UnixCCompiler, and this is not what we want.)
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000124
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000125 # we want to put some files in the same directory as the
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000126 # object files are, build_temp doesn't help much
127 # where are the object files
128 temp_dir = os.path.dirname(objects[0])
129 # name of dll to give the helper files the same base name
130 (dll_name, dll_extension) = os.path.splitext(
131 os.path.basename(output_filename))
132
133 # generate the filenames for these files
134 def_file = os.path.join(temp_dir, dll_name + ".def")
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000135
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000136 # Generate .def file
137 contents = [
Jeremy Hyltona2f99892002-06-04 20:26:44 +0000138 "LIBRARY %s INITINSTANCE TERMINSTANCE" % \
139 os.path.splitext(os.path.basename(output_filename))[0],
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000140 "DATA MULTIPLE NONSHARED",
141 "EXPORTS"]
142 for sym in export_symbols:
143 contents.append(' "%s"' % sym)
144 self.execute(write_file, (def_file, contents),
145 "writing %s" % def_file)
146
147 # next add options for def-file and to creating import libraries
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000148 # for gcc/ld the def-file is specified as any other object files
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000149 objects.append(def_file)
150
151 #end: if ((export_symbols is not None) and
152 # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000153
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000154 # who wants symbols and a many times larger output file
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000155 # should explicitly switch the debug mode on
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000156 # otherwise we let dllwrap/ld strip the output file
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000157 # (On my machine: 10KB < stripped_file < ??100KB
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000158 # unstripped_file = stripped_file + XXX KB
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000159 # ( XXX=254 for a typical python extension))
160 if not debug:
161 extra_preargs.append("-s")
162
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000163 UnixCCompiler.link(self,
164 target_desc,
165 objects,
166 output_filename,
167 output_dir,
168 libraries,
169 library_dirs,
170 runtime_library_dirs,
171 None, # export_symbols, we do this in our def-file
172 debug,
173 extra_preargs,
174 extra_postargs,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000175 build_temp,
176 target_lang)
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000177
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000178 # link ()
179
180 # -- Miscellaneous methods -----------------------------------------
181
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000182 # override the object_filenames method from CCompiler to
183 # support rc and res-files
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000184 def object_filenames (self,
185 source_filenames,
186 strip_dir=0,
187 output_dir=''):
188 if output_dir is None: output_dir = ''
189 obj_names = []
190 for src_name in source_filenames:
191 # use normcase to make sure '.rc' is really '.rc' and not '.RC'
192 (base, ext) = os.path.splitext (os.path.normcase(src_name))
193 if ext not in (self.src_extensions + ['.rc']):
194 raise UnknownFileError, \
195 "unknown file type '%s' (from '%s')" % \
196 (ext, src_name)
197 if strip_dir:
198 base = os.path.basename (base)
199 if ext == '.rc':
200 # these need to be compiled to object files
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000201 obj_names.append (os.path.join (output_dir,
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000202 base + self.res_extension))
203 else:
204 obj_names.append (os.path.join (output_dir,
205 base + self.obj_extension))
206 return obj_names
207
208 # object_filenames ()
209
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000210 # override the find_library_file method from UnixCCompiler
211 # to deal with file naming/searching differences
212 def find_library_file(self, dirs, lib, debug=0):
213 shortlib = '%s.lib' % lib
214 longlib = 'lib%s.lib' % lib # this form very rare
215
216 # get EMX's default library directory search path
217 try:
218 emx_dirs = os.environ['LIBRARY_PATH'].split(';')
219 except KeyError:
220 emx_dirs = []
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000221
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000222 for dir in dirs + emx_dirs:
223 shortlibp = os.path.join(dir, shortlib)
224 longlibp = os.path.join(dir, longlib)
225 if os.path.exists(shortlibp):
226 return shortlibp
227 elif os.path.exists(longlibp):
228 return longlibp
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000229
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000230 # Oops, didn't find it in *any* of 'dirs'
231 return None
232
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000233# class EMXCCompiler
234
235
236# Because these compilers aren't configured in Python's pyconfig.h file by
237# default, we should at least warn the user if he is using a unmodified
238# version.
239
240CONFIG_H_OK = "ok"
241CONFIG_H_NOTOK = "not ok"
242CONFIG_H_UNCERTAIN = "uncertain"
243
244def check_config_h():
245
246 """Check if the current Python installation (specifically, pyconfig.h)
247 appears amenable to building extensions with GCC. Returns a tuple
248 (status, details), where 'status' is one of the following constants:
249 CONFIG_H_OK
250 all is well, go ahead and compile
251 CONFIG_H_NOTOK
252 doesn't look good
253 CONFIG_H_UNCERTAIN
254 not sure -- unable to read pyconfig.h
255 'details' is a human-readable string explaining the situation.
256
257 Note there are two ways to conclude "OK": either 'sys.version' contains
258 the string "GCC" (implying that this Python was built with GCC), or the
259 installed "pyconfig.h" contains the string "__GNUC__".
260 """
261
262 # XXX since this function also checks sys.version, it's not strictly a
263 # "pyconfig.h" check -- should probably be renamed...
264
265 from distutils import sysconfig
266 import string
267 # if sys.version contains GCC then python was compiled with
268 # GCC, and the pyconfig.h file should be OK
269 if string.find(sys.version,"GCC") >= 0:
270 return (CONFIG_H_OK, "sys.version mentions 'GCC'")
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000271
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000272 fn = sysconfig.get_config_h_filename()
273 try:
274 # It would probably better to read single lines to search.
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000275 # But we do this only once, and it is fast enough
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000276 f = open(fn)
277 s = f.read()
278 f.close()
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000279
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000280 except IOError, exc:
281 # if we can't read this file, we cannot say it is wrong
282 # the compiler will complain later about this file as missing
283 return (CONFIG_H_UNCERTAIN,
284 "couldn't read '%s': %s" % (fn, exc.strerror))
285
286 else:
287 # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
288 if string.find(s,"__GNUC__") >= 0:
289 return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
290 else:
291 return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
292
293
294def get_versions():
295 """ Try to find out the versions of gcc and ld.
296 If not possible it returns None for it.
297 """
298 from distutils.version import StrictVersion
299 from distutils.spawn import find_executable
300 import re
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000301
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000302 gcc_exe = find_executable('gcc')
303 if gcc_exe:
304 out = os.popen(gcc_exe + ' -dumpversion','r')
305 out_string = out.read()
306 out.close()
307 result = re.search('(\d+\.\d+\.\d+)',out_string)
308 if result:
309 gcc_version = StrictVersion(result.group(1))
310 else:
311 gcc_version = None
312 else:
313 gcc_version = None
314 # EMX ld has no way of reporting version number, and we use GCC
315 # anyway - so we can link OMF DLLs
316 ld_version = None
317 return (gcc_version, ld_version)