17db96d56Sopenharmony_ci"""distutils.unixccompiler 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciContains the UnixCCompiler class, a subclass of CCompiler that handles 47db96d56Sopenharmony_cithe "typical" Unix-style command-line C compiler: 57db96d56Sopenharmony_ci * macros defined with -Dname[=value] 67db96d56Sopenharmony_ci * macros undefined with -Uname 77db96d56Sopenharmony_ci * include search directories specified with -Idir 87db96d56Sopenharmony_ci * libraries specified with -lllib 97db96d56Sopenharmony_ci * library search directories specified with -Ldir 107db96d56Sopenharmony_ci * compile handled by 'cc' (or similar) executable with -c option: 117db96d56Sopenharmony_ci compiles .c to .o 127db96d56Sopenharmony_ci * link static library handled by 'ar' command (possibly with 'ranlib') 137db96d56Sopenharmony_ci * link shared library handled by 'cc -shared' 147db96d56Sopenharmony_ci""" 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ciimport os, sys, re 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_cifrom distutils import sysconfig 197db96d56Sopenharmony_cifrom distutils.dep_util import newer 207db96d56Sopenharmony_cifrom distutils.ccompiler import \ 217db96d56Sopenharmony_ci CCompiler, gen_preprocess_options, gen_lib_options 227db96d56Sopenharmony_cifrom distutils.errors import \ 237db96d56Sopenharmony_ci DistutilsExecError, CompileError, LibError, LinkError 247db96d56Sopenharmony_cifrom distutils import log 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ciif sys.platform == 'darwin': 277db96d56Sopenharmony_ci import _osx_support 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci# XXX Things not currently handled: 307db96d56Sopenharmony_ci# * optimization/debug/warning flags; we just use whatever's in Python's 317db96d56Sopenharmony_ci# Makefile and live with it. Is this adequate? If not, we might 327db96d56Sopenharmony_ci# have to have a bunch of subclasses GNUCCompiler, SGICCompiler, 337db96d56Sopenharmony_ci# SunCCompiler, and I suspect down that road lies madness. 347db96d56Sopenharmony_ci# * even if we don't know a warning flag from an optimization flag, 357db96d56Sopenharmony_ci# we need some way for outsiders to feed preprocessor/compiler/linker 367db96d56Sopenharmony_ci# flags in to us -- eg. a sysadmin might want to mandate certain flags 377db96d56Sopenharmony_ci# via a site config file, or a user might want to set something for 387db96d56Sopenharmony_ci# compiling this module distribution only via the setup.py command 397db96d56Sopenharmony_ci# line, whatever. As long as these options come from something on the 407db96d56Sopenharmony_ci# current system, they can be as system-dependent as they like, and we 417db96d56Sopenharmony_ci# should just happily stuff them into the preprocessor/compiler/linker 427db96d56Sopenharmony_ci# options and carry on. 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ciclass UnixCCompiler(CCompiler): 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci compiler_type = 'unix' 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ci # These are used by CCompiler in two places: the constructor sets 507db96d56Sopenharmony_ci # instance attributes 'preprocessor', 'compiler', etc. from them, and 517db96d56Sopenharmony_ci # 'set_executable()' allows any of these to be set. The defaults here 527db96d56Sopenharmony_ci # are pretty generic; they will probably have to be set by an outsider 537db96d56Sopenharmony_ci # (eg. using information discovered by the sysconfig about building 547db96d56Sopenharmony_ci # Python extensions). 557db96d56Sopenharmony_ci executables = {'preprocessor' : None, 567db96d56Sopenharmony_ci 'compiler' : ["cc"], 577db96d56Sopenharmony_ci 'compiler_so' : ["cc"], 587db96d56Sopenharmony_ci 'compiler_cxx' : ["cc"], 597db96d56Sopenharmony_ci 'linker_so' : ["cc", "-shared"], 607db96d56Sopenharmony_ci 'linker_exe' : ["cc"], 617db96d56Sopenharmony_ci 'archiver' : ["ar", "-cr"], 627db96d56Sopenharmony_ci 'ranlib' : None, 637db96d56Sopenharmony_ci } 647db96d56Sopenharmony_ci 657db96d56Sopenharmony_ci if sys.platform[:6] == "darwin": 667db96d56Sopenharmony_ci executables['ranlib'] = ["ranlib"] 677db96d56Sopenharmony_ci 687db96d56Sopenharmony_ci # Needed for the filename generation methods provided by the base 697db96d56Sopenharmony_ci # class, CCompiler. NB. whoever instantiates/uses a particular 707db96d56Sopenharmony_ci # UnixCCompiler instance should set 'shared_lib_ext' -- we set a 717db96d56Sopenharmony_ci # reasonable common default here, but it's not necessarily used on all 727db96d56Sopenharmony_ci # Unices! 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"] 757db96d56Sopenharmony_ci obj_extension = ".o" 767db96d56Sopenharmony_ci static_lib_extension = ".a" 777db96d56Sopenharmony_ci shared_lib_extension = ".so" 787db96d56Sopenharmony_ci dylib_lib_extension = ".dylib" 797db96d56Sopenharmony_ci xcode_stub_lib_extension = ".tbd" 807db96d56Sopenharmony_ci static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s" 817db96d56Sopenharmony_ci xcode_stub_lib_format = dylib_lib_format 827db96d56Sopenharmony_ci if sys.platform == "cygwin": 837db96d56Sopenharmony_ci exe_extension = ".exe" 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci def preprocess(self, source, output_file=None, macros=None, 867db96d56Sopenharmony_ci include_dirs=None, extra_preargs=None, extra_postargs=None): 877db96d56Sopenharmony_ci fixed_args = self._fix_compile_args(None, macros, include_dirs) 887db96d56Sopenharmony_ci ignore, macros, include_dirs = fixed_args 897db96d56Sopenharmony_ci pp_opts = gen_preprocess_options(macros, include_dirs) 907db96d56Sopenharmony_ci pp_args = self.preprocessor + pp_opts 917db96d56Sopenharmony_ci if output_file: 927db96d56Sopenharmony_ci pp_args.extend(['-o', output_file]) 937db96d56Sopenharmony_ci if extra_preargs: 947db96d56Sopenharmony_ci pp_args[:0] = extra_preargs 957db96d56Sopenharmony_ci if extra_postargs: 967db96d56Sopenharmony_ci pp_args.extend(extra_postargs) 977db96d56Sopenharmony_ci pp_args.append(source) 987db96d56Sopenharmony_ci 997db96d56Sopenharmony_ci # We need to preprocess: either we're being forced to, or we're 1007db96d56Sopenharmony_ci # generating output to stdout, or there's a target output file and 1017db96d56Sopenharmony_ci # the source file is newer than the target (or the target doesn't 1027db96d56Sopenharmony_ci # exist). 1037db96d56Sopenharmony_ci if self.force or output_file is None or newer(source, output_file): 1047db96d56Sopenharmony_ci if output_file: 1057db96d56Sopenharmony_ci self.mkpath(os.path.dirname(output_file)) 1067db96d56Sopenharmony_ci try: 1077db96d56Sopenharmony_ci self.spawn(pp_args) 1087db96d56Sopenharmony_ci except DistutilsExecError as msg: 1097db96d56Sopenharmony_ci raise CompileError(msg) 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ci def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): 1127db96d56Sopenharmony_ci compiler_so = self.compiler_so 1137db96d56Sopenharmony_ci if sys.platform == 'darwin': 1147db96d56Sopenharmony_ci compiler_so = _osx_support.compiler_fixup(compiler_so, 1157db96d56Sopenharmony_ci cc_args + extra_postargs) 1167db96d56Sopenharmony_ci try: 1177db96d56Sopenharmony_ci self.spawn(compiler_so + cc_args + [src, '-o', obj] + 1187db96d56Sopenharmony_ci extra_postargs) 1197db96d56Sopenharmony_ci except DistutilsExecError as msg: 1207db96d56Sopenharmony_ci raise CompileError(msg) 1217db96d56Sopenharmony_ci 1227db96d56Sopenharmony_ci def create_static_lib(self, objects, output_libname, 1237db96d56Sopenharmony_ci output_dir=None, debug=0, target_lang=None): 1247db96d56Sopenharmony_ci objects, output_dir = self._fix_object_args(objects, output_dir) 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci output_filename = \ 1277db96d56Sopenharmony_ci self.library_filename(output_libname, output_dir=output_dir) 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_ci if self._need_link(objects, output_filename): 1307db96d56Sopenharmony_ci self.mkpath(os.path.dirname(output_filename)) 1317db96d56Sopenharmony_ci self.spawn(self.archiver + 1327db96d56Sopenharmony_ci [output_filename] + 1337db96d56Sopenharmony_ci objects + self.objects) 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ci # Not many Unices required ranlib anymore -- SunOS 4.x is, I 1367db96d56Sopenharmony_ci # think the only major Unix that does. Maybe we need some 1377db96d56Sopenharmony_ci # platform intelligence here to skip ranlib if it's not 1387db96d56Sopenharmony_ci # needed -- or maybe Python's configure script took care of 1397db96d56Sopenharmony_ci # it for us, hence the check for leading colon. 1407db96d56Sopenharmony_ci if self.ranlib: 1417db96d56Sopenharmony_ci try: 1427db96d56Sopenharmony_ci self.spawn(self.ranlib + [output_filename]) 1437db96d56Sopenharmony_ci except DistutilsExecError as msg: 1447db96d56Sopenharmony_ci raise LibError(msg) 1457db96d56Sopenharmony_ci else: 1467db96d56Sopenharmony_ci log.debug("skipping %s (up-to-date)", output_filename) 1477db96d56Sopenharmony_ci 1487db96d56Sopenharmony_ci def link(self, target_desc, objects, 1497db96d56Sopenharmony_ci output_filename, output_dir=None, libraries=None, 1507db96d56Sopenharmony_ci library_dirs=None, runtime_library_dirs=None, 1517db96d56Sopenharmony_ci export_symbols=None, debug=0, extra_preargs=None, 1527db96d56Sopenharmony_ci extra_postargs=None, build_temp=None, target_lang=None): 1537db96d56Sopenharmony_ci objects, output_dir = self._fix_object_args(objects, output_dir) 1547db96d56Sopenharmony_ci fixed_args = self._fix_lib_args(libraries, library_dirs, 1557db96d56Sopenharmony_ci runtime_library_dirs) 1567db96d56Sopenharmony_ci libraries, library_dirs, runtime_library_dirs = fixed_args 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, 1597db96d56Sopenharmony_ci libraries) 1607db96d56Sopenharmony_ci if not isinstance(output_dir, (str, type(None))): 1617db96d56Sopenharmony_ci raise TypeError("'output_dir' must be a string or None") 1627db96d56Sopenharmony_ci if output_dir is not None: 1637db96d56Sopenharmony_ci output_filename = os.path.join(output_dir, output_filename) 1647db96d56Sopenharmony_ci 1657db96d56Sopenharmony_ci if self._need_link(objects, output_filename): 1667db96d56Sopenharmony_ci ld_args = (objects + self.objects + 1677db96d56Sopenharmony_ci lib_opts + ['-o', output_filename]) 1687db96d56Sopenharmony_ci if debug: 1697db96d56Sopenharmony_ci ld_args[:0] = ['-g'] 1707db96d56Sopenharmony_ci if extra_preargs: 1717db96d56Sopenharmony_ci ld_args[:0] = extra_preargs 1727db96d56Sopenharmony_ci if extra_postargs: 1737db96d56Sopenharmony_ci ld_args.extend(extra_postargs) 1747db96d56Sopenharmony_ci self.mkpath(os.path.dirname(output_filename)) 1757db96d56Sopenharmony_ci try: 1767db96d56Sopenharmony_ci if target_desc == CCompiler.EXECUTABLE: 1777db96d56Sopenharmony_ci linker = self.linker_exe[:] 1787db96d56Sopenharmony_ci else: 1797db96d56Sopenharmony_ci linker = self.linker_so[:] 1807db96d56Sopenharmony_ci if target_lang == "c++" and self.compiler_cxx: 1817db96d56Sopenharmony_ci # skip over environment variable settings if /usr/bin/env 1827db96d56Sopenharmony_ci # is used to set up the linker's environment. 1837db96d56Sopenharmony_ci # This is needed on OSX. Note: this assumes that the 1847db96d56Sopenharmony_ci # normal and C++ compiler have the same environment 1857db96d56Sopenharmony_ci # settings. 1867db96d56Sopenharmony_ci i = 0 1877db96d56Sopenharmony_ci if os.path.basename(linker[0]) == "env": 1887db96d56Sopenharmony_ci i = 1 1897db96d56Sopenharmony_ci while '=' in linker[i]: 1907db96d56Sopenharmony_ci i += 1 1917db96d56Sopenharmony_ci 1927db96d56Sopenharmony_ci if os.path.basename(linker[i]) == 'ld_so_aix': 1937db96d56Sopenharmony_ci # AIX platforms prefix the compiler with the ld_so_aix 1947db96d56Sopenharmony_ci # script, so we need to adjust our linker index 1957db96d56Sopenharmony_ci offset = 1 1967db96d56Sopenharmony_ci else: 1977db96d56Sopenharmony_ci offset = 0 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci linker[i+offset] = self.compiler_cxx[i] 2007db96d56Sopenharmony_ci 2017db96d56Sopenharmony_ci if sys.platform == 'darwin': 2027db96d56Sopenharmony_ci linker = _osx_support.compiler_fixup(linker, ld_args) 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ci self.spawn(linker + ld_args) 2057db96d56Sopenharmony_ci except DistutilsExecError as msg: 2067db96d56Sopenharmony_ci raise LinkError(msg) 2077db96d56Sopenharmony_ci else: 2087db96d56Sopenharmony_ci log.debug("skipping %s (up-to-date)", output_filename) 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ci # -- Miscellaneous methods ----------------------------------------- 2117db96d56Sopenharmony_ci # These are all used by the 'gen_lib_options() function, in 2127db96d56Sopenharmony_ci # ccompiler.py. 2137db96d56Sopenharmony_ci 2147db96d56Sopenharmony_ci def library_dir_option(self, dir): 2157db96d56Sopenharmony_ci return "-L" + dir 2167db96d56Sopenharmony_ci 2177db96d56Sopenharmony_ci def _is_gcc(self, compiler_name): 2187db96d56Sopenharmony_ci # clang uses same syntax for rpath as gcc 2197db96d56Sopenharmony_ci return any(name in compiler_name for name in ("gcc", "g++", "clang")) 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci def runtime_library_dir_option(self, dir): 2227db96d56Sopenharmony_ci # XXX Hackish, at the very least. See Python bug #445902: 2237db96d56Sopenharmony_ci # http://sourceforge.net/tracker/index.php 2247db96d56Sopenharmony_ci # ?func=detail&aid=445902&group_id=5470&atid=105470 2257db96d56Sopenharmony_ci # Linkers on different platforms need different options to 2267db96d56Sopenharmony_ci # specify that directories need to be added to the list of 2277db96d56Sopenharmony_ci # directories searched for dependencies when a dynamic library 2287db96d56Sopenharmony_ci # is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to 2297db96d56Sopenharmony_ci # be told to pass the -R option through to the linker, whereas 2307db96d56Sopenharmony_ci # other compilers and gcc on other systems just know this. 2317db96d56Sopenharmony_ci # Other compilers may need something slightly different. At 2327db96d56Sopenharmony_ci # this time, there's no way to determine this information from 2337db96d56Sopenharmony_ci # the configuration data stored in the Python installation, so 2347db96d56Sopenharmony_ci # we use this hack. 2357db96d56Sopenharmony_ci compiler = os.path.basename(sysconfig.get_config_var("CC")) 2367db96d56Sopenharmony_ci if sys.platform[:6] == "darwin": 2377db96d56Sopenharmony_ci # MacOSX's linker doesn't understand the -R flag at all 2387db96d56Sopenharmony_ci return "-L" + dir 2397db96d56Sopenharmony_ci elif sys.platform[:7] == "freebsd": 2407db96d56Sopenharmony_ci return "-Wl,-rpath=" + dir 2417db96d56Sopenharmony_ci elif sys.platform[:5] == "hp-ux": 2427db96d56Sopenharmony_ci if self._is_gcc(compiler): 2437db96d56Sopenharmony_ci return ["-Wl,+s", "-L" + dir] 2447db96d56Sopenharmony_ci return ["+s", "-L" + dir] 2457db96d56Sopenharmony_ci else: 2467db96d56Sopenharmony_ci if self._is_gcc(compiler): 2477db96d56Sopenharmony_ci # gcc on non-GNU systems does not need -Wl, but can 2487db96d56Sopenharmony_ci # use it anyway. Since distutils has always passed in 2497db96d56Sopenharmony_ci # -Wl whenever gcc was used in the past it is probably 2507db96d56Sopenharmony_ci # safest to keep doing so. 2517db96d56Sopenharmony_ci if sysconfig.get_config_var("GNULD") == "yes": 2527db96d56Sopenharmony_ci # GNU ld needs an extra option to get a RUNPATH 2537db96d56Sopenharmony_ci # instead of just an RPATH. 2547db96d56Sopenharmony_ci return "-Wl,--enable-new-dtags,-R" + dir 2557db96d56Sopenharmony_ci else: 2567db96d56Sopenharmony_ci return "-Wl,-R" + dir 2577db96d56Sopenharmony_ci else: 2587db96d56Sopenharmony_ci # No idea how --enable-new-dtags would be passed on to 2597db96d56Sopenharmony_ci # ld if this system was using GNU ld. Don't know if a 2607db96d56Sopenharmony_ci # system like this even exists. 2617db96d56Sopenharmony_ci return "-R" + dir 2627db96d56Sopenharmony_ci 2637db96d56Sopenharmony_ci def library_option(self, lib): 2647db96d56Sopenharmony_ci return "-l" + lib 2657db96d56Sopenharmony_ci 2667db96d56Sopenharmony_ci def find_library_file(self, dirs, lib, debug=0): 2677db96d56Sopenharmony_ci shared_f = self.library_filename(lib, lib_type='shared') 2687db96d56Sopenharmony_ci dylib_f = self.library_filename(lib, lib_type='dylib') 2697db96d56Sopenharmony_ci xcode_stub_f = self.library_filename(lib, lib_type='xcode_stub') 2707db96d56Sopenharmony_ci static_f = self.library_filename(lib, lib_type='static') 2717db96d56Sopenharmony_ci 2727db96d56Sopenharmony_ci if sys.platform == 'darwin': 2737db96d56Sopenharmony_ci # On OSX users can specify an alternate SDK using 2747db96d56Sopenharmony_ci # '-isysroot', calculate the SDK root if it is specified 2757db96d56Sopenharmony_ci # (and use it further on) 2767db96d56Sopenharmony_ci # 2777db96d56Sopenharmony_ci # Note that, as of Xcode 7, Apple SDKs may contain textual stub 2787db96d56Sopenharmony_ci # libraries with .tbd extensions rather than the normal .dylib 2797db96d56Sopenharmony_ci # shared libraries installed in /. The Apple compiler tool 2807db96d56Sopenharmony_ci # chain handles this transparently but it can cause problems 2817db96d56Sopenharmony_ci # for programs that are being built with an SDK and searching 2827db96d56Sopenharmony_ci # for specific libraries. Callers of find_library_file need to 2837db96d56Sopenharmony_ci # keep in mind that the base filename of the returned SDK library 2847db96d56Sopenharmony_ci # file might have a different extension from that of the library 2857db96d56Sopenharmony_ci # file installed on the running system, for example: 2867db96d56Sopenharmony_ci # /Applications/Xcode.app/Contents/Developer/Platforms/ 2877db96d56Sopenharmony_ci # MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/ 2887db96d56Sopenharmony_ci # usr/lib/libedit.tbd 2897db96d56Sopenharmony_ci # vs 2907db96d56Sopenharmony_ci # /usr/lib/libedit.dylib 2917db96d56Sopenharmony_ci cflags = sysconfig.get_config_var('CFLAGS') 2927db96d56Sopenharmony_ci m = re.search(r'-isysroot\s*(\S+)', cflags) 2937db96d56Sopenharmony_ci if m is None: 2947db96d56Sopenharmony_ci sysroot = _osx_support._default_sysroot(sysconfig.get_config_var('CC')) 2957db96d56Sopenharmony_ci else: 2967db96d56Sopenharmony_ci sysroot = m.group(1) 2977db96d56Sopenharmony_ci 2987db96d56Sopenharmony_ci 2997db96d56Sopenharmony_ci 3007db96d56Sopenharmony_ci for dir in dirs: 3017db96d56Sopenharmony_ci shared = os.path.join(dir, shared_f) 3027db96d56Sopenharmony_ci dylib = os.path.join(dir, dylib_f) 3037db96d56Sopenharmony_ci static = os.path.join(dir, static_f) 3047db96d56Sopenharmony_ci xcode_stub = os.path.join(dir, xcode_stub_f) 3057db96d56Sopenharmony_ci 3067db96d56Sopenharmony_ci if sys.platform == 'darwin' and ( 3077db96d56Sopenharmony_ci dir.startswith('/System/') or ( 3087db96d56Sopenharmony_ci dir.startswith('/usr/') and not dir.startswith('/usr/local/'))): 3097db96d56Sopenharmony_ci 3107db96d56Sopenharmony_ci shared = os.path.join(sysroot, dir[1:], shared_f) 3117db96d56Sopenharmony_ci dylib = os.path.join(sysroot, dir[1:], dylib_f) 3127db96d56Sopenharmony_ci static = os.path.join(sysroot, dir[1:], static_f) 3137db96d56Sopenharmony_ci xcode_stub = os.path.join(sysroot, dir[1:], xcode_stub_f) 3147db96d56Sopenharmony_ci 3157db96d56Sopenharmony_ci # We're second-guessing the linker here, with not much hard 3167db96d56Sopenharmony_ci # data to go on: GCC seems to prefer the shared library, so I'm 3177db96d56Sopenharmony_ci # assuming that *all* Unix C compilers do. And of course I'm 3187db96d56Sopenharmony_ci # ignoring even GCC's "-static" option. So sue me. 3197db96d56Sopenharmony_ci if os.path.exists(dylib): 3207db96d56Sopenharmony_ci return dylib 3217db96d56Sopenharmony_ci elif os.path.exists(xcode_stub): 3227db96d56Sopenharmony_ci return xcode_stub 3237db96d56Sopenharmony_ci elif os.path.exists(shared): 3247db96d56Sopenharmony_ci return shared 3257db96d56Sopenharmony_ci elif os.path.exists(static): 3267db96d56Sopenharmony_ci return static 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ci # Oops, didn't find it in *any* of 'dirs' 3297db96d56Sopenharmony_ci return None 330