blob: a13055cf8c2712f79546d55e9bf13114b8cd9ef6 [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
12# created 2000/05/29, Greg Ward
13
14__revision__ = "$Id$"
15
Greg Ward59ac7092000-06-21 03:00:50 +000016import sys, os, string, re
Greg Ward28a5f442000-06-06 02:57:07 +000017from distutils.core import Command
18from distutils.errors import DistutilsExecError
19
20
21LANG_EXT = {'c': '.c',
22 'c++': '.cxx'}
23
24class config (Command):
25
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
54 def initialize_options (self):
55 self.compiler = None
56 self.cc = None
57 self.include_dirs = None
58 #self.define = None
59 #self.undef = None
60 self.libraries = None
61 self.library_dirs = None
62
Greg Ward59ac7092000-06-21 03:00:50 +000063 # maximal output for now
64 self.noisy = 1
65 self.dump_source = 1
66
67 # list of temporary files generated along-the-way that we have
68 # to clean at some point
69 self.temp_files = []
70
Greg Ward28a5f442000-06-06 02:57:07 +000071 def finalize_options (self):
72 pass
73
74 def run (self):
75 pass
76
77
78 # Utility methods for actual "config" commands. The interfaces are
79 # loosely based on Autoconf macros of similar names. Sub-classes
80 # may use these freely.
81
82 def _check_compiler (self):
83 """Check that 'self.compiler' really is a CCompiler object;
84 if not, make it one.
85 """
86 # We do this late, and only on-demand, because this is an expensive
87 # import.
88 from distutils.ccompiler import CCompiler, new_compiler
89 if not isinstance(self.compiler, CCompiler):
Greg Wardcb1f4c42000-09-30 18:27:54 +000090 self.compiler = new_compiler(compiler=self.compiler,
91 verbose=self.noisy,
92 dry_run=self.dry_run,
93 force=1)
Greg Ward28a5f442000-06-06 02:57:07 +000094 if self.include_dirs:
95 self.compiler.set_include_dirs(self.include_dirs)
96 if self.libraries:
97 self.compiler.set_libraries(self.libraries)
98 if self.library_dirs:
99 self.compiler.set_library_dirs(self.library_dirs)
100
101
Greg Ward59ac7092000-06-21 03:00:50 +0000102 def _gen_temp_sourcefile (self, body, headers, lang):
Greg Ward28a5f442000-06-06 02:57:07 +0000103 filename = "_configtest" + LANG_EXT[lang]
104 file = open(filename, "w")
Greg Ward59ac7092000-06-21 03:00:50 +0000105 if headers:
106 for header in headers:
107 file.write("#include <%s>\n" % header)
108 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000109 file.write(body)
Greg Ward59ac7092000-06-21 03:00:50 +0000110 if body[-1] != "\n":
111 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000112 file.close()
113 return filename
114
Greg Ward855dab92000-06-27 01:21:22 +0000115 def _preprocess (self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000116 src = self._gen_temp_sourcefile(body, headers, lang)
117 out = "_configtest.i"
118 self.temp_files.extend([src, out])
Greg Ward855dab92000-06-27 01:21:22 +0000119 self.compiler.preprocess(src, out, include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000120 return (src, out)
121
Greg Ward855dab92000-06-27 01:21:22 +0000122 def _compile (self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000123 src = self._gen_temp_sourcefile(body, headers, lang)
124 if self.dump_source:
125 dump_file(src, "compiling '%s':" % src)
126 (obj,) = self.compiler.object_filenames([src])
127 self.temp_files.extend([src, obj])
Greg Ward855dab92000-06-27 01:21:22 +0000128 self.compiler.compile([src], include_dirs=include_dirs)
Greg Ward28a5f442000-06-06 02:57:07 +0000129 return (src, obj)
130
Greg Ward855dab92000-06-27 01:21:22 +0000131 def _link (self, body,
132 headers, include_dirs,
133 libraries, library_dirs, lang):
134 (src, obj) = self._compile(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000135 prog = os.path.splitext(os.path.basename(src))[0]
136 self.temp_files.append(prog) # XXX should be prog + exe_ext
137 self.compiler.link_executable([obj], prog,
138 libraries=libraries,
139 library_dirs=library_dirs)
140 return (src, obj, prog)
Greg Ward28a5f442000-06-06 02:57:07 +0000141
142 def _clean (self, *filenames):
Greg Ward59ac7092000-06-21 03:00:50 +0000143 if not filenames:
144 filenames = self.temp_files
145 self.temp_files = []
Greg Ward28a5f442000-06-06 02:57:07 +0000146 self.announce("removing: " + string.join(filenames))
147 for filename in filenames:
148 try:
149 os.remove(filename)
150 except OSError:
151 pass
152
153
Greg Ward28a5f442000-06-06 02:57:07 +0000154 # XXX these ignore the dry-run flag: what to do, what to do? even if
155 # you want a dry-run build, you still need some sort of configuration
156 # info. My inclination is to make it up to the real config command to
157 # consult 'dry_run', and assume a default (minimal) configuration if
158 # true. The problem with trying to do it here is that you'd have to
159 # return either true or false from all the 'try' methods, neither of
160 # which is correct.
161
Greg Ward59ac7092000-06-21 03:00:50 +0000162 # XXX need access to the header search path and maybe default macros.
163
Greg Ward855dab92000-06-27 01:21:22 +0000164 def try_cpp (self, body=None, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000165 """Construct a source file from 'body' (a string containing lines
166 of C/C++ code) and 'headers' (a list of header files to include)
167 and run it through the preprocessor. Return true if the
168 preprocessor succeeded, false if there were any errors.
169 ('body' probably isn't of much use, but what the heck.)
170 """
171 from distutils.ccompiler import CompileError
172 self._check_compiler()
173 ok = 1
174 try:
175 self._preprocess(body, headers, lang)
176 except CompileError:
177 ok = 0
178
179 self._clean()
180 return ok
181
Greg Ward855dab92000-06-27 01:21:22 +0000182 def search_cpp (self, pattern, body=None,
183 headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000184 """Construct a source file (just like 'try_cpp()'), run it through
185 the preprocessor, and return true if any line of the output matches
186 'pattern'. 'pattern' should either be a compiled regex object or a
187 string containing a regex. If both 'body' and 'headers' are None,
188 preprocesses an empty file -- which can be useful to determine the
189 symbols the preprocessor and compiler set by default.
190 """
191
192 self._check_compiler()
193 (src, out) = self._preprocess(body, headers, lang)
194
195 if type(pattern) is StringType:
196 pattern = re.compile(pattern)
197
198 file = open(out)
199 match = 0
200 while 1:
201 line = file.readline()
202 if line == '':
203 break
204 if pattern.search(pattern):
205 match = 1
206 break
207
208 file.close()
209 self._clean()
210 return match
211
Greg Ward855dab92000-06-27 01:21:22 +0000212 def try_compile (self, body, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000213 """Try to compile a source file built from 'body' and 'headers'.
214 Return true on success, false otherwise.
Greg Ward28a5f442000-06-06 02:57:07 +0000215 """
216 from distutils.ccompiler import CompileError
217 self._check_compiler()
218 try:
Greg Ward59ac7092000-06-21 03:00:50 +0000219 self._compile(body, headers, lang)
Greg Ward28a5f442000-06-06 02:57:07 +0000220 ok = 1
221 except CompileError:
222 ok = 0
223
224 self.announce(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000225 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000226 return ok
227
Greg Ward855dab92000-06-27 01:21:22 +0000228 def try_link (self, body,
229 headers=None, include_dirs=None,
Greg Ward59ac7092000-06-21 03:00:50 +0000230 libraries=None, library_dirs=None,
231 lang="c"):
232 """Try to compile and link a source file, built from 'body' and
233 'headers', to executable form. Return true on success, false
Greg Ward28a5f442000-06-06 02:57:07 +0000234 otherwise.
235 """
236 from distutils.ccompiler import CompileError, LinkError
237 self._check_compiler()
238 try:
Greg Ward855dab92000-06-27 01:21:22 +0000239 self._link(body, headers, include_dirs,
240 libraries, library_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000241 ok = 1
242 except (CompileError, LinkError):
243 ok = 0
244
245 self.announce(ok and "success!" or "failure.")
246 self._clean()
247 return ok
248
Greg Ward855dab92000-06-27 01:21:22 +0000249 def try_run (self, body,
250 headers=None, include_dirs=None,
Greg Ward59ac7092000-06-21 03:00:50 +0000251 libraries=None, library_dirs=None,
252 lang="c"):
253 """Try to compile, link to an executable, and run a program
254 built from 'body' and 'headers'. Return true on success, false
255 otherwise.
256 """
257 from distutils.ccompiler import CompileError, LinkError
258 self._check_compiler()
259 try:
Greg Ward855dab92000-06-27 01:21:22 +0000260 self._link(body, headers, include_dirs,
261 libraries, library_dirs, lang)
Greg Ward28a5f442000-06-06 02:57:07 +0000262 self.spawn([exe])
263 ok = 1
264 except (CompileError, LinkError, DistutilsExecError):
265 ok = 0
266
267 self.announce(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000268 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000269 return ok
270
Greg Ward59ac7092000-06-21 03:00:50 +0000271
272 # -- High-level methods --------------------------------------------
273 # (these are the ones that are actually likely to be useful
274 # when implementing a real-world config command!)
275
Greg Ward855dab92000-06-27 01:21:22 +0000276 def check_func (self, func,
277 headers=None, include_dirs=None,
Greg Ward59ac7092000-06-21 03:00:50 +0000278 libraries=None, library_dirs=None,
279 decl=0, call=0):
280
281 """Determine if function 'func' is available by constructing a
282 source file that refers to 'func', and compiles and links it.
283 If everything succeeds, returns true; otherwise returns false.
284
285 The constructed source file starts out by including the header
286 files listed in 'headers'. If 'decl' is true, it then declares
287 'func' (as "int func()"); you probably shouldn't supply 'headers'
288 and set 'decl' true in the same call, or you might get errors about
289 a conflicting declarations for 'func'. Finally, the constructed
290 'main()' function either references 'func' or (if 'call' is true)
291 calls it. 'libraries' and 'library_dirs' are used when
292 linking.
293 """
294
295 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("}")
305 body = string.join(body, "\n") + "\n"
306
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
310 # check_func ()
311
Greg Ward855dab92000-06-27 01:21:22 +0000312 def check_lib (self, library, library_dirs=None,
313 headers=None, include_dirs=None):
314 """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
318 header files listed are available.
319 """
320 self._check_compiler()
321 return self.try_link("int main (void) { }",
322 headers, include_dirs, [library], library_dirs)
323
324 def check_header (self, header, include_dirs=None,
325 library_dirs=None, 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 """
Greg Ward855dab92000-06-27 01:21:22 +0000330 return self.try_cpp(headers=[header], include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000331
332
Greg Ward28a5f442000-06-06 02:57:07 +0000333# class config
Greg Ward59ac7092000-06-21 03:00:50 +0000334
335
336def dump_file (filename, head=None):
337 if head is None:
338 print filename + ":"
339 else:
340 print head
341
342 file = open(filename)
343 sys.stdout.write(file.read())
344 file.close()