1 | n/a | """distutils.unixccompiler |
---|
2 | n/a | |
---|
3 | n/a | Contains the UnixCCompiler class, a subclass of CCompiler that handles |
---|
4 | n/a | the "typical" Unix-style command-line C compiler: |
---|
5 | n/a | * macros defined with -Dname[=value] |
---|
6 | n/a | * macros undefined with -Uname |
---|
7 | n/a | * include search directories specified with -Idir |
---|
8 | n/a | * libraries specified with -lllib |
---|
9 | n/a | * library search directories specified with -Ldir |
---|
10 | n/a | * compile handled by 'cc' (or similar) executable with -c option: |
---|
11 | n/a | compiles .c to .o |
---|
12 | n/a | * link static library handled by 'ar' command (possibly with 'ranlib') |
---|
13 | n/a | * link shared library handled by 'cc -shared' |
---|
14 | n/a | """ |
---|
15 | n/a | |
---|
16 | n/a | import os, sys, re |
---|
17 | n/a | |
---|
18 | n/a | from distutils import sysconfig |
---|
19 | n/a | from distutils.dep_util import newer |
---|
20 | n/a | from distutils.ccompiler import \ |
---|
21 | n/a | CCompiler, gen_preprocess_options, gen_lib_options |
---|
22 | n/a | from distutils.errors import \ |
---|
23 | n/a | DistutilsExecError, CompileError, LibError, LinkError |
---|
24 | n/a | from distutils import log |
---|
25 | n/a | |
---|
26 | n/a | if sys.platform == 'darwin': |
---|
27 | n/a | import _osx_support |
---|
28 | n/a | |
---|
29 | n/a | # XXX Things not currently handled: |
---|
30 | n/a | # * optimization/debug/warning flags; we just use whatever's in Python's |
---|
31 | n/a | # Makefile and live with it. Is this adequate? If not, we might |
---|
32 | n/a | # have to have a bunch of subclasses GNUCCompiler, SGICCompiler, |
---|
33 | n/a | # SunCCompiler, and I suspect down that road lies madness. |
---|
34 | n/a | # * even if we don't know a warning flag from an optimization flag, |
---|
35 | n/a | # we need some way for outsiders to feed preprocessor/compiler/linker |
---|
36 | n/a | # flags in to us -- eg. a sysadmin might want to mandate certain flags |
---|
37 | n/a | # via a site config file, or a user might want to set something for |
---|
38 | n/a | # compiling this module distribution only via the setup.py command |
---|
39 | n/a | # line, whatever. As long as these options come from something on the |
---|
40 | n/a | # current system, they can be as system-dependent as they like, and we |
---|
41 | n/a | # should just happily stuff them into the preprocessor/compiler/linker |
---|
42 | n/a | # options and carry on. |
---|
43 | n/a | |
---|
44 | n/a | |
---|
45 | n/a | class UnixCCompiler(CCompiler): |
---|
46 | n/a | |
---|
47 | n/a | compiler_type = 'unix' |
---|
48 | n/a | |
---|
49 | n/a | # These are used by CCompiler in two places: the constructor sets |
---|
50 | n/a | # instance attributes 'preprocessor', 'compiler', etc. from them, and |
---|
51 | n/a | # 'set_executable()' allows any of these to be set. The defaults here |
---|
52 | n/a | # are pretty generic; they will probably have to be set by an outsider |
---|
53 | n/a | # (eg. using information discovered by the sysconfig about building |
---|
54 | n/a | # Python extensions). |
---|
55 | n/a | executables = {'preprocessor' : None, |
---|
56 | n/a | 'compiler' : ["cc"], |
---|
57 | n/a | 'compiler_so' : ["cc"], |
---|
58 | n/a | 'compiler_cxx' : ["cc"], |
---|
59 | n/a | 'linker_so' : ["cc", "-shared"], |
---|
60 | n/a | 'linker_exe' : ["cc"], |
---|
61 | n/a | 'archiver' : ["ar", "-cr"], |
---|
62 | n/a | 'ranlib' : None, |
---|
63 | n/a | } |
---|
64 | n/a | |
---|
65 | n/a | if sys.platform[:6] == "darwin": |
---|
66 | n/a | executables['ranlib'] = ["ranlib"] |
---|
67 | n/a | |
---|
68 | n/a | # Needed for the filename generation methods provided by the base |
---|
69 | n/a | # class, CCompiler. NB. whoever instantiates/uses a particular |
---|
70 | n/a | # UnixCCompiler instance should set 'shared_lib_ext' -- we set a |
---|
71 | n/a | # reasonable common default here, but it's not necessarily used on all |
---|
72 | n/a | # Unices! |
---|
73 | n/a | |
---|
74 | n/a | src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"] |
---|
75 | n/a | obj_extension = ".o" |
---|
76 | n/a | static_lib_extension = ".a" |
---|
77 | n/a | shared_lib_extension = ".so" |
---|
78 | n/a | dylib_lib_extension = ".dylib" |
---|
79 | n/a | xcode_stub_lib_extension = ".tbd" |
---|
80 | n/a | static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s" |
---|
81 | n/a | xcode_stub_lib_format = dylib_lib_format |
---|
82 | n/a | if sys.platform == "cygwin": |
---|
83 | n/a | exe_extension = ".exe" |
---|
84 | n/a | |
---|
85 | n/a | def preprocess(self, source, output_file=None, macros=None, |
---|
86 | n/a | include_dirs=None, extra_preargs=None, extra_postargs=None): |
---|
87 | n/a | fixed_args = self._fix_compile_args(None, macros, include_dirs) |
---|
88 | n/a | ignore, macros, include_dirs = fixed_args |
---|
89 | n/a | pp_opts = gen_preprocess_options(macros, include_dirs) |
---|
90 | n/a | pp_args = self.preprocessor + pp_opts |
---|
91 | n/a | if output_file: |
---|
92 | n/a | pp_args.extend(['-o', output_file]) |
---|
93 | n/a | if extra_preargs: |
---|
94 | n/a | pp_args[:0] = extra_preargs |
---|
95 | n/a | if extra_postargs: |
---|
96 | n/a | pp_args.extend(extra_postargs) |
---|
97 | n/a | pp_args.append(source) |
---|
98 | n/a | |
---|
99 | n/a | # We need to preprocess: either we're being forced to, or we're |
---|
100 | n/a | # generating output to stdout, or there's a target output file and |
---|
101 | n/a | # the source file is newer than the target (or the target doesn't |
---|
102 | n/a | # exist). |
---|
103 | n/a | if self.force or output_file is None or newer(source, output_file): |
---|
104 | n/a | if output_file: |
---|
105 | n/a | self.mkpath(os.path.dirname(output_file)) |
---|
106 | n/a | try: |
---|
107 | n/a | self.spawn(pp_args) |
---|
108 | n/a | except DistutilsExecError as msg: |
---|
109 | n/a | raise CompileError(msg) |
---|
110 | n/a | |
---|
111 | n/a | def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): |
---|
112 | n/a | compiler_so = self.compiler_so |
---|
113 | n/a | if sys.platform == 'darwin': |
---|
114 | n/a | compiler_so = _osx_support.compiler_fixup(compiler_so, |
---|
115 | n/a | cc_args + extra_postargs) |
---|
116 | n/a | try: |
---|
117 | n/a | self.spawn(compiler_so + cc_args + [src, '-o', obj] + |
---|
118 | n/a | extra_postargs) |
---|
119 | n/a | except DistutilsExecError as msg: |
---|
120 | n/a | raise CompileError(msg) |
---|
121 | n/a | |
---|
122 | n/a | def create_static_lib(self, objects, output_libname, |
---|
123 | n/a | output_dir=None, debug=0, target_lang=None): |
---|
124 | n/a | objects, output_dir = self._fix_object_args(objects, output_dir) |
---|
125 | n/a | |
---|
126 | n/a | output_filename = \ |
---|
127 | n/a | self.library_filename(output_libname, output_dir=output_dir) |
---|
128 | n/a | |
---|
129 | n/a | if self._need_link(objects, output_filename): |
---|
130 | n/a | self.mkpath(os.path.dirname(output_filename)) |
---|
131 | n/a | self.spawn(self.archiver + |
---|
132 | n/a | [output_filename] + |
---|
133 | n/a | objects + self.objects) |
---|
134 | n/a | |
---|
135 | n/a | # Not many Unices required ranlib anymore -- SunOS 4.x is, I |
---|
136 | n/a | # think the only major Unix that does. Maybe we need some |
---|
137 | n/a | # platform intelligence here to skip ranlib if it's not |
---|
138 | n/a | # needed -- or maybe Python's configure script took care of |
---|
139 | n/a | # it for us, hence the check for leading colon. |
---|
140 | n/a | if self.ranlib: |
---|
141 | n/a | try: |
---|
142 | n/a | self.spawn(self.ranlib + [output_filename]) |
---|
143 | n/a | except DistutilsExecError as msg: |
---|
144 | n/a | raise LibError(msg) |
---|
145 | n/a | else: |
---|
146 | n/a | log.debug("skipping %s (up-to-date)", output_filename) |
---|
147 | n/a | |
---|
148 | n/a | def link(self, target_desc, objects, |
---|
149 | n/a | output_filename, output_dir=None, libraries=None, |
---|
150 | n/a | library_dirs=None, runtime_library_dirs=None, |
---|
151 | n/a | export_symbols=None, debug=0, extra_preargs=None, |
---|
152 | n/a | extra_postargs=None, build_temp=None, target_lang=None): |
---|
153 | n/a | objects, output_dir = self._fix_object_args(objects, output_dir) |
---|
154 | n/a | fixed_args = self._fix_lib_args(libraries, library_dirs, |
---|
155 | n/a | runtime_library_dirs) |
---|
156 | n/a | libraries, library_dirs, runtime_library_dirs = fixed_args |
---|
157 | n/a | |
---|
158 | n/a | lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, |
---|
159 | n/a | libraries) |
---|
160 | n/a | if not isinstance(output_dir, (str, type(None))): |
---|
161 | n/a | raise TypeError("'output_dir' must be a string or None") |
---|
162 | n/a | if output_dir is not None: |
---|
163 | n/a | output_filename = os.path.join(output_dir, output_filename) |
---|
164 | n/a | |
---|
165 | n/a | if self._need_link(objects, output_filename): |
---|
166 | n/a | ld_args = (objects + self.objects + |
---|
167 | n/a | lib_opts + ['-o', output_filename]) |
---|
168 | n/a | if debug: |
---|
169 | n/a | ld_args[:0] = ['-g'] |
---|
170 | n/a | if extra_preargs: |
---|
171 | n/a | ld_args[:0] = extra_preargs |
---|
172 | n/a | if extra_postargs: |
---|
173 | n/a | ld_args.extend(extra_postargs) |
---|
174 | n/a | self.mkpath(os.path.dirname(output_filename)) |
---|
175 | n/a | try: |
---|
176 | n/a | if target_desc == CCompiler.EXECUTABLE: |
---|
177 | n/a | linker = self.linker_exe[:] |
---|
178 | n/a | else: |
---|
179 | n/a | linker = self.linker_so[:] |
---|
180 | n/a | if target_lang == "c++" and self.compiler_cxx: |
---|
181 | n/a | # skip over environment variable settings if /usr/bin/env |
---|
182 | n/a | # is used to set up the linker's environment. |
---|
183 | n/a | # This is needed on OSX. Note: this assumes that the |
---|
184 | n/a | # normal and C++ compiler have the same environment |
---|
185 | n/a | # settings. |
---|
186 | n/a | i = 0 |
---|
187 | n/a | if os.path.basename(linker[0]) == "env": |
---|
188 | n/a | i = 1 |
---|
189 | n/a | while '=' in linker[i]: |
---|
190 | n/a | i += 1 |
---|
191 | n/a | linker[i] = self.compiler_cxx[i] |
---|
192 | n/a | |
---|
193 | n/a | if sys.platform == 'darwin': |
---|
194 | n/a | linker = _osx_support.compiler_fixup(linker, ld_args) |
---|
195 | n/a | |
---|
196 | n/a | self.spawn(linker + ld_args) |
---|
197 | n/a | except DistutilsExecError as msg: |
---|
198 | n/a | raise LinkError(msg) |
---|
199 | n/a | else: |
---|
200 | n/a | log.debug("skipping %s (up-to-date)", output_filename) |
---|
201 | n/a | |
---|
202 | n/a | # -- Miscellaneous methods ----------------------------------------- |
---|
203 | n/a | # These are all used by the 'gen_lib_options() function, in |
---|
204 | n/a | # ccompiler.py. |
---|
205 | n/a | |
---|
206 | n/a | def library_dir_option(self, dir): |
---|
207 | n/a | return "-L" + dir |
---|
208 | n/a | |
---|
209 | n/a | def _is_gcc(self, compiler_name): |
---|
210 | n/a | return "gcc" in compiler_name or "g++" in compiler_name |
---|
211 | n/a | |
---|
212 | n/a | def runtime_library_dir_option(self, dir): |
---|
213 | n/a | # XXX Hackish, at the very least. See Python bug #445902: |
---|
214 | n/a | # http://sourceforge.net/tracker/index.php |
---|
215 | n/a | # ?func=detail&aid=445902&group_id=5470&atid=105470 |
---|
216 | n/a | # Linkers on different platforms need different options to |
---|
217 | n/a | # specify that directories need to be added to the list of |
---|
218 | n/a | # directories searched for dependencies when a dynamic library |
---|
219 | n/a | # is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to |
---|
220 | n/a | # be told to pass the -R option through to the linker, whereas |
---|
221 | n/a | # other compilers and gcc on other systems just know this. |
---|
222 | n/a | # Other compilers may need something slightly different. At |
---|
223 | n/a | # this time, there's no way to determine this information from |
---|
224 | n/a | # the configuration data stored in the Python installation, so |
---|
225 | n/a | # we use this hack. |
---|
226 | n/a | compiler = os.path.basename(sysconfig.get_config_var("CC")) |
---|
227 | n/a | if sys.platform[:6] == "darwin": |
---|
228 | n/a | # MacOSX's linker doesn't understand the -R flag at all |
---|
229 | n/a | return "-L" + dir |
---|
230 | n/a | elif sys.platform[:7] == "freebsd": |
---|
231 | n/a | return "-Wl,-rpath=" + dir |
---|
232 | n/a | elif sys.platform[:5] == "hp-ux": |
---|
233 | n/a | if self._is_gcc(compiler): |
---|
234 | n/a | return ["-Wl,+s", "-L" + dir] |
---|
235 | n/a | return ["+s", "-L" + dir] |
---|
236 | n/a | elif sys.platform[:7] == "irix646" or sys.platform[:6] == "osf1V5": |
---|
237 | n/a | return ["-rpath", dir] |
---|
238 | n/a | else: |
---|
239 | n/a | if self._is_gcc(compiler): |
---|
240 | n/a | # gcc on non-GNU systems does not need -Wl, but can |
---|
241 | n/a | # use it anyway. Since distutils has always passed in |
---|
242 | n/a | # -Wl whenever gcc was used in the past it is probably |
---|
243 | n/a | # safest to keep doing so. |
---|
244 | n/a | if sysconfig.get_config_var("GNULD") == "yes": |
---|
245 | n/a | # GNU ld needs an extra option to get a RUNPATH |
---|
246 | n/a | # instead of just an RPATH. |
---|
247 | n/a | return "-Wl,--enable-new-dtags,-R" + dir |
---|
248 | n/a | else: |
---|
249 | n/a | return "-Wl,-R" + dir |
---|
250 | n/a | else: |
---|
251 | n/a | # No idea how --enable-new-dtags would be passed on to |
---|
252 | n/a | # ld if this system was using GNU ld. Don't know if a |
---|
253 | n/a | # system like this even exists. |
---|
254 | n/a | return "-R" + dir |
---|
255 | n/a | |
---|
256 | n/a | def library_option(self, lib): |
---|
257 | n/a | return "-l" + lib |
---|
258 | n/a | |
---|
259 | n/a | def find_library_file(self, dirs, lib, debug=0): |
---|
260 | n/a | shared_f = self.library_filename(lib, lib_type='shared') |
---|
261 | n/a | dylib_f = self.library_filename(lib, lib_type='dylib') |
---|
262 | n/a | xcode_stub_f = self.library_filename(lib, lib_type='xcode_stub') |
---|
263 | n/a | static_f = self.library_filename(lib, lib_type='static') |
---|
264 | n/a | |
---|
265 | n/a | if sys.platform == 'darwin': |
---|
266 | n/a | # On OSX users can specify an alternate SDK using |
---|
267 | n/a | # '-isysroot', calculate the SDK root if it is specified |
---|
268 | n/a | # (and use it further on) |
---|
269 | n/a | # |
---|
270 | n/a | # Note that, as of Xcode 7, Apple SDKs may contain textual stub |
---|
271 | n/a | # libraries with .tbd extensions rather than the normal .dylib |
---|
272 | n/a | # shared libraries installed in /. The Apple compiler tool |
---|
273 | n/a | # chain handles this transparently but it can cause problems |
---|
274 | n/a | # for programs that are being built with an SDK and searching |
---|
275 | n/a | # for specific libraries. Callers of find_library_file need to |
---|
276 | n/a | # keep in mind that the base filename of the returned SDK library |
---|
277 | n/a | # file might have a different extension from that of the library |
---|
278 | n/a | # file installed on the running system, for example: |
---|
279 | n/a | # /Applications/Xcode.app/Contents/Developer/Platforms/ |
---|
280 | n/a | # MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/ |
---|
281 | n/a | # usr/lib/libedit.tbd |
---|
282 | n/a | # vs |
---|
283 | n/a | # /usr/lib/libedit.dylib |
---|
284 | n/a | cflags = sysconfig.get_config_var('CFLAGS') |
---|
285 | n/a | m = re.search(r'-isysroot\s+(\S+)', cflags) |
---|
286 | n/a | if m is None: |
---|
287 | n/a | sysroot = '/' |
---|
288 | n/a | else: |
---|
289 | n/a | sysroot = m.group(1) |
---|
290 | n/a | |
---|
291 | n/a | |
---|
292 | n/a | |
---|
293 | n/a | for dir in dirs: |
---|
294 | n/a | shared = os.path.join(dir, shared_f) |
---|
295 | n/a | dylib = os.path.join(dir, dylib_f) |
---|
296 | n/a | static = os.path.join(dir, static_f) |
---|
297 | n/a | xcode_stub = os.path.join(dir, xcode_stub_f) |
---|
298 | n/a | |
---|
299 | n/a | if sys.platform == 'darwin' and ( |
---|
300 | n/a | dir.startswith('/System/') or ( |
---|
301 | n/a | dir.startswith('/usr/') and not dir.startswith('/usr/local/'))): |
---|
302 | n/a | |
---|
303 | n/a | shared = os.path.join(sysroot, dir[1:], shared_f) |
---|
304 | n/a | dylib = os.path.join(sysroot, dir[1:], dylib_f) |
---|
305 | n/a | static = os.path.join(sysroot, dir[1:], static_f) |
---|
306 | n/a | xcode_stub = os.path.join(sysroot, dir[1:], xcode_stub_f) |
---|
307 | n/a | |
---|
308 | n/a | # We're second-guessing the linker here, with not much hard |
---|
309 | n/a | # data to go on: GCC seems to prefer the shared library, so I'm |
---|
310 | n/a | # assuming that *all* Unix C compilers do. And of course I'm |
---|
311 | n/a | # ignoring even GCC's "-static" option. So sue me. |
---|
312 | n/a | if os.path.exists(dylib): |
---|
313 | n/a | return dylib |
---|
314 | n/a | elif os.path.exists(xcode_stub): |
---|
315 | n/a | return xcode_stub |
---|
316 | n/a | elif os.path.exists(shared): |
---|
317 | n/a | return shared |
---|
318 | n/a | elif os.path.exists(static): |
---|
319 | n/a | return static |
---|
320 | n/a | |
---|
321 | n/a | # Oops, didn't find it in *any* of 'dirs' |
---|
322 | n/a | return None |
---|