]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/distutils/command/config.py
   1 """distutils.command.config 
   3 Implements the Distutils 'config' command, a (mostly) empty command class 
   4 that exists mainly to be sub-classed by specific module distributions and 
   5 applications.  The idea is that while every "config" command is different, 
   6 at least they're all named the same, and users always see "config" in the 
   7 list of standard commands.  Also, this is a good place to put common 
   8 configure-like tasks: "try to compile this C code", or "figure out where 
   9 this header file lives". 
  12 # This module should be kept compatible with Python 1.5.2. 
  16 import sys
, os
, string
, re
 
  18 from distutils
.core 
import Command
 
  19 from distutils
.errors 
import DistutilsExecError
 
  20 from distutils
.sysconfig 
import customize_compiler
 
  21 from distutils 
import log
 
  23 LANG_EXT 
= {'c': '.c', 
  26 class config (Command
): 
  28     description 
= "prepare to build" 
  32          "specify the compiler type"), 
  34          "specify the compiler executable"), 
  35         ('include-dirs=', 'I', 
  36          "list of directories to search for header files"), 
  38          "C preprocessor macros to define"), 
  40          "C preprocessor macros to undefine"), 
  42          "external C libraries to link with"), 
  43         ('library-dirs=', 'L', 
  44          "directories to search for external C libraries"), 
  47          "show every action (compile, link, run, ...) taken"), 
  49          "dump generated source files before attempting to compile them"), 
  53     # The three standard command methods: since the "config" command 
  54     # does nothing by default, these are empty. 
  56     def initialize_options (self
): 
  59         self
.include_dirs 
= None 
  63         self
.library_dirs 
= None 
  65         # maximal output for now 
  69         # list of temporary files generated along-the-way that we have 
  70         # to clean at some point 
  73     def finalize_options (self
): 
  74         if self
.include_dirs 
is None: 
  75             self
.include_dirs 
= self
.distribution
.include_dirs 
or [] 
  76         elif type(self
.include_dirs
) is StringType
: 
  77             self
.include_dirs 
= string
.split(self
.include_dirs
, os
.pathsep
) 
  79         if self
.libraries 
is None: 
  81         elif type(self
.libraries
) is StringType
: 
  82             self
.libraries 
= [self
.libraries
] 
  84         if self
.library_dirs 
is None: 
  85             self
.library_dirs 
= [] 
  86         elif type(self
.library_dirs
) is StringType
: 
  87             self
.library_dirs 
= string
.split(self
.library_dirs
, os
.pathsep
) 
  94     # Utility methods for actual "config" commands.  The interfaces are 
  95     # loosely based on Autoconf macros of similar names.  Sub-classes 
  96     # may use these freely. 
  98     def _check_compiler (self
): 
  99         """Check that 'self.compiler' really is a CCompiler object; 
 102         # We do this late, and only on-demand, because this is an expensive 
 104         from distutils
.ccompiler 
import CCompiler
, new_compiler
 
 105         if not isinstance(self
.compiler
, CCompiler
): 
 106             self
.compiler 
= new_compiler(compiler
=self
.compiler
, 
 107                                          dry_run
=self
.dry_run
, force
=1) 
 108             customize_compiler(self
.compiler
) 
 109             if self
.include_dirs
: 
 110                 self
.compiler
.set_include_dirs(self
.include_dirs
) 
 112                 self
.compiler
.set_libraries(self
.libraries
) 
 113             if self
.library_dirs
: 
 114                 self
.compiler
.set_library_dirs(self
.library_dirs
) 
 117     def _gen_temp_sourcefile (self
, body
, headers
, lang
): 
 118         filename 
= "_configtest" + LANG_EXT
[lang
] 
 119         file = open(filename
, "w") 
 121             for header 
in headers
: 
 122                 file.write("#include <%s>\n" % header
) 
 130     def _preprocess (self
, body
, headers
, include_dirs
, lang
): 
 131         src 
= self
._gen
_temp
_sourcefile
(body
, headers
, lang
) 
 132         out 
= "_configtest.i" 
 133         self
.temp_files
.extend([src
, out
]) 
 134         self
.compiler
.preprocess(src
, out
, include_dirs
=include_dirs
) 
 137     def _compile (self
, body
, headers
, include_dirs
, lang
): 
 138         src 
= self
._gen
_temp
_sourcefile
(body
, headers
, lang
) 
 140             dump_file(src
, "compiling '%s':" % src
) 
 141         (obj
,) = self
.compiler
.object_filenames([src
]) 
 142         self
.temp_files
.extend([src
, obj
]) 
 143         self
.compiler
.compile([src
], include_dirs
=include_dirs
) 
 146     def _link (self
, body
, 
 147                headers
, include_dirs
, 
 148                libraries
, library_dirs
, lang
): 
 149         (src
, obj
) = self
._compile
(body
, headers
, include_dirs
, lang
) 
 150         prog 
= os
.path
.splitext(os
.path
.basename(src
))[0] 
 151         self
.compiler
.link_executable([obj
], prog
, 
 153                                       library_dirs
=library_dirs
, 
 156         if self
.compiler
.exe_extension 
is not None: 
 157             prog 
= prog 
+ self
.compiler
.exe_extension
 
 158         self
.temp_files
.append(prog
) 
 160         return (src
, obj
, prog
) 
 162     def _clean (self
, *filenames
): 
 164             filenames 
= self
.temp_files
 
 166         log
.info("removing: %s", string
.join(filenames
)) 
 167         for filename 
in filenames
: 
 174     # XXX these ignore the dry-run flag: what to do, what to do? even if 
 175     # you want a dry-run build, you still need some sort of configuration 
 176     # info.  My inclination is to make it up to the real config command to 
 177     # consult 'dry_run', and assume a default (minimal) configuration if 
 178     # true.  The problem with trying to do it here is that you'd have to 
 179     # return either true or false from all the 'try' methods, neither of 
 182     # XXX need access to the header search path and maybe default macros. 
 184     def try_cpp (self
, body
=None, headers
=None, include_dirs
=None, lang
="c"): 
 185         """Construct a source file from 'body' (a string containing lines 
 186         of C/C++ code) and 'headers' (a list of header files to include) 
 187         and run it through the preprocessor.  Return true if the 
 188         preprocessor succeeded, false if there were any errors. 
 189         ('body' probably isn't of much use, but what the heck.) 
 191         from distutils
.ccompiler 
import CompileError
 
 192         self
._check
_compiler
() 
 195             self
._preprocess
(body
, headers
, include_dirs
, lang
) 
 202     def search_cpp (self
, pattern
, body
=None, 
 203                     headers
=None, include_dirs
=None, lang
="c"): 
 204         """Construct a source file (just like 'try_cpp()'), run it through 
 205         the preprocessor, and return true if any line of the output matches 
 206         'pattern'.  'pattern' should either be a compiled regex object or a 
 207         string containing a regex.  If both 'body' and 'headers' are None, 
 208         preprocesses an empty file -- which can be useful to determine the 
 209         symbols the preprocessor and compiler set by default. 
 212         self
._check
_compiler
() 
 213         (src
, out
) = self
._preprocess
(body
, headers
, include_dirs
, lang
) 
 215         if type(pattern
) is StringType
: 
 216             pattern 
= re
.compile(pattern
) 
 221             line 
= file.readline() 
 224             if pattern
.search(line
): 
 232     def try_compile (self
, body
, headers
=None, include_dirs
=None, lang
="c"): 
 233         """Try to compile a source file built from 'body' and 'headers'. 
 234         Return true on success, false otherwise. 
 236         from distutils
.ccompiler 
import CompileError
 
 237         self
._check
_compiler
() 
 239             self
._compile
(body
, headers
, include_dirs
, lang
) 
 244         log
.info(ok 
and "success!" or "failure.") 
 248     def try_link (self
, body
, 
 249                   headers
=None, include_dirs
=None, 
 250                   libraries
=None, library_dirs
=None, 
 252         """Try to compile and link a source file, built from 'body' and 
 253         'headers', to executable form.  Return true on success, false 
 256         from distutils
.ccompiler 
import CompileError
, LinkError
 
 257         self
._check
_compiler
() 
 259             self
._link
(body
, headers
, include_dirs
, 
 260                        libraries
, library_dirs
, lang
) 
 262         except (CompileError
, LinkError
): 
 265         log
.info(ok 
and "success!" or "failure.") 
 269     def try_run (self
, body
, 
 270                  headers
=None, include_dirs
=None, 
 271                  libraries
=None, library_dirs
=None, 
 273         """Try to compile, link to an executable, and run a program 
 274         built from 'body' and 'headers'.  Return true on success, false 
 277         from distutils
.ccompiler 
import CompileError
, LinkError
 
 278         self
._check
_compiler
() 
 280             src
, obj
, exe 
= self
._link
(body
, headers
, include_dirs
, 
 281                                        libraries
, library_dirs
, lang
) 
 284         except (CompileError
, LinkError
, DistutilsExecError
): 
 287         log
.info(ok 
and "success!" or "failure.") 
 292     # -- High-level methods -------------------------------------------- 
 293     # (these are the ones that are actually likely to be useful 
 294     # when implementing a real-world config command!) 
 296     def check_func (self
, func
, 
 297                     headers
=None, include_dirs
=None, 
 298                     libraries
=None, library_dirs
=None, 
 301         """Determine if function 'func' is available by constructing a 
 302         source file that refers to 'func', and compiles and links it. 
 303         If everything succeeds, returns true; otherwise returns false. 
 305         The constructed source file starts out by including the header 
 306         files listed in 'headers'.  If 'decl' is true, it then declares 
 307         'func' (as "int func()"); you probably shouldn't supply 'headers' 
 308         and set 'decl' true in the same call, or you might get errors about 
 309         a conflicting declarations for 'func'.  Finally, the constructed 
 310         'main()' function either references 'func' or (if 'call' is true) 
 311         calls it.  'libraries' and 'library_dirs' are used when 
 315         self
._check
_compiler
() 
 318             body
.append("int %s ();" % func
) 
 319         body
.append("int main () {") 
 321             body
.append("  %s();" % func
) 
 323             body
.append("  %s;" % func
) 
 325         body 
= string
.join(body
, "\n") + "\n" 
 327         return self
.try_link(body
, headers
, include_dirs
, 
 328                              libraries
, library_dirs
) 
 332     def check_lib (self
, library
, library_dirs
=None, 
 333                    headers
=None, include_dirs
=None, other_libraries
=[]): 
 334         """Determine if 'library' is available to be linked against, 
 335         without actually checking that any particular symbols are provided 
 336         by it.  'headers' will be used in constructing the source file to 
 337         be compiled, but the only effect of this is to check if all the 
 338         header files listed are available.  Any libraries listed in 
 339         'other_libraries' will be included in the link, in case 'library' 
 340         has symbols that depend on other libraries. 
 342         self
._check
_compiler
() 
 343         return self
.try_link("int main (void) { }", 
 344                              headers
, include_dirs
, 
 345                              [library
]+other_libraries
, library_dirs
) 
 347     def check_header (self
, header
, include_dirs
=None, 
 348                       library_dirs
=None, lang
="c"): 
 349         """Determine if the system header file named by 'header_file' 
 350         exists and can be found by the preprocessor; return true if so, 
 353         return self
.try_cpp(body
="/* No body */", headers
=[header
], 
 354                             include_dirs
=include_dirs
) 
 360 def dump_file (filename
, head
=None): 
 366     file = open(filename
) 
 367     sys
.stdout
.write(file.read())