blob: cad75bcb27482cb121aef433f9c6259784868bde [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
16import os, string
17from 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"),
43 ]
44
45
46 # The three standard command methods: since the "config" command
47 # does nothing by default, these are empty.
48
49 def initialize_options (self):
50 self.compiler = None
51 self.cc = None
52 self.include_dirs = None
53 #self.define = None
54 #self.undef = None
55 self.libraries = None
56 self.library_dirs = None
57
58 def finalize_options (self):
59 pass
60
61 def run (self):
62 pass
63
64
65 # Utility methods for actual "config" commands. The interfaces are
66 # loosely based on Autoconf macros of similar names. Sub-classes
67 # may use these freely.
68
69 def _check_compiler (self):
70 """Check that 'self.compiler' really is a CCompiler object;
71 if not, make it one.
72 """
73 # We do this late, and only on-demand, because this is an expensive
74 # import.
75 from distutils.ccompiler import CCompiler, new_compiler
76 if not isinstance(self.compiler, CCompiler):
77 self.compiler = new_compiler (compiler=self.compiler,
78 verbose=self.verbose, # for now
79 dry_run=self.dry_run,
80 force=1)
81 if self.include_dirs:
82 self.compiler.set_include_dirs(self.include_dirs)
83 if self.libraries:
84 self.compiler.set_libraries(self.libraries)
85 if self.library_dirs:
86 self.compiler.set_library_dirs(self.library_dirs)
87
88
89 def _gen_temp_sourcefile (self, body, lang):
90 filename = "_configtest" + LANG_EXT[lang]
91 file = open(filename, "w")
92 file.write(body)
93 file.close()
94 return filename
95
96 def _compile (self, body, lang):
97 src = self._gen_temp_sourcefile(body, lang)
98 (obj,) = self.compiler.compile([src])
99 return (src, obj)
100
101 def _link (self, body, lang):
102 (src, obj) = self._compile(body, lang)
103 exe = os.path.splitext(os.path.basename(src))[0]
104 self.compiler.link_executable([obj], exe)
105 return (src, obj, exe)
106
107 def _clean (self, *filenames):
108 self.announce("removing: " + string.join(filenames))
109 for filename in filenames:
110 try:
111 os.remove(filename)
112 except OSError:
113 pass
114
115
116 # XXX no 'try_cpp()' or 'search_cpp()' since the CCompiler interface
117 # does not provide access to the preprocessor. This is an oversight
118 # that should be fixed.
119
120 # XXX these ignore the dry-run flag: what to do, what to do? even if
121 # you want a dry-run build, you still need some sort of configuration
122 # info. My inclination is to make it up to the real config command to
123 # consult 'dry_run', and assume a default (minimal) configuration if
124 # true. The problem with trying to do it here is that you'd have to
125 # return either true or false from all the 'try' methods, neither of
126 # which is correct.
127
128 def try_compile (self, body, lang="c"):
129 """Try to compile a source file that consists of the text in 'body'
130 (a multi-line string). Return true on success, false
131 otherwise.
132 """
133 from distutils.ccompiler import CompileError
134 self._check_compiler()
135 try:
136 (src, obj) = self._compile(body, lang)
137 ok = 1
138 except CompileError:
139 ok = 0
140
141 self.announce(ok and "success!" or "failure.")
142 self._clean(src, obj)
143 return ok
144
145 def try_link (self, body, lang="c"):
146 """Try to compile and link a source file (to an executable) that
147 consists of the text in 'body' (a multi-line string). Return true
148 on success, false otherwise.
149 """
150 from distutils.ccompiler import CompileError, LinkError
151 self._check_compiler()
152 try:
153 (src, obj, exe) = self._link(body, lang)
154 ok = 1
155 except (CompileError, LinkError):
156 ok = 0
157
158 self.announce(ok and "success!" or "failure.")
159 self._clean(src, obj, exe)
160 return ok
161
162 def try_run (self, body, lang="c"):
163 """Try to compile, link to an executable, and run a program that
164 consists of the text in 'body'. Return true on success, false
165 otherwise.
166 """
167 from distutils.ccompiler import CompileError, LinkError
168 self._check_compiler()
169 try:
170 (src, obj, exe) = self._link(body, lang)
171 self.spawn([exe])
172 ok = 1
173 except (CompileError, LinkError, DistutilsExecError):
174 ok = 0
175
176 self.announce(ok and "success!" or "failure.")
177 self._clean(src, obj, exe)
178 return ok
179
180# class config