]> git.saurik.com Git - wxWidgets.git/blame_incremental - wxPython/distutils/command/config.py
changed to behave in same way as native win32 control and generic wxListCtrl when...
[wxWidgets.git] / wxPython / distutils / command / config.py
... / ...
CommitLineData
1"""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# This module should be kept compatible with Python 1.5.2.
13
14__revision__ = "$Id$"
15
16import sys, os, string, re
17from types import *
18from distutils.core import Command
19from distutils.errors import DistutilsExecError
20from distutils.sysconfig import customize_compiler
21from distutils import log
22
23LANG_EXT = {'c': '.c',
24 'c++': '.cxx'}
25
26class config (Command):
27
28 description = "prepare to build"
29
30 user_options = [
31 ('compiler=', None,
32 "specify the compiler type"),
33 ('cc=', None,
34 "specify the compiler executable"),
35 ('include-dirs=', 'I',
36 "list of directories to search for header files"),
37 ('define=', 'D',
38 "C preprocessor macros to define"),
39 ('undef=', 'U',
40 "C preprocessor macros to undefine"),
41 ('libraries=', 'l',
42 "external C libraries to link with"),
43 ('library-dirs=', 'L',
44 "directories to search for external C libraries"),
45
46 ('noisy', None,
47 "show every action (compile, link, run, ...) taken"),
48 ('dump-source', None,
49 "dump generated source files before attempting to compile them"),
50 ]
51
52
53 # The three standard command methods: since the "config" command
54 # does nothing by default, these are empty.
55
56 def initialize_options (self):
57 self.compiler = None
58 self.cc = None
59 self.include_dirs = None
60 #self.define = None
61 #self.undef = None
62 self.libraries = None
63 self.library_dirs = None
64
65 # maximal output for now
66 self.noisy = 1
67 self.dump_source = 1
68
69 # list of temporary files generated along-the-way that we have
70 # to clean at some point
71 self.temp_files = []
72
73 def finalize_options (self):
74 if self.include_dirs is None:
75 self.include_dirs = self.distribution.include_dirs or []
76 elif type(self.include_dirs) is StringType:
77 self.include_dirs = string.split(self.include_dirs, os.pathsep)
78
79 if self.libraries is None:
80 self.libraries = []
81 elif type(self.libraries) is StringType:
82 self.libraries = [self.libraries]
83
84 if self.library_dirs is None:
85 self.library_dirs = []
86 elif type(self.library_dirs) is StringType:
87 self.library_dirs = string.split(self.library_dirs, os.pathsep)
88
89
90 def run (self):
91 pass
92
93
94 # Utility methods for actual "config" commands. The interfaces are
95 # loosely based on Autoconf macros of similar names. Sub-classes
96 # may use these freely.
97
98 def _check_compiler (self):
99 """Check that 'self.compiler' really is a CCompiler object;
100 if not, make it one.
101 """
102 # We do this late, and only on-demand, because this is an expensive
103 # import.
104 from distutils.ccompiler import CCompiler, new_compiler
105 if not isinstance(self.compiler, CCompiler):
106 self.compiler = new_compiler(compiler=self.compiler,
107 dry_run=self.dry_run, force=1)
108 customize_compiler(self.compiler)
109 if self.include_dirs:
110 self.compiler.set_include_dirs(self.include_dirs)
111 if self.libraries:
112 self.compiler.set_libraries(self.libraries)
113 if self.library_dirs:
114 self.compiler.set_library_dirs(self.library_dirs)
115
116
117 def _gen_temp_sourcefile (self, body, headers, lang):
118 filename = "_configtest" + LANG_EXT[lang]
119 file = open(filename, "w")
120 if headers:
121 for header in headers:
122 file.write("#include <%s>\n" % header)
123 file.write("\n")
124 file.write(body)
125 if body[-1] != "\n":
126 file.write("\n")
127 file.close()
128 return filename
129
130 def _preprocess (self, body, headers, include_dirs, lang):
131 src = self._gen_temp_sourcefile(body, headers, lang)
132 out = "_configtest.i"
133 self.temp_files.extend([src, out])
134 self.compiler.preprocess(src, out, include_dirs=include_dirs)
135 return (src, out)
136
137 def _compile (self, body, headers, include_dirs, lang):
138 src = self._gen_temp_sourcefile(body, headers, lang)
139 if self.dump_source:
140 dump_file(src, "compiling '%s':" % src)
141 (obj,) = self.compiler.object_filenames([src])
142 self.temp_files.extend([src, obj])
143 self.compiler.compile([src], include_dirs=include_dirs)
144 return (src, obj)
145
146 def _link (self, body,
147 headers, include_dirs,
148 libraries, library_dirs, lang):
149 (src, obj) = self._compile(body, headers, include_dirs, lang)
150 prog = os.path.splitext(os.path.basename(src))[0]
151 self.compiler.link_executable([obj], prog,
152 libraries=libraries,
153 library_dirs=library_dirs,
154 target_lang=lang)
155
156 if self.compiler.exe_extension is not None:
157 prog = prog + self.compiler.exe_extension
158 self.temp_files.append(prog)
159
160 return (src, obj, prog)
161
162 def _clean (self, *filenames):
163 if not filenames:
164 filenames = self.temp_files
165 self.temp_files = []
166 log.info("removing: %s", string.join(filenames))
167 for filename in filenames:
168 try:
169 os.remove(filename)
170 except OSError:
171 pass
172
173
174 # XXX these ignore the dry-run flag: what to do, what to do? even if
175 # you want a dry-run build, you still need some sort of configuration
176 # info. My inclination is to make it up to the real config command to
177 # consult 'dry_run', and assume a default (minimal) configuration if
178 # true. The problem with trying to do it here is that you'd have to
179 # return either true or false from all the 'try' methods, neither of
180 # which is correct.
181
182 # XXX need access to the header search path and maybe default macros.
183
184 def try_cpp (self, body=None, headers=None, include_dirs=None, lang="c"):
185 """Construct a source file from 'body' (a string containing lines
186 of C/C++ code) and 'headers' (a list of header files to include)
187 and run it through the preprocessor. Return true if the
188 preprocessor succeeded, false if there were any errors.
189 ('body' probably isn't of much use, but what the heck.)
190 """
191 from distutils.ccompiler import CompileError
192 self._check_compiler()
193 ok = 1
194 try:
195 self._preprocess(body, headers, include_dirs, lang)
196 except CompileError:
197 ok = 0
198
199 self._clean()
200 return ok
201
202 def search_cpp (self, pattern, body=None,
203 headers=None, include_dirs=None, lang="c"):
204 """Construct a source file (just like 'try_cpp()'), run it through
205 the preprocessor, and return true if any line of the output matches
206 'pattern'. 'pattern' should either be a compiled regex object or a
207 string containing a regex. If both 'body' and 'headers' are None,
208 preprocesses an empty file -- which can be useful to determine the
209 symbols the preprocessor and compiler set by default.
210 """
211
212 self._check_compiler()
213 (src, out) = self._preprocess(body, headers, include_dirs, lang)
214
215 if type(pattern) is StringType:
216 pattern = re.compile(pattern)
217
218 file = open(out)
219 match = 0
220 while 1:
221 line = file.readline()
222 if line == '':
223 break
224 if pattern.search(line):
225 match = 1
226 break
227
228 file.close()
229 self._clean()
230 return match
231
232 def try_compile (self, body, headers=None, include_dirs=None, lang="c"):
233 """Try to compile a source file built from 'body' and 'headers'.
234 Return true on success, false otherwise.
235 """
236 from distutils.ccompiler import CompileError
237 self._check_compiler()
238 try:
239 self._compile(body, headers, include_dirs, lang)
240 ok = 1
241 except CompileError:
242 ok = 0
243
244 log.info(ok and "success!" or "failure.")
245 self._clean()
246 return ok
247
248 def try_link (self, body,
249 headers=None, include_dirs=None,
250 libraries=None, library_dirs=None,
251 lang="c"):
252 """Try to compile and link a source file, built from 'body' and
253 'headers', to executable form. Return true on success, false
254 otherwise.
255 """
256 from distutils.ccompiler import CompileError, LinkError
257 self._check_compiler()
258 try:
259 self._link(body, headers, include_dirs,
260 libraries, library_dirs, lang)
261 ok = 1
262 except (CompileError, LinkError):
263 ok = 0
264
265 log.info(ok and "success!" or "failure.")
266 self._clean()
267 return ok
268
269 def try_run (self, body,
270 headers=None, include_dirs=None,
271 libraries=None, library_dirs=None,
272 lang="c"):
273 """Try to compile, link to an executable, and run a program
274 built from 'body' and 'headers'. Return true on success, false
275 otherwise.
276 """
277 from distutils.ccompiler import CompileError, LinkError
278 self._check_compiler()
279 try:
280 src, obj, exe = self._link(body, headers, include_dirs,
281 libraries, library_dirs, lang)
282 self.spawn([exe])
283 ok = 1
284 except (CompileError, LinkError, DistutilsExecError):
285 ok = 0
286
287 log.info(ok and "success!" or "failure.")
288 self._clean()
289 return ok
290
291
292 # -- High-level methods --------------------------------------------
293 # (these are the ones that are actually likely to be useful
294 # when implementing a real-world config command!)
295
296 def check_func (self, func,
297 headers=None, include_dirs=None,
298 libraries=None, library_dirs=None,
299 decl=0, call=0):
300
301 """Determine if function 'func' is available by constructing a
302 source file that refers to 'func', and compiles and links it.
303 If everything succeeds, returns true; otherwise returns false.
304
305 The constructed source file starts out by including the header
306 files listed in 'headers'. If 'decl' is true, it then declares
307 'func' (as "int func()"); you probably shouldn't supply 'headers'
308 and set 'decl' true in the same call, or you might get errors about
309 a conflicting declarations for 'func'. Finally, the constructed
310 'main()' function either references 'func' or (if 'call' is true)
311 calls it. 'libraries' and 'library_dirs' are used when
312 linking.
313 """
314
315 self._check_compiler()
316 body = []
317 if decl:
318 body.append("int %s ();" % func)
319 body.append("int main () {")
320 if call:
321 body.append(" %s();" % func)
322 else:
323 body.append(" %s;" % func)
324 body.append("}")
325 body = string.join(body, "\n") + "\n"
326
327 return self.try_link(body, headers, include_dirs,
328 libraries, library_dirs)
329
330 # check_func ()
331
332 def check_lib (self, library, library_dirs=None,
333 headers=None, include_dirs=None, other_libraries=[]):
334 """Determine if 'library' is available to be linked against,
335 without actually checking that any particular symbols are provided
336 by it. 'headers' will be used in constructing the source file to
337 be compiled, but the only effect of this is to check if all the
338 header files listed are available. Any libraries listed in
339 'other_libraries' will be included in the link, in case 'library'
340 has symbols that depend on other libraries.
341 """
342 self._check_compiler()
343 return self.try_link("int main (void) { }",
344 headers, include_dirs,
345 [library]+other_libraries, library_dirs)
346
347 def check_header (self, header, include_dirs=None,
348 library_dirs=None, lang="c"):
349 """Determine if the system header file named by 'header_file'
350 exists and can be found by the preprocessor; return true if so,
351 false otherwise.
352 """
353 return self.try_cpp(body="/* No body */", headers=[header],
354 include_dirs=include_dirs)
355
356
357# class config
358
359
360def dump_file (filename, head=None):
361 if head is None:
362 print filename + ":"
363 else:
364 print head
365
366 file = open(filename)
367 sys.stdout.write(file.read())
368 file.close()