blob: aeda408e731979bf5884e4830fed142a70bfb25e [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
Serhiy Storchakaccd047e2016-04-25 00:12:32 +030012import 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]
Serhiy Storchakac5d5dfd2018-12-20 19:00:14 +0200109 with open(filename, "w") as file:
110 if headers:
111 for header in headers:
112 file.write("#include <%s>\n" % header)
113 file.write("\n")
114 file.write(body)
115 if body[-1] != "\n":
116 file.write("\n")
Greg Ward28a5f442000-06-06 02:57:07 +0000117 return filename
118
Collin Winter5b7e9d72007-08-30 03:52:21 +0000119 def _preprocess(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000120 src = self._gen_temp_sourcefile(body, headers, lang)
121 out = "_configtest.i"
122 self.temp_files.extend([src, out])
Greg Ward855dab92000-06-27 01:21:22 +0000123 self.compiler.preprocess(src, out, include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000124 return (src, out)
125
Collin Winter5b7e9d72007-08-30 03:52:21 +0000126 def _compile(self, body, headers, include_dirs, lang):
Greg Ward59ac7092000-06-21 03:00:50 +0000127 src = self._gen_temp_sourcefile(body, headers, lang)
128 if self.dump_source:
129 dump_file(src, "compiling '%s':" % src)
130 (obj,) = self.compiler.object_filenames([src])
131 self.temp_files.extend([src, obj])
Greg Ward855dab92000-06-27 01:21:22 +0000132 self.compiler.compile([src], include_dirs=include_dirs)
Greg Ward28a5f442000-06-06 02:57:07 +0000133 return (src, obj)
134
Tarek Ziadé9d254892009-04-12 15:07:31 +0000135 def _link(self, body, headers, include_dirs, libraries, library_dirs,
136 lang):
Greg Ward855dab92000-06-27 01:21:22 +0000137 (src, obj) = self._compile(body, headers, include_dirs, lang)
Fred Drake21d45352001-12-06 21:01:19 +0000138 prog = os.path.splitext(os.path.basename(src))[0]
Greg Ward59ac7092000-06-21 03:00:50 +0000139 self.compiler.link_executable([obj], prog,
140 libraries=libraries,
Gustavo Niemeyer6b016852002-11-05 16:12:02 +0000141 library_dirs=library_dirs,
142 target_lang=lang)
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000143
Just van Rossumca3fec72003-02-03 11:43:54 +0000144 if self.compiler.exe_extension is not None:
145 prog = prog + self.compiler.exe_extension
Andrew M. Kuchlingb1d60292001-08-16 14:08:02 +0000146 self.temp_files.append(prog)
147
Greg Ward59ac7092000-06-21 03:00:50 +0000148 return (src, obj, prog)
Greg Ward28a5f442000-06-06 02:57:07 +0000149
Collin Winter5b7e9d72007-08-30 03:52:21 +0000150 def _clean(self, *filenames):
Greg Ward59ac7092000-06-21 03:00:50 +0000151 if not filenames:
152 filenames = self.temp_files
153 self.temp_files = []
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000154 log.info("removing: %s", ' '.join(filenames))
Greg Ward28a5f442000-06-06 02:57:07 +0000155 for filename in filenames:
156 try:
157 os.remove(filename)
158 except OSError:
159 pass
160
161
Greg Ward28a5f442000-06-06 02:57:07 +0000162 # XXX these ignore the dry-run flag: what to do, what to do? even if
163 # you want a dry-run build, you still need some sort of configuration
164 # info. My inclination is to make it up to the real config command to
165 # consult 'dry_run', and assume a default (minimal) configuration if
166 # true. The problem with trying to do it here is that you'd have to
167 # return either true or false from all the 'try' methods, neither of
168 # which is correct.
169
Greg Ward59ac7092000-06-21 03:00:50 +0000170 # XXX need access to the header search path and maybe default macros.
171
Collin Winter5b7e9d72007-08-30 03:52:21 +0000172 def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000173 """Construct a source file from 'body' (a string containing lines
174 of C/C++ code) and 'headers' (a list of header files to include)
175 and run it through the preprocessor. Return true if the
176 preprocessor succeeded, false if there were any errors.
177 ('body' probably isn't of much use, but what the heck.)
178 """
179 from distutils.ccompiler import CompileError
180 self._check_compiler()
Collin Winter5b7e9d72007-08-30 03:52:21 +0000181 ok = True
Greg Ward59ac7092000-06-21 03:00:50 +0000182 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000183 self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000184 except CompileError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000185 ok = False
Greg Ward59ac7092000-06-21 03:00:50 +0000186
187 self._clean()
188 return ok
189
Tarek Ziadé9d254892009-04-12 15:07:31 +0000190 def search_cpp(self, pattern, body=None, headers=None, include_dirs=None,
191 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000192 """Construct a source file (just like 'try_cpp()'), run it through
193 the preprocessor, and return true if any line of the output matches
194 'pattern'. 'pattern' should either be a compiled regex object or a
195 string containing a regex. If both 'body' and 'headers' are None,
196 preprocesses an empty file -- which can be useful to determine the
197 symbols the preprocessor and compiler set by default.
198 """
Greg Ward59ac7092000-06-21 03:00:50 +0000199 self._check_compiler()
Tarek Ziadéfd39b7a2009-04-12 16:34:34 +0000200 src, out = self._preprocess(body, headers, include_dirs, lang)
Greg Ward59ac7092000-06-21 03:00:50 +0000201
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000202 if isinstance(pattern, str):
Greg Ward59ac7092000-06-21 03:00:50 +0000203 pattern = re.compile(pattern)
204
Serhiy Storchakac5d5dfd2018-12-20 19:00:14 +0200205 with open(out) as file:
206 match = False
207 while True:
208 line = file.readline()
209 if line == '':
210 break
211 if pattern.search(line):
212 match = True
213 break
Greg Ward59ac7092000-06-21 03:00:50 +0000214
Greg Ward59ac7092000-06-21 03:00:50 +0000215 self._clean()
216 return match
217
Collin Winter5b7e9d72007-08-30 03:52:21 +0000218 def try_compile(self, body, headers=None, include_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000219 """Try to compile a source file built from 'body' and 'headers'.
220 Return true on success, false otherwise.
Greg Ward28a5f442000-06-06 02:57:07 +0000221 """
222 from distutils.ccompiler import CompileError
223 self._check_compiler()
224 try:
Andrew M. Kuchling6fb8d3a2001-08-16 13:56:40 +0000225 self._compile(body, headers, include_dirs, lang)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000226 ok = True
Greg Ward28a5f442000-06-06 02:57:07 +0000227 except CompileError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000228 ok = False
Greg Ward28a5f442000-06-06 02:57:07 +0000229
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000230 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000231 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000232 return ok
233
Tarek Ziadé9d254892009-04-12 15:07:31 +0000234 def try_link(self, body, headers=None, include_dirs=None, libraries=None,
235 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000236 """Try to compile and link a source file, built from 'body' and
237 'headers', to executable form. Return true on success, false
Greg Ward28a5f442000-06-06 02:57:07 +0000238 otherwise.
239 """
240 from distutils.ccompiler import CompileError, LinkError
241 self._check_compiler()
242 try:
Greg Ward855dab92000-06-27 01:21:22 +0000243 self._link(body, headers, include_dirs,
244 libraries, library_dirs, lang)
Collin Winter5b7e9d72007-08-30 03:52:21 +0000245 ok = True
Greg Ward59ac7092000-06-21 03:00:50 +0000246 except (CompileError, LinkError):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000247 ok = False
Greg Ward59ac7092000-06-21 03:00:50 +0000248
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000249 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000250 self._clean()
251 return ok
Fred Drake21d45352001-12-06 21:01:19 +0000252
Tarek Ziadé9d254892009-04-12 15:07:31 +0000253 def try_run(self, body, headers=None, include_dirs=None, libraries=None,
254 library_dirs=None, lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000255 """Try to compile, link to an executable, and run a program
256 built from 'body' and 'headers'. Return true on success, false
257 otherwise.
258 """
259 from distutils.ccompiler import CompileError, LinkError
260 self._check_compiler()
261 try:
Andrew M. Kuchling246c4252001-08-13 13:56:24 +0000262 src, obj, exe = self._link(body, headers, include_dirs,
263 libraries, library_dirs, lang)
Greg Ward28a5f442000-06-06 02:57:07 +0000264 self.spawn([exe])
Collin Winter5b7e9d72007-08-30 03:52:21 +0000265 ok = True
Greg Ward28a5f442000-06-06 02:57:07 +0000266 except (CompileError, LinkError, DistutilsExecError):
Collin Winter5b7e9d72007-08-30 03:52:21 +0000267 ok = False
Greg Ward28a5f442000-06-06 02:57:07 +0000268
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000269 log.info(ok and "success!" or "failure.")
Greg Ward59ac7092000-06-21 03:00:50 +0000270 self._clean()
Greg Ward28a5f442000-06-06 02:57:07 +0000271 return ok
272
Greg Ward59ac7092000-06-21 03:00:50 +0000273
274 # -- High-level methods --------------------------------------------
275 # (these are the ones that are actually likely to be useful
276 # when implementing a real-world config command!)
277
Collin Winter5b7e9d72007-08-30 03:52:21 +0000278 def check_func(self, func, headers=None, include_dirs=None,
279 libraries=None, library_dirs=None, decl=0, call=0):
Greg Ward59ac7092000-06-21 03:00:50 +0000280 """Determine if function 'func' is available by constructing a
281 source file that refers to 'func', and compiles and links it.
282 If everything succeeds, returns true; otherwise returns false.
283
284 The constructed source file starts out by including the header
285 files listed in 'headers'. If 'decl' is true, it then declares
286 'func' (as "int func()"); you probably shouldn't supply 'headers'
287 and set 'decl' true in the same call, or you might get errors about
288 a conflicting declarations for 'func'. Finally, the constructed
289 'main()' function either references 'func' or (if 'call' is true)
290 calls it. 'libraries' and 'library_dirs' are used when
291 linking.
292 """
Greg Ward59ac7092000-06-21 03:00:50 +0000293 self._check_compiler()
294 body = []
295 if decl:
296 body.append("int %s ();" % func)
297 body.append("int main () {")
298 if call:
299 body.append(" %s();" % func)
300 else:
301 body.append(" %s;" % func)
302 body.append("}")
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000303 body = "\n".join(body) + "\n"
Greg Ward59ac7092000-06-21 03:00:50 +0000304
Greg Ward855dab92000-06-27 01:21:22 +0000305 return self.try_link(body, headers, include_dirs,
306 libraries, library_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000307
Collin Winter5b7e9d72007-08-30 03:52:21 +0000308 def check_lib(self, library, library_dirs=None, headers=None,
309 include_dirs=None, other_libraries=[]):
Greg Ward855dab92000-06-27 01:21:22 +0000310 """Determine if 'library' is available to be linked against,
311 without actually checking that any particular symbols are provided
312 by it. 'headers' will be used in constructing the source file to
313 be compiled, but the only effect of this is to check if all the
Greg Ward4cd6f2a2000-10-14 03:56:42 +0000314 header files listed are available. Any libraries listed in
315 'other_libraries' will be included in the link, in case 'library'
316 has symbols that depend on other libraries.
Greg Ward855dab92000-06-27 01:21:22 +0000317 """
318 self._check_compiler()
Collin Winter5b7e9d72007-08-30 03:52:21 +0000319 return self.try_link("int main (void) { }", headers, include_dirs,
320 [library] + other_libraries, library_dirs)
Greg Ward855dab92000-06-27 01:21:22 +0000321
Collin Winter5b7e9d72007-08-30 03:52:21 +0000322 def check_header(self, header, include_dirs=None, library_dirs=None,
323 lang="c"):
Greg Ward59ac7092000-06-21 03:00:50 +0000324 """Determine if the system header file named by 'header_file'
325 exists and can be found by the preprocessor; return true if so,
326 false otherwise.
327 """
Andrew M. Kuchling4013cbd2002-09-09 12:10:00 +0000328 return self.try_cpp(body="/* No body */", headers=[header],
329 include_dirs=include_dirs)
Greg Ward59ac7092000-06-21 03:00:50 +0000330
Collin Winter5b7e9d72007-08-30 03:52:21 +0000331def dump_file(filename, head=None):
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000332 """Dumps a file content into log.info.
Greg Ward59ac7092000-06-21 03:00:50 +0000333
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000334 If head is not None, will be dumped before the file content.
335 """
336 if head is None:
Vinay Sajipdd917f82016-08-31 08:22:29 +0100337 log.info('%s', filename)
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000338 else:
339 log.info(head)
Greg Ward59ac7092000-06-21 03:00:50 +0000340 file = open(filename)
Tarek Ziadé0eb13042009-04-12 14:57:46 +0000341 try:
342 log.info(file.read())
343 finally:
344 file.close()