blob: 847e8581605b16af2eebfb0d78edcbf652b141e7 [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
Tarek Ziadé36797272010-07-22 12:50:05 +000012import sys, os, re
Tarek Ziadébccb0c92009-04-12 16:49:20 +000013
Greg Ward28a5f442000-06-06 02:57:07 +000014from distutils.core import Command
15from distutils.errors import DistutilsExecError
Tarek Ziadé36797272010-07-22 12:50:05 +000016from distutils.sysconfig import customize_compiler
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000017from distutils import log
Greg Ward28a5f442000-06-06 02:57:07 +000018
Collin Winter5b7e9d72007-08-30 03:52:21 +000019LANG_EXT = {"c": ".c", "c++": ".cxx"}
Greg Ward28a5f442000-06-06 02:57:07 +000020
Collin Winter5b7e9d72007-08-30 03:52:21 +000021class config(Command):
Greg Ward28a5f442000-06-06 02:57:07 +000022
23 description = "prepare to build"
24
25 user_options = [
26 ('compiler=', None,
27 "specify the compiler type"),
28 ('cc=', None,
29 "specify the compiler executable"),
30 ('include-dirs=', 'I',
31 "list of directories to search for header files"),
32 ('define=', 'D',
33 "C preprocessor macros to define"),
34 ('undef=', 'U',
35 "C preprocessor macros to undefine"),
36 ('libraries=', 'l',
37 "external C libraries to link with"),
38 ('library-dirs=', 'L',
39 "directories to search for external C libraries"),
Greg Ward59ac7092000-06-21 03:00:50 +000040
41 ('noisy', None,
42 "show every action (compile, link, run, ...) taken"),
43 ('dump-source', None,
44 "dump generated source files before attempting to compile them"),
Greg Ward28a5f442000-06-06 02:57:07 +000045 ]
46
47
48 # The three standard command methods: since the "config" command
49 # does nothing by default, these are empty.
50
Collin Winter5b7e9d72007-08-30 03:52:21 +000051 def initialize_options(self):
Greg Ward28a5f442000-06-06 02:57:07 +000052 self.compiler = None
53 self.cc = None
54 self.include_dirs = None
Greg Ward28a5f442000-06-06 02:57:07 +000055 self.libraries = None
56 self.library_dirs = None
57
Greg Ward59ac7092000-06-21 03:00:50 +000058 # maximal output for now
59 self.noisy = 1
60 self.dump_source = 1
61
62 # list of temporary files generated along-the-way that we have
63 # to clean at some point
64 self.temp_files = []
65
Collin Winter5b7e9d72007-08-30 03:52:21 +000066 def finalize_options(self):
Greg Ward2e38a502000-10-14 03:40:20 +000067 if self.include_dirs is None:
68 self.include_dirs = self.distribution.include_dirs or []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000069 elif isinstance(self.include_dirs, str):
Neal Norwitz9d72bb42007-04-17 08:48:32 +000070 self.include_dirs = self.include_dirs.split(os.pathsep)
Greg Ward2e38a502000-10-14 03:40:20 +000071
72 if self.libraries is None:
73 self.libraries = []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000074 elif isinstance(self.libraries, str):
Greg Ward2e38a502000-10-14 03:40:20 +000075 self.libraries = [self.libraries]
76
77 if self.library_dirs is None:
78 self.library_dirs = []
Guido van Rossum3172c5d2007-10-16 18:12:55 +000079 elif isinstance(self.library_dirs, str):
Neal Norwitz9d72bb42007-04-17 08:48:32 +000080 self.library_dirs = self.library_dirs.split(os.pathsep)
Greg Ward2e38a502000-10-14 03:40:20 +000081
Collin Winter5b7e9d72007-08-30 03:52:21 +000082 def run(self):
Greg Ward28a5f442000-06-06 02:57:07 +000083 pass
84
Greg Ward28a5f442000-06-06 02:57:07 +000085 # Utility methods for actual "config" commands. The interfaces are
86 # loosely based on Autoconf macros of similar names. Sub-classes
87 # may use these freely.
88
Collin Winter5b7e9d72007-08-30 03:52:21 +000089 def _check_compiler(self):
Greg Ward28a5f442000-06-06 02:57:07 +000090 """Check that 'self.compiler' really is a CCompiler object;
91 if not, make it one.
92 """
93 # We do this late, and only on-demand, because this is an expensive
94 # import.
95 from distutils.ccompiler import CCompiler, new_compiler
96 if not isinstance(self.compiler, CCompiler):
Greg Wardcb1f4c42000-09-30 18:27:54 +000097 self.compiler = new_compiler(compiler=self.compiler,
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000098 dry_run=self.dry_run, force=1)
Andrew M. Kuchling679bc9f2003-02-18 01:28:51 +000099 customize_compiler(self.compiler)
Greg Ward28a5f442000-06-06 02:57:07 +0000100 if self.include_dirs:
101 self.compiler.set_include_dirs(self.include_dirs)
102 if self.libraries:
103 self.compiler.set_libraries(self.libraries)
104 if self.library_dirs:
105 self.compiler.set_library_dirs(self.library_dirs)
106
Collin Winter5b7e9d72007-08-30 03:52:21 +0000107 def _gen_temp_sourcefile(self, body, headers, lang):
Greg Ward28a5f442000-06-06 02:57:07 +0000108 filename = "_configtest" + LANG_EXT[lang]
109 file = open(filename, "w")
Greg Ward59ac7092000-06-21 03:00:50 +0000110 if headers:
111 for header in headers:
112 file.write("#include <%s>\n" % header)
113 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000114 file.write(body)
Greg Ward59ac7092000-06-21 03:00:50 +0000115 if body[-1] != "\n":
116 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000117 file.close()
118 return filename
119
Collin Winter5b7e9d72007-08-30 03:52:21 +0000120 def _preprocess(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000121 src = self._gen_temp_sourcefile(body, headers, lang)
122 out = "_configtest.i"
123 self.temp_files.extend([src, out])
Greg Ward855dab92000-06-27 01:21:22 +0000124 self.compiler.preprocess(src, out, include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000125 return (src, out)
126
Collin Winter5b7e9d72007-08-30 03:52:21 +0000127 def _compile(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000128 src = self._gen_temp_sourcefile(body, headers, lang)
129 if self.dump_source:
130 dump_file(src, "compiling '%s':" % src)
131 (obj,) = self.compiler.object_filenames([src])
132 self.temp_files.extend([src, obj])
Greg Ward855dab92000-06-27 01:21:22 +0000133 self.compiler.compile([src], include_dirs=include_dirs)
Greg Ward28a5f442000-06-06 02:57:07 +0000134 return (src, obj)
135
Tarek Ziadé9d254892009-04-12 15:07:31 +0000136 def _link(self, body, headers, include_dirs, libraries, library_dirs,
137 lang):
Greg Ward855dab92000-06-27 01:21:22 +0000138 (src, obj) = self._compile(body, headers, include_dirs, lang)
Fred Drake21d45352001-12-06 21:01:19 +0000139 prog = os.path.splitext(os.path.basename(src))[0]
Greg Ward59ac7092000-06-21 03:00:50 +0000140 self.compiler.link_executable([obj], prog,
141 libraries=libraries,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000142 library_dirs=library_dirs,
143 target_lang=lang)
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000144
Just van Rossumca3fec72003-02-03 11:43:54 +0000145 if self.compiler.exe_extension is not None:
146 prog = prog + self.compiler.exe_extension
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000147 self.temp_files.append(prog)
148
Greg Ward59ac7092000-06-21 03:00:50 +0000149 return (src, obj, prog)
Greg Ward28a5f442000-06-06 02:57:07 +0000150
Collin Winter5b7e9d72007-08-30 03:52:21 +0000151 def _clean(self, *filenames):
Greg Ward59ac7092000-06-21 03:00:50 +0000152 if not filenames:
153 filenames = self.temp_files
154 self.temp_files = []
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000155 log.info("removing: %s", ' '.join(filenames))
Greg Ward28a5f442000-06-06 02:57:07 +0000156 for filename in filenames:
157 try:
158 os.remove(filename)
159 except OSError:
160 pass
161
162
Greg Ward28a5f442000-06-06 02:57:07 +0000163 # XXX these ignore the dry-run flag: what to do, what to do? even if
164 # you want a dry-run build, you still need some sort of configuration
165 # info. My inclination is to make it up to the real config command to
166 # consult 'dry_run', and assume a default (minimal) configuration if
167 # true. The problem with trying to do it here is that you'd have to
168 # return either true or false from all the 'try' methods, neither of
169 # which is correct.
170
Greg Ward59ac7092000-06-21 03:00:50 +0000171 # XXX need access to the header search path and maybe default macros.
172
Collin Winter5b7e9d72007-08-30 03:52:21 +0000173 def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000174 """Construct a source file from 'body' (a string containing lines
175 of C/C++ code) and 'headers' (a list of header files to include)
176 and run it through the preprocessor. Return true if the
177 preprocessor succeeded, false if there were any errors.
178 ('body' probably isn't of much use, but what the heck.)
179 """
180 from distutils.ccompiler import CompileError
181 self._check_compiler()
Collin Winter5b7e9d72007-08-30 03:52:21 +0000182 ok = True
Greg Ward59ac7092000-06-21 03:00:50 +0000183 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000184 self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000185 except CompileError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000186 ok = False
Greg Ward59ac7092000-06-21 03:00:50 +0000187
188 self._clean()
189 return ok
190
Tarek Ziadé9d254892009-04-12 15:07:31 +0000191 def search_cpp(self, pattern, body=None, headers=None, include_dirs=None,
192 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000193 """Construct a source file (just like 'try_cpp()'), run it through
194 the preprocessor, and return true if any line of the output matches
195 'pattern'. 'pattern' should either be a compiled regex object or a
196 string containing a regex. If both 'body' and 'headers' are None,
197 preprocesses an empty file -- which can be useful to determine the
198 symbols the preprocessor and compiler set by default.
199 """
Greg Ward59ac7092000-06-21 03:00:50 +0000200 self._check_compiler()
Tarek Ziadéfd39b7a2009-04-12 16:34:34 +0000201 src, out = self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000202
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000203 if isinstance(pattern, str):
Greg Ward59ac7092000-06-21 03:00:50 +0000204 pattern = re.compile(pattern)
205
206 file = open(out)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000207 match = False
208 while True:
Greg Ward59ac7092000-06-21 03:00:50 +0000209 line = file.readline()
210 if line == '':
211 break
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000212 if pattern.search(line):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000213 match = True
Greg Ward59ac7092000-06-21 03:00:50 +0000214 break
215
216 file.close()
217 self._clean()
218 return match
219
Collin Winter5b7e9d72007-08-30 03:52:21 +0000220 def try_compile(self, body, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000221 """Try to compile a source file built from 'body' and 'headers'.
222 Return true on success, false otherwise.
Greg Ward28a5f442000-06-06 02:57:07 +0000223 """
224 from distutils.ccompiler import CompileError
225 self._check_compiler()
226 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000227 self._compile(body, headers, include_dirs, lang)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000228 ok = True
Greg Ward28a5f442000-06-06 02:57:07 +0000229 except CompileError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000230 ok = False
Greg Ward28a5f442000-06-06 02:57:07 +0000231
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000232 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000233 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000234 return ok
235
Tarek Ziadé9d254892009-04-12 15:07:31 +0000236 def try_link(self, body, headers=None, include_dirs=None, libraries=None,
237 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000238 """Try to compile and link a source file, built from 'body' and
239 'headers', to executable form. Return true on success, false
Greg Ward28a5f442000-06-06 02:57:07 +0000240 otherwise.
241 """
242 from distutils.ccompiler import CompileError, LinkError
243 self._check_compiler()
244 try:
Greg Ward855dab92000-06-27 01:21:22 +0000245 self._link(body, headers, include_dirs,
246 libraries, library_dirs, lang)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000247 ok = True
Greg Ward59ac7092000-06-21 03:00:50 +0000248 except (CompileError, LinkError):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000249 ok = False
Greg Ward59ac7092000-06-21 03:00:50 +0000250
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000251 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000252 self._clean()
253 return ok
Fred Drake21d45352001-12-06 21:01:19 +0000254
Tarek Ziadé9d254892009-04-12 15:07:31 +0000255 def try_run(self, body, headers=None, include_dirs=None, libraries=None,
256 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000257 """Try to compile, link to an executable, and run a program
258 built from 'body' and 'headers'. Return true on success, false
259 otherwise.
260 """
261 from distutils.ccompiler import CompileError, LinkError
262 self._check_compiler()
263 try:
Andrew M. Kuchling246c4252001-08-13 13:56:24 +0000264 src, obj, exe = self._link(body, headers, include_dirs,
265 libraries, library_dirs, lang)
Greg Ward28a5f442000-06-06 02:57:07 +0000266 self.spawn([exe])
Collin Winter5b7e9d72007-08-30 03:52:21 +0000267 ok = True
Greg Ward28a5f442000-06-06 02:57:07 +0000268 except (CompileError, LinkError, DistutilsExecError):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000269 ok = False
Greg Ward28a5f442000-06-06 02:57:07 +0000270
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000271 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000272 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000273 return ok
274
Greg Ward59ac7092000-06-21 03:00:50 +0000275
276 # -- High-level methods --------------------------------------------
277 # (these are the ones that are actually likely to be useful
278 # when implementing a real-world config command!)
279
Collin Winter5b7e9d72007-08-30 03:52:21 +0000280 def check_func(self, func, headers=None, include_dirs=None,
281 libraries=None, library_dirs=None, decl=0, call=0):
Greg Ward59ac7092000-06-21 03:00:50 +0000282 """Determine if function 'func' is available by constructing a
283 source file that refers to 'func', and compiles and links it.
284 If everything succeeds, returns true; otherwise returns false.
285
286 The constructed source file starts out by including the header
287 files listed in 'headers'. If 'decl' is true, it then declares
288 'func' (as "int func()"); you probably shouldn't supply 'headers'
289 and set 'decl' true in the same call, or you might get errors about
290 a conflicting declarations for 'func'. Finally, the constructed
291 'main()' function either references 'func' or (if 'call' is true)
292 calls it. 'libraries' and 'library_dirs' are used when
293 linking.
294 """
Greg Ward59ac7092000-06-21 03:00:50 +0000295 self._check_compiler()
296 body = []
297 if decl:
298 body.append("int %s ();" % func)
299 body.append("int main () {")
300 if call:
301 body.append(" %s();" % func)
302 else:
303 body.append(" %s;" % func)
304 body.append("}")
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000305 body = "\n".join(body) + "\n"
Greg Ward59ac7092000-06-21 03:00:50 +0000306
Greg Ward855dab92000-06-27 01:21:22 +0000307 return self.try_link(body, headers, include_dirs,
308 libraries, library_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000309
Collin Winter5b7e9d72007-08-30 03:52:21 +0000310 def check_lib(self, library, library_dirs=None, headers=None,
311 include_dirs=None, other_libraries=[]):
Greg Ward855dab92000-06-27 01:21:22 +0000312 """Determine if 'library' is available to be linked against,
313 without actually checking that any particular symbols are provided
314 by it. 'headers' will be used in constructing the source file to
315 be compiled, but the only effect of this is to check if all the
Greg Ward4cd6f2a2000-10-14 03:56:42 +0000316 header files listed are available. Any libraries listed in
317 'other_libraries' will be included in the link, in case 'library'
318 has symbols that depend on other libraries.
Greg Ward855dab92000-06-27 01:21:22 +0000319 """
320 self._check_compiler()
Collin Winter5b7e9d72007-08-30 03:52:21 +0000321 return self.try_link("int main (void) { }", headers, include_dirs,
322 [library] + other_libraries, library_dirs)
Greg Ward855dab92000-06-27 01:21:22 +0000323
Collin Winter5b7e9d72007-08-30 03:52:21 +0000324 def check_header(self, header, include_dirs=None, library_dirs=None,
325 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000326 """Determine if the system header file named by 'header_file'
327 exists and can be found by the preprocessor; return true if so,
328 false otherwise.
329 """
Andrew M. Kuchling4013cbd2002-09-09 12:10:00 +0000330 return self.try_cpp(body="/* No body */", headers=[header],
331 include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000332
333
Collin Winter5b7e9d72007-08-30 03:52:21 +0000334def dump_file(filename, head=None):
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000335 """Dumps a file content into log.info.
Greg Ward59ac7092000-06-21 03:00:50 +0000336
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000337 If head is not None, will be dumped before the file content.
338 """
339 if head is None:
340 log.info('%s' % filename)
341 else:
342 log.info(head)
Greg Ward59ac7092000-06-21 03:00:50 +0000343 file = open(filename)
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000344 try:
345 log.info(file.read())
346 finally:
347 file.close()