0001 """distutils.emxccompiler 0002 0003 Provides the EMXCCompiler class, a subclass of UnixCCompiler that 0004 handles the EMX port of the GNU C compiler to OS/2. 0005 """ 0006 0007 # issues: 0008 # 0009 # * OS/2 insists that DLLs can have names no longer than 8 characters 0010 # We put export_symbols in a def-file, as though the DLL can have 0011 # an arbitrary length name, but truncate the output filename. 0012 # 0013 # * only use OMF objects and use LINK386 as the linker (-Zomf) 0014 # 0015 # * always build for multithreading (-Zmt) as the accompanying OS/2 port 0016 # of Python is only distributed with threads enabled. 0017 # 0018 # tested configurations: 0019 # 0020 # * EMX gcc 2.81/EMX 0.9d fix03 0021 0022 __revision__ = "$Id: emxccompiler.py,v 1.11 2003/12/02 12:17:59 aimacintyre Exp $" 0023 0024 import os,sys,copy 0025 from distutils.ccompiler import gen_preprocess_options, gen_lib_options 0026 from distutils.unixccompiler import UnixCCompiler 0027 from distutils.file_util import write_file 0028 from distutils.errors import DistutilsExecError, CompileError, UnknownFileError 0029 from distutils import log 0030 0031 class EMXCCompiler (UnixCCompiler): 0032 0033 compiler_type = 'emx' 0034 obj_extension = ".obj" 0035 static_lib_extension = ".lib" 0036 shared_lib_extension = ".dll" 0037 static_lib_format = "%s%s" 0038 shared_lib_format = "%s%s" 0039 res_extension = ".res" # compiled resource file 0040 exe_extension = ".exe" 0041 0042 def __init__ (self, 0043 verbose=0, 0044 dry_run=0, 0045 force=0): 0046 0047 UnixCCompiler.__init__ (self, verbose, dry_run, force) 0048 0049 (status, details) = check_config_h() 0050 self.debug_print("Python's GCC status: %s (details: %s)" % 0051 (status, details)) 0052 if status is not CONFIG_H_OK: 0053 self.warn( 0054 "Python's pyconfig.h doesn't seem to support your compiler. " + 0055 ("Reason: %s." % details) + 0056 "Compiling may fail because of undefined preprocessor macros.") 0057 0058 (self.gcc_version, self.ld_version) = \ 0059 get_versions() 0060 self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" % 0061 (self.gcc_version, 0062 self.ld_version) ) 0063 0064 # Hard-code GCC because that's what this is all about. 0065 # XXX optimization, warnings etc. should be customizable. 0066 self.set_executables(compiler='gcc -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall', 0067 compiler_so='gcc -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall', 0068 linker_exe='gcc -Zomf -Zmt -Zcrtdll', 0069 linker_so='gcc -Zomf -Zmt -Zcrtdll -Zdll') 0070 0071 # want the gcc library statically linked (so that we don't have 0072 # to distribute a version dependent on the compiler we have) 0073 self.dll_libraries=["gcc"] 0074 0075 # __init__ () 0076 0077 def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): 0078 if ext == '.rc': 0079 # gcc requires '.rc' compiled to binary ('.res') files !!! 0080 try: 0081 self.spawn(["rc", "-r", src]) 0082 except DistutilsExecError, msg: 0083 raise CompileError, msg 0084 else: # for other files use the C-compiler 0085 try: 0086 self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + 0087 extra_postargs) 0088 except DistutilsExecError, msg: 0089 raise CompileError, msg 0090 0091 def link (self, 0092 target_desc, 0093 objects, 0094 output_filename, 0095 output_dir=None, 0096 libraries=None, 0097 library_dirs=None, 0098 runtime_library_dirs=None, 0099 export_symbols=None, 0100 debug=0, 0101 extra_preargs=None, 0102 extra_postargs=None, 0103 build_temp=None, 0104 target_lang=None): 0105 0106 # use separate copies, so we can modify the lists 0107 extra_preargs = copy.copy(extra_preargs or []) 0108 libraries = copy.copy(libraries or []) 0109 objects = copy.copy(objects or []) 0110 0111 # Additional libraries 0112 libraries.extend(self.dll_libraries) 0113 0114 # handle export symbols by creating a def-file 0115 # with executables this only works with gcc/ld as linker 0116 if ((export_symbols is not None) and 0117 (target_desc != self.EXECUTABLE)): 0118 # (The linker doesn't do anything if output is up-to-date. 0119 # So it would probably better to check if we really need this, 0120 # but for this we had to insert some unchanged parts of 0121 # UnixCCompiler, and this is not what we want.) 0122 0123 # we want to put some files in the same directory as the 0124 # object files are, build_temp doesn't help much 0125 # where are the object files 0126 temp_dir = os.path.dirname(objects[0]) 0127 # name of dll to give the helper files the same base name 0128 (dll_name, dll_extension) = os.path.splitext( 0129 os.path.basename(output_filename)) 0130 0131 # generate the filenames for these files 0132 def_file = os.path.join(temp_dir, dll_name + ".def") 0133 0134 # Generate .def file 0135 contents = [ 0136 "LIBRARY %s INITINSTANCE TERMINSTANCE" % \ 0137 os.path.splitext(os.path.basename(output_filename))[0], 0138 "DATA MULTIPLE NONSHARED", 0139 "EXPORTS"] 0140 for sym in export_symbols: 0141 contents.append(' "%s"' % sym) 0142 self.execute(write_file, (def_file, contents), 0143 "writing %s" % def_file) 0144 0145 # next add options for def-file and to creating import libraries 0146 # for gcc/ld the def-file is specified as any other object files 0147 objects.append(def_file) 0148 0149 #end: if ((export_symbols is not None) and 0150 # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): 0151 0152 # who wants symbols and a many times larger output file 0153 # should explicitly switch the debug mode on 0154 # otherwise we let dllwrap/ld strip the output file 0155 # (On my machine: 10KB < stripped_file < ??100KB 0156 # unstripped_file = stripped_file + XXX KB 0157 # ( XXX=254 for a typical python extension)) 0158 if not debug: 0159 extra_preargs.append("-s") 0160 0161 UnixCCompiler.link(self, 0162 target_desc, 0163 objects, 0164 output_filename, 0165 output_dir, 0166 libraries, 0167 library_dirs, 0168 runtime_library_dirs, 0169 None, # export_symbols, we do this in our def-file 0170 debug, 0171 extra_preargs, 0172 extra_postargs, 0173 build_temp, 0174 target_lang) 0175 0176 # link () 0177 0178 # -- Miscellaneous methods ----------------------------------------- 0179 0180 # override the object_filenames method from CCompiler to 0181 # support rc and res-files 0182 def object_filenames (self, 0183 source_filenames, 0184 strip_dir=0, 0185 output_dir=''): 0186 if output_dir is None: output_dir = '' 0187 obj_names = [] 0188 for src_name in source_filenames: 0189 # use normcase to make sure '.rc' is really '.rc' and not '.RC' 0190 (base, ext) = os.path.splitext (os.path.normcase(src_name)) 0191 if ext not in (self.src_extensions + ['.rc']): 0192 raise UnknownFileError, \ 0193 "unknown file type '%s' (from '%s')" % \ 0194 (ext, src_name) 0195 if strip_dir: 0196 base = os.path.basename (base) 0197 if ext == '.rc': 0198 # these need to be compiled to object files 0199 obj_names.append (os.path.join (output_dir, 0200 base + self.res_extension)) 0201 else: 0202 obj_names.append (os.path.join (output_dir, 0203 base + self.obj_extension)) 0204 return obj_names 0205 0206 # object_filenames () 0207 0208 # override the find_library_file method from UnixCCompiler 0209 # to deal with file naming/searching differences 0210 def find_library_file(self, dirs, lib, debug=0): 0211 shortlib = '%s.lib' % lib 0212 longlib = 'lib%s.lib' % lib # this form very rare 0213 0214 # get EMX's default library directory search path 0215 try: 0216 emx_dirs = os.environ['LIBRARY_PATH'].split(';') 0217 except KeyError: 0218 emx_dirs = [] 0219 0220 for dir in dirs + emx_dirs: 0221 shortlibp = os.path.join(dir, shortlib) 0222 longlibp = os.path.join(dir, longlib) 0223 if os.path.exists(shortlibp): 0224 return shortlibp 0225 elif os.path.exists(longlibp): 0226 return longlibp 0227 0228 # Oops, didn't find it in *any* of 'dirs' 0229 return None 0230 0231 # class EMXCCompiler 0232 0233 0234 # Because these compilers aren't configured in Python's pyconfig.h file by 0235 # default, we should at least warn the user if he is using a unmodified 0236 # version. 0237 0238 CONFIG_H_OK = "ok" 0239 CONFIG_H_NOTOK = "not ok" 0240 CONFIG_H_UNCERTAIN = "uncertain" 0241 0242 def check_config_h(): 0243 0244 """Check if the current Python installation (specifically, pyconfig.h) 0245 appears amenable to building extensions with GCC. Returns a tuple 0246 (status, details), where 'status' is one of the following constants: 0247 CONFIG_H_OK 0248 all is well, go ahead and compile 0249 CONFIG_H_NOTOK 0250 doesn't look good 0251 CONFIG_H_UNCERTAIN 0252 not sure -- unable to read pyconfig.h 0253 'details' is a human-readable string explaining the situation. 0254 0255 Note there are two ways to conclude "OK": either 'sys.version' contains 0256 the string "GCC" (implying that this Python was built with GCC), or the 0257 installed "pyconfig.h" contains the string "__GNUC__". 0258 """ 0259 0260 # XXX since this function also checks sys.version, it's not strictly a 0261 # "pyconfig.h" check -- should probably be renamed... 0262 0263 from distutils import sysconfig 0264 import string 0265 # if sys.version contains GCC then python was compiled with 0266 # GCC, and the pyconfig.h file should be OK 0267 if string.find(sys.version,"GCC") >= 0: 0268 return (CONFIG_H_OK, "sys.version mentions 'GCC'") 0269 0270 fn = sysconfig.get_config_h_filename() 0271 try: 0272 # It would probably better to read single lines to search. 0273 # But we do this only once, and it is fast enough 0274 f = open(fn) 0275 s = f.read() 0276 f.close() 0277 0278 except IOError, exc: 0279 # if we can't read this file, we cannot say it is wrong 0280 # the compiler will complain later about this file as missing 0281 return (CONFIG_H_UNCERTAIN, 0282 "couldn't read '%s': %s" % (fn, exc.strerror)) 0283 0284 else: 0285 # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar 0286 if string.find(s,"__GNUC__") >= 0: 0287 return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn) 0288 else: 0289 return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn) 0290 0291 0292 def get_versions(): 0293 """ Try to find out the versions of gcc and ld. 0294 If not possible it returns None for it. 0295 """ 0296 from distutils.version import StrictVersion 0297 from distutils.spawn import find_executable 0298 import re 0299 0300 gcc_exe = find_executable('gcc') 0301 if gcc_exe: 0302 out = os.popen(gcc_exe + ' -dumpversion','r') 0303 out_string = out.read() 0304 out.close() 0305 result = re.search('(\d+\.\d+\.\d+)',out_string) 0306 if result: 0307 gcc_version = StrictVersion(result.group(1)) 0308 else: 0309 gcc_version = None 0310 else: 0311 gcc_version = None 0312 # EMX ld has no way of reporting version number, and we use GCC 0313 # anyway - so we can link OMF DLLs 0314 ld_version = None 0315 return (gcc_version, ld_version) 0316
Generated by PyXR 0.9.4