| """distutils.command.config | 
 |  | 
 | Implements the Distutils 'config' command, a (mostly) empty command class | 
 | that exists mainly to be sub-classed by specific module distributions and | 
 | applications.  The idea is that while every "config" command is different, | 
 | at least they're all named the same, and users always see "config" in the | 
 | list of standard commands.  Also, this is a good place to put common | 
 | configure-like tasks: "try to compile this C code", or "figure out where | 
 | this header file lives". | 
 | """ | 
 |  | 
 | # created 2000/05/29, Greg Ward | 
 |  | 
 | __revision__ = "$Id$" | 
 |  | 
 | import os, string | 
 | from distutils.core import Command | 
 | from distutils.errors import DistutilsExecError | 
 |  | 
 |  | 
 | LANG_EXT = {'c': '.c', | 
 |             'c++': '.cxx'} | 
 |  | 
 | class config (Command): | 
 |  | 
 |     description = "prepare to build" | 
 |  | 
 |     user_options = [ | 
 |         ('compiler=', None, | 
 |          "specify the compiler type"), | 
 |         ('cc=', None, | 
 |          "specify the compiler executable"), | 
 |         ('include-dirs=', 'I', | 
 |          "list of directories to search for header files"), | 
 |         ('define=', 'D', | 
 |          "C preprocessor macros to define"), | 
 |         ('undef=', 'U', | 
 |          "C preprocessor macros to undefine"), | 
 |         ('libraries=', 'l', | 
 |          "external C libraries to link with"), | 
 |         ('library-dirs=', 'L', | 
 |          "directories to search for external C libraries"), | 
 |         ] | 
 |  | 
 |  | 
 |     # The three standard command methods: since the "config" command | 
 |     # does nothing by default, these are empty. | 
 |  | 
 |     def initialize_options (self): | 
 |         self.compiler = None | 
 |         self.cc = None | 
 |         self.include_dirs = None | 
 |         #self.define = None | 
 |         #self.undef = None | 
 |         self.libraries = None | 
 |         self.library_dirs = None | 
 |  | 
 |     def finalize_options (self): | 
 |         pass | 
 |  | 
 |     def run (self): | 
 |         pass | 
 |  | 
 |  | 
 |     # Utility methods for actual "config" commands.  The interfaces are | 
 |     # loosely based on Autoconf macros of similar names.  Sub-classes | 
 |     # may use these freely. | 
 |  | 
 |     def _check_compiler (self): | 
 |         """Check that 'self.compiler' really is a CCompiler object; | 
 |         if not, make it one. | 
 |         """ | 
 |         # We do this late, and only on-demand, because this is an expensive | 
 |         # import. | 
 |         from distutils.ccompiler import CCompiler, new_compiler | 
 |         if not isinstance(self.compiler, CCompiler): | 
 |             self.compiler = new_compiler (compiler=self.compiler, | 
 |                                           verbose=self.verbose, # for now | 
 |                                           dry_run=self.dry_run, | 
 |                                           force=1) | 
 |             if self.include_dirs: | 
 |                 self.compiler.set_include_dirs(self.include_dirs) | 
 |             if self.libraries: | 
 |                 self.compiler.set_libraries(self.libraries) | 
 |             if self.library_dirs: | 
 |                 self.compiler.set_library_dirs(self.library_dirs) | 
 |  | 
 |  | 
 |     def _gen_temp_sourcefile (self, body, lang): | 
 |         filename = "_configtest" + LANG_EXT[lang] | 
 |         file = open(filename, "w") | 
 |         file.write(body) | 
 |         file.close() | 
 |         return filename | 
 |  | 
 |     def _compile (self, body, lang): | 
 |         src = self._gen_temp_sourcefile(body, lang) | 
 |         (obj,) = self.compiler.compile([src]) | 
 |         return (src, obj) | 
 |  | 
 |     def _link (self, body, lang): | 
 |         (src, obj) = self._compile(body, lang) | 
 |         exe = os.path.splitext(os.path.basename(src))[0] | 
 |         self.compiler.link_executable([obj], exe) | 
 |         return (src, obj, exe) | 
 |  | 
 |     def _clean (self, *filenames): | 
 |         self.announce("removing: " + string.join(filenames)) | 
 |         for filename in filenames: | 
 |             try: | 
 |                 os.remove(filename) | 
 |             except OSError: | 
 |                 pass | 
 |  | 
 |  | 
 |     # XXX no 'try_cpp()' or 'search_cpp()' since the CCompiler interface | 
 |     # does not provide access to the preprocessor.  This is an oversight | 
 |     # that should be fixed. | 
 |  | 
 |     # XXX these ignore the dry-run flag: what to do, what to do? even if | 
 |     # you want a dry-run build, you still need some sort of configuration | 
 |     # info.  My inclination is to make it up to the real config command to | 
 |     # consult 'dry_run', and assume a default (minimal) configuration if | 
 |     # true.  The problem with trying to do it here is that you'd have to | 
 |     # return either true or false from all the 'try' methods, neither of | 
 |     # which is correct. | 
 |  | 
 |     def try_compile (self, body, lang="c"): | 
 |         """Try to compile a source file that consists of the text in 'body' | 
 |         (a multi-line string).  Return true on success, false | 
 |         otherwise. | 
 |         """ | 
 |         from distutils.ccompiler import CompileError | 
 |         self._check_compiler() | 
 |         try: | 
 |             (src, obj) = self._compile(body, lang) | 
 |             ok = 1 | 
 |         except CompileError: | 
 |             ok = 0 | 
 |  | 
 |         self.announce(ok and "success!" or "failure.") | 
 |         self._clean(src, obj) | 
 |         return ok | 
 |  | 
 |     def try_link (self, body, lang="c"): | 
 |         """Try to compile and link a source file (to an executable) that | 
 |         consists of the text in 'body' (a multi-line string).  Return true | 
 |         on success, false otherwise. | 
 |         """ | 
 |         from distutils.ccompiler import CompileError, LinkError | 
 |         self._check_compiler() | 
 |         try: | 
 |             (src, obj, exe) = self._link(body, lang) | 
 |             ok = 1 | 
 |         except (CompileError, LinkError): | 
 |             ok = 0 | 
 |  | 
 |         self.announce(ok and "success!" or "failure.") | 
 |         self._clean(src, obj, exe) | 
 |         return ok | 
 |              | 
 |     def try_run (self, body, lang="c"): | 
 |         """Try to compile, link to an executable, and run a program that | 
 |         consists of the text in 'body'.  Return true on success, false | 
 |         otherwise. | 
 |         """ | 
 |         from distutils.ccompiler import CompileError, LinkError | 
 |         self._check_compiler() | 
 |         try: | 
 |             (src, obj, exe) = self._link(body, lang) | 
 |             self.spawn([exe]) | 
 |             ok = 1 | 
 |         except (CompileError, LinkError, DistutilsExecError): | 
 |             ok = 0 | 
 |  | 
 |         self.announce(ok and "success!" or "failure.") | 
 |         self._clean(src, obj, exe) | 
 |         return ok | 
 |  | 
 | # class config |