python (3.11.7)

(root)/
lib/
python3.11/
site-packages/
setuptools/
_distutils/
cygwinccompiler.py
       1  """distutils.cygwinccompiler
       2  
       3  Provides the CygwinCCompiler class, a subclass of UnixCCompiler that
       4  handles the Cygwin port of the GNU C compiler to Windows.  It also contains
       5  the Mingw32CCompiler class which handles the mingw32 port of GCC (same as
       6  cygwin in no-cygwin mode).
       7  """
       8  
       9  import os
      10  import sys
      11  import copy
      12  import shlex
      13  import warnings
      14  from subprocess import check_output
      15  
      16  from distutils.unixccompiler import UnixCCompiler
      17  from distutils.file_util import write_file
      18  from distutils.errors import (
      19      DistutilsExecError,
      20      DistutilsPlatformError,
      21      CCompilerError,
      22      CompileError,
      23  )
      24  from distutils.version import LooseVersion, suppress_known_deprecation
      25  
      26  
      27  def get_msvcr():
      28      """Include the appropriate MSVC runtime library if Python was built
      29      with MSVC 7.0 or later.
      30      """
      31      msc_pos = sys.version.find('MSC v.')
      32      if msc_pos != -1:
      33          msc_ver = sys.version[msc_pos + 6 : msc_pos + 10]
      34          if msc_ver == '1300':
      35              # MSVC 7.0
      36              return ['msvcr70']
      37          elif msc_ver == '1310':
      38              # MSVC 7.1
      39              return ['msvcr71']
      40          elif msc_ver == '1400':
      41              # VS2005 / MSVC 8.0
      42              return ['msvcr80']
      43          elif msc_ver == '1500':
      44              # VS2008 / MSVC 9.0
      45              return ['msvcr90']
      46          elif msc_ver == '1600':
      47              # VS2010 / MSVC 10.0
      48              return ['msvcr100']
      49          elif msc_ver == '1700':
      50              # VS2012 / MSVC 11.0
      51              return ['msvcr110']
      52          elif msc_ver == '1800':
      53              # VS2013 / MSVC 12.0
      54              return ['msvcr120']
      55          elif 1900 <= int(msc_ver) < 2000:
      56              # VS2015 / MSVC 14.0
      57              return ['ucrt', 'vcruntime140']
      58          else:
      59              raise ValueError("Unknown MS Compiler version %s " % msc_ver)
      60  
      61  
      62  _runtime_library_dirs_msg = (
      63      "Unable to set runtime library search path on Windows, "
      64      "usually indicated by `runtime_library_dirs` parameter to Extension"
      65  )
      66  
      67  
      68  class ESC[4;38;5;81mCygwinCCompiler(ESC[4;38;5;149mUnixCCompiler):
      69      """Handles the Cygwin port of the GNU C compiler to Windows."""
      70  
      71      compiler_type = 'cygwin'
      72      obj_extension = ".o"
      73      static_lib_extension = ".a"
      74      shared_lib_extension = ".dll.a"
      75      dylib_lib_extension = ".dll"
      76      static_lib_format = "lib%s%s"
      77      shared_lib_format = "lib%s%s"
      78      dylib_lib_format = "cyg%s%s"
      79      exe_extension = ".exe"
      80  
      81      def __init__(self, verbose=0, dry_run=0, force=0):
      82  
      83          super().__init__(verbose, dry_run, force)
      84  
      85          status, details = check_config_h()
      86          self.debug_print(
      87              "Python's GCC status: {} (details: {})".format(status, details)
      88          )
      89          if status is not CONFIG_H_OK:
      90              self.warn(
      91                  "Python's pyconfig.h doesn't seem to support your compiler. "
      92                  "Reason: %s. "
      93                  "Compiling may fail because of undefined preprocessor macros." % details
      94              )
      95  
      96          self.cc = os.environ.get('CC', 'gcc')
      97          self.cxx = os.environ.get('CXX', 'g++')
      98  
      99          self.linker_dll = self.cc
     100          shared_option = "-shared"
     101  
     102          self.set_executables(
     103              compiler='%s -mcygwin -O -Wall' % self.cc,
     104              compiler_so='%s -mcygwin -mdll -O -Wall' % self.cc,
     105              compiler_cxx='%s -mcygwin -O -Wall' % self.cxx,
     106              linker_exe='%s -mcygwin' % self.cc,
     107              linker_so=('{} -mcygwin {}'.format(self.linker_dll, shared_option)),
     108          )
     109  
     110          # Include the appropriate MSVC runtime library if Python was built
     111          # with MSVC 7.0 or later.
     112          self.dll_libraries = get_msvcr()
     113  
     114      @property
     115      def gcc_version(self):
     116          # Older numpy dependend on this existing to check for ancient
     117          # gcc versions. This doesn't make much sense with clang etc so
     118          # just hardcode to something recent.
     119          # https://github.com/numpy/numpy/pull/20333
     120          warnings.warn(
     121              "gcc_version attribute of CygwinCCompiler is deprecated. "
     122              "Instead of returning actual gcc version a fixed value 11.2.0 is returned.",
     123              DeprecationWarning,
     124              stacklevel=2,
     125          )
     126          with suppress_known_deprecation():
     127              return LooseVersion("11.2.0")
     128  
     129      def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
     130          """Compiles the source by spawning GCC and windres if needed."""
     131          if ext == '.rc' or ext == '.res':
     132              # gcc needs '.res' and '.rc' compiled to object files !!!
     133              try:
     134                  self.spawn(["windres", "-i", src, "-o", obj])
     135              except DistutilsExecError as msg:
     136                  raise CompileError(msg)
     137          else:  # for other files use the C-compiler
     138              try:
     139                  self.spawn(
     140                      self.compiler_so + cc_args + [src, '-o', obj] + extra_postargs
     141                  )
     142              except DistutilsExecError as msg:
     143                  raise CompileError(msg)
     144  
     145      def link(
     146          self,
     147          target_desc,
     148          objects,
     149          output_filename,
     150          output_dir=None,
     151          libraries=None,
     152          library_dirs=None,
     153          runtime_library_dirs=None,
     154          export_symbols=None,
     155          debug=0,
     156          extra_preargs=None,
     157          extra_postargs=None,
     158          build_temp=None,
     159          target_lang=None,
     160      ):
     161          """Link the objects."""
     162          # use separate copies, so we can modify the lists
     163          extra_preargs = copy.copy(extra_preargs or [])
     164          libraries = copy.copy(libraries or [])
     165          objects = copy.copy(objects or [])
     166  
     167          if runtime_library_dirs:
     168              self.warn(_runtime_library_dirs_msg)
     169  
     170          # Additional libraries
     171          libraries.extend(self.dll_libraries)
     172  
     173          # handle export symbols by creating a def-file
     174          # with executables this only works with gcc/ld as linker
     175          if (export_symbols is not None) and (
     176              target_desc != self.EXECUTABLE or self.linker_dll == "gcc"
     177          ):
     178              # (The linker doesn't do anything if output is up-to-date.
     179              # So it would probably better to check if we really need this,
     180              # but for this we had to insert some unchanged parts of
     181              # UnixCCompiler, and this is not what we want.)
     182  
     183              # we want to put some files in the same directory as the
     184              # object files are, build_temp doesn't help much
     185              # where are the object files
     186              temp_dir = os.path.dirname(objects[0])
     187              # name of dll to give the helper files the same base name
     188              (dll_name, dll_extension) = os.path.splitext(
     189                  os.path.basename(output_filename)
     190              )
     191  
     192              # generate the filenames for these files
     193              def_file = os.path.join(temp_dir, dll_name + ".def")
     194  
     195              # Generate .def file
     196              contents = ["LIBRARY %s" % os.path.basename(output_filename), "EXPORTS"]
     197              for sym in export_symbols:
     198                  contents.append(sym)
     199              self.execute(write_file, (def_file, contents), "writing %s" % def_file)
     200  
     201              # next add options for def-file
     202  
     203              # for gcc/ld the def-file is specified as any object files
     204              objects.append(def_file)
     205  
     206          # end: if ((export_symbols is not None) and
     207          #        (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
     208  
     209          # who wants symbols and a many times larger output file
     210          # should explicitly switch the debug mode on
     211          # otherwise we let ld strip the output file
     212          # (On my machine: 10KiB < stripped_file < ??100KiB
     213          #   unstripped_file = stripped_file + XXX KiB
     214          #  ( XXX=254 for a typical python extension))
     215          if not debug:
     216              extra_preargs.append("-s")
     217  
     218          UnixCCompiler.link(
     219              self,
     220              target_desc,
     221              objects,
     222              output_filename,
     223              output_dir,
     224              libraries,
     225              library_dirs,
     226              runtime_library_dirs,
     227              None,  # export_symbols, we do this in our def-file
     228              debug,
     229              extra_preargs,
     230              extra_postargs,
     231              build_temp,
     232              target_lang,
     233          )
     234  
     235      def runtime_library_dir_option(self, dir):
     236          # cygwin doesn't support rpath. While in theory we could error
     237          # out like MSVC does, code might expect it to work like on Unix, so
     238          # just warn and hope for the best.
     239          self.warn(_runtime_library_dirs_msg)
     240          return []
     241  
     242      # -- Miscellaneous methods -----------------------------------------
     243  
     244      def _make_out_path(self, output_dir, strip_dir, src_name):
     245          # use normcase to make sure '.rc' is really '.rc' and not '.RC'
     246          norm_src_name = os.path.normcase(src_name)
     247          return super()._make_out_path(output_dir, strip_dir, norm_src_name)
     248  
     249      @property
     250      def out_extensions(self):
     251          """
     252          Add support for rc and res files.
     253          """
     254          return {
     255              **super().out_extensions,
     256              **{ext: ext + self.obj_extension for ext in ('.res', '.rc')},
     257          }
     258  
     259  
     260  # the same as cygwin plus some additional parameters
     261  class ESC[4;38;5;81mMingw32CCompiler(ESC[4;38;5;149mCygwinCCompiler):
     262      """Handles the Mingw32 port of the GNU C compiler to Windows."""
     263  
     264      compiler_type = 'mingw32'
     265  
     266      def __init__(self, verbose=0, dry_run=0, force=0):
     267  
     268          super().__init__(verbose, dry_run, force)
     269  
     270          shared_option = "-shared"
     271  
     272          if is_cygwincc(self.cc):
     273              raise CCompilerError('Cygwin gcc cannot be used with --compiler=mingw32')
     274  
     275          self.set_executables(
     276              compiler='%s -O -Wall' % self.cc,
     277              compiler_so='%s -mdll -O -Wall' % self.cc,
     278              compiler_cxx='%s -O -Wall' % self.cxx,
     279              linker_exe='%s' % self.cc,
     280              linker_so='{} {}'.format(self.linker_dll, shared_option),
     281          )
     282  
     283          # Maybe we should also append -mthreads, but then the finished
     284          # dlls need another dll (mingwm10.dll see Mingw32 docs)
     285          # (-mthreads: Support thread-safe exception handling on `Mingw32')
     286  
     287          # no additional libraries needed
     288          self.dll_libraries = []
     289  
     290          # Include the appropriate MSVC runtime library if Python was built
     291          # with MSVC 7.0 or later.
     292          self.dll_libraries = get_msvcr()
     293  
     294      def runtime_library_dir_option(self, dir):
     295          raise DistutilsPlatformError(_runtime_library_dirs_msg)
     296  
     297  
     298  # Because these compilers aren't configured in Python's pyconfig.h file by
     299  # default, we should at least warn the user if he is using an unmodified
     300  # version.
     301  
     302  CONFIG_H_OK = "ok"
     303  CONFIG_H_NOTOK = "not ok"
     304  CONFIG_H_UNCERTAIN = "uncertain"
     305  
     306  
     307  def check_config_h():
     308      """Check if the current Python installation appears amenable to building
     309      extensions with GCC.
     310  
     311      Returns a tuple (status, details), where 'status' is one of the following
     312      constants:
     313  
     314      - CONFIG_H_OK: all is well, go ahead and compile
     315      - CONFIG_H_NOTOK: doesn't look good
     316      - CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h
     317  
     318      'details' is a human-readable string explaining the situation.
     319  
     320      Note there are two ways to conclude "OK": either 'sys.version' contains
     321      the string "GCC" (implying that this Python was built with GCC), or the
     322      installed "pyconfig.h" contains the string "__GNUC__".
     323      """
     324  
     325      # XXX since this function also checks sys.version, it's not strictly a
     326      # "pyconfig.h" check -- should probably be renamed...
     327  
     328      from distutils import sysconfig
     329  
     330      # if sys.version contains GCC then python was compiled with GCC, and the
     331      # pyconfig.h file should be OK
     332      if "GCC" in sys.version:
     333          return CONFIG_H_OK, "sys.version mentions 'GCC'"
     334  
     335      # Clang would also work
     336      if "Clang" in sys.version:
     337          return CONFIG_H_OK, "sys.version mentions 'Clang'"
     338  
     339      # let's see if __GNUC__ is mentioned in python.h
     340      fn = sysconfig.get_config_h_filename()
     341      try:
     342          config_h = open(fn)
     343          try:
     344              if "__GNUC__" in config_h.read():
     345                  return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn
     346              else:
     347                  return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn
     348          finally:
     349              config_h.close()
     350      except OSError as exc:
     351          return (CONFIG_H_UNCERTAIN, "couldn't read '{}': {}".format(fn, exc.strerror))
     352  
     353  
     354  def is_cygwincc(cc):
     355      '''Try to determine if the compiler that would be used is from cygwin.'''
     356      out_string = check_output(shlex.split(cc) + ['-dumpmachine'])
     357      return out_string.strip().endswith(b'cygwin')
     358  
     359  
     360  get_versions = None
     361  """
     362  A stand-in for the previous get_versions() function to prevent failures
     363  when monkeypatched. See pypa/setuptools#2969.
     364  """