| 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 |
|---|