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