PyXR

c:\python24\lib \ distutils \ command \ config.py



0001 """distutils.command.config
0002 
0003 Implements the Distutils 'config' command, a (mostly) empty command class
0004 that exists mainly to be sub-classed by specific module distributions and
0005 applications.  The idea is that while every "config" command is different,
0006 at least they're all named the same, and users always see "config" in the
0007 list of standard commands.  Also, this is a good place to put common
0008 configure-like tasks: "try to compile this C code", or "figure out where
0009 this header file lives".
0010 """
0011 
0012 # This module should be kept compatible with Python 1.5.2.
0013 
0014 __revision__ = "$Id: config.py,v 1.17 2003/02/18 01:28:51 akuchling Exp $"
0015 
0016 import sys, os, string, re
0017 from types import *
0018 from distutils.core import Command
0019 from distutils.errors import DistutilsExecError
0020 from distutils.sysconfig import customize_compiler
0021 from distutils import log
0022 
0023 LANG_EXT = {'c': '.c',
0024             'c++': '.cxx'}
0025 
0026 class config (Command):
0027 
0028     description = "prepare to build"
0029 
0030     user_options = [
0031         ('compiler=', None,
0032          "specify the compiler type"),
0033         ('cc=', None,
0034          "specify the compiler executable"),
0035         ('include-dirs=', 'I',
0036          "list of directories to search for header files"),
0037         ('define=', 'D',
0038          "C preprocessor macros to define"),
0039         ('undef=', 'U',
0040          "C preprocessor macros to undefine"),
0041         ('libraries=', 'l',
0042          "external C libraries to link with"),
0043         ('library-dirs=', 'L',
0044          "directories to search for external C libraries"),
0045 
0046         ('noisy', None,
0047          "show every action (compile, link, run, ...) taken"),
0048         ('dump-source', None,
0049          "dump generated source files before attempting to compile them"),
0050         ]
0051 
0052 
0053     # The three standard command methods: since the "config" command
0054     # does nothing by default, these are empty.
0055 
0056     def initialize_options (self):
0057         self.compiler = None
0058         self.cc = None
0059         self.include_dirs = None
0060         #self.define = None
0061         #self.undef = None
0062         self.libraries = None
0063         self.library_dirs = None
0064 
0065         # maximal output for now
0066         self.noisy = 1
0067         self.dump_source = 1
0068 
0069         # list of temporary files generated along-the-way that we have
0070         # to clean at some point
0071         self.temp_files = []
0072 
0073     def finalize_options (self):
0074         if self.include_dirs is None:
0075             self.include_dirs = self.distribution.include_dirs or []
0076         elif type(self.include_dirs) is StringType:
0077             self.include_dirs = string.split(self.include_dirs, os.pathsep)
0078 
0079         if self.libraries is None:
0080             self.libraries = []
0081         elif type(self.libraries) is StringType:
0082             self.libraries = [self.libraries]
0083 
0084         if self.library_dirs is None:
0085             self.library_dirs = []
0086         elif type(self.library_dirs) is StringType:
0087             self.library_dirs = string.split(self.library_dirs, os.pathsep)
0088 
0089 
0090     def run (self):
0091         pass
0092 
0093 
0094     # Utility methods for actual "config" commands.  The interfaces are
0095     # loosely based on Autoconf macros of similar names.  Sub-classes
0096     # may use these freely.
0097 
0098     def _check_compiler (self):
0099         """Check that 'self.compiler' really is a CCompiler object;
0100         if not, make it one.
0101         """
0102         # We do this late, and only on-demand, because this is an expensive
0103         # import.
0104         from distutils.ccompiler import CCompiler, new_compiler
0105         if not isinstance(self.compiler, CCompiler):
0106             self.compiler = new_compiler(compiler=self.compiler,
0107                                          dry_run=self.dry_run, force=1)
0108             customize_compiler(self.compiler)
0109             if self.include_dirs:
0110                 self.compiler.set_include_dirs(self.include_dirs)
0111             if self.libraries:
0112                 self.compiler.set_libraries(self.libraries)
0113             if self.library_dirs:
0114                 self.compiler.set_library_dirs(self.library_dirs)
0115 
0116 
0117     def _gen_temp_sourcefile (self, body, headers, lang):
0118         filename = "_configtest" + LANG_EXT[lang]
0119         file = open(filename, "w")
0120         if headers:
0121             for header in headers:
0122                 file.write("#include <%s>\n" % header)
0123             file.write("\n")
0124         file.write(body)
0125         if body[-1] != "\n":
0126             file.write("\n")
0127         file.close()
0128         return filename
0129 
0130     def _preprocess (self, body, headers, include_dirs, lang):
0131         src = self._gen_temp_sourcefile(body, headers, lang)
0132         out = "_configtest.i"
0133         self.temp_files.extend([src, out])
0134         self.compiler.preprocess(src, out, include_dirs=include_dirs)
0135         return (src, out)
0136 
0137     def _compile (self, body, headers, include_dirs, lang):
0138         src = self._gen_temp_sourcefile(body, headers, lang)
0139         if self.dump_source:
0140             dump_file(src, "compiling '%s':" % src)
0141         (obj,) = self.compiler.object_filenames([src])
0142         self.temp_files.extend([src, obj])
0143         self.compiler.compile([src], include_dirs=include_dirs)
0144         return (src, obj)
0145 
0146     def _link (self, body,
0147                headers, include_dirs,
0148                libraries, library_dirs, lang):
0149         (src, obj) = self._compile(body, headers, include_dirs, lang)
0150         prog = os.path.splitext(os.path.basename(src))[0]
0151         self.compiler.link_executable([obj], prog,
0152                                       libraries=libraries,
0153                                       library_dirs=library_dirs,
0154                                       target_lang=lang)
0155 
0156         if self.compiler.exe_extension is not None:
0157             prog = prog + self.compiler.exe_extension
0158         self.temp_files.append(prog)
0159 
0160         return (src, obj, prog)
0161 
0162     def _clean (self, *filenames):
0163         if not filenames:
0164             filenames = self.temp_files
0165             self.temp_files = []
0166         log.info("removing: %s", string.join(filenames))
0167         for filename in filenames:
0168             try:
0169                 os.remove(filename)
0170             except OSError:
0171                 pass
0172 
0173 
0174     # XXX these ignore the dry-run flag: what to do, what to do? even if
0175     # you want a dry-run build, you still need some sort of configuration
0176     # info.  My inclination is to make it up to the real config command to
0177     # consult 'dry_run', and assume a default (minimal) configuration if
0178     # true.  The problem with trying to do it here is that you'd have to
0179     # return either true or false from all the 'try' methods, neither of
0180     # which is correct.
0181 
0182     # XXX need access to the header search path and maybe default macros.
0183 
0184     def try_cpp (self, body=None, headers=None, include_dirs=None, lang="c"):
0185         """Construct a source file from 'body' (a string containing lines
0186         of C/C++ code) and 'headers' (a list of header files to include)
0187         and run it through the preprocessor.  Return true if the
0188         preprocessor succeeded, false if there were any errors.
0189         ('body' probably isn't of much use, but what the heck.)
0190         """
0191         from distutils.ccompiler import CompileError
0192         self._check_compiler()
0193         ok = 1
0194         try:
0195             self._preprocess(body, headers, include_dirs, lang)
0196         except CompileError:
0197             ok = 0
0198 
0199         self._clean()
0200         return ok
0201 
0202     def search_cpp (self, pattern, body=None,
0203                     headers=None, include_dirs=None, lang="c"):
0204         """Construct a source file (just like 'try_cpp()'), run it through
0205         the preprocessor, and return true if any line of the output matches
0206         'pattern'.  'pattern' should either be a compiled regex object or a
0207         string containing a regex.  If both 'body' and 'headers' are None,
0208         preprocesses an empty file -- which can be useful to determine the
0209         symbols the preprocessor and compiler set by default.
0210         """
0211 
0212         self._check_compiler()
0213         (src, out) = self._preprocess(body, headers, include_dirs, lang)
0214 
0215         if type(pattern) is StringType:
0216             pattern = re.compile(pattern)
0217 
0218         file = open(out)
0219         match = 0
0220         while 1:
0221             line = file.readline()
0222             if line == '':
0223                 break
0224             if pattern.search(line):
0225                 match = 1
0226                 break
0227 
0228         file.close()
0229         self._clean()
0230         return match
0231 
0232     def try_compile (self, body, headers=None, include_dirs=None, lang="c"):
0233         """Try to compile a source file built from 'body' and 'headers'.
0234         Return true on success, false otherwise.
0235         """
0236         from distutils.ccompiler import CompileError
0237         self._check_compiler()
0238         try:
0239             self._compile(body, headers, include_dirs, lang)
0240             ok = 1
0241         except CompileError:
0242             ok = 0
0243 
0244         log.info(ok and "success!" or "failure.")
0245         self._clean()
0246         return ok
0247 
0248     def try_link (self, body,
0249                   headers=None, include_dirs=None,
0250                   libraries=None, library_dirs=None,
0251                   lang="c"):
0252         """Try to compile and link a source file, built from 'body' and
0253         'headers', to executable form.  Return true on success, false
0254         otherwise.
0255         """
0256         from distutils.ccompiler import CompileError, LinkError
0257         self._check_compiler()
0258         try:
0259             self._link(body, headers, include_dirs,
0260                        libraries, library_dirs, lang)
0261             ok = 1
0262         except (CompileError, LinkError):
0263             ok = 0
0264 
0265         log.info(ok and "success!" or "failure.")
0266         self._clean()
0267         return ok
0268 
0269     def try_run (self, body,
0270                  headers=None, include_dirs=None,
0271                  libraries=None, library_dirs=None,
0272                  lang="c"):
0273         """Try to compile, link to an executable, and run a program
0274         built from 'body' and 'headers'.  Return true on success, false
0275         otherwise.
0276         """
0277         from distutils.ccompiler import CompileError, LinkError
0278         self._check_compiler()
0279         try:
0280             src, obj, exe = self._link(body, headers, include_dirs,
0281                                        libraries, library_dirs, lang)
0282             self.spawn([exe])
0283             ok = 1
0284         except (CompileError, LinkError, DistutilsExecError):
0285             ok = 0
0286 
0287         log.info(ok and "success!" or "failure.")
0288         self._clean()
0289         return ok
0290 
0291 
0292     # -- High-level methods --------------------------------------------
0293     # (these are the ones that are actually likely to be useful
0294     # when implementing a real-world config command!)
0295 
0296     def check_func (self, func,
0297                     headers=None, include_dirs=None,
0298                     libraries=None, library_dirs=None,
0299                     decl=0, call=0):
0300 
0301         """Determine if function 'func' is available by constructing a
0302         source file that refers to 'func', and compiles and links it.
0303         If everything succeeds, returns true; otherwise returns false.
0304 
0305         The constructed source file starts out by including the header
0306         files listed in 'headers'.  If 'decl' is true, it then declares
0307         'func' (as "int func()"); you probably shouldn't supply 'headers'
0308         and set 'decl' true in the same call, or you might get errors about
0309         a conflicting declarations for 'func'.  Finally, the constructed
0310         'main()' function either references 'func' or (if 'call' is true)
0311         calls it.  'libraries' and 'library_dirs' are used when
0312         linking.
0313         """
0314 
0315         self._check_compiler()
0316         body = []
0317         if decl:
0318             body.append("int %s ();" % func)
0319         body.append("int main () {")
0320         if call:
0321             body.append("  %s();" % func)
0322         else:
0323             body.append("  %s;" % func)
0324         body.append("}")
0325         body = string.join(body, "\n") + "\n"
0326 
0327         return self.try_link(body, headers, include_dirs,
0328                              libraries, library_dirs)
0329 
0330     # check_func ()
0331 
0332     def check_lib (self, library, library_dirs=None,
0333                    headers=None, include_dirs=None, other_libraries=[]):
0334         """Determine if 'library' is available to be linked against,
0335         without actually checking that any particular symbols are provided
0336         by it.  'headers' will be used in constructing the source file to
0337         be compiled, but the only effect of this is to check if all the
0338         header files listed are available.  Any libraries listed in
0339         'other_libraries' will be included in the link, in case 'library'
0340         has symbols that depend on other libraries.
0341         """
0342         self._check_compiler()
0343         return self.try_link("int main (void) { }",
0344                              headers, include_dirs,
0345                              [library]+other_libraries, library_dirs)
0346 
0347     def check_header (self, header, include_dirs=None,
0348                       library_dirs=None, lang="c"):
0349         """Determine if the system header file named by 'header_file'
0350         exists and can be found by the preprocessor; return true if so,
0351         false otherwise.
0352         """
0353         return self.try_cpp(body="/* No body */", headers=[header],
0354                             include_dirs=include_dirs)
0355 
0356 
0357 # class config
0358 
0359 
0360 def dump_file (filename, head=None):
0361     if head is None:
0362         print filename + ":"
0363     else:
0364         print head
0365 
0366     file = open(filename)
0367     sys.stdout.write(file.read())
0368     file.close()
0369 

Generated by PyXR 0.9.4
SourceForge.net Logo