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