blob: d9ee82d58a0e0c658e67e1399ef82fc3b3c5009a [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
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000022__revision__ = "$Id$"
23
24import os,sys,copy
25from distutils.ccompiler import gen_preprocess_options, gen_lib_options
26from distutils.unixccompiler import UnixCCompiler
27from distutils.file_util import write_file
28from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000029from distutils import log
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000030
31class EMXCCompiler (UnixCCompiler):
32
33 compiler_type = 'emx'
34 obj_extension = ".obj"
35 static_lib_extension = ".lib"
36 shared_lib_extension = ".dll"
37 static_lib_format = "%s%s"
38 shared_lib_format = "%s%s"
39 res_extension = ".res" # compiled resource file
40 exe_extension = ".exe"
Guido van Rossumbffa52f2002-09-29 00:25:51 +000041
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000042 def __init__ (self,
43 verbose=0,
44 dry_run=0,
45 force=0):
46
47 UnixCCompiler.__init__ (self, verbose, dry_run, force)
48
49 (status, details) = check_config_h()
50 self.debug_print("Python's GCC status: %s (details: %s)" %
51 (status, details))
52 if status is not CONFIG_H_OK:
53 self.warn(
54 "Python's pyconfig.h doesn't seem to support your compiler. " +
55 ("Reason: %s." % details) +
56 "Compiling may fail because of undefined preprocessor macros.")
Guido van Rossumbffa52f2002-09-29 00:25:51 +000057
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000058 (self.gcc_version, self.ld_version) = \
59 get_versions()
60 self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" %
Guido van Rossumbffa52f2002-09-29 00:25:51 +000061 (self.gcc_version,
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000062 self.ld_version) )
63
64 # Hard-code GCC because that's what this is all about.
65 # XXX optimization, warnings etc. should be customizable.
Andrew MacIntyre63ee1102003-12-02 12:17:59 +000066 self.set_executables(compiler='gcc -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall',
67 compiler_so='gcc -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall',
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000068 linker_exe='gcc -Zomf -Zmt -Zcrtdll',
69 linker_so='gcc -Zomf -Zmt -Zcrtdll -Zdll')
70
71 # want the gcc library statically linked (so that we don't have
72 # to distribute a version dependent on the compiler we have)
73 self.dll_libraries=["gcc"]
Guido van Rossumbffa52f2002-09-29 00:25:51 +000074
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000075 # __init__ ()
76
Andrew MacIntyre428a38c2002-08-04 06:17:08 +000077 def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
Jeremy Hylton1b046e42002-06-18 18:48:55 +000078 if ext == '.rc':
79 # gcc requires '.rc' compiled to binary ('.res') files !!!
80 try:
81 self.spawn(["rc", "-r", src])
Guido van Rossumb940e112007-01-10 16:19:56 +000082 except DistutilsExecError as msg:
Collin Winter5b7e9d72007-08-30 03:52:21 +000083 raise CompileError(msg)
Guido van Rossumbffa52f2002-09-29 00:25:51 +000084 else: # for other files use the C-compiler
Jeremy Hylton1b046e42002-06-18 18:48:55 +000085 try:
86 self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
87 extra_postargs)
Guido van Rossumb940e112007-01-10 16:19:56 +000088 except DistutilsExecError as msg:
Collin Winter5b7e9d72007-08-30 03:52:21 +000089 raise CompileError(msg)
Marc-André Lemburg9273ec72002-02-06 18:22:48 +000090
91 def link (self,
92 target_desc,
93 objects,
94 output_filename,
95 output_dir=None,
96 libraries=None,
97 library_dirs=None,
98 runtime_library_dirs=None,
99 export_symbols=None,
100 debug=0,
101 extra_preargs=None,
102 extra_postargs=None,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000103 build_temp=None,
104 target_lang=None):
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000105
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000106 # use separate copies, so we can modify the lists
107 extra_preargs = copy.copy(extra_preargs or [])
108 libraries = copy.copy(libraries or [])
109 objects = copy.copy(objects or [])
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000110
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000111 # Additional libraries
112 libraries.extend(self.dll_libraries)
113
114 # handle export symbols by creating a def-file
115 # with executables this only works with gcc/ld as linker
116 if ((export_symbols is not None) and
117 (target_desc != self.EXECUTABLE)):
118 # (The linker doesn't do anything if output is up-to-date.
119 # So it would probably better to check if we really need this,
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000120 # but for this we had to insert some unchanged parts of
121 # UnixCCompiler, and this is not what we want.)
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000122
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000123 # we want to put some files in the same directory as the
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000124 # object files are, build_temp doesn't help much
125 # where are the object files
126 temp_dir = os.path.dirname(objects[0])
127 # name of dll to give the helper files the same base name
128 (dll_name, dll_extension) = os.path.splitext(
129 os.path.basename(output_filename))
130
131 # generate the filenames for these files
132 def_file = os.path.join(temp_dir, dll_name + ".def")
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000133
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000134 # Generate .def file
135 contents = [
Jeremy Hyltona2f99892002-06-04 20:26:44 +0000136 "LIBRARY %s INITINSTANCE TERMINSTANCE" % \
137 os.path.splitext(os.path.basename(output_filename))[0],
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000138 "DATA MULTIPLE NONSHARED",
139 "EXPORTS"]
140 for sym in export_symbols:
141 contents.append(' "%s"' % sym)
142 self.execute(write_file, (def_file, contents),
143 "writing %s" % def_file)
144
145 # next add options for def-file and to creating import libraries
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000146 # for gcc/ld the def-file is specified as any other object files
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000147 objects.append(def_file)
148
149 #end: if ((export_symbols is not None) and
150 # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000151
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000152 # who wants symbols and a many times larger output file
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000153 # should explicitly switch the debug mode on
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000154 # otherwise we let dllwrap/ld strip the output file
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000155 # (On my machine: 10KB < stripped_file < ??100KB
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000156 # unstripped_file = stripped_file + XXX KB
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000157 # ( XXX=254 for a typical python extension))
158 if not debug:
159 extra_preargs.append("-s")
160
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000161 UnixCCompiler.link(self,
162 target_desc,
163 objects,
164 output_filename,
165 output_dir,
166 libraries,
167 library_dirs,
168 runtime_library_dirs,
169 None, # export_symbols, we do this in our def-file
170 debug,
171 extra_preargs,
172 extra_postargs,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000173 build_temp,
174 target_lang)
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']):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000192 raise UnknownFileError("unknown file type '%s' (from '%s')" % \
193 (ext, src_name))
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000194 if strip_dir:
195 base = os.path.basename (base)
196 if ext == '.rc':
197 # these need to be compiled to object files
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000198 obj_names.append (os.path.join (output_dir,
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000199 base + self.res_extension))
200 else:
201 obj_names.append (os.path.join (output_dir,
202 base + self.obj_extension))
203 return obj_names
204
205 # object_filenames ()
206
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000207 # override the find_library_file method from UnixCCompiler
208 # to deal with file naming/searching differences
209 def find_library_file(self, dirs, lib, debug=0):
210 shortlib = '%s.lib' % lib
211 longlib = 'lib%s.lib' % lib # this form very rare
212
213 # get EMX's default library directory search path
214 try:
215 emx_dirs = os.environ['LIBRARY_PATH'].split(';')
216 except KeyError:
217 emx_dirs = []
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000218
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000219 for dir in dirs + emx_dirs:
220 shortlibp = os.path.join(dir, shortlib)
221 longlibp = os.path.join(dir, longlib)
222 if os.path.exists(shortlibp):
223 return shortlibp
224 elif os.path.exists(longlibp):
225 return longlibp
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000226
Andrew MacIntyre4104db32002-08-04 06:21:25 +0000227 # Oops, didn't find it in *any* of 'dirs'
228 return None
229
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000230# class EMXCCompiler
231
232
233# Because these compilers aren't configured in Python's pyconfig.h file by
234# default, we should at least warn the user if he is using a unmodified
235# version.
236
237CONFIG_H_OK = "ok"
238CONFIG_H_NOTOK = "not ok"
239CONFIG_H_UNCERTAIN = "uncertain"
240
241def check_config_h():
242
243 """Check if the current Python installation (specifically, pyconfig.h)
244 appears amenable to building extensions with GCC. Returns a tuple
245 (status, details), where 'status' is one of the following constants:
246 CONFIG_H_OK
247 all is well, go ahead and compile
248 CONFIG_H_NOTOK
249 doesn't look good
250 CONFIG_H_UNCERTAIN
251 not sure -- unable to read pyconfig.h
252 'details' is a human-readable string explaining the situation.
253
254 Note there are two ways to conclude "OK": either 'sys.version' contains
255 the string "GCC" (implying that this Python was built with GCC), or the
256 installed "pyconfig.h" contains the string "__GNUC__".
257 """
258
259 # XXX since this function also checks sys.version, it's not strictly a
260 # "pyconfig.h" check -- should probably be renamed...
261
262 from distutils import sysconfig
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000263 # if sys.version contains GCC then python was compiled with
264 # GCC, and the pyconfig.h file should be OK
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000265 if sys.version.find("GCC") >= 0:
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000266 return (CONFIG_H_OK, "sys.version mentions 'GCC'")
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000267
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000268 fn = sysconfig.get_config_h_filename()
269 try:
270 # It would probably better to read single lines to search.
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000271 # But we do this only once, and it is fast enough
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000272 f = open(fn)
273 s = f.read()
274 f.close()
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000275
Guido van Rossumb940e112007-01-10 16:19:56 +0000276 except IOError as exc:
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000277 # if we can't read this file, we cannot say it is wrong
278 # the compiler will complain later about this file as missing
279 return (CONFIG_H_UNCERTAIN,
280 "couldn't read '%s': %s" % (fn, exc.strerror))
281
282 else:
283 # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000284 if s.find("__GNUC__") >= 0:
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000285 return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
286 else:
287 return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
288
289
290def get_versions():
291 """ Try to find out the versions of gcc and ld.
292 If not possible it returns None for it.
293 """
294 from distutils.version import StrictVersion
295 from distutils.spawn import find_executable
296 import re
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000297
Marc-André Lemburg9273ec72002-02-06 18:22:48 +0000298 gcc_exe = find_executable('gcc')
299 if gcc_exe:
300 out = os.popen(gcc_exe + ' -dumpversion','r')
301 out_string = out.read()
302 out.close()
303 result = re.search('(\d+\.\d+\.\d+)',out_string)
304 if result:
305 gcc_version = StrictVersion(result.group(1))
306 else:
307 gcc_version = None
308 else:
309 gcc_version = None
310 # EMX ld has no way of reporting version number, and we use GCC
311 # anyway - so we can link OMF DLLs
312 ld_version = None
313 return (gcc_version, ld_version)