python (3.11.7)
       1  """Provide access to Python's configuration information.  The specific
       2  configuration variables available depend heavily on the platform and
       3  configuration.  The values may be retrieved using
       4  get_config_var(name), and the list of variables is available via
       5  get_config_vars().keys().  Additional convenience functions are also
       6  available.
       7  
       8  Written by:   Fred L. Drake, Jr.
       9  Email:        <fdrake@acm.org>
      10  """
      11  
      12  import _imp
      13  import os
      14  import re
      15  import sys
      16  import warnings
      17  
      18  from functools import partial
      19  
      20  from .errors import DistutilsPlatformError
      21  
      22  from sysconfig import (
      23      _PREFIX as PREFIX,
      24      _BASE_PREFIX as BASE_PREFIX,
      25      _EXEC_PREFIX as EXEC_PREFIX,
      26      _BASE_EXEC_PREFIX as BASE_EXEC_PREFIX,
      27      _PROJECT_BASE as project_base,
      28      _PYTHON_BUILD as python_build,
      29      _init_posix as sysconfig_init_posix,
      30      parse_config_h as sysconfig_parse_config_h,
      31  
      32      _init_non_posix,
      33  
      34      _variable_rx,
      35      _findvar1_rx,
      36      _findvar2_rx,
      37  
      38      expand_makefile_vars,
      39      is_python_build,
      40      get_config_h_filename,
      41      get_config_var,
      42      get_config_vars,
      43      get_makefile_filename,
      44      get_python_version,
      45  )
      46  
      47  # This is better than
      48  # from sysconfig import _CONFIG_VARS as _config_vars
      49  # because it makes sure that the global dictionary is initialized
      50  # which might not be true in the time of import.
      51  _config_vars = get_config_vars()
      52  
      53  warnings.warn(
      54      'The distutils.sysconfig module is deprecated, use sysconfig instead',
      55      DeprecationWarning,
      56      stacklevel=2
      57  )
      58  
      59  
      60  # Following functions are the same as in sysconfig but with different API
      61  def parse_config_h(fp, g=None):
      62      return sysconfig_parse_config_h(fp, vars=g)
      63  
      64  
      65  _python_build = partial(is_python_build, check_home=True)
      66  _init_posix = partial(sysconfig_init_posix, _config_vars)
      67  _init_nt = partial(_init_non_posix, _config_vars)
      68  
      69  
      70  # Similar function is also implemented in sysconfig as _parse_makefile
      71  # but without the parsing capabilities of distutils.text_file.TextFile.
      72  def parse_makefile(fn, g=None):
      73      """Parse a Makefile-style file.
      74      A dictionary containing name/value pairs is returned.  If an
      75      optional dictionary is passed in as the second argument, it is
      76      used instead of a new dictionary.
      77      """
      78      from distutils.text_file import TextFile
      79      fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape")
      80  
      81      if g is None:
      82          g = {}
      83      done = {}
      84      notdone = {}
      85  
      86      while True:
      87          line = fp.readline()
      88          if line is None: # eof
      89              break
      90          m = re.match(_variable_rx, line)
      91          if m:
      92              n, v = m.group(1, 2)
      93              v = v.strip()
      94              # `$$' is a literal `$' in make
      95              tmpv = v.replace('$$', '')
      96  
      97              if "$" in tmpv:
      98                  notdone[n] = v
      99              else:
     100                  try:
     101                      v = int(v)
     102                  except ValueError:
     103                      # insert literal `$'
     104                      done[n] = v.replace('$$', '$')
     105                  else:
     106                      done[n] = v
     107  
     108      # Variables with a 'PY_' prefix in the makefile. These need to
     109      # be made available without that prefix through sysconfig.
     110      # Special care is needed to ensure that variable expansion works, even
     111      # if the expansion uses the name without a prefix.
     112      renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
     113  
     114      # do variable interpolation here
     115      while notdone:
     116          for name in list(notdone):
     117              value = notdone[name]
     118              m = re.search(_findvar1_rx, value) or re.search(_findvar2_rx, value)
     119              if m:
     120                  n = m.group(1)
     121                  found = True
     122                  if n in done:
     123                      item = str(done[n])
     124                  elif n in notdone:
     125                      # get it on a subsequent round
     126                      found = False
     127                  elif n in os.environ:
     128                      # do it like make: fall back to environment
     129                      item = os.environ[n]
     130  
     131                  elif n in renamed_variables:
     132                      if name.startswith('PY_') and name[3:] in renamed_variables:
     133                          item = ""
     134  
     135                      elif 'PY_' + n in notdone:
     136                          found = False
     137  
     138                      else:
     139                          item = str(done['PY_' + n])
     140                  else:
     141                      done[n] = item = ""
     142                  if found:
     143                      after = value[m.end():]
     144                      value = value[:m.start()] + item + after
     145                      if "$" in after:
     146                          notdone[name] = value
     147                      else:
     148                          try: value = int(value)
     149                          except ValueError:
     150                              done[name] = value.strip()
     151                          else:
     152                              done[name] = value
     153                          del notdone[name]
     154  
     155                          if name.startswith('PY_') \
     156                              and name[3:] in renamed_variables:
     157  
     158                              name = name[3:]
     159                              if name not in done:
     160                                  done[name] = value
     161              else:
     162                  # bogus variable reference; just drop it since we can't deal
     163                  del notdone[name]
     164  
     165      fp.close()
     166  
     167      # strip spurious spaces
     168      for k, v in done.items():
     169          if isinstance(v, str):
     170              done[k] = v.strip()
     171  
     172      # save the results in the global dictionary
     173      g.update(done)
     174      return g
     175  
     176  
     177  # Following functions are deprecated together with this module and they
     178  # have no direct replacement
     179  
     180  # Calculate the build qualifier flags if they are defined.  Adding the flags
     181  # to the include and lib directories only makes sense for an installation, not
     182  # an in-source build.
     183  build_flags = ''
     184  try:
     185      if not python_build:
     186          build_flags = sys.abiflags
     187  except AttributeError:
     188      # It's not a configure-based build, so the sys module doesn't have
     189      # this attribute, which is fine.
     190      pass
     191  
     192  
     193  def customize_compiler(compiler):
     194      """Do any platform-specific customization of a CCompiler instance.
     195  
     196      Mainly needed on Unix, so we can plug in the information that
     197      varies across Unices and is stored in Python's Makefile.
     198      """
     199      if compiler.compiler_type == "unix":
     200          if sys.platform == "darwin":
     201              # Perform first-time customization of compiler-related
     202              # config vars on OS X now that we know we need a compiler.
     203              # This is primarily to support Pythons from binary
     204              # installers.  The kind and paths to build tools on
     205              # the user system may vary significantly from the system
     206              # that Python itself was built on.  Also the user OS
     207              # version and build tools may not support the same set
     208              # of CPU architectures for universal builds.
     209              if not _config_vars.get('CUSTOMIZED_OSX_COMPILER'):
     210                  import _osx_support
     211                  _osx_support.customize_compiler(_config_vars)
     212                  _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
     213  
     214          (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
     215              get_config_vars('CC', 'CXX', 'CFLAGS',
     216                              'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
     217  
     218          if 'CC' in os.environ:
     219              newcc = os.environ['CC']
     220              if (sys.platform == 'darwin'
     221                      and 'LDSHARED' not in os.environ
     222                      and ldshared.startswith(cc)):
     223                  # On OS X, if CC is overridden, use that as the default
     224                  #       command for LDSHARED as well
     225                  ldshared = newcc + ldshared[len(cc):]
     226              cc = newcc
     227          if 'CXX' in os.environ:
     228              cxx = os.environ['CXX']
     229          if 'LDSHARED' in os.environ:
     230              ldshared = os.environ['LDSHARED']
     231          if 'CPP' in os.environ:
     232              cpp = os.environ['CPP']
     233          else:
     234              cpp = cc + " -E"           # not always
     235          if 'LDFLAGS' in os.environ:
     236              ldshared = ldshared + ' ' + os.environ['LDFLAGS']
     237          if 'CFLAGS' in os.environ:
     238              cflags = cflags + ' ' + os.environ['CFLAGS']
     239              ldshared = ldshared + ' ' + os.environ['CFLAGS']
     240          if 'CPPFLAGS' in os.environ:
     241              cpp = cpp + ' ' + os.environ['CPPFLAGS']
     242              cflags = cflags + ' ' + os.environ['CPPFLAGS']
     243              ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
     244          if 'AR' in os.environ:
     245              ar = os.environ['AR']
     246          if 'ARFLAGS' in os.environ:
     247              archiver = ar + ' ' + os.environ['ARFLAGS']
     248          else:
     249              archiver = ar + ' ' + ar_flags
     250  
     251          cc_cmd = cc + ' ' + cflags
     252          compiler.set_executables(
     253              preprocessor=cpp,
     254              compiler=cc_cmd,
     255              compiler_so=cc_cmd + ' ' + ccshared,
     256              compiler_cxx=cxx,
     257              linker_so=ldshared,
     258              linker_exe=cc,
     259              archiver=archiver)
     260  
     261          compiler.shared_lib_extension = shlib_suffix
     262  
     263  
     264  def get_python_inc(plat_specific=0, prefix=None):
     265      """Return the directory containing installed Python header files.
     266  
     267      If 'plat_specific' is false (the default), this is the path to the
     268      non-platform-specific header files, i.e. Python.h and so on;
     269      otherwise, this is the path to platform-specific header files
     270      (namely pyconfig.h).
     271  
     272      If 'prefix' is supplied, use it instead of sys.base_prefix or
     273      sys.base_exec_prefix -- i.e., ignore 'plat_specific'.
     274      """
     275      if prefix is None:
     276          prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX
     277      if os.name == "posix":
     278          if python_build:
     279              # Assume the executable is in the build directory.  The
     280              # pyconfig.h file should be in the same directory.  Since
     281              # the build directory may not be the source directory, we
     282              # must use "srcdir" from the makefile to find the "Include"
     283              # directory.
     284              if plat_specific:
     285                  return project_base
     286              else:
     287                  incdir = os.path.join(get_config_var('srcdir'), 'Include')
     288                  return os.path.normpath(incdir)
     289          python_dir = 'python' + get_python_version() + build_flags
     290          return os.path.join(prefix, "include", python_dir)
     291      elif os.name == "nt":
     292          if python_build:
     293              # Include both the include and PC dir to ensure we can find
     294              # pyconfig.h
     295              return (os.path.join(prefix, "include") + os.path.pathsep +
     296                      os.path.join(prefix, "PC"))
     297          return os.path.join(prefix, "include")
     298      else:
     299          raise DistutilsPlatformError(
     300              "I don't know where Python installs its C header files "
     301              "on platform '%s'" % os.name)
     302  
     303  
     304  def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
     305      """Return the directory containing the Python library (standard or
     306      site additions).
     307  
     308      If 'plat_specific' is true, return the directory containing
     309      platform-specific modules, i.e. any module from a non-pure-Python
     310      module distribution; otherwise, return the platform-shared library
     311      directory.  If 'standard_lib' is true, return the directory
     312      containing standard Python library modules; otherwise, return the
     313      directory for site-specific modules.
     314  
     315      If 'prefix' is supplied, use it instead of sys.base_prefix or
     316      sys.base_exec_prefix -- i.e., ignore 'plat_specific'.
     317      """
     318      if prefix is None:
     319          if standard_lib:
     320              prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX
     321          else:
     322              prefix = plat_specific and EXEC_PREFIX or PREFIX
     323  
     324      if os.name == "posix":
     325          if plat_specific or standard_lib:
     326              # Platform-specific modules (any module from a non-pure-Python
     327              # module distribution) or standard Python library modules.
     328              libdir = sys.platlibdir
     329          else:
     330              # Pure Python
     331              libdir = "lib"
     332          libpython = os.path.join(prefix, libdir,
     333                                   "python" + get_python_version())
     334          if standard_lib:
     335              return libpython
     336          else:
     337              return os.path.join(libpython, "site-packages")
     338      elif os.name == "nt":
     339          if standard_lib:
     340              return os.path.join(prefix, "Lib")
     341          else:
     342              return os.path.join(prefix, "Lib", "site-packages")
     343      else:
     344          raise DistutilsPlatformError(
     345              "I don't know where Python installs its library "
     346              "on platform '%s'" % os.name)