diff options
author | Greg Ward <gward@python.net> | 2000-06-06 02:57:07 (GMT) |
---|---|---|
committer | Greg Ward <gward@python.net> | 2000-06-06 02:57:07 (GMT) |
commit | 28a5f44cca9c5f6abe319f3a446bf057d66e980e (patch) | |
tree | 726ce055eaf74936c473dbb014b43f2514b8aff1 /Lib | |
parent | 43955c9a023ea7b50b28052112dbdc914c090a27 (diff) | |
download | cpython-28a5f44cca9c5f6abe319f3a446bf057d66e980e.zip cpython-28a5f44cca9c5f6abe319f3a446bf057d66e980e.tar.gz cpython-28a5f44cca9c5f6abe319f3a446bf057d66e980e.tar.bz2 |
First crack at the Distutils "config" command. Unlike other commands, this
one doesn't *do* anything by default; it's just there as a conduit for data
(eg. include dirs, libraries) from the user to the "build" commands.
However, it provides a couple of Autoconf-ish methods ('try_compile()',
'try_link()', 'try_run()') that derived, per-distribution "config" commands
can use to poke around the target system and see what's available.
Initial experimenst with mxDateTime indicate that higher-level methods are
necessary: analogs of Autoconf's AC_CHECK_HEADER, AC_CHECK_LIB will be
needed too (and that's just to probe the C/C++ system: how to probe the
Python system is wide open, and someday we'll have to worry about probing a
Java system too).
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/distutils/command/config.py | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/Lib/distutils/command/config.py b/Lib/distutils/command/config.py new file mode 100644 index 0000000..cad75bc --- /dev/null +++ b/Lib/distutils/command/config.py @@ -0,0 +1,180 @@ +"""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 |