source: python/trunk/Lib/distutils/emxccompiler.py@ 390

Last change on this file since 390 was 21, checked in by Yuri Dario, 15 years ago

python: clean up in code.

  • Property svn:eol-style set to native
File size: 11.1 KB
Line 
1"""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:
19#
20# * EMX gcc 2.81/EMX 0.9d fix03
21
22__revision__ = "$Id: emxccompiler.py 34786 2003-12-02 12:17:59Z aimacintyre $"
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
29from distutils import log
30
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"
41
42 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.")
57
58 (self.gcc_version, self.ld_version) = \
59 get_versions()
60 self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" %
61 (self.gcc_version,
62 self.ld_version) )
63
64 # want the gcc library statically linked (so that we don't have
65 # to distribute a version dependent on the compiler we have)
66 self.dll_libraries=["gcc"]
67
68 # __init__ ()
69
70 def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
71 if ext == '.rc':
72 # gcc requires '.rc' compiled to binary ('.res') files !!!
73 try:
74 self.spawn(["rc", "-r", src])
75 except DistutilsExecError, msg:
76 raise CompileError, msg
77 else: # for other files use the C-compiler
78 try:
79 self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
80 extra_postargs)
81 except DistutilsExecError, msg:
82 raise CompileError, msg
83
84 def link (self,
85 target_desc,
86 objects,
87 output_filename,
88 output_dir=None,
89 libraries=None,
90 library_dirs=None,
91 runtime_library_dirs=None,
92 export_symbols=None,
93 debug=0,
94 extra_preargs=None,
95 extra_postargs=None,
96 build_temp=None,
97 target_lang=None):
98
99 # use separate copies, so we can modify the lists
100 extra_preargs = copy.copy(extra_preargs or [])
101 libraries = copy.copy(libraries or [])
102 objects = copy.copy(objects or [])
103
104 # Additional libraries
105 libraries.extend(self.dll_libraries)
106
107 # handle export symbols by creating a def-file
108 # with executables this only works with gcc/ld as linker
109 if ((export_symbols is not None) and
110 (target_desc != self.EXECUTABLE)):
111 # (The linker doesn't do anything if output is up-to-date.
112 # So it would probably better to check if we really need this,
113 # but for this we had to insert some unchanged parts of
114 # UnixCCompiler, and this is not what we want.)
115
116 # we want to put some files in the same directory as the
117 # object files are, build_temp doesn't help much
118 # where are the object files
119 temp_dir = os.path.dirname(objects[0])
120 # name of dll to give the helper files the same base name
121 (dll_name, dll_extension) = os.path.splitext(
122 os.path.basename(output_filename))
123
124 # generate the filenames for these files
125 def_file = os.path.join(temp_dir, dll_name + ".def")
126
127 # Generate .def file
128 contents = [
129 "LIBRARY %s INITINSTANCE TERMINSTANCE" % \
130 os.path.splitext(os.path.basename(output_filename))[0],
131 "DATA MULTIPLE NONSHARED",
132 "EXPORTS"]
133 for sym in export_symbols:
134 contents.append(' "_%s"' % sym)
135 self.execute(write_file, (def_file, contents),
136 "writing %s" % def_file)
137
138 # next add options for def-file and to creating import libraries
139 # for gcc/ld the def-file is specified as any other object files
140 objects.append(def_file)
141
142 #end: if ((export_symbols is not None) and
143 # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
144
145 # who wants symbols and a many times larger output file
146 # should explicitly switch the debug mode on
147 # otherwise we let dllwrap/ld strip the output file
148 # (On my machine: 10KB < stripped_file < ??100KB
149 # unstripped_file = stripped_file + XXX KB
150 # ( XXX=254 for a typical python extension))
151 if not debug:
152 extra_preargs.append("-s")
153
154 UnixCCompiler.link(self,
155 target_desc,
156 objects,
157 output_filename,
158 output_dir,
159 libraries,
160 library_dirs,
161 runtime_library_dirs,
162 None, # export_symbols, we do this in our def-file
163 debug,
164 extra_preargs,
165 extra_postargs,
166 build_temp,
167 target_lang)
168
169 # link ()
170
171 # -- Miscellaneous methods -----------------------------------------
172
173 # override the object_filenames method from CCompiler to
174 # support rc and res-files
175 def object_filenames (self,
176 source_filenames,
177 strip_dir=0,
178 output_dir=''):
179 if output_dir is None: output_dir = ''
180 obj_names = []
181 for src_name in source_filenames:
182 # use normcase to make sure '.rc' is really '.rc' and not '.RC'
183 (base, ext) = os.path.splitext (os.path.normcase(src_name))
184 if ext not in (self.src_extensions + ['.rc']):
185 raise UnknownFileError, \
186 "unknown file type '%s' (from '%s')" % \
187 (ext, src_name)
188 if strip_dir:
189 base = os.path.basename (base)
190 if ext == '.rc':
191 # these need to be compiled to object files
192 obj_names.append (os.path.join (output_dir,
193 base + self.res_extension))
194 else:
195 obj_names.append (os.path.join (output_dir,
196 base + self.obj_extension))
197 return obj_names
198
199 # object_filenames ()
200
201 # override the find_library_file method from UnixCCompiler
202 # to deal with file naming/searching differences
203 def find_library_file(self, dirs, lib, debug=0):
204 try_names = [lib + ".lib", lib + ".a", "lib" + lib + ".lib", "lib" + lib + ".a"]
205
206 # get EMX's default library directory search path
207 try:
208 emx_dirs = os.environ['LIBRARY_PATH'].split(';')
209 except KeyError:
210 emx_dirs = []
211
212 for dir in dirs + emx_dirs:
213 for name in try_names:
214 libfile = os.path.join(dir, name)
215 #print "libfile:",libfile
216 if os.path.exists(libfile):
217 return libfile
218
219 # Oops, didn't find it in *any* of 'dirs'
220 return None
221
222# class EMXCCompiler
223
224
225# Because these compilers aren't configured in Python's pyconfig.h file by
226# default, we should at least warn the user if he is using a unmodified
227# version.
228
229CONFIG_H_OK = "ok"
230CONFIG_H_NOTOK = "not ok"
231CONFIG_H_UNCERTAIN = "uncertain"
232
233def check_config_h():
234
235 """Check if the current Python installation (specifically, pyconfig.h)
236 appears amenable to building extensions with GCC. Returns a tuple
237 (status, details), where 'status' is one of the following constants:
238 CONFIG_H_OK
239 all is well, go ahead and compile
240 CONFIG_H_NOTOK
241 doesn't look good
242 CONFIG_H_UNCERTAIN
243 not sure -- unable to read pyconfig.h
244 'details' is a human-readable string explaining the situation.
245
246 Note there are two ways to conclude "OK": either 'sys.version' contains
247 the string "GCC" (implying that this Python was built with GCC), or the
248 installed "pyconfig.h" contains the string "__GNUC__".
249 """
250
251 # XXX since this function also checks sys.version, it's not strictly a
252 # "pyconfig.h" check -- should probably be renamed...
253
254 from distutils import sysconfig
255 import string
256 # if sys.version contains GCC then python was compiled with
257 # GCC, and the pyconfig.h file should be OK
258 if string.find(sys.version,"GCC") >= 0:
259 return (CONFIG_H_OK, "sys.version mentions 'GCC'")
260
261 fn = sysconfig.get_config_h_filename()
262 try:
263 # It would probably better to read single lines to search.
264 # But we do this only once, and it is fast enough
265 f = open(fn)
266 s = f.read()
267 f.close()
268
269 except IOError, exc:
270 # if we can't read this file, we cannot say it is wrong
271 # the compiler will complain later about this file as missing
272 return (CONFIG_H_UNCERTAIN,
273 "couldn't read '%s': %s" % (fn, exc.strerror))
274
275 else:
276 # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
277 if string.find(s,"__GNUC__") >= 0:
278 return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
279 else:
280 return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
281
282
283def get_versions():
284 """ Try to find out the versions of gcc and ld.
285 If not possible it returns None for it.
286 """
287 from distutils.version import StrictVersion
288 from distutils.spawn import find_executable
289 import re
290
291 gcc_exe = find_executable('gcc')
292 if gcc_exe:
293 out = os.popen(gcc_exe + ' -dumpversion','r')
294 out_string = out.read()
295 out.close()
296 result = re.search('(\d+\.\d+\.\d+)',out_string)
297 if result:
298 gcc_version = StrictVersion(result.group(1))
299 else:
300 gcc_version = None
301 else:
302 gcc_version = None
303 # EMX ld has no way of reporting version number, and we use GCC
304 # anyway - so we can link OMF DLLs
305 ld_version = None
306 return (gcc_version, ld_version)
Note: See TracBrowser for help on using the repository browser.