]>
Commit | Line | Data |
---|---|---|
1 | """distutils.unixccompiler | |
2 | ||
3 | Contains the UnixCCompiler class, a subclass of CCompiler that handles | |
4 | the "typical" Unix-style command-line C compiler: | |
5 | * macros defined with -Dname[=value] | |
6 | * macros undefined with -Uname | |
7 | * include search directories specified with -Idir | |
8 | * libraries specified with -lllib | |
9 | * library search directories specified with -Ldir | |
10 | * compile handled by 'cc' (or similar) executable with -c option: | |
11 | compiles .c to .o | |
12 | * link static library handled by 'ar' command (possibly with 'ranlib') | |
13 | * link shared library handled by 'cc -shared' | |
14 | """ | |
15 | ||
16 | __revision__ = "$Id$" | |
17 | ||
18 | import os, sys | |
19 | from types import StringType, NoneType | |
20 | from copy import copy | |
21 | ||
22 | from distutils import sysconfig | |
23 | from distutils.dep_util import newer | |
24 | from distutils.ccompiler import \ | |
25 | CCompiler, gen_preprocess_options, gen_lib_options | |
26 | from distutils.errors import \ | |
27 | DistutilsExecError, CompileError, LibError, LinkError | |
28 | from distutils import log | |
29 | ||
30 | # XXX Things not currently handled: | |
31 | # * optimization/debug/warning flags; we just use whatever's in Python's | |
32 | # Makefile and live with it. Is this adequate? If not, we might | |
33 | # have to have a bunch of subclasses GNUCCompiler, SGICCompiler, | |
34 | # SunCCompiler, and I suspect down that road lies madness. | |
35 | # * even if we don't know a warning flag from an optimization flag, | |
36 | # we need some way for outsiders to feed preprocessor/compiler/linker | |
37 | # flags in to us -- eg. a sysadmin might want to mandate certain flags | |
38 | # via a site config file, or a user might want to set something for | |
39 | # compiling this module distribution only via the setup.py command | |
40 | # line, whatever. As long as these options come from something on the | |
41 | # current system, they can be as system-dependent as they like, and we | |
42 | # should just happily stuff them into the preprocessor/compiler/linker | |
43 | # options and carry on. | |
44 | ||
45 | class UnixCCompiler(CCompiler): | |
46 | ||
47 | compiler_type = 'unix' | |
48 | ||
49 | # These are used by CCompiler in two places: the constructor sets | |
50 | # instance attributes 'preprocessor', 'compiler', etc. from them, and | |
51 | # 'set_executable()' allows any of these to be set. The defaults here | |
52 | # are pretty generic; they will probably have to be set by an outsider | |
53 | # (eg. using information discovered by the sysconfig about building | |
54 | # Python extensions). | |
55 | executables = {'preprocessor' : None, | |
56 | 'compiler' : ["cc"], | |
57 | 'compiler_so' : ["cc"], | |
58 | 'compiler_cxx' : ["cc"], | |
59 | 'linker_so' : ["cc", "-shared"], | |
60 | 'linker_exe' : ["cc"], | |
61 | 'archiver' : ["ar", "-cr"], | |
62 | 'ranlib' : None, | |
63 | } | |
64 | ||
65 | if sys.platform[:6] == "darwin": | |
66 | executables['ranlib'] = ["ranlib"] | |
67 | ||
68 | # Needed for the filename generation methods provided by the base | |
69 | # class, CCompiler. NB. whoever instantiates/uses a particular | |
70 | # UnixCCompiler instance should set 'shared_lib_ext' -- we set a | |
71 | # reasonable common default here, but it's not necessarily used on all | |
72 | # Unices! | |
73 | ||
74 | src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"] | |
75 | obj_extension = ".o" | |
76 | static_lib_extension = ".a" | |
77 | shared_lib_extension = ".so" | |
78 | dylib_lib_extension = ".dylib" | |
79 | static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s" | |
80 | if sys.platform == "cygwin": | |
81 | exe_extension = ".exe" | |
82 | ||
83 | def preprocess(self, source, | |
84 | output_file=None, macros=None, include_dirs=None, | |
85 | extra_preargs=None, extra_postargs=None): | |
86 | ignore, macros, include_dirs = \ | |
87 | self._fix_compile_args(None, macros, include_dirs) | |
88 | pp_opts = gen_preprocess_options(macros, include_dirs) | |
89 | pp_args = self.preprocessor + pp_opts | |
90 | if output_file: | |
91 | pp_args.extend(['-o', output_file]) | |
92 | if extra_preargs: | |
93 | pp_args[:0] = extra_preargs | |
94 | if extra_postargs: | |
95 | pp_args.extend(extra_postargs) | |
96 | pp_args.append(source) | |
97 | ||
98 | # We need to preprocess: either we're being forced to, or we're | |
99 | # generating output to stdout, or there's a target output file and | |
100 | # the source file is newer than the target (or the target doesn't | |
101 | # exist). | |
102 | if self.force or output_file is None or newer(source, output_file): | |
103 | if output_file: | |
104 | self.mkpath(os.path.dirname(output_file)) | |
105 | try: | |
106 | self.spawn(pp_args) | |
107 | except DistutilsExecError, msg: | |
108 | raise CompileError, msg | |
109 | ||
110 | def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): | |
111 | try: | |
112 | self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + | |
113 | extra_postargs) | |
114 | except DistutilsExecError, msg: | |
115 | raise CompileError, msg | |
116 | ||
117 | def create_static_lib(self, objects, output_libname, | |
118 | output_dir=None, debug=0, target_lang=None): | |
119 | objects, output_dir = self._fix_object_args(objects, output_dir) | |
120 | ||
121 | output_filename = \ | |
122 | self.library_filename(output_libname, output_dir=output_dir) | |
123 | ||
124 | if self._need_link(objects, output_filename): | |
125 | self.mkpath(os.path.dirname(output_filename)) | |
126 | self.spawn(self.archiver + | |
127 | [output_filename] + | |
128 | objects + self.objects) | |
129 | ||
130 | # Not many Unices required ranlib anymore -- SunOS 4.x is, I | |
131 | # think the only major Unix that does. Maybe we need some | |
132 | # platform intelligence here to skip ranlib if it's not | |
133 | # needed -- or maybe Python's configure script took care of | |
134 | # it for us, hence the check for leading colon. | |
135 | if self.ranlib: | |
136 | try: | |
137 | self.spawn(self.ranlib + [output_filename]) | |
138 | except DistutilsExecError, msg: | |
139 | raise LibError, msg | |
140 | else: | |
141 | log.debug("skipping %s (up-to-date)", output_filename) | |
142 | ||
143 | def link(self, target_desc, objects, | |
144 | output_filename, output_dir=None, libraries=None, | |
145 | library_dirs=None, runtime_library_dirs=None, | |
146 | export_symbols=None, debug=0, extra_preargs=None, | |
147 | extra_postargs=None, build_temp=None, target_lang=None): | |
148 | objects, output_dir = self._fix_object_args(objects, output_dir) | |
149 | libraries, library_dirs, runtime_library_dirs = \ | |
150 | self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) | |
151 | ||
152 | lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, | |
153 | libraries) | |
154 | if type(output_dir) not in (StringType, NoneType): | |
155 | raise TypeError, "'output_dir' must be a string or None" | |
156 | if output_dir is not None: | |
157 | output_filename = os.path.join(output_dir, output_filename) | |
158 | ||
159 | if self._need_link(objects, output_filename): | |
160 | ld_args = (objects + self.objects + | |
161 | lib_opts + ['-o', output_filename]) | |
162 | if debug: | |
163 | ld_args[:0] = ['-g'] | |
164 | if extra_preargs: | |
165 | ld_args[:0] = extra_preargs | |
166 | if extra_postargs: | |
167 | ld_args.extend(extra_postargs) | |
168 | self.mkpath(os.path.dirname(output_filename)) | |
169 | try: | |
170 | if target_desc == CCompiler.EXECUTABLE: | |
171 | linker = self.linker_exe[:] | |
172 | else: | |
173 | linker = self.linker_so[:] | |
174 | if target_lang == "c++" and self.compiler_cxx: | |
175 | linker[0] = self.compiler_cxx[0] | |
176 | self.spawn(linker + ld_args) | |
177 | except DistutilsExecError, msg: | |
178 | raise LinkError, msg | |
179 | else: | |
180 | log.debug("skipping %s (up-to-date)", output_filename) | |
181 | ||
182 | # -- Miscellaneous methods ----------------------------------------- | |
183 | # These are all used by the 'gen_lib_options() function, in | |
184 | # ccompiler.py. | |
185 | ||
186 | def library_dir_option(self, dir): | |
187 | return "-L" + dir | |
188 | ||
189 | def runtime_library_dir_option(self, dir): | |
190 | # XXX Hackish, at the very least. See Python bug #445902: | |
191 | # http://sourceforge.net/tracker/index.php | |
192 | # ?func=detail&aid=445902&group_id=5470&atid=105470 | |
193 | # Linkers on different platforms need different options to | |
194 | # specify that directories need to be added to the list of | |
195 | # directories searched for dependencies when a dynamic library | |
196 | # is sought. GCC has to be told to pass the -R option through | |
197 | # to the linker, whereas other compilers just know this. | |
198 | # Other compilers may need something slightly different. At | |
199 | # this time, there's no way to determine this information from | |
200 | # the configuration data stored in the Python installation, so | |
201 | # we use this hack. | |
202 | compiler = os.path.basename(sysconfig.get_config_var("CC")) | |
203 | if sys.platform[:6] == "darwin": | |
204 | # MacOSX's linker doesn't understand the -R flag at all | |
205 | return "-L" + dir | |
206 | elif sys.platform[:5] == "hp-ux": | |
207 | return "+s -L" + dir | |
208 | elif compiler[:3] == "gcc" or compiler[:3] == "g++": | |
209 | return "-Wl,-R" + dir | |
210 | else: | |
211 | return "-R" + dir | |
212 | ||
213 | def library_option(self, lib): | |
214 | return "-l" + lib | |
215 | ||
216 | def find_library_file(self, dirs, lib, debug=0): | |
217 | shared_f = self.library_filename(lib, lib_type='shared') | |
218 | dylib_f = self.library_filename(lib, lib_type='dylib') | |
219 | static_f = self.library_filename(lib, lib_type='static') | |
220 | ||
221 | for dir in dirs: | |
222 | shared = os.path.join(dir, shared_f) | |
223 | dylib = os.path.join(dir, dylib_f) | |
224 | static = os.path.join(dir, static_f) | |
225 | # We're second-guessing the linker here, with not much hard | |
226 | # data to go on: GCC seems to prefer the shared library, so I'm | |
227 | # assuming that *all* Unix C compilers do. And of course I'm | |
228 | # ignoring even GCC's "-static" option. So sue me. | |
229 | if os.path.exists(dylib): | |
230 | return dylib | |
231 | elif os.path.exists(shared): | |
232 | return shared | |
233 | elif os.path.exists(static): | |
234 | return static | |
235 | ||
236 | # Oops, didn't find it in *any* of 'dirs' | |
237 | return None |