blob: 56f643c88be5993feab24fea55ad40f273237921 [file] [log] [blame]
Greg Ward28a5f442000-06-06 02:57:07 +00001"""distutils.command.config
2
3Implements the Distutils 'config' command, a (mostly) empty command class
4that exists mainly to be sub-classed by specific module distributions and
5applications. The idea is that while every "config" command is different,
6at least they're all named the same, and users always see "config" in the
7list of standard commands. Also, this is a good place to put common
8configure-like tasks: "try to compile this C code", or "figure out where
9this header file lives".
10"""
11
Greg Ward28a5f442000-06-06 02:57:07 +000012__revision__ = "$Id$"
13
Tarek Ziadé88e2c5d2009-12-21 01:49:00 +000014import os
15import re
Tarek Ziadébccb0c92009-04-12 16:49:20 +000016
Greg Ward28a5f442000-06-06 02:57:07 +000017from distutils.core import Command
18from distutils.errors import DistutilsExecError
Tarek Ziadéedacea32010-01-29 11:41:03 +000019from distutils.ccompiler import customize_compiler
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000020from distutils import log
Greg Ward28a5f442000-06-06 02:57:07 +000021
Collin Winter5b7e9d72007-08-30 03:52:21 +000022LANG_EXT = {"c": ".c", "c++": ".cxx"}
Greg Ward28a5f442000-06-06 02:57:07 +000023
Collin Winter5b7e9d72007-08-30 03:52:21 +000024class config(Command):
Greg Ward28a5f442000-06-06 02:57:07 +000025
26 description = "prepare to build"
27
28 user_options = [
29 ('compiler=', None,
30 "specify the compiler type"),
31 ('cc=', None,
32 "specify the compiler executable"),
33 ('include-dirs=', 'I',
34 "list of directories to search for header files"),
35 ('define=', 'D',
36 "C preprocessor macros to define"),
37 ('undef=', 'U',
38 "C preprocessor macros to undefine"),
39 ('libraries=', 'l',
40 "external C libraries to link with"),
41 ('library-dirs=', 'L',
42 "directories to search for external C libraries"),
Greg Ward59ac7092000-06-21 03:00:50 +000043
44 ('noisy', None,
45 "show every action (compile, link, run, ...) taken"),
46 ('dump-source', None,
47 "dump generated source files before attempting to compile them"),
Greg Ward28a5f442000-06-06 02:57:07 +000048 ]
49
50
51 # The three standard command methods: since the "config" command
52 # does nothing by default, these are empty.
53
Collin Winter5b7e9d72007-08-30 03:52:21 +000054 def initialize_options(self):
Greg Ward28a5f442000-06-06 02:57:07 +000055 self.compiler = None
56 self.cc = None
57 self.include_dirs = None
Greg Ward28a5f442000-06-06 02:57:07 +000058 self.libraries = None
59 self.library_dirs = None
60
Greg Ward59ac7092000-06-21 03:00:50 +000061 # maximal output for now
62 self.noisy = 1
63 self.dump_source = 1
64
65 # list of temporary files generated along-the-way that we have
66 # to clean at some point
67 self.temp_files = []
68
Collin Winter5b7e9d72007-08-30 03:52:21 +000069 def finalize_options(self):
Greg Ward2e38a502000-10-14 03:40:20 +000070 if self.include_dirs is None:
71 self.include_dirs = self.distribution.include_dirs or []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000072 elif isinstance(self.include_dirs, str):
Neal Norwitz9d72bb42007-04-17 08:48:32 +000073 self.include_dirs = self.include_dirs.split(os.pathsep)
Greg Ward2e38a502000-10-14 03:40:20 +000074
75 if self.libraries is None:
76 self.libraries = []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000077 elif isinstance(self.libraries, str):
Greg Ward2e38a502000-10-14 03:40:20 +000078 self.libraries = [self.libraries]
79
80 if self.library_dirs is None:
81 self.library_dirs = []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000082 elif isinstance(self.library_dirs, str):
Neal Norwitz9d72bb42007-04-17 08:48:32 +000083 self.library_dirs = self.library_dirs.split(os.pathsep)
Greg Ward2e38a502000-10-14 03:40:20 +000084
Collin Winter5b7e9d72007-08-30 03:52:21 +000085 def run(self):
Greg Ward28a5f442000-06-06 02:57:07 +000086 pass
87
Greg Ward28a5f442000-06-06 02:57:07 +000088 # Utility methods for actual "config" commands. The interfaces are
89 # loosely based on Autoconf macros of similar names. Sub-classes
90 # may use these freely.
91
Collin Winter5b7e9d72007-08-30 03:52:21 +000092 def _check_compiler(self):
Greg Ward28a5f442000-06-06 02:57:07 +000093 """Check that 'self.compiler' really is a CCompiler object;
94 if not, make it one.
95 """
96 # We do this late, and only on-demand, because this is an expensive
97 # import.
98 from distutils.ccompiler import CCompiler, new_compiler
99 if not isinstance(self.compiler, CCompiler):
Greg Wardcb1f4c42000-09-30 18:27:54 +0000100 self.compiler = new_compiler(compiler=self.compiler,
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000101 dry_run=self.dry_run, force=1)
Andrew M. Kuchling679bc9f2003-02-18 01:28:51 +0000102 customize_compiler(self.compiler)
Greg Ward28a5f442000-06-06 02:57:07 +0000103 if self.include_dirs:
104 self.compiler.set_include_dirs(self.include_dirs)
105 if self.libraries:
106 self.compiler.set_libraries(self.libraries)
107 if self.library_dirs:
108 self.compiler.set_library_dirs(self.library_dirs)
109
Collin Winter5b7e9d72007-08-30 03:52:21 +0000110 def _gen_temp_sourcefile(self, body, headers, lang):
Greg Ward28a5f442000-06-06 02:57:07 +0000111 filename = "_configtest" + LANG_EXT[lang]
112 file = open(filename, "w")
Greg Ward59ac7092000-06-21 03:00:50 +0000113 if headers:
114 for header in headers:
115 file.write("#include <%s>\n" % header)
116 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000117 file.write(body)
Greg Ward59ac7092000-06-21 03:00:50 +0000118 if body[-1] != "\n":
119 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000120 file.close()
121 return filename
122
Collin Winter5b7e9d72007-08-30 03:52:21 +0000123 def _preprocess(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000124 src = self._gen_temp_sourcefile(body, headers, lang)
125 out = "_configtest.i"
126 self.temp_files.extend([src, out])
Greg Ward855dab92000-06-27 01:21:22 +0000127 self.compiler.preprocess(src, out, include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000128 return (src, out)
129
Collin Winter5b7e9d72007-08-30 03:52:21 +0000130 def _compile(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000131 src = self._gen_temp_sourcefile(body, headers, lang)
132 if self.dump_source:
133 dump_file(src, "compiling '%s':" % src)
134 (obj,) = self.compiler.object_filenames([src])
135 self.temp_files.extend([src, obj])
Greg Ward855dab92000-06-27 01:21:22 +0000136 self.compiler.compile([src], include_dirs=include_dirs)
Greg Ward28a5f442000-06-06 02:57:07 +0000137 return (src, obj)
138
Tarek Ziadé9d254892009-04-12 15:07:31 +0000139 def _link(self, body, headers, include_dirs, libraries, library_dirs,
140 lang):
Greg Ward855dab92000-06-27 01:21:22 +0000141 (src, obj) = self._compile(body, headers, include_dirs, lang)
Fred Drake21d45352001-12-06 21:01:19 +0000142 prog = os.path.splitext(os.path.basename(src))[0]
Greg Ward59ac7092000-06-21 03:00:50 +0000143 self.compiler.link_executable([obj], prog,
144 libraries=libraries,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000145 library_dirs=library_dirs,
146 target_lang=lang)
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000147
Just van Rossumca3fec72003-02-03 11:43:54 +0000148 if self.compiler.exe_extension is not None:
149 prog = prog + self.compiler.exe_extension
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000150 self.temp_files.append(prog)
151
Greg Ward59ac7092000-06-21 03:00:50 +0000152 return (src, obj, prog)
Greg Ward28a5f442000-06-06 02:57:07 +0000153
Collin Winter5b7e9d72007-08-30 03:52:21 +0000154 def _clean(self, *filenames):
Greg Ward59ac7092000-06-21 03:00:50 +0000155 if not filenames:
156 filenames = self.temp_files
157 self.temp_files = []
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000158 log.info("removing: %s", ' '.join(filenames))
Greg Ward28a5f442000-06-06 02:57:07 +0000159 for filename in filenames:
160 try:
161 os.remove(filename)
162 except OSError:
163 pass
164
165
Greg Ward28a5f442000-06-06 02:57:07 +0000166 # XXX these ignore the dry-run flag: what to do, what to do? even if
167 # you want a dry-run build, you still need some sort of configuration
168 # info. My inclination is to make it up to the real config command to
169 # consult 'dry_run', and assume a default (minimal) configuration if
170 # true. The problem with trying to do it here is that you'd have to
171 # return either true or false from all the 'try' methods, neither of
172 # which is correct.
173
Greg Ward59ac7092000-06-21 03:00:50 +0000174 # XXX need access to the header search path and maybe default macros.
175
Collin Winter5b7e9d72007-08-30 03:52:21 +0000176 def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000177 """Construct a source file from 'body' (a string containing lines
178 of C/C++ code) and 'headers' (a list of header files to include)
179 and run it through the preprocessor. Return true if the
180 preprocessor succeeded, false if there were any errors.
181 ('body' probably isn't of much use, but what the heck.)
182 """
183 from distutils.ccompiler import CompileError
184 self._check_compiler()
Collin Winter5b7e9d72007-08-30 03:52:21 +0000185 ok = True
Greg Ward59ac7092000-06-21 03:00:50 +0000186 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000187 self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000188 except CompileError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000189 ok = False
Greg Ward59ac7092000-06-21 03:00:50 +0000190
191 self._clean()
192 return ok
193
Tarek Ziadé9d254892009-04-12 15:07:31 +0000194 def search_cpp(self, pattern, body=None, headers=None, include_dirs=None,
195 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000196 """Construct a source file (just like 'try_cpp()'), run it through
197 the preprocessor, and return true if any line of the output matches
198 'pattern'. 'pattern' should either be a compiled regex object or a
199 string containing a regex. If both 'body' and 'headers' are None,
200 preprocesses an empty file -- which can be useful to determine the
201 symbols the preprocessor and compiler set by default.
202 """
Greg Ward59ac7092000-06-21 03:00:50 +0000203 self._check_compiler()
Tarek Ziadéfd39b7a2009-04-12 16:34:34 +0000204 src, out = self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000205
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000206 if isinstance(pattern, str):
Greg Ward59ac7092000-06-21 03:00:50 +0000207 pattern = re.compile(pattern)
208
209 file = open(out)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000210 match = False
211 while True:
Greg Ward59ac7092000-06-21 03:00:50 +0000212 line = file.readline()
213 if line == '':
214 break
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000215 if pattern.search(line):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000216 match = True
Greg Ward59ac7092000-06-21 03:00:50 +0000217 break
218
219 file.close()
220 self._clean()
221 return match
222
Collin Winter5b7e9d72007-08-30 03:52:21 +0000223 def try_compile(self, body, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000224 """Try to compile a source file built from 'body' and 'headers'.
225 Return true on success, false otherwise.
Greg Ward28a5f442000-06-06 02:57:07 +0000226 """
227 from distutils.ccompiler import CompileError
228 self._check_compiler()
229 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000230 self._compile(body, headers, include_dirs, lang)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000231 ok = True
Greg Ward28a5f442000-06-06 02:57:07 +0000232 except CompileError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000233 ok = False
Greg Ward28a5f442000-06-06 02:57:07 +0000234
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000235 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000236 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000237 return ok
238
Tarek Ziadé9d254892009-04-12 15:07:31 +0000239 def try_link(self, body, headers=None, include_dirs=None, libraries=None,
240 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000241 """Try to compile and link a source file, built from 'body' and
242 'headers', to executable form. Return true on success, false
Greg Ward28a5f442000-06-06 02:57:07 +0000243 otherwise.
244 """
245 from distutils.ccompiler import CompileError, LinkError
246 self._check_compiler()
247 try:
Greg Ward855dab92000-06-27 01:21:22 +0000248 self._link(body, headers, include_dirs,
249 libraries, library_dirs, lang)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000250 ok = True
Greg Ward59ac7092000-06-21 03:00:50 +0000251 except (CompileError, LinkError):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000252 ok = False
Greg Ward59ac7092000-06-21 03:00:50 +0000253
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000254 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000255 self._clean()
256 return ok
Fred Drake21d45352001-12-06 21:01:19 +0000257
Tarek Ziadé9d254892009-04-12 15:07:31 +0000258 def try_run(self, body, headers=None, include_dirs=None, libraries=None,
259 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000260 """Try to compile, link to an executable, and run a program
261 built from 'body' and 'headers'. Return true on success, false
262 otherwise.
263 """
264 from distutils.ccompiler import CompileError, LinkError
265 self._check_compiler()
266 try:
Andrew M. Kuchling246c4252001-08-13 13:56:24 +0000267 src, obj, exe = self._link(body, headers, include_dirs,
268 libraries, library_dirs, lang)
Greg Ward28a5f442000-06-06 02:57:07 +0000269 self.spawn([exe])
Collin Winter5b7e9d72007-08-30 03:52:21 +0000270 ok = True
Greg Ward28a5f442000-06-06 02:57:07 +0000271 except (CompileError, LinkError, DistutilsExecError):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000272 ok = False
Greg Ward28a5f442000-06-06 02:57:07 +0000273
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000274 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000275 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000276 return ok
277
Greg Ward59ac7092000-06-21 03:00:50 +0000278
279 # -- High-level methods --------------------------------------------
280 # (these are the ones that are actually likely to be useful
281 # when implementing a real-world config command!)
282
Collin Winter5b7e9d72007-08-30 03:52:21 +0000283 def check_func(self, func, headers=None, include_dirs=None,
284 libraries=None, library_dirs=None, decl=0, call=0):
Greg Ward59ac7092000-06-21 03:00:50 +0000285 """Determine if function 'func' is available by constructing a
286 source file that refers to 'func', and compiles and links it.
287 If everything succeeds, returns true; otherwise returns false.
288
289 The constructed source file starts out by including the header
290 files listed in 'headers'. If 'decl' is true, it then declares
291 'func' (as "int func()"); you probably shouldn't supply 'headers'
292 and set 'decl' true in the same call, or you might get errors about
293 a conflicting declarations for 'func'. Finally, the constructed
294 'main()' function either references 'func' or (if 'call' is true)
295 calls it. 'libraries' and 'library_dirs' are used when
296 linking.
297 """
Greg Ward59ac7092000-06-21 03:00:50 +0000298 self._check_compiler()
299 body = []
300 if decl:
301 body.append("int %s ();" % func)
302 body.append("int main () {")
303 if call:
304 body.append(" %s();" % func)
305 else:
306 body.append(" %s;" % func)
307 body.append("}")
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000308 body = "\n".join(body) + "\n"
Greg Ward59ac7092000-06-21 03:00:50 +0000309
Greg Ward855dab92000-06-27 01:21:22 +0000310 return self.try_link(body, headers, include_dirs,
311 libraries, library_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000312
Collin Winter5b7e9d72007-08-30 03:52:21 +0000313 def check_lib(self, library, library_dirs=None, headers=None,
314 include_dirs=None, other_libraries=[]):
Greg Ward855dab92000-06-27 01:21:22 +0000315 """Determine if 'library' is available to be linked against,
316 without actually checking that any particular symbols are provided
317 by it. 'headers' will be used in constructing the source file to
318 be compiled, but the only effect of this is to check if all the
Greg Ward4cd6f2a2000-10-14 03:56:42 +0000319 header files listed are available. Any libraries listed in
320 'other_libraries' will be included in the link, in case 'library'
321 has symbols that depend on other libraries.
Greg Ward855dab92000-06-27 01:21:22 +0000322 """
323 self._check_compiler()
Collin Winter5b7e9d72007-08-30 03:52:21 +0000324 return self.try_link("int main (void) { }", headers, include_dirs,
325 [library] + other_libraries, library_dirs)
Greg Ward855dab92000-06-27 01:21:22 +0000326
Collin Winter5b7e9d72007-08-30 03:52:21 +0000327 def check_header(self, header, include_dirs=None, library_dirs=None,
328 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000329 """Determine if the system header file named by 'header_file'
330 exists and can be found by the preprocessor; return true if so,
331 false otherwise.
332 """
Andrew M. Kuchling4013cbd2002-09-09 12:10:00 +0000333 return self.try_cpp(body="/* No body */", headers=[header],
334 include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000335
336
Collin Winter5b7e9d72007-08-30 03:52:21 +0000337def dump_file(filename, head=None):
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000338 """Dumps a file content into log.info.
Greg Ward59ac7092000-06-21 03:00:50 +0000339
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000340 If head is not None, will be dumped before the file content.
341 """
342 if head is None:
343 log.info('%s' % filename)
344 else:
345 log.info(head)
Greg Ward59ac7092000-06-21 03:00:50 +0000346 file = open(filename)
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000347 try:
348 log.info(file.read())
349 finally:
350 file.close()