1 """distutils.emxccompiler
3 Provides the EMXCCompiler class, a subclass of UnixCCompiler that
4 handles the EMX port of the GNU C compiler to OS/2.
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.
13 # * only use OMF objects and use LINK386 as the linker (-Zomf)
15 # * always build for multithreading (-Zmt) as the accompanying OS/2 port
16 # of Python is only distributed with threads enabled.
18 # tested configurations:
20 # * EMX gcc 2.81/EMX 0.9d fix03
25 from distutils
.ccompiler
import gen_preprocess_options
, gen_lib_options
26 from distutils
.unixccompiler
import UnixCCompiler
27 from distutils
.file_util
import write_file
28 from distutils
.errors
import DistutilsExecError
, CompileError
, UnknownFileError
29 from distutils
import log
31 class EMXCCompiler (UnixCCompiler
):
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"
47 UnixCCompiler
.__init
__ (self
, verbose
, dry_run
, force
)
49 (status
, details
) = check_config_h()
50 self
.debug_print("Python's GCC status: %s (details: %s)" %
52 if status
is not CONFIG_H_OK
:
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.")
58 (self
.gcc_version
, self
.ld_version
) = \
60 self
.debug_print(self
.compiler_type
+ ": gcc %s, ld %s\n" %
64 # Hard-code GCC because that's what this is all about.
65 # XXX optimization, warnings etc. should be customizable.
66 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',
68 linker_exe
='gcc -Zomf -Zmt -Zcrtdll',
69 linker_so
='gcc -Zomf -Zmt -Zcrtdll -Zdll')
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"]
77 def _compile(self
, obj
, src
, ext
, cc_args
, extra_postargs
, pp_opts
):
79 # gcc requires '.rc' compiled to binary ('.res') files !!!
81 self
.spawn(["rc", "-r", src
])
82 except DistutilsExecError
, msg
:
83 raise CompileError
, msg
84 else: # for other files use the C-compiler
86 self
.spawn(self
.compiler_so
+ cc_args
+ [src
, '-o', obj
] +
88 except DistutilsExecError
, msg
:
89 raise CompileError
, msg
98 runtime_library_dirs
=None,
106 # 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 [])
111 # Additional libraries
112 libraries
.extend(self
.dll_libraries
)
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,
120 # but for this we had to insert some unchanged parts of
121 # UnixCCompiler, and this is not what we want.)
123 # we want to put some files in the same directory as the
124 # 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
))
131 # generate the filenames for these files
132 def_file
= os
.path
.join(temp_dir
, dll_name
+ ".def")
136 "LIBRARY %s INITINSTANCE TERMINSTANCE" % \
137 os
.path
.splitext(os
.path
.basename(output_filename
))[0],
138 "DATA MULTIPLE NONSHARED",
140 for sym
in export_symbols
:
141 contents
.append(' "%s"' % sym
)
142 self
.execute(write_file
, (def_file
, contents
),
143 "writing %s" % def_file
)
145 # next add options for def-file and to creating import libraries
146 # for gcc/ld the def-file is specified as any other object files
147 objects
.append(def_file
)
149 #end: if ((export_symbols is not None) and
150 # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
152 # who wants symbols and a many times larger output file
153 # should explicitly switch the debug mode on
154 # otherwise we let dllwrap/ld strip the output file
155 # (On my machine: 10KB < stripped_file < ??100KB
156 # unstripped_file = stripped_file + XXX KB
157 # ( XXX=254 for a typical python extension))
159 extra_preargs
.append("-s")
161 UnixCCompiler
.link(self
,
168 runtime_library_dirs
,
169 None, # export_symbols, we do this in our def-file
178 # -- Miscellaneous methods -----------------------------------------
180 # override the object_filenames method from CCompiler to
181 # support rc and res-files
182 def object_filenames (self
,
186 if output_dir
is None: output_dir
= ''
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')" % \
196 base
= os
.path
.basename (base
)
198 # these need to be compiled to object files
199 obj_names
.append (os
.path
.join (output_dir
,
200 base
+ self
.res_extension
))
202 obj_names
.append (os
.path
.join (output_dir
,
203 base
+ self
.obj_extension
))
206 # object_filenames ()
208 # 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
214 # get EMX's default library directory search path
216 emx_dirs
= os
.environ
['LIBRARY_PATH'].split(';')
220 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
):
225 elif os
.path
.exists(longlibp
):
228 # Oops, didn't find it in *any* of 'dirs'
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
239 CONFIG_H_NOTOK
= "not ok"
240 CONFIG_H_UNCERTAIN
= "uncertain"
242 def check_config_h():
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:
248 all is well, go ahead and compile
252 not sure -- unable to read pyconfig.h
253 'details' is a human-readable string explaining the situation.
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__".
260 # XXX since this function also checks sys.version, it's not strictly a
261 # "pyconfig.h" check -- should probably be renamed...
263 from distutils
import sysconfig
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'")
270 fn
= sysconfig
.get_config_h_filename()
272 # It would probably better to read single lines to search.
273 # But we do this only once, and it is fast enough
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
))
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
)
289 return (CONFIG_H_NOTOK
, "'%s' does not mention '__GNUC__'" % fn
)
293 """ Try to find out the versions of gcc and ld.
294 If not possible it returns None for it.
296 from distutils
.version
import StrictVersion
297 from distutils
.spawn
import find_executable
300 gcc_exe
= find_executable('gcc')
302 out
= os
.popen(gcc_exe
+ ' -dumpversion','r')
303 out_string
= out
.read()
305 result
= re
.search('(\d+\.\d+\.\d+)',out_string
)
307 gcc_version
= StrictVersion(result
.group(1))
312 # EMX ld has no way of reporting version number, and we use GCC
313 # anyway - so we can link OMF DLLs
315 return (gcc_version
, ld_version
)