|
1 """distutils.extension |
|
2 |
|
3 Provides the Extension class, used to describe C/C++ extension |
|
4 modules in setup scripts.""" |
|
5 |
|
6 __revision__ = "$Id: extension.py 37623 2004-10-14 10:02:08Z anthonybaxter $" |
|
7 |
|
8 import os, string, sys |
|
9 from types import * |
|
10 |
|
11 try: |
|
12 import warnings |
|
13 except ImportError: |
|
14 warnings = None |
|
15 |
|
16 # This class is really only used by the "build_ext" command, so it might |
|
17 # make sense to put it in distutils.command.build_ext. However, that |
|
18 # module is already big enough, and I want to make this class a bit more |
|
19 # complex to simplify some common cases ("foo" module in "foo.c") and do |
|
20 # better error-checking ("foo.c" actually exists). |
|
21 # |
|
22 # Also, putting this in build_ext.py means every setup script would have to |
|
23 # import that large-ish module (indirectly, through distutils.core) in |
|
24 # order to do anything. |
|
25 |
|
26 class Extension: |
|
27 """Just a collection of attributes that describes an extension |
|
28 module and everything needed to build it (hopefully in a portable |
|
29 way, but there are hooks that let you be as unportable as you need). |
|
30 |
|
31 Instance attributes: |
|
32 name : string |
|
33 the full name of the extension, including any packages -- ie. |
|
34 *not* a filename or pathname, but Python dotted name |
|
35 sources : [string] |
|
36 list of source filenames, relative to the distribution root |
|
37 (where the setup script lives), in Unix form (slash-separated) |
|
38 for portability. Source files may be C, C++, SWIG (.i), |
|
39 platform-specific resource files, or whatever else is recognized |
|
40 by the "build_ext" command as source for a Python extension. |
|
41 include_dirs : [string] |
|
42 list of directories to search for C/C++ header files (in Unix |
|
43 form for portability) |
|
44 define_macros : [(name : string, value : string|None)] |
|
45 list of macros to define; each macro is defined using a 2-tuple, |
|
46 where 'value' is either the string to define it to or None to |
|
47 define it without a particular value (equivalent of "#define |
|
48 FOO" in source or -DFOO on Unix C compiler command line) |
|
49 undef_macros : [string] |
|
50 list of macros to undefine explicitly |
|
51 library_dirs : [string] |
|
52 list of directories to search for C/C++ libraries at link time |
|
53 libraries : [string] |
|
54 list of library names (not filenames or paths) to link against |
|
55 runtime_library_dirs : [string] |
|
56 list of directories to search for C/C++ libraries at run time |
|
57 (for shared extensions, this is when the extension is loaded) |
|
58 extra_objects : [string] |
|
59 list of extra files to link with (eg. object files not implied |
|
60 by 'sources', static library that must be explicitly specified, |
|
61 binary resource files, etc.) |
|
62 extra_compile_args : [string] |
|
63 any extra platform- and compiler-specific information to use |
|
64 when compiling the source files in 'sources'. For platforms and |
|
65 compilers where "command line" makes sense, this is typically a |
|
66 list of command-line arguments, but for other platforms it could |
|
67 be anything. |
|
68 extra_link_args : [string] |
|
69 any extra platform- and compiler-specific information to use |
|
70 when linking object files together to create the extension (or |
|
71 to create a new static Python interpreter). Similar |
|
72 interpretation as for 'extra_compile_args'. |
|
73 export_symbols : [string] |
|
74 list of symbols to be exported from a shared extension. Not |
|
75 used on all platforms, and not generally necessary for Python |
|
76 extensions, which typically export exactly one symbol: "init" + |
|
77 extension_name. |
|
78 swig_opts : [string] |
|
79 any extra options to pass to SWIG if a source file has the .i |
|
80 extension. |
|
81 depends : [string] |
|
82 list of files that the extension depends on |
|
83 language : string |
|
84 extension language (i.e. "c", "c++", "objc"). Will be detected |
|
85 from the source extensions if not provided. |
|
86 """ |
|
87 |
|
88 # When adding arguments to this constructor, be sure to update |
|
89 # setup_keywords in core.py. |
|
90 def __init__ (self, name, sources, |
|
91 include_dirs=None, |
|
92 define_macros=None, |
|
93 undef_macros=None, |
|
94 library_dirs=None, |
|
95 libraries=None, |
|
96 runtime_library_dirs=None, |
|
97 extra_objects=None, |
|
98 extra_compile_args=None, |
|
99 extra_link_args=None, |
|
100 export_symbols=None, |
|
101 swig_opts = None, |
|
102 depends=None, |
|
103 language=None, |
|
104 **kw # To catch unknown keywords |
|
105 ): |
|
106 assert type(name) is StringType, "'name' must be a string" |
|
107 assert (type(sources) is ListType and |
|
108 map(type, sources) == [StringType]*len(sources)), \ |
|
109 "'sources' must be a list of strings" |
|
110 |
|
111 self.name = name |
|
112 self.sources = sources |
|
113 self.include_dirs = include_dirs or [] |
|
114 self.define_macros = define_macros or [] |
|
115 self.undef_macros = undef_macros or [] |
|
116 self.library_dirs = library_dirs or [] |
|
117 self.libraries = libraries or [] |
|
118 self.runtime_library_dirs = runtime_library_dirs or [] |
|
119 self.extra_objects = extra_objects or [] |
|
120 self.extra_compile_args = extra_compile_args or [] |
|
121 self.extra_link_args = extra_link_args or [] |
|
122 self.export_symbols = export_symbols or [] |
|
123 self.swig_opts = swig_opts or [] |
|
124 self.depends = depends or [] |
|
125 self.language = language |
|
126 |
|
127 # If there are unknown keyword options, warn about them |
|
128 if len(kw): |
|
129 L = kw.keys() ; L.sort() |
|
130 L = map(repr, L) |
|
131 msg = "Unknown Extension options: " + string.join(L, ', ') |
|
132 if warnings is not None: |
|
133 warnings.warn(msg) |
|
134 else: |
|
135 sys.stderr.write(msg + '\n') |
|
136 # class Extension |
|
137 |
|
138 |
|
139 def read_setup_file (filename): |
|
140 from distutils.sysconfig import \ |
|
141 parse_makefile, expand_makefile_vars, _variable_rx |
|
142 from distutils.text_file import TextFile |
|
143 from distutils.util import split_quoted |
|
144 |
|
145 # First pass over the file to gather "VAR = VALUE" assignments. |
|
146 vars = parse_makefile(filename) |
|
147 |
|
148 # Second pass to gobble up the real content: lines of the form |
|
149 # <module> ... [<sourcefile> ...] [<cpparg> ...] [<library> ...] |
|
150 file = TextFile(filename, |
|
151 strip_comments=1, skip_blanks=1, join_lines=1, |
|
152 lstrip_ws=1, rstrip_ws=1) |
|
153 extensions = [] |
|
154 |
|
155 while 1: |
|
156 line = file.readline() |
|
157 if line is None: # eof |
|
158 break |
|
159 if _variable_rx.match(line): # VAR=VALUE, handled in first pass |
|
160 continue |
|
161 |
|
162 if line[0] == line[-1] == "*": |
|
163 file.warn("'%s' lines not handled yet" % line) |
|
164 continue |
|
165 |
|
166 #print "original line: " + line |
|
167 line = expand_makefile_vars(line, vars) |
|
168 words = split_quoted(line) |
|
169 #print "expanded line: " + line |
|
170 |
|
171 # NB. this parses a slightly different syntax than the old |
|
172 # makesetup script: here, there must be exactly one extension per |
|
173 # line, and it must be the first word of the line. I have no idea |
|
174 # why the old syntax supported multiple extensions per line, as |
|
175 # they all wind up being the same. |
|
176 |
|
177 module = words[0] |
|
178 ext = Extension(module, []) |
|
179 append_next_word = None |
|
180 |
|
181 for word in words[1:]: |
|
182 if append_next_word is not None: |
|
183 append_next_word.append(word) |
|
184 append_next_word = None |
|
185 continue |
|
186 |
|
187 suffix = os.path.splitext(word)[1] |
|
188 switch = word[0:2] ; value = word[2:] |
|
189 |
|
190 if suffix in (".c", ".cc", ".cpp", ".cxx", ".c++", ".m", ".mm"): |
|
191 # hmm, should we do something about C vs. C++ sources? |
|
192 # or leave it up to the CCompiler implementation to |
|
193 # worry about? |
|
194 ext.sources.append(word) |
|
195 elif switch == "-I": |
|
196 ext.include_dirs.append(value) |
|
197 elif switch == "-D": |
|
198 equals = string.find(value, "=") |
|
199 if equals == -1: # bare "-DFOO" -- no value |
|
200 ext.define_macros.append((value, None)) |
|
201 else: # "-DFOO=blah" |
|
202 ext.define_macros.append((value[0:equals], |
|
203 value[equals+2:])) |
|
204 elif switch == "-U": |
|
205 ext.undef_macros.append(value) |
|
206 elif switch == "-C": # only here 'cause makesetup has it! |
|
207 ext.extra_compile_args.append(word) |
|
208 elif switch == "-l": |
|
209 ext.libraries.append(value) |
|
210 elif switch == "-L": |
|
211 ext.library_dirs.append(value) |
|
212 elif switch == "-R": |
|
213 ext.runtime_library_dirs.append(value) |
|
214 elif word == "-rpath": |
|
215 append_next_word = ext.runtime_library_dirs |
|
216 elif word == "-Xlinker": |
|
217 append_next_word = ext.extra_link_args |
|
218 elif word == "-Xcompiler": |
|
219 append_next_word = ext.extra_compile_args |
|
220 elif switch == "-u": |
|
221 ext.extra_link_args.append(word) |
|
222 if not value: |
|
223 append_next_word = ext.extra_link_args |
|
224 elif suffix in (".a", ".so", ".sl", ".o", ".dylib"): |
|
225 # NB. a really faithful emulation of makesetup would |
|
226 # append a .o file to extra_objects only if it |
|
227 # had a slash in it; otherwise, it would s/.o/.c/ |
|
228 # and append it to sources. Hmmmm. |
|
229 ext.extra_objects.append(word) |
|
230 else: |
|
231 file.warn("unrecognized argument '%s'" % word) |
|
232 |
|
233 extensions.append(ext) |
|
234 |
|
235 #print "module:", module |
|
236 #print "source files:", source_files |
|
237 #print "cpp args:", cpp_args |
|
238 #print "lib args:", library_args |
|
239 |
|
240 #extensions[module] = { 'sources': source_files, |
|
241 # 'cpp_args': cpp_args, |
|
242 # 'lib_args': library_args } |
|
243 |
|
244 return extensions |
|
245 |
|
246 # read_setup_file () |