]>
Commit | Line | Data |
---|---|---|
1e4a197e RD |
1 | """distutils.command.build_clib |
2 | ||
3 | Implements the Distutils 'build_clib' command, to build a C/C++ library | |
4 | that is included in the module distribution and needed by an extension | |
5 | module.""" | |
6 | ||
7 | # This module should be kept compatible with Python 1.5.2. | |
8 | ||
9 | __revision__ = "$Id$" | |
10 | ||
11 | ||
12 | # XXX this module has *lots* of code ripped-off quite transparently from | |
13 | # build_ext.py -- not surprisingly really, as the work required to build | |
14 | # a static library from a collection of C source files is not really all | |
15 | # that different from what's required to build a shared object file from | |
16 | # a collection of C source files. Nevertheless, I haven't done the | |
17 | # necessary refactoring to account for the overlap in code between the | |
18 | # two modules, mainly because a number of subtle details changed in the | |
19 | # cut 'n paste. Sigh. | |
20 | ||
21 | import os, string | |
22 | from types import * | |
23 | from distutils.core import Command | |
24 | from distutils.errors import * | |
25 | from distutils.sysconfig import customize_compiler | |
26 | from distutils import log | |
27 | ||
28 | def show_compilers (): | |
29 | from distutils.ccompiler import show_compilers | |
30 | show_compilers() | |
31 | ||
32 | ||
33 | class build_clib (Command): | |
34 | ||
35 | description = "build C/C++ libraries used by Python extensions" | |
36 | ||
37 | user_options = [ | |
38 | ('build-clib', 'b', | |
39 | "directory to build C/C++ libraries to"), | |
40 | ('build-temp', 't', | |
41 | "directory to put temporary build by-products"), | |
42 | ('debug', 'g', | |
43 | "compile with debugging information"), | |
44 | ('force', 'f', | |
45 | "forcibly build everything (ignore file timestamps)"), | |
46 | ('compiler=', 'c', | |
47 | "specify the compiler type"), | |
48 | ] | |
49 | ||
50 | boolean_options = ['debug', 'force'] | |
51 | ||
52 | help_options = [ | |
53 | ('help-compiler', None, | |
54 | "list available compilers", show_compilers), | |
55 | ] | |
56 | ||
57 | def initialize_options (self): | |
58 | self.build_clib = None | |
59 | self.build_temp = None | |
60 | ||
61 | # List of libraries to build | |
62 | self.libraries = None | |
63 | ||
64 | # Compilation options for all libraries | |
65 | self.include_dirs = None | |
66 | self.define = None | |
67 | self.undef = None | |
68 | self.debug = None | |
69 | self.force = 0 | |
70 | self.compiler = None | |
71 | ||
72 | # initialize_options() | |
73 | ||
74 | ||
75 | def finalize_options (self): | |
76 | ||
77 | # This might be confusing: both build-clib and build-temp default | |
78 | # to build-temp as defined by the "build" command. This is because | |
79 | # I think that C libraries are really just temporary build | |
80 | # by-products, at least from the point of view of building Python | |
81 | # extensions -- but I want to keep my options open. | |
82 | self.set_undefined_options('build', | |
83 | ('build_temp', 'build_clib'), | |
84 | ('build_temp', 'build_temp'), | |
85 | ('compiler', 'compiler'), | |
86 | ('debug', 'debug'), | |
87 | ('force', 'force')) | |
88 | ||
89 | self.libraries = self.distribution.libraries | |
90 | if self.libraries: | |
91 | self.check_library_list(self.libraries) | |
92 | ||
93 | if self.include_dirs is None: | |
94 | self.include_dirs = self.distribution.include_dirs or [] | |
95 | if type(self.include_dirs) is StringType: | |
96 | self.include_dirs = string.split(self.include_dirs, | |
97 | os.pathsep) | |
98 | ||
99 | # XXX same as for build_ext -- what about 'self.define' and | |
100 | # 'self.undef' ? | |
101 | ||
102 | # finalize_options() | |
103 | ||
104 | ||
105 | def run (self): | |
106 | ||
107 | if not self.libraries: | |
108 | return | |
109 | ||
110 | # Yech -- this is cut 'n pasted from build_ext.py! | |
111 | from distutils.ccompiler import new_compiler | |
112 | self.compiler = new_compiler(compiler=self.compiler, | |
113 | dry_run=self.dry_run, | |
114 | force=self.force) | |
115 | customize_compiler(self.compiler) | |
116 | ||
117 | if self.include_dirs is not None: | |
118 | self.compiler.set_include_dirs(self.include_dirs) | |
119 | if self.define is not None: | |
120 | # 'define' option is a list of (name,value) tuples | |
121 | for (name,value) in self.define: | |
122 | self.compiler.define_macro(name, value) | |
123 | if self.undef is not None: | |
124 | for macro in self.undef: | |
125 | self.compiler.undefine_macro(macro) | |
126 | ||
127 | self.build_libraries(self.libraries) | |
128 | ||
129 | # run() | |
130 | ||
131 | ||
132 | def check_library_list (self, libraries): | |
133 | """Ensure that the list of libraries (presumably provided as a | |
134 | command option 'libraries') is valid, i.e. it is a list of | |
135 | 2-tuples, where the tuples are (library_name, build_info_dict). | |
136 | Raise DistutilsSetupError if the structure is invalid anywhere; | |
137 | just returns otherwise.""" | |
138 | ||
139 | # Yechh, blecch, ackk: this is ripped straight out of build_ext.py, | |
140 | # with only names changed to protect the innocent! | |
141 | ||
142 | if type(libraries) is not ListType: | |
143 | raise DistutilsSetupError, \ | |
144 | "'libraries' option must be a list of tuples" | |
145 | ||
146 | for lib in libraries: | |
147 | if type(lib) is not TupleType and len(lib) != 2: | |
148 | raise DistutilsSetupError, \ | |
149 | "each element of 'libraries' must a 2-tuple" | |
150 | ||
151 | if type(lib[0]) is not StringType: | |
152 | raise DistutilsSetupError, \ | |
153 | "first element of each tuple in 'libraries' " + \ | |
154 | "must be a string (the library name)" | |
155 | if '/' in lib[0] or (os.sep != '/' and os.sep in lib[0]): | |
156 | raise DistutilsSetupError, \ | |
157 | ("bad library name '%s': " + | |
158 | "may not contain directory separators") % \ | |
159 | lib[0] | |
160 | ||
161 | if type(lib[1]) is not DictionaryType: | |
162 | raise DistutilsSetupError, \ | |
163 | "second element of each tuple in 'libraries' " + \ | |
164 | "must be a dictionary (build info)" | |
165 | # for lib | |
166 | ||
167 | # check_library_list () | |
168 | ||
169 | ||
170 | def get_library_names (self): | |
171 | # Assume the library list is valid -- 'check_library_list()' is | |
172 | # called from 'finalize_options()', so it should be! | |
173 | ||
174 | if not self.libraries: | |
175 | return None | |
176 | ||
177 | lib_names = [] | |
178 | for (lib_name, build_info) in self.libraries: | |
179 | lib_names.append(lib_name) | |
180 | return lib_names | |
181 | ||
182 | # get_library_names () | |
183 | ||
184 | ||
185 | def get_source_files (self): | |
186 | self.check_library_list(self.libraries) | |
187 | filenames = [] | |
188 | for (lib_name, build_info) in self.libraries: | |
189 | sources = build_info.get('sources') | |
190 | if (sources is None or | |
191 | type(sources) not in (ListType, TupleType) ): | |
192 | raise DistutilsSetupError, \ | |
193 | ("in 'libraries' option (library '%s'), " | |
194 | "'sources' must be present and must be " | |
195 | "a list of source filenames") % lib_name | |
196 | ||
197 | filenames.extend(sources) | |
198 | ||
199 | return filenames | |
200 | # get_source_files () | |
201 | ||
202 | ||
203 | def build_libraries (self, libraries): | |
204 | ||
205 | for (lib_name, build_info) in libraries: | |
206 | sources = build_info.get('sources') | |
207 | if sources is None or type(sources) not in (ListType, TupleType): | |
208 | raise DistutilsSetupError, \ | |
209 | ("in 'libraries' option (library '%s'), " + | |
210 | "'sources' must be present and must be " + | |
211 | "a list of source filenames") % lib_name | |
212 | sources = list(sources) | |
213 | ||
214 | log.info("building '%s' library", lib_name) | |
215 | ||
216 | # First, compile the source code to object files in the library | |
217 | # directory. (This should probably change to putting object | |
218 | # files in a temporary build directory.) | |
219 | macros = build_info.get('macros') | |
220 | include_dirs = build_info.get('include_dirs') | |
221 | objects = self.compiler.compile(sources, | |
222 | output_dir=self.build_temp, | |
223 | macros=macros, | |
224 | include_dirs=include_dirs, | |
225 | debug=self.debug) | |
226 | ||
227 | # Now "link" the object files together into a static library. | |
228 | # (On Unix at least, this isn't really linking -- it just | |
229 | # builds an archive. Whatever.) | |
230 | self.compiler.create_static_lib(objects, lib_name, | |
231 | output_dir=self.build_clib, | |
232 | debug=self.debug) | |
233 | ||
234 | # for libraries | |
235 | ||
236 | # build_libraries () | |
237 | ||
238 | # class build_lib |