summaryrefslogtreecommitdiffstats
path: root/Lib/distutils/command/config.py
diff options
context:
space:
mode:
authorGreg Ward <gward@python.net>2000-06-06 02:57:07 (GMT)
committerGreg Ward <gward@python.net>2000-06-06 02:57:07 (GMT)
commit28a5f44cca9c5f6abe319f3a446bf057d66e980e (patch)
tree726ce055eaf74936c473dbb014b43f2514b8aff1 /Lib/distutils/command/config.py
parent43955c9a023ea7b50b28052112dbdc914c090a27 (diff)
downloadcpython-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/distutils/command/config.py')
-rw-r--r--Lib/distutils/command/config.py180
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