python-2.5.2/win32/Lib/distutils/command/config.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """distutils.command.config
       
     2 
       
     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".
       
    10 """
       
    11 
       
    12 # This module should be kept compatible with Python 2.1.
       
    13 
       
    14 __revision__ = "$Id: config.py 37828 2004-11-10 22:23:15Z loewis $"
       
    15 
       
    16 import sys, os, string, re
       
    17 from types import *
       
    18 from distutils.core import Command
       
    19 from distutils.errors import DistutilsExecError
       
    20 from distutils.sysconfig import customize_compiler
       
    21 from distutils import log
       
    22 
       
    23 LANG_EXT = {'c': '.c',
       
    24             'c++': '.cxx'}
       
    25 
       
    26 class config (Command):
       
    27 
       
    28     description = "prepare to build"
       
    29 
       
    30     user_options = [
       
    31         ('compiler=', None,
       
    32          "specify the compiler type"),
       
    33         ('cc=', None,
       
    34          "specify the compiler executable"),
       
    35         ('include-dirs=', 'I',
       
    36          "list of directories to search for header files"),
       
    37         ('define=', 'D',
       
    38          "C preprocessor macros to define"),
       
    39         ('undef=', 'U',
       
    40          "C preprocessor macros to undefine"),
       
    41         ('libraries=', 'l',
       
    42          "external C libraries to link with"),
       
    43         ('library-dirs=', 'L',
       
    44          "directories to search for external C libraries"),
       
    45 
       
    46         ('noisy', None,
       
    47          "show every action (compile, link, run, ...) taken"),
       
    48         ('dump-source', None,
       
    49          "dump generated source files before attempting to compile them"),
       
    50         ]
       
    51 
       
    52 
       
    53     # The three standard command methods: since the "config" command
       
    54     # does nothing by default, these are empty.
       
    55 
       
    56     def initialize_options (self):
       
    57         self.compiler = None
       
    58         self.cc = None
       
    59         self.include_dirs = None
       
    60         #self.define = None
       
    61         #self.undef = None
       
    62         self.libraries = None
       
    63         self.library_dirs = None
       
    64 
       
    65         # maximal output for now
       
    66         self.noisy = 1
       
    67         self.dump_source = 1
       
    68 
       
    69         # list of temporary files generated along-the-way that we have
       
    70         # to clean at some point
       
    71         self.temp_files = []
       
    72 
       
    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)
       
    78 
       
    79         if self.libraries is None:
       
    80             self.libraries = []
       
    81         elif type(self.libraries) is StringType:
       
    82             self.libraries = [self.libraries]
       
    83 
       
    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)
       
    88 
       
    89 
       
    90     def run (self):
       
    91         pass
       
    92 
       
    93 
       
    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.
       
    97 
       
    98     def _check_compiler (self):
       
    99         """Check that 'self.compiler' really is a CCompiler object;
       
   100         if not, make it one.
       
   101         """
       
   102         # We do this late, and only on-demand, because this is an expensive
       
   103         # import.
       
   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)
       
   111             if self.libraries:
       
   112                 self.compiler.set_libraries(self.libraries)
       
   113             if self.library_dirs:
       
   114                 self.compiler.set_library_dirs(self.library_dirs)
       
   115 
       
   116 
       
   117     def _gen_temp_sourcefile (self, body, headers, lang):
       
   118         filename = "_configtest" + LANG_EXT[lang]
       
   119         file = open(filename, "w")
       
   120         if headers:
       
   121             for header in headers:
       
   122                 file.write("#include <%s>\n" % header)
       
   123             file.write("\n")
       
   124         file.write(body)
       
   125         if body[-1] != "\n":
       
   126             file.write("\n")
       
   127         file.close()
       
   128         return filename
       
   129 
       
   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)
       
   135         return (src, out)
       
   136 
       
   137     def _compile (self, body, headers, include_dirs, lang):
       
   138         src = self._gen_temp_sourcefile(body, headers, lang)
       
   139         if self.dump_source:
       
   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)
       
   144         return (src, obj)
       
   145 
       
   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,
       
   152                                       libraries=libraries,
       
   153                                       library_dirs=library_dirs,
       
   154                                       target_lang=lang)
       
   155 
       
   156         if self.compiler.exe_extension is not None:
       
   157             prog = prog + self.compiler.exe_extension
       
   158         self.temp_files.append(prog)
       
   159 
       
   160         return (src, obj, prog)
       
   161 
       
   162     def _clean (self, *filenames):
       
   163         if not filenames:
       
   164             filenames = self.temp_files
       
   165             self.temp_files = []
       
   166         log.info("removing: %s", string.join(filenames))
       
   167         for filename in filenames:
       
   168             try:
       
   169                 os.remove(filename)
       
   170             except OSError:
       
   171                 pass
       
   172 
       
   173 
       
   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
       
   180     # which is correct.
       
   181 
       
   182     # XXX need access to the header search path and maybe default macros.
       
   183 
       
   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.)
       
   190         """
       
   191         from distutils.ccompiler import CompileError
       
   192         self._check_compiler()
       
   193         ok = 1
       
   194         try:
       
   195             self._preprocess(body, headers, include_dirs, lang)
       
   196         except CompileError:
       
   197             ok = 0
       
   198 
       
   199         self._clean()
       
   200         return ok
       
   201 
       
   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.
       
   210         """
       
   211 
       
   212         self._check_compiler()
       
   213         (src, out) = self._preprocess(body, headers, include_dirs, lang)
       
   214 
       
   215         if type(pattern) is StringType:
       
   216             pattern = re.compile(pattern)
       
   217 
       
   218         file = open(out)
       
   219         match = 0
       
   220         while 1:
       
   221             line = file.readline()
       
   222             if line == '':
       
   223                 break
       
   224             if pattern.search(line):
       
   225                 match = 1
       
   226                 break
       
   227 
       
   228         file.close()
       
   229         self._clean()
       
   230         return match
       
   231 
       
   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.
       
   235         """
       
   236         from distutils.ccompiler import CompileError
       
   237         self._check_compiler()
       
   238         try:
       
   239             self._compile(body, headers, include_dirs, lang)
       
   240             ok = 1
       
   241         except CompileError:
       
   242             ok = 0
       
   243 
       
   244         log.info(ok and "success!" or "failure.")
       
   245         self._clean()
       
   246         return ok
       
   247 
       
   248     def try_link (self, body,
       
   249                   headers=None, include_dirs=None,
       
   250                   libraries=None, library_dirs=None,
       
   251                   lang="c"):
       
   252         """Try to compile and link a source file, built from 'body' and
       
   253         'headers', to executable form.  Return true on success, false
       
   254         otherwise.
       
   255         """
       
   256         from distutils.ccompiler import CompileError, LinkError
       
   257         self._check_compiler()
       
   258         try:
       
   259             self._link(body, headers, include_dirs,
       
   260                        libraries, library_dirs, lang)
       
   261             ok = 1
       
   262         except (CompileError, LinkError):
       
   263             ok = 0
       
   264 
       
   265         log.info(ok and "success!" or "failure.")
       
   266         self._clean()
       
   267         return ok
       
   268 
       
   269     def try_run (self, body,
       
   270                  headers=None, include_dirs=None,
       
   271                  libraries=None, library_dirs=None,
       
   272                  lang="c"):
       
   273         """Try to compile, link to an executable, and run a program
       
   274         built from 'body' and 'headers'.  Return true on success, false
       
   275         otherwise.
       
   276         """
       
   277         from distutils.ccompiler import CompileError, LinkError
       
   278         self._check_compiler()
       
   279         try:
       
   280             src, obj, exe = self._link(body, headers, include_dirs,
       
   281                                        libraries, library_dirs, lang)
       
   282             self.spawn([exe])
       
   283             ok = 1
       
   284         except (CompileError, LinkError, DistutilsExecError):
       
   285             ok = 0
       
   286 
       
   287         log.info(ok and "success!" or "failure.")
       
   288         self._clean()
       
   289         return ok
       
   290 
       
   291 
       
   292     # -- High-level methods --------------------------------------------
       
   293     # (these are the ones that are actually likely to be useful
       
   294     # when implementing a real-world config command!)
       
   295 
       
   296     def check_func (self, func,
       
   297                     headers=None, include_dirs=None,
       
   298                     libraries=None, library_dirs=None,
       
   299                     decl=0, call=0):
       
   300 
       
   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.
       
   304 
       
   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
       
   312         linking.
       
   313         """
       
   314 
       
   315         self._check_compiler()
       
   316         body = []
       
   317         if decl:
       
   318             body.append("int %s ();" % func)
       
   319         body.append("int main () {")
       
   320         if call:
       
   321             body.append("  %s();" % func)
       
   322         else:
       
   323             body.append("  %s;" % func)
       
   324         body.append("}")
       
   325         body = string.join(body, "\n") + "\n"
       
   326 
       
   327         return self.try_link(body, headers, include_dirs,
       
   328                              libraries, library_dirs)
       
   329 
       
   330     # check_func ()
       
   331 
       
   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.
       
   341         """
       
   342         self._check_compiler()
       
   343         return self.try_link("int main (void) { }",
       
   344                              headers, include_dirs,
       
   345                              [library]+other_libraries, library_dirs)
       
   346 
       
   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,
       
   351         false otherwise.
       
   352         """
       
   353         return self.try_cpp(body="/* No body */", headers=[header],
       
   354                             include_dirs=include_dirs)
       
   355 
       
   356 
       
   357 # class config
       
   358 
       
   359 
       
   360 def dump_file (filename, head=None):
       
   361     if head is None:
       
   362         print filename + ":"
       
   363     else:
       
   364         print head
       
   365 
       
   366     file = open(filename)
       
   367     sys.stdout.write(file.read())
       
   368     file.close()