]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/distutils/emxccompiler.py
   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 -O2 -Wall', 
  67                              compiler_so
='gcc -Zomf -Zmt -O2 -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
)