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