[Python-checkins] CVS: distutils/distutils/command config.py,1.1,1.2
Greg Ward
python-dev@python.org
2000年6月20日 20:00:53 -0700
Update of /cvsroot/python/distutils/distutils/command
In directory slayer.i.sourceforge.net:/tmp/cvs-serv17164
Modified Files:
config.py
Log Message:
Fleshed out and added a bunch of useful stuff, notably 'check_func()',
'try_cpp()', 'search_cpp()', and 'check_header()'. This is enough that
the base config is actually useful for implementing a real config
command, specifically one for mxDateTime.
Index: config.py
===================================================================
RCS file: /cvsroot/python/distutils/distutils/command/config.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -r1.1 -r1.2
*** config.py 2000年06月06日 02:57:07 1.1
--- config.py 2000年06月21日 03:00:50 1.2
***************
*** 14,18 ****
__revision__ = "$Id$"
! import os, string
from distutils.core import Command
from distutils.errors import DistutilsExecError
--- 14,18 ----
__revision__ = "$Id$"
! import sys, os, string, re
from distutils.core import Command
from distutils.errors import DistutilsExecError
***************
*** 41,44 ****
--- 41,49 ----
('library-dirs=', 'L',
"directories to search for external C libraries"),
+
+ ('noisy', None,
+ "show every action (compile, link, run, ...) taken"),
+ ('dump-source', None,
+ "dump generated source files before attempting to compile them"),
]
***************
*** 56,59 ****
--- 61,72 ----
self.library_dirs = None
+ # maximal output for now
+ self.noisy = 1
+ self.dump_source = 1
+
+ # list of temporary files generated along-the-way that we have
+ # to clean at some point
+ self.temp_files = []
+
def finalize_options (self):
pass
***************
*** 76,80 ****
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)
--- 89,93 ----
if not isinstance(self.compiler, CCompiler):
self.compiler = new_compiler (compiler=self.compiler,
! verbose=self.noisy,
dry_run=self.dry_run,
force=1)
***************
*** 87,109 ****
! 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:
--- 100,145 ----
! def _gen_temp_sourcefile (self, body, headers, lang):
filename = "_configtest" + LANG_EXT[lang]
file = open(filename, "w")
+ if headers:
+ for header in headers:
+ file.write("#include <%s>\n" % header)
+ file.write("\n")
file.write(body)
+ if body[-1] != "\n":
+ file.write("\n")
file.close()
return filename
! def _preprocess (self, body, headers, lang):
! src = self._gen_temp_sourcefile(body, headers, lang)
! out = "_configtest.i"
! self.temp_files.extend([src, out])
! self.compiler.preprocess(src, out)
! return (src, out)
!
! def _compile (self, body, headers, lang):
! src = self._gen_temp_sourcefile(body, headers, lang)
! if self.dump_source:
! dump_file(src, "compiling '%s':" % src)
! (obj,) = self.compiler.object_filenames([src])
! self.temp_files.extend([src, obj])
! self.compiler.compile([src])
return (src, obj)
! def _link (self, body, headers, libraries, library_dirs, lang):
! (src, obj) = self._compile(body, headers, lang)
! prog = os.path.splitext(os.path.basename(src))[0]
! self.temp_files.append(prog) # XXX should be prog + exe_ext
! self.compiler.link_executable([obj], prog,
! libraries=libraries,
! library_dirs=library_dirs)
! return (src, obj, prog)
def _clean (self, *filenames):
+ if not filenames:
+ filenames = self.temp_files
+ self.temp_files = []
self.announce("removing: " + string.join(filenames))
for filename in filenames:
***************
*** 114,121 ****
- # 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
--- 150,153 ----
***************
*** 126,138 ****
# 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:
--- 158,218 ----
# which is correct.
! # XXX need access to the header search path and maybe default macros.
!
! def try_cpp (self, body=None, headers=None, lang="c"):
! """Construct a source file from 'body' (a string containing lines
! of C/C++ code) and 'headers' (a list of header files to include)
! and run it through the preprocessor. Return true if the
! preprocessor succeeded, false if there were any errors.
! ('body' probably isn't of much use, but what the heck.)
! """
! from distutils.ccompiler import CompileError
! self._check_compiler()
! ok = 1
! try:
! self._preprocess(body, headers, lang)
! except CompileError:
! ok = 0
!
! self._clean()
! return ok
!
! def search_cpp (self, pattern, body=None, headers=None, lang="c"):
! """Construct a source file (just like 'try_cpp()'), run it through
! the preprocessor, and return true if any line of the output matches
! 'pattern'. 'pattern' should either be a compiled regex object or a
! string containing a regex. If both 'body' and 'headers' are None,
! preprocesses an empty file -- which can be useful to determine the
! symbols the preprocessor and compiler set by default.
! """
!
! self._check_compiler()
! (src, out) = self._preprocess(body, headers, lang)
!
! if type(pattern) is StringType:
! pattern = re.compile(pattern)
!
! file = open(out)
! match = 0
! while 1:
! line = file.readline()
! if line == '':
! break
! if pattern.search(pattern):
! match = 1
! break
!
! file.close()
! self._clean()
! return match
!
! def try_compile (self, body, headers=None, lang="c"):
! """Try to compile a source file built from 'body' and 'headers'.
! Return true on success, false otherwise.
"""
from distutils.ccompiler import CompileError
self._check_compiler()
try:
! self._compile(body, headers, lang)
ok = 1
except CompileError:
***************
*** 140,155 ****
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):
--- 220,238 ----
self.announce(ok and "success!" or "failure.")
! self._clean()
return ok
! def try_link (self,
! body, headers=None,
! libraries=None, library_dirs=None,
! lang="c"):
! """Try to compile and link a source file, built from 'body' and
! 'headers', to executable form. Return true on success, false
! otherwise.
"""
from distutils.ccompiler import CompileError, LinkError
self._check_compiler()
try:
! self._link(body, headers, libraries, library_dirs, lang)
ok = 1
except (CompileError, LinkError):
***************
*** 157,166 ****
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.
"""
--- 240,252 ----
self.announce(ok and "success!" or "failure.")
! self._clean()
return ok
! def try_run (self,
! body, headers=None,
! libraries=None, library_dirs=None,
! lang="c"):
! """Try to compile, link to an executable, and run a program
! built from 'body' and 'headers'. Return true on success, false
otherwise.
"""
***************
*** 168,172 ****
self._check_compiler()
try:
! (src, obj, exe) = self._link(body, lang)
self.spawn([exe])
ok = 1
--- 254,258 ----
self._check_compiler()
try:
! self._link(body, headers, libraries, library_dirs, lang)
self.spawn([exe])
ok = 1
***************
*** 175,180 ****
self.announce(ok and "success!" or "failure.")
! self._clean(src, obj, exe)
return ok
# class config
--- 261,324 ----
self.announce(ok and "success!" or "failure.")
! self._clean()
return ok
+
+ # -- High-level methods --------------------------------------------
+ # (these are the ones that are actually likely to be useful
+ # when implementing a real-world config command!)
+
+ def check_func (self, func, headers=None,
+ libraries=None, library_dirs=None,
+ decl=0, call=0):
+
+ """Determine if function 'func' is available by constructing a
+ source file that refers to 'func', and compiles and links it.
+ If everything succeeds, returns true; otherwise returns false.
+
+ The constructed source file starts out by including the header
+ files listed in 'headers'. If 'decl' is true, it then declares
+ 'func' (as "int func()"); you probably shouldn't supply 'headers'
+ and set 'decl' true in the same call, or you might get errors about
+ a conflicting declarations for 'func'. Finally, the constructed
+ 'main()' function either references 'func' or (if 'call' is true)
+ calls it. 'libraries' and 'library_dirs' are used when
+ linking.
+ """
+
+ self._check_compiler()
+ body = []
+ if decl:
+ body.append("int %s ();" % func)
+ body.append("int main () {")
+ if call:
+ body.append(" %s();" % func)
+ else:
+ body.append(" %s;" % func)
+ body.append("}")
+ body = string.join(body, "\n") + "\n"
+
+ return self.try_link(body, headers, libraries, library_dirs)
+
+ # check_func ()
+
+ def check_header (self, header, lang="c"):
+ """Determine if the system header file named by 'header_file'
+ exists and can be found by the preprocessor; return true if so,
+ false otherwise.
+ """
+ return self.try_cpp(headers=[header])
+
+
# class config
+
+
+ def dump_file (filename, head=None):
+ if head is None:
+ print filename + ":"
+ else:
+ print head
+
+ file = open(filename)
+ sys.stdout.write(file.read())
+ file.close()