blob: 74eed78391ca963733089b93d71d5c3f1329b6bb [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
Greg Ward59ac7092000-06-21 03:00:50 +000014import sys, os, string, re
Greg Ward2e38a502000-10-14 03:40:20 +000015from types import *
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
Tarek Ziadé7bea3442009-04-12 15:03:50 +000021LANG_EXT = {'c': '.c', 'c++': '.cxx'}
Greg Ward28a5f442000-06-06 02:57:07 +000022
Tarek Ziadé7bea3442009-04-12 15:03:50 +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
Tarek Ziadé7bea3442009-04-12 15:03:50 +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
Tarek Ziadé7bea3442009-04-12 15:03:50 +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 []
71 elif type(self.include_dirs) is StringType:
72 self.include_dirs = string.split(self.include_dirs, os.pathsep)
73
74 if self.libraries is None:
75 self.libraries = []
76 elif type(self.libraries) is StringType:
77 self.libraries = [self.libraries]
78
79 if self.library_dirs is None:
80 self.library_dirs = []
81 elif type(self.library_dirs) is StringType:
82 self.library_dirs = string.split(self.library_dirs, os.pathsep)
83
Greg Ward28a5f442000-06-06 02:57:07 +000084
85 def run (self):
86 pass
87
88
89 # Utility methods for actual "config" commands. The interfaces are
90 # loosely based on Autoconf macros of similar names. Sub-classes
91 # may use these freely.
92
Tarek Ziadé7bea3442009-04-12 15:03:50 +000093 def _check_compiler(self):
Greg Ward28a5f442000-06-06 02:57:07 +000094 """Check that 'self.compiler' really is a CCompiler object;
95 if not, make it one.
96 """
97 # We do this late, and only on-demand, because this is an expensive
98 # import.
99 from distutils.ccompiler import CCompiler, new_compiler
100 if not isinstance(self.compiler, CCompiler):
Greg Wardcb1f4c42000-09-30 18:27:54 +0000101 self.compiler = new_compiler(compiler=self.compiler,
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000102 dry_run=self.dry_run, force=1)
Andrew M. Kuchling679bc9f2003-02-18 01:28:51 +0000103 customize_compiler(self.compiler)
Greg Ward28a5f442000-06-06 02:57:07 +0000104 if self.include_dirs:
105 self.compiler.set_include_dirs(self.include_dirs)
106 if self.libraries:
107 self.compiler.set_libraries(self.libraries)
108 if self.library_dirs:
109 self.compiler.set_library_dirs(self.library_dirs)
110
111
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000112 def _gen_temp_sourcefile(self, body, headers, lang):
Greg Ward28a5f442000-06-06 02:57:07 +0000113 filename = "_configtest" + LANG_EXT[lang]
114 file = open(filename, "w")
Greg Ward59ac7092000-06-21 03:00:50 +0000115 if headers:
116 for header in headers:
117 file.write("#include <%s>\n" % header)
118 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000119 file.write(body)
Greg Ward59ac7092000-06-21 03:00:50 +0000120 if body[-1] != "\n":
121 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000122 file.close()
123 return filename
124
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000125 def _preprocess(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000126 src = self._gen_temp_sourcefile(body, headers, lang)
127 out = "_configtest.i"
128 self.temp_files.extend([src, out])
Greg Ward855dab92000-06-27 01:21:22 +0000129 self.compiler.preprocess(src, out, include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000130 return (src, out)
131
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000132 def _compile(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000133 src = self._gen_temp_sourcefile(body, headers, lang)
134 if self.dump_source:
135 dump_file(src, "compiling '%s':" % src)
136 (obj,) = self.compiler.object_filenames([src])
137 self.temp_files.extend([src, obj])
Greg Ward855dab92000-06-27 01:21:22 +0000138 self.compiler.compile([src], include_dirs=include_dirs)
Greg Ward28a5f442000-06-06 02:57:07 +0000139 return (src, obj)
140
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000141 def _link(self, body, headers, include_dirs, libraries, library_dirs,
142 lang):
Greg Ward855dab92000-06-27 01:21:22 +0000143 (src, obj) = self._compile(body, headers, include_dirs, lang)
Fred Drake21d45352001-12-06 21:01:19 +0000144 prog = os.path.splitext(os.path.basename(src))[0]
Greg Ward59ac7092000-06-21 03:00:50 +0000145 self.compiler.link_executable([obj], prog,
146 libraries=libraries,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000147 library_dirs=library_dirs,
148 target_lang=lang)
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000149
Just van Rossumca3fec72003-02-03 11:43:54 +0000150 if self.compiler.exe_extension is not None:
151 prog = prog + self.compiler.exe_extension
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000152 self.temp_files.append(prog)
153
Greg Ward59ac7092000-06-21 03:00:50 +0000154 return (src, obj, prog)
Greg Ward28a5f442000-06-06 02:57:07 +0000155
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000156 def _clean(self, *filenames):
Greg Ward59ac7092000-06-21 03:00:50 +0000157 if not filenames:
158 filenames = self.temp_files
159 self.temp_files = []
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000160 log.info("removing: %s", string.join(filenames))
Greg Ward28a5f442000-06-06 02:57:07 +0000161 for filename in filenames:
162 try:
163 os.remove(filename)
164 except OSError:
165 pass
166
167
Greg Ward28a5f442000-06-06 02:57:07 +0000168 # XXX these ignore the dry-run flag: what to do, what to do? even if
169 # you want a dry-run build, you still need some sort of configuration
170 # info. My inclination is to make it up to the real config command to
171 # consult 'dry_run', and assume a default (minimal) configuration if
172 # true. The problem with trying to do it here is that you'd have to
173 # return either true or false from all the 'try' methods, neither of
174 # which is correct.
175
Greg Ward59ac7092000-06-21 03:00:50 +0000176 # XXX need access to the header search path and maybe default macros.
177
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000178 def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000179 """Construct a source file from 'body' (a string containing lines
180 of C/C++ code) and 'headers' (a list of header files to include)
181 and run it through the preprocessor. Return true if the
182 preprocessor succeeded, false if there were any errors.
183 ('body' probably isn't of much use, but what the heck.)
184 """
185 from distutils.ccompiler import CompileError
186 self._check_compiler()
187 ok = 1
188 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000189 self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000190 except CompileError:
191 ok = 0
192
193 self._clean()
194 return ok
195
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000196 def search_cpp(self, pattern, body=None, headers=None, include_dirs=None,
197 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000198 """Construct a source file (just like 'try_cpp()'), run it through
199 the preprocessor, and return true if any line of the output matches
200 'pattern'. 'pattern' should either be a compiled regex object or a
201 string containing a regex. If both 'body' and 'headers' are None,
202 preprocesses an empty file -- which can be useful to determine the
203 symbols the preprocessor and compiler set by default.
204 """
205
206 self._check_compiler()
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000207 (src, out) = self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000208
209 if type(pattern) is StringType:
210 pattern = re.compile(pattern)
211
212 file = open(out)
213 match = 0
214 while 1:
215 line = file.readline()
216 if line == '':
217 break
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000218 if pattern.search(line):
Greg Ward59ac7092000-06-21 03:00:50 +0000219 match = 1
220 break
221
222 file.close()
223 self._clean()
224 return match
225
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000226 def try_compile(self, body, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000227 """Try to compile a source file built from 'body' and 'headers'.
228 Return true on success, false otherwise.
Greg Ward28a5f442000-06-06 02:57:07 +0000229 """
230 from distutils.ccompiler import CompileError
231 self._check_compiler()
232 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000233 self._compile(body, headers, include_dirs, lang)
Greg Ward28a5f442000-06-06 02:57:07 +0000234 ok = 1
235 except CompileError:
236 ok = 0
237
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000238 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000239 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000240 return ok
241
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000242 def try_link(self, body, headers=None, include_dirs=None, libraries=None,
243 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000244 """Try to compile and link a source file, built from 'body' and
245 'headers', to executable form. Return true on success, false
Greg Ward28a5f442000-06-06 02:57:07 +0000246 otherwise.
247 """
248 from distutils.ccompiler import CompileError, LinkError
249 self._check_compiler()
250 try:
Greg Ward855dab92000-06-27 01:21:22 +0000251 self._link(body, headers, include_dirs,
252 libraries, library_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000253 ok = 1
254 except (CompileError, LinkError):
255 ok = 0
256
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000257 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000258 self._clean()
259 return ok
Fred Drake21d45352001-12-06 21:01:19 +0000260
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000261 def try_run(self, body, headers=None, include_dirs=None, libraries=None,
262 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000263 """Try to compile, link to an executable, and run a program
264 built from 'body' and 'headers'. Return true on success, false
265 otherwise.
266 """
267 from distutils.ccompiler import CompileError, LinkError
268 self._check_compiler()
269 try:
Andrew M. Kuchling246c4252001-08-13 13:56:24 +0000270 src, obj, exe = self._link(body, headers, include_dirs,
271 libraries, library_dirs, lang)
Greg Ward28a5f442000-06-06 02:57:07 +0000272 self.spawn([exe])
273 ok = 1
274 except (CompileError, LinkError, DistutilsExecError):
275 ok = 0
276
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000277 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000278 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000279 return ok
280
Greg Ward59ac7092000-06-21 03:00:50 +0000281
282 # -- High-level methods --------------------------------------------
283 # (these are the ones that are actually likely to be useful
284 # when implementing a real-world config command!)
285
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000286 def check_func(self, func, headers=None, include_dirs=None,
287 libraries=None, library_dirs=None, decl=0, call=0):
Greg Ward59ac7092000-06-21 03:00:50 +0000288
289 """Determine if function 'func' is available by constructing a
290 source file that refers to 'func', and compiles and links it.
291 If everything succeeds, returns true; otherwise returns false.
292
293 The constructed source file starts out by including the header
294 files listed in 'headers'. If 'decl' is true, it then declares
295 'func' (as "int func()"); you probably shouldn't supply 'headers'
296 and set 'decl' true in the same call, or you might get errors about
297 a conflicting declarations for 'func'. Finally, the constructed
298 'main()' function either references 'func' or (if 'call' is true)
299 calls it. 'libraries' and 'library_dirs' are used when
300 linking.
301 """
302
303 self._check_compiler()
304 body = []
305 if decl:
306 body.append("int %s ();" % func)
307 body.append("int main () {")
308 if call:
309 body.append(" %s();" % func)
310 else:
311 body.append(" %s;" % func)
312 body.append("}")
313 body = string.join(body, "\n") + "\n"
314
Greg Ward855dab92000-06-27 01:21:22 +0000315 return self.try_link(body, headers, include_dirs,
316 libraries, library_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000317
318 # check_func ()
319
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000320 def check_lib(self, library, library_dirs=None, headers=None,
321 include_dirs=None, other_libraries=[]):
Greg Ward855dab92000-06-27 01:21:22 +0000322 """Determine if 'library' is available to be linked against,
323 without actually checking that any particular symbols are provided
324 by it. 'headers' will be used in constructing the source file to
325 be compiled, but the only effect of this is to check if all the
Greg Ward4cd6f2a2000-10-14 03:56:42 +0000326 header files listed are available. Any libraries listed in
327 'other_libraries' will be included in the link, in case 'library'
328 has symbols that depend on other libraries.
Greg Ward855dab92000-06-27 01:21:22 +0000329 """
330 self._check_compiler()
331 return self.try_link("int main (void) { }",
Greg Ward4cd6f2a2000-10-14 03:56:42 +0000332 headers, include_dirs,
333 [library]+other_libraries, library_dirs)
Greg Ward855dab92000-06-27 01:21:22 +0000334
Tarek Ziadé7bea3442009-04-12 15:03:50 +0000335 def check_header(self, header, include_dirs=None, library_dirs=None,
336 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000337 """Determine if the system header file named by 'header_file'
338 exists and can be found by the preprocessor; return true if so,
339 false otherwise.
340 """
Andrew M. Kuchling4013cbd2002-09-09 12:10:00 +0000341 return self.try_cpp(body="/* No body */", headers=[header],
342 include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000343
344
Tarek Ziadéaa487982009-04-12 14:53:51 +0000345def dump_file(filename, head=None):
346 """Dumps a file content into log.info.
Greg Ward59ac7092000-06-21 03:00:50 +0000347
Tarek Ziadéaa487982009-04-12 14:53:51 +0000348 If head is not None, will be dumped before the file content.
349 """
Greg Ward59ac7092000-06-21 03:00:50 +0000350 if head is None:
Tarek Ziadéaa487982009-04-12 14:53:51 +0000351 log.info('%s' % filename)
Greg Ward59ac7092000-06-21 03:00:50 +0000352 else:
Tarek Ziadéaa487982009-04-12 14:53:51 +0000353 log.info(head)
Greg Ward59ac7092000-06-21 03:00:50 +0000354 file = open(filename)
Tarek Ziadéaa487982009-04-12 14:53:51 +0000355 try:
356 log.info(file.read())
357 finally:
358 file.close()