blob: ac80a54eb1ab582ee39944e0dc20bc22b019c917 [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
Neal Norwitz9d72bb42007-04-17 08:48:32 +000014import sys, os, re
Tarek Ziadébccb0c92009-04-12 16:49:20 +000015
Greg Ward28a5f442000-06-06 02:57:07 +000016from distutils.core import Command
17from distutils.errors import DistutilsExecError
Andrew M. Kuchling679bc9f2003-02-18 01:28:51 +000018from distutils.sysconfig import customize_compiler
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000019from distutils import log
Greg Ward28a5f442000-06-06 02:57:07 +000020
Collin Winter5b7e9d72007-08-30 03:52:21 +000021LANG_EXT = {"c": ".c", "c++": ".cxx"}
Greg Ward28a5f442000-06-06 02:57:07 +000022
Collin Winter5b7e9d72007-08-30 03:52:21 +000023class config(Command):
Greg Ward28a5f442000-06-06 02:57:07 +000024
25 description = "prepare to build"
26
27 user_options = [
28 ('compiler=', None,
29 "specify the compiler type"),
30 ('cc=', None,
31 "specify the compiler executable"),
32 ('include-dirs=', 'I',
33 "list of directories to search for header files"),
34 ('define=', 'D',
35 "C preprocessor macros to define"),
36 ('undef=', 'U',
37 "C preprocessor macros to undefine"),
38 ('libraries=', 'l',
39 "external C libraries to link with"),
40 ('library-dirs=', 'L',
41 "directories to search for external C libraries"),
Greg Ward59ac7092000-06-21 03:00:50 +000042
43 ('noisy', None,
44 "show every action (compile, link, run, ...) taken"),
45 ('dump-source', None,
46 "dump generated source files before attempting to compile them"),
Greg Ward28a5f442000-06-06 02:57:07 +000047 ]
48
49
50 # The three standard command methods: since the "config" command
51 # does nothing by default, these are empty.
52
Collin Winter5b7e9d72007-08-30 03:52:21 +000053 def initialize_options(self):
Greg Ward28a5f442000-06-06 02:57:07 +000054 self.compiler = None
55 self.cc = None
56 self.include_dirs = None
Greg Ward28a5f442000-06-06 02:57:07 +000057 self.libraries = None
58 self.library_dirs = None
59
Greg Ward59ac7092000-06-21 03:00:50 +000060 # maximal output for now
61 self.noisy = 1
62 self.dump_source = 1
63
64 # list of temporary files generated along-the-way that we have
65 # to clean at some point
66 self.temp_files = []
67
Collin Winter5b7e9d72007-08-30 03:52:21 +000068 def finalize_options(self):
Greg Ward2e38a502000-10-14 03:40:20 +000069 if self.include_dirs is None:
70 self.include_dirs = self.distribution.include_dirs or []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000071 elif isinstance(self.include_dirs, str):
Neal Norwitz9d72bb42007-04-17 08:48:32 +000072 self.include_dirs = self.include_dirs.split(os.pathsep)
Greg Ward2e38a502000-10-14 03:40:20 +000073
74 if self.libraries is None:
75 self.libraries = []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000076 elif isinstance(self.libraries, str):
Greg Ward2e38a502000-10-14 03:40:20 +000077 self.libraries = [self.libraries]
78
79 if self.library_dirs is None:
80 self.library_dirs = []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000081 elif isinstance(self.library_dirs, str):
Neal Norwitz9d72bb42007-04-17 08:48:32 +000082 self.library_dirs = self.library_dirs.split(os.pathsep)
Greg Ward2e38a502000-10-14 03:40:20 +000083
Collin Winter5b7e9d72007-08-30 03:52:21 +000084 def run(self):
Greg Ward28a5f442000-06-06 02:57:07 +000085 pass
86
Greg Ward28a5f442000-06-06 02:57:07 +000087 # Utility methods for actual "config" commands. The interfaces are
88 # loosely based on Autoconf macros of similar names. Sub-classes
89 # may use these freely.
90
Collin Winter5b7e9d72007-08-30 03:52:21 +000091 def _check_compiler(self):
Greg Ward28a5f442000-06-06 02:57:07 +000092 """Check that 'self.compiler' really is a CCompiler object;
93 if not, make it one.
94 """
95 # We do this late, and only on-demand, because this is an expensive
96 # import.
97 from distutils.ccompiler import CCompiler, new_compiler
98 if not isinstance(self.compiler, CCompiler):
Greg Wardcb1f4c42000-09-30 18:27:54 +000099 self.compiler = new_compiler(compiler=self.compiler,
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000100 dry_run=self.dry_run, force=1)
Andrew M. Kuchling679bc9f2003-02-18 01:28:51 +0000101 customize_compiler(self.compiler)
Greg Ward28a5f442000-06-06 02:57:07 +0000102 if self.include_dirs:
103 self.compiler.set_include_dirs(self.include_dirs)
104 if self.libraries:
105 self.compiler.set_libraries(self.libraries)
106 if self.library_dirs:
107 self.compiler.set_library_dirs(self.library_dirs)
108
Collin Winter5b7e9d72007-08-30 03:52:21 +0000109 def _gen_temp_sourcefile(self, body, headers, lang):
Greg Ward28a5f442000-06-06 02:57:07 +0000110 filename = "_configtest" + LANG_EXT[lang]
111 file = open(filename, "w")
Greg Ward59ac7092000-06-21 03:00:50 +0000112 if headers:
113 for header in headers:
114 file.write("#include <%s>\n" % header)
115 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000116 file.write(body)
Greg Ward59ac7092000-06-21 03:00:50 +0000117 if body[-1] != "\n":
118 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000119 file.close()
120 return filename
121
Collin Winter5b7e9d72007-08-30 03:52:21 +0000122 def _preprocess(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000123 src = self._gen_temp_sourcefile(body, headers, lang)
124 out = "_configtest.i"
125 self.temp_files.extend([src, out])
Greg Ward855dab92000-06-27 01:21:22 +0000126 self.compiler.preprocess(src, out, include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000127 return (src, out)
128
Collin Winter5b7e9d72007-08-30 03:52:21 +0000129 def _compile(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000130 src = self._gen_temp_sourcefile(body, headers, lang)
131 if self.dump_source:
132 dump_file(src, "compiling '%s':" % src)
133 (obj,) = self.compiler.object_filenames([src])
134 self.temp_files.extend([src, obj])
Greg Ward855dab92000-06-27 01:21:22 +0000135 self.compiler.compile([src], include_dirs=include_dirs)
Greg Ward28a5f442000-06-06 02:57:07 +0000136 return (src, obj)
137
Tarek Ziadé9d254892009-04-12 15:07:31 +0000138 def _link(self, body, headers, include_dirs, libraries, library_dirs,
139 lang):
Greg Ward855dab92000-06-27 01:21:22 +0000140 (src, obj) = self._compile(body, headers, include_dirs, lang)
Fred Drake21d45352001-12-06 21:01:19 +0000141 prog = os.path.splitext(os.path.basename(src))[0]
Greg Ward59ac7092000-06-21 03:00:50 +0000142 self.compiler.link_executable([obj], prog,
143 libraries=libraries,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000144 library_dirs=library_dirs,
145 target_lang=lang)
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000146
Just van Rossumca3fec72003-02-03 11:43:54 +0000147 if self.compiler.exe_extension is not None:
148 prog = prog + self.compiler.exe_extension
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000149 self.temp_files.append(prog)
150
Greg Ward59ac7092000-06-21 03:00:50 +0000151 return (src, obj, prog)
Greg Ward28a5f442000-06-06 02:57:07 +0000152
Collin Winter5b7e9d72007-08-30 03:52:21 +0000153 def _clean(self, *filenames):
Greg Ward59ac7092000-06-21 03:00:50 +0000154 if not filenames:
155 filenames = self.temp_files
156 self.temp_files = []
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000157 log.info("removing: %s", ' '.join(filenames))
Greg Ward28a5f442000-06-06 02:57:07 +0000158 for filename in filenames:
159 try:
160 os.remove(filename)
161 except OSError:
162 pass
163
164
Greg Ward28a5f442000-06-06 02:57:07 +0000165 # XXX these ignore the dry-run flag: what to do, what to do? even if
166 # you want a dry-run build, you still need some sort of configuration
167 # info. My inclination is to make it up to the real config command to
168 # consult 'dry_run', and assume a default (minimal) configuration if
169 # true. The problem with trying to do it here is that you'd have to
170 # return either true or false from all the 'try' methods, neither of
171 # which is correct.
172
Greg Ward59ac7092000-06-21 03:00:50 +0000173 # XXX need access to the header search path and maybe default macros.
174
Collin Winter5b7e9d72007-08-30 03:52:21 +0000175 def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000176 """Construct a source file from 'body' (a string containing lines
177 of C/C++ code) and 'headers' (a list of header files to include)
178 and run it through the preprocessor. Return true if the
179 preprocessor succeeded, false if there were any errors.
180 ('body' probably isn't of much use, but what the heck.)
181 """
182 from distutils.ccompiler import CompileError
183 self._check_compiler()
Collin Winter5b7e9d72007-08-30 03:52:21 +0000184 ok = True
Greg Ward59ac7092000-06-21 03:00:50 +0000185 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000186 self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000187 except CompileError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000188 ok = False
Greg Ward59ac7092000-06-21 03:00:50 +0000189
190 self._clean()
191 return ok
192
Tarek Ziadé9d254892009-04-12 15:07:31 +0000193 def search_cpp(self, pattern, body=None, headers=None, include_dirs=None,
194 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000195 """Construct a source file (just like 'try_cpp()'), run it through
196 the preprocessor, and return true if any line of the output matches
197 'pattern'. 'pattern' should either be a compiled regex object or a
198 string containing a regex. If both 'body' and 'headers' are None,
199 preprocesses an empty file -- which can be useful to determine the
200 symbols the preprocessor and compiler set by default.
201 """
Greg Ward59ac7092000-06-21 03:00:50 +0000202 self._check_compiler()
Tarek Ziadéfd39b7a2009-04-12 16:34:34 +0000203 src, out = self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000204
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000205 if isinstance(pattern, str):
Greg Ward59ac7092000-06-21 03:00:50 +0000206 pattern = re.compile(pattern)
207
208 file = open(out)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000209 match = False
210 while True:
Greg Ward59ac7092000-06-21 03:00:50 +0000211 line = file.readline()
212 if line == '':
213 break
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000214 if pattern.search(line):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000215 match = True
Greg Ward59ac7092000-06-21 03:00:50 +0000216 break
217
218 file.close()
219 self._clean()
220 return match
221
Collin Winter5b7e9d72007-08-30 03:52:21 +0000222 def try_compile(self, body, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000223 """Try to compile a source file built from 'body' and 'headers'.
224 Return true on success, false otherwise.
Greg Ward28a5f442000-06-06 02:57:07 +0000225 """
226 from distutils.ccompiler import CompileError
227 self._check_compiler()
228 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000229 self._compile(body, headers, include_dirs, lang)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000230 ok = True
Greg Ward28a5f442000-06-06 02:57:07 +0000231 except CompileError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000232 ok = False
Greg Ward28a5f442000-06-06 02:57:07 +0000233
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000234 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000235 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000236 return ok
237
Tarek Ziadé9d254892009-04-12 15:07:31 +0000238 def try_link(self, body, headers=None, include_dirs=None, libraries=None,
239 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000240 """Try to compile and link a source file, built from 'body' and
241 'headers', to executable form. Return true on success, false
Greg Ward28a5f442000-06-06 02:57:07 +0000242 otherwise.
243 """
244 from distutils.ccompiler import CompileError, LinkError
245 self._check_compiler()
246 try:
Greg Ward855dab92000-06-27 01:21:22 +0000247 self._link(body, headers, include_dirs,
248 libraries, library_dirs, lang)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000249 ok = True
Greg Ward59ac7092000-06-21 03:00:50 +0000250 except (CompileError, LinkError):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000251 ok = False
Greg Ward59ac7092000-06-21 03:00:50 +0000252
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000253 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000254 self._clean()
255 return ok
Fred Drake21d45352001-12-06 21:01:19 +0000256
Tarek Ziadé9d254892009-04-12 15:07:31 +0000257 def try_run(self, body, headers=None, include_dirs=None, libraries=None,
258 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000259 """Try to compile, link to an executable, and run a program
260 built from 'body' and 'headers'. Return true on success, false
261 otherwise.
262 """
263 from distutils.ccompiler import CompileError, LinkError
264 self._check_compiler()
265 try:
Andrew M. Kuchling246c4252001-08-13 13:56:24 +0000266 src, obj, exe = self._link(body, headers, include_dirs,
267 libraries, library_dirs, lang)
Greg Ward28a5f442000-06-06 02:57:07 +0000268 self.spawn([exe])
Collin Winter5b7e9d72007-08-30 03:52:21 +0000269 ok = True
Greg Ward28a5f442000-06-06 02:57:07 +0000270 except (CompileError, LinkError, DistutilsExecError):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000271 ok = False
Greg Ward28a5f442000-06-06 02:57:07 +0000272
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000273 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000274 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000275 return ok
276
Greg Ward59ac7092000-06-21 03:00:50 +0000277
278 # -- High-level methods --------------------------------------------
279 # (these are the ones that are actually likely to be useful
280 # when implementing a real-world config command!)
281
Collin Winter5b7e9d72007-08-30 03:52:21 +0000282 def check_func(self, func, headers=None, include_dirs=None,
283 libraries=None, library_dirs=None, decl=0, call=0):
Greg Ward59ac7092000-06-21 03:00:50 +0000284 """Determine if function 'func' is available by constructing a
285 source file that refers to 'func', and compiles and links it.
286 If everything succeeds, returns true; otherwise returns false.
287
288 The constructed source file starts out by including the header
289 files listed in 'headers'. If 'decl' is true, it then declares
290 'func' (as "int func()"); you probably shouldn't supply 'headers'
291 and set 'decl' true in the same call, or you might get errors about
292 a conflicting declarations for 'func'. Finally, the constructed
293 'main()' function either references 'func' or (if 'call' is true)
294 calls it. 'libraries' and 'library_dirs' are used when
295 linking.
296 """
Greg Ward59ac7092000-06-21 03:00:50 +0000297 self._check_compiler()
298 body = []
299 if decl:
300 body.append("int %s ();" % func)
301 body.append("int main () {")
302 if call:
303 body.append(" %s();" % func)
304 else:
305 body.append(" %s;" % func)
306 body.append("}")
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000307 body = "\n".join(body) + "\n"
Greg Ward59ac7092000-06-21 03:00:50 +0000308
Greg Ward855dab92000-06-27 01:21:22 +0000309 return self.try_link(body, headers, include_dirs,
310 libraries, library_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000311
Collin Winter5b7e9d72007-08-30 03:52:21 +0000312 def check_lib(self, library, library_dirs=None, headers=None,
313 include_dirs=None, other_libraries=[]):
Greg Ward855dab92000-06-27 01:21:22 +0000314 """Determine if 'library' is available to be linked against,
315 without actually checking that any particular symbols are provided
316 by it. 'headers' will be used in constructing the source file to
317 be compiled, but the only effect of this is to check if all the
Greg Ward4cd6f2a2000-10-14 03:56:42 +0000318 header files listed are available. Any libraries listed in
319 'other_libraries' will be included in the link, in case 'library'
320 has symbols that depend on other libraries.
Greg Ward855dab92000-06-27 01:21:22 +0000321 """
322 self._check_compiler()
Collin Winter5b7e9d72007-08-30 03:52:21 +0000323 return self.try_link("int main (void) { }", headers, include_dirs,
324 [library] + other_libraries, library_dirs)
Greg Ward855dab92000-06-27 01:21:22 +0000325
Collin Winter5b7e9d72007-08-30 03:52:21 +0000326 def check_header(self, header, include_dirs=None, library_dirs=None,
327 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000328 """Determine if the system header file named by 'header_file'
329 exists and can be found by the preprocessor; return true if so,
330 false otherwise.
331 """
Andrew M. Kuchling4013cbd2002-09-09 12:10:00 +0000332 return self.try_cpp(body="/* No body */", headers=[header],
333 include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000334
335
Collin Winter5b7e9d72007-08-30 03:52:21 +0000336def dump_file(filename, head=None):
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000337 """Dumps a file content into log.info.
Greg Ward59ac7092000-06-21 03:00:50 +0000338
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000339 If head is not None, will be dumped before the file content.
340 """
341 if head is None:
342 log.info('%s' % filename)
343 else:
344 log.info(head)
Greg Ward59ac7092000-06-21 03:00:50 +0000345 file = open(filename)
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000346 try:
347 log.info(file.read())
348 finally:
349 file.close()