(root)/
Python-3.12.0/
Modules/
getpath.py
       1  # ******************************************************************************
       2  # getpath.py
       3  # ******************************************************************************
       4  
       5  # This script is designed to be precompiled to bytecode, frozen into the
       6  # main binary, and then directly evaluated. It is not an importable module,
       7  # and does not import any other modules (besides winreg on Windows).
       8  # Rather, the values listed below must be specified in the globals dict
       9  # used when evaluating the bytecode.
      10  
      11  # See _PyConfig_InitPathConfig in Modules/getpath.c for the execution.
      12  
      13  # ******************************************************************************
      14  # REQUIRED GLOBALS
      15  # ******************************************************************************
      16  
      17  # ** Helper functions **
      18  # abspath(path)     -- make relative paths absolute against CWD
      19  # basename(path)    -- the filename of path
      20  # dirname(path)     -- the directory name of path
      21  # hassuffix(path, suffix) -- returns True if path has suffix
      22  # isabs(path)       -- path is absolute or not
      23  # isdir(path)       -- path exists and is a directory
      24  # isfile(path)      -- path exists and is a file
      25  # isxfile(path)     -- path exists and is an executable file
      26  # joinpath(*paths)  -- combine the paths
      27  # readlines(path)   -- a list of each line of text in the UTF-8 encoded file
      28  # realpath(path)    -- resolves symlinks in path
      29  # warn(message)     -- print a warning (if enabled)
      30  
      31  # ** Values known at compile time **
      32  # os_name           -- [in] one of 'nt', 'posix', 'darwin'
      33  # PREFIX            -- [in] sysconfig.get_config_var(...)
      34  # EXEC_PREFIX       -- [in] sysconfig.get_config_var(...)
      35  # PYTHONPATH        -- [in] sysconfig.get_config_var(...)
      36  # WITH_NEXT_FRAMEWORK   -- [in] sysconfig.get_config_var(...)
      37  # VPATH             -- [in] sysconfig.get_config_var(...)
      38  # PLATLIBDIR        -- [in] sysconfig.get_config_var(...)
      39  # PYDEBUGEXT        -- [in, opt] '_d' on Windows for debug builds
      40  # EXE_SUFFIX        -- [in, opt] '.exe' on Windows/Cygwin/similar
      41  # VERSION_MAJOR     -- [in] sys.version_info.major
      42  # VERSION_MINOR     -- [in] sys.version_info.minor
      43  # PYWINVER          -- [in] the Windows platform-specific version (e.g. 3.8-32)
      44  
      45  # ** Values read from the environment **
      46  #   There is no need to check the use_environment flag before reading
      47  #   these, as the flag will be tested in this script.
      48  #   Also note that ENV_PYTHONPATH is read from config['pythonpath_env']
      49  #   to allow for embedders who choose to specify it via that struct.
      50  # ENV_PATH                -- [in] getenv(...)
      51  # ENV_PYTHONHOME          -- [in] getenv(...)
      52  # ENV_PYTHONEXECUTABLE    -- [in] getenv(...)
      53  # ENV___PYVENV_LAUNCHER__ -- [in] getenv(...)
      54  
      55  # ** Values calculated at runtime **
      56  # config            -- [in/out] dict of the PyConfig structure
      57  # real_executable   -- [in, optional] resolved path to main process
      58  #   On Windows and macOS, read directly from the running process
      59  #   Otherwise, leave None and it will be calculated from executable
      60  # executable_dir    -- [in, optional] real directory containing binary
      61  #   If None, will be calculated from real_executable or executable
      62  # py_setpath        -- [in] argument provided to Py_SetPath
      63  #   If None, 'prefix' and 'exec_prefix' may be updated in config
      64  # library           -- [in, optional] path of dylib/DLL/so
      65  #   Only used for locating ._pth files
      66  # winreg            -- [in, optional] the winreg module (only on Windows)
      67  
      68  # ******************************************************************************
      69  # HIGH-LEVEL ALGORITHM
      70  # ******************************************************************************
      71  
      72  # IMPORTANT: The code is the actual specification at time of writing.
      73  # This prose description is based on the original comment from the old
      74  # getpath.c to help capture the intent, but should not be considered
      75  # a specification.
      76  
      77  # Search in some common locations for the associated Python libraries.
      78  
      79  # Two directories must be found, the platform independent directory
      80  # (prefix), containing the common .py and .pyc files, and the platform
      81  # dependent directory (exec_prefix), containing the shared library
      82  # modules.  Note that prefix and exec_prefix can be the same directory,
      83  # but for some installations, they are different.
      84  
      85  # This script carries out separate searches for prefix and exec_prefix.
      86  # Each search tries a number of different locations until a ``landmark''
      87  # file or directory is found.  If no prefix or exec_prefix is found, a
      88  # warning message is issued and the preprocessor defined PREFIX and
      89  # EXEC_PREFIX are used (even though they will not work); python carries on
      90  # as best as is possible, but most imports will fail.
      91  
      92  # Before any searches are done, the location of the executable is
      93  # determined.  If Py_SetPath() was called, or if we are running on
      94  # Windows, the 'real_executable' path is used (if known).  Otherwise,
      95  # we use the config-specified program name or default to argv[0].
      96  # If this has one or more slashes in it, it is made absolute against
      97  # the current working directory.  If it only contains a name, it must
      98  # have been invoked from the shell's path, so we search $PATH for the
      99  # named executable and use that.  If the executable was not found on
     100  # $PATH (or there was no $PATH environment variable), the original
     101  # argv[0] string is used.
     102  
     103  # At this point, provided Py_SetPath was not used, the
     104  # __PYVENV_LAUNCHER__ variable may override the executable (on macOS,
     105  # the PYTHON_EXECUTABLE variable may also override). This allows
     106  # certain launchers that run Python as a subprocess to properly
     107  # specify the executable path. They are not intended for users.
     108  
     109  # Next, the executable location is examined to see if it is a symbolic
     110  # link.  If so, the link is realpath-ed and the directory of the link
     111  # target is used for the remaining searches.  The same steps are
     112  # performed for prefix and for exec_prefix, but with different landmarks.
     113  
     114  # Step 1. Are we running in a virtual environment? Unless 'home' has
     115  # been specified another way, check for a pyvenv.cfg and use its 'home'
     116  # property to override the executable dir used later for prefix searches.
     117  # We do not activate the venv here - that is performed later by site.py.
     118  
     119  # Step 2. Is there a ._pth file? A ._pth file lives adjacent to the
     120  # runtime library (if any) or the actual executable (not the symlink),
     121  # and contains precisely the intended contents of sys.path as relative
     122  # paths (to its own location). Its presence also enables isolated mode
     123  # and suppresses other environment variable usage. Unless already
     124  # specified by Py_SetHome(), the directory containing the ._pth file is
     125  # set as 'home'.
     126  
     127  # Step 3. Are we running python out of the build directory?  This is
     128  # checked by looking for the BUILDDIR_TXT file, which contains the
     129  # relative path to the platlib dir. The executable_dir value is
     130  # derived from joining the VPATH preprocessor variable to the
     131  # directory containing pybuilddir.txt. If it is not found, the
     132  # BUILD_LANDMARK file is found, which is part of the source tree.
     133  # prefix is then found by searching up for a file that should only
     134  # exist in the source tree, and the stdlib dir is set to prefix/Lib.
     135  
     136  # Step 4. If 'home' is set, either by Py_SetHome(), ENV_PYTHONHOME,
     137  # a pyvenv.cfg file, ._pth file, or by detecting a build directory, it
     138  # is assumed to point to prefix and exec_prefix. $PYTHONHOME can be a
     139  # single directory, which is used for both, or the prefix and exec_prefix
     140  # directories separated by DELIM (colon on POSIX; semicolon on Windows).
     141  
     142  # Step 5. Try to find prefix and exec_prefix relative to executable_dir,
     143  # backtracking up the path until it is exhausted.  This is the most common
     144  # step to succeed.  Note that if prefix and exec_prefix are different,
     145  # exec_prefix is more likely to be found; however if exec_prefix is a
     146  # subdirectory of prefix, both will be found.
     147  
     148  # Step 6. Search the directories pointed to by the preprocessor variables
     149  # PREFIX and EXEC_PREFIX.  These are supplied by the Makefile but can be
     150  # passed in as options to the configure script.
     151  
     152  # That's it!
     153  
     154  # Well, almost.  Once we have determined prefix and exec_prefix, the
     155  # preprocessor variable PYTHONPATH is used to construct a path.  Each
     156  # relative path on PYTHONPATH is prefixed with prefix.  Then the directory
     157  # containing the shared library modules is appended.  The environment
     158  # variable $PYTHONPATH is inserted in front of it all. On POSIX, if we are
     159  # in a build directory, both prefix and exec_prefix are reset to the
     160  # corresponding preprocessor variables (so sys.prefix will reflect the
     161  # installation location, even though sys.path points into the build
     162  # directory).  This seems to make more sense given that currently the only
     163  # known use of sys.prefix and sys.exec_prefix is for the ILU installation
     164  # process to find the installed Python tree.
     165  
     166  # An embedding application can use Py_SetPath() to override all of
     167  # these automatic path computations.
     168  
     169  
     170  # ******************************************************************************
     171  # PLATFORM CONSTANTS
     172  # ******************************************************************************
     173  
     174  platlibdir = config.get('platlibdir') or PLATLIBDIR
     175  
     176  if os_name == 'posix' or os_name == 'darwin':
     177      BUILDDIR_TXT = 'pybuilddir.txt'
     178      BUILD_LANDMARK = 'Modules/Setup.local'
     179      DEFAULT_PROGRAM_NAME = f'python{VERSION_MAJOR}'
     180      STDLIB_SUBDIR = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}'
     181      STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}/os.py', f'{STDLIB_SUBDIR}/os.pyc']
     182      PLATSTDLIB_LANDMARK = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}/lib-dynload'
     183      BUILDSTDLIB_LANDMARKS = ['Lib/os.py']
     184      VENV_LANDMARK = 'pyvenv.cfg'
     185      ZIP_LANDMARK = f'{platlibdir}/python{VERSION_MAJOR}{VERSION_MINOR}.zip'
     186      DELIM = ':'
     187      SEP = '/'
     188  
     189  elif os_name == 'nt':
     190      BUILDDIR_TXT = 'pybuilddir.txt'
     191      BUILD_LANDMARK = f'{VPATH}\\Modules\\Setup.local'
     192      DEFAULT_PROGRAM_NAME = f'python'
     193      STDLIB_SUBDIR = 'Lib'
     194      STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}\\os.py', f'{STDLIB_SUBDIR}\\os.pyc']
     195      PLATSTDLIB_LANDMARK = f'{platlibdir}'
     196      BUILDSTDLIB_LANDMARKS = ['Lib\\os.py']
     197      VENV_LANDMARK = 'pyvenv.cfg'
     198      ZIP_LANDMARK = f'python{VERSION_MAJOR}{VERSION_MINOR}{PYDEBUGEXT or ""}.zip'
     199      WINREG_KEY = f'SOFTWARE\\Python\\PythonCore\\{PYWINVER}\\PythonPath'
     200      DELIM = ';'
     201      SEP = '\\'
     202  
     203  
     204  # ******************************************************************************
     205  # HELPER FUNCTIONS (note that we prefer C functions for performance)
     206  # ******************************************************************************
     207  
     208  def search_up(prefix, *landmarks, test=isfile):
     209      while prefix:
     210          if any(test(joinpath(prefix, f)) for f in landmarks):
     211              return prefix
     212          prefix = dirname(prefix)
     213  
     214  
     215  # ******************************************************************************
     216  # READ VARIABLES FROM config
     217  # ******************************************************************************
     218  
     219  program_name = config.get('program_name')
     220  home = config.get('home')
     221  executable = config.get('executable')
     222  base_executable = config.get('base_executable')
     223  prefix = config.get('prefix')
     224  exec_prefix = config.get('exec_prefix')
     225  base_prefix = config.get('base_prefix')
     226  base_exec_prefix = config.get('base_exec_prefix')
     227  ENV_PYTHONPATH = config['pythonpath_env']
     228  use_environment = config.get('use_environment', 1)
     229  
     230  pythonpath = config.get('module_search_paths')
     231  pythonpath_was_set = config.get('module_search_paths_set')
     232  
     233  real_executable_dir = None
     234  stdlib_dir = None
     235  platstdlib_dir = None
     236  
     237  # ******************************************************************************
     238  # CALCULATE program_name
     239  # ******************************************************************************
     240  
     241  program_name_was_set = bool(program_name)
     242  
     243  if not program_name:
     244      try:
     245          program_name = config.get('orig_argv', [])[0]
     246      except IndexError:
     247          pass
     248  
     249  if not program_name:
     250      program_name = DEFAULT_PROGRAM_NAME
     251  
     252  if EXE_SUFFIX and not hassuffix(program_name, EXE_SUFFIX) and isxfile(program_name + EXE_SUFFIX):
     253      program_name = program_name + EXE_SUFFIX
     254  
     255  
     256  # ******************************************************************************
     257  # CALCULATE executable
     258  # ******************************************************************************
     259  
     260  if py_setpath:
     261      # When Py_SetPath has been called, executable defaults to
     262      # the real executable path.
     263      if not executable:
     264          executable = real_executable
     265  
     266  if not executable and SEP in program_name:
     267      # Resolve partial path program_name against current directory
     268      executable = abspath(program_name)
     269  
     270  if not executable:
     271      # All platforms default to real_executable if known at this
     272      # stage. POSIX does not set this value.
     273      executable = real_executable
     274  elif os_name == 'darwin':
     275      # QUIRK: On macOS we may know the real executable path, but
     276      # if our caller has lied to us about it (e.g. most of
     277      # test_embed), we need to use their path in order to detect
     278      # whether we are in a build tree. This is true even if the
     279      # executable path was provided in the config.
     280      real_executable = executable
     281  
     282  if not executable and program_name and ENV_PATH:
     283      # Resolve names against PATH.
     284      # NOTE: The use_environment value is ignored for this lookup.
     285      # To properly isolate, launch Python with a full path.
     286      for p in ENV_PATH.split(DELIM):
     287          p = joinpath(p, program_name)
     288          if isxfile(p):
     289              executable = p
     290              break
     291  
     292  if not executable:
     293      executable = ''
     294      # When we cannot calculate the executable, subsequent searches
     295      # look in the current working directory. Here, we emulate that
     296      # (the former getpath.c would do it apparently by accident).
     297      executable_dir = abspath('.')
     298      # Also need to set this fallback in case we are running from a
     299      # build directory with an invalid argv0 (i.e. test_sys.test_executable)
     300      real_executable_dir = executable_dir
     301  
     302  if ENV_PYTHONEXECUTABLE or ENV___PYVENV_LAUNCHER__:
     303      # If set, these variables imply that we should be using them as
     304      # sys.executable and when searching for venvs. However, we should
     305      # use the argv0 path for prefix calculation
     306  
     307      if os_name == 'darwin' and WITH_NEXT_FRAMEWORK:
     308          # In a framework build the binary in {sys.exec_prefix}/bin is
     309          # a stub executable that execs the real interpreter in an
     310          # embedded app bundle. That bundle is an implementation detail
     311          # and should not affect base_executable.
     312          base_executable = f"{dirname(library)}/bin/python{VERSION_MAJOR}.{VERSION_MINOR}"
     313      else:
     314          base_executable = executable
     315  
     316      if not real_executable:
     317          real_executable = base_executable
     318          #real_executable_dir = dirname(real_executable)
     319      executable = ENV_PYTHONEXECUTABLE or ENV___PYVENV_LAUNCHER__
     320      executable_dir = dirname(executable)
     321  
     322  
     323  # ******************************************************************************
     324  # CALCULATE (default) home
     325  # ******************************************************************************
     326  
     327  # Used later to distinguish between Py_SetPythonHome and other
     328  # ways that it may have been set
     329  home_was_set = False
     330  
     331  if home:
     332      home_was_set = True
     333  elif use_environment and ENV_PYTHONHOME and not py_setpath:
     334      home = ENV_PYTHONHOME
     335  
     336  
     337  # ******************************************************************************
     338  # READ pyvenv.cfg
     339  # ******************************************************************************
     340  
     341  venv_prefix = None
     342  
     343  # Calling Py_SetPythonHome(), Py_SetPath() or
     344  # setting $PYTHONHOME will override venv detection.
     345  if not home and not py_setpath:
     346      try:
     347          # prefix2 is just to avoid calculating dirname again later,
     348          # as the path in venv_prefix is the more common case.
     349          venv_prefix2 = executable_dir or dirname(executable)
     350          venv_prefix = dirname(venv_prefix2)
     351          try:
     352              # Read pyvenv.cfg from one level above executable
     353              pyvenvcfg = readlines(joinpath(venv_prefix, VENV_LANDMARK))
     354          except (FileNotFoundError, PermissionError):
     355              # Try the same directory as executable
     356              pyvenvcfg = readlines(joinpath(venv_prefix2, VENV_LANDMARK))
     357              venv_prefix = venv_prefix2
     358      except (FileNotFoundError, PermissionError):
     359          venv_prefix = None
     360          pyvenvcfg = []
     361  
     362      for line in pyvenvcfg:
     363          key, had_equ, value = line.partition('=')
     364          if had_equ and key.strip().lower() == 'home':
     365              executable_dir = real_executable_dir = value.strip()
     366              if not base_executable:
     367                  # First try to resolve symlinked executables, since that may be
     368                  # more accurate than assuming the executable in 'home'.
     369                  try:
     370                      base_executable = realpath(executable)
     371                      if base_executable == executable:
     372                          # No change, so probably not a link. Clear it and fall back
     373                          base_executable = ''
     374                  except OSError:
     375                      pass
     376                  if not base_executable:
     377                      base_executable = joinpath(executable_dir, basename(executable))
     378                      # It's possible "python" is executed from within a posix venv but that
     379                      # "python" is not available in the "home" directory as the standard
     380                      # `make install` does not create it and distros often do not provide it.
     381                      #
     382                      # In this case, try to fall back to known alternatives
     383                      if os_name != 'nt' and not isfile(base_executable):
     384                          base_exe = basename(executable)
     385                          for candidate in (DEFAULT_PROGRAM_NAME, f'python{VERSION_MAJOR}.{VERSION_MINOR}'):
     386                              candidate += EXE_SUFFIX if EXE_SUFFIX else ''
     387                              if base_exe == candidate:
     388                                  continue
     389                              candidate = joinpath(executable_dir, candidate)
     390                              # Only set base_executable if the candidate exists.
     391                              # If no candidate succeeds, subsequent errors related to
     392                              # base_executable (like FileNotFoundError) remain in the
     393                              # context of the original executable name
     394                              if isfile(candidate):
     395                                  base_executable = candidate
     396                                  break
     397              break
     398      else:
     399          venv_prefix = None
     400  
     401  
     402  # ******************************************************************************
     403  # CALCULATE base_executable, real_executable AND executable_dir
     404  # ******************************************************************************
     405  
     406  if not base_executable:
     407      base_executable = executable or real_executable or ''
     408  
     409  if not real_executable:
     410      real_executable = base_executable
     411  
     412  try:
     413      real_executable = realpath(real_executable)
     414  except OSError as ex:
     415      # Only warn if the file actually exists and was unresolvable
     416      # Otherwise users who specify a fake executable may get spurious warnings.
     417      if isfile(real_executable):
     418          warn(f'Failed to find real location of {base_executable}')
     419  
     420  if not executable_dir and os_name == 'darwin' and library:
     421      # QUIRK: macOS checks adjacent to its library early
     422      library_dir = dirname(library)
     423      if any(isfile(joinpath(library_dir, p)) for p in STDLIB_LANDMARKS):
     424          # Exceptions here should abort the whole process (to match
     425          # previous behavior)
     426          executable_dir = realpath(library_dir)
     427          real_executable_dir = executable_dir
     428  
     429  # If we do not have the executable's directory, we can calculate it.
     430  # This is the directory used to find prefix/exec_prefix if necessary.
     431  if not executable_dir:
     432      executable_dir = real_executable_dir = dirname(real_executable)
     433  
     434  # If we do not have the real executable's directory, we calculate it.
     435  # This is the directory used to detect build layouts.
     436  if not real_executable_dir:
     437      real_executable_dir = dirname(real_executable)
     438  
     439  # ******************************************************************************
     440  # DETECT _pth FILE
     441  # ******************************************************************************
     442  
     443  # The contents of an optional ._pth file are used to totally override
     444  # sys.path calculation. Its presence also implies isolated mode and
     445  # no-site (unless explicitly requested)
     446  pth = None
     447  pth_dir = None
     448  
     449  # Calling Py_SetPythonHome() or Py_SetPath() will override ._pth search,
     450  # but environment variables and command-line options cannot.
     451  if not py_setpath and not home_was_set:
     452      # 1. Check adjacent to the main DLL/dylib/so (if set)
     453      # 2. Check adjacent to the original executable
     454      # 3. Check adjacent to our actual executable
     455      # This may allow a venv to override the base_executable's
     456      # ._pth file, but it cannot override the library's one.
     457      for p in [library, executable, real_executable]:
     458          if p:
     459              if os_name == 'nt' and (hassuffix(p, 'exe') or hassuffix(p, 'dll')):
     460                  p = p.rpartition('.')[0]
     461              p += '._pth'
     462              try:
     463                  pth = readlines(p)
     464                  pth_dir = dirname(p)
     465                  break
     466              except OSError:
     467                  pass
     468  
     469      # If we found a ._pth file, disable environment and home
     470      # detection now. Later, we will do the rest.
     471      if pth_dir:
     472          use_environment = 0
     473          home = pth_dir
     474          pythonpath = []
     475  
     476  
     477  # ******************************************************************************
     478  # CHECK FOR BUILD DIRECTORY
     479  # ******************************************************************************
     480  
     481  build_prefix = None
     482  
     483  if ((not home_was_set and real_executable_dir and not py_setpath)
     484          or config.get('_is_python_build', 0) > 0):
     485      # Detect a build marker and use it to infer prefix, exec_prefix,
     486      # stdlib_dir and the platstdlib_dir directories.
     487      try:
     488          platstdlib_dir = joinpath(
     489              real_executable_dir,
     490              readlines(joinpath(real_executable_dir, BUILDDIR_TXT))[0],
     491          )
     492          build_prefix = joinpath(real_executable_dir, VPATH)
     493      except IndexError:
     494          # File exists but is empty
     495          platstdlib_dir = real_executable_dir
     496          build_prefix = joinpath(real_executable_dir, VPATH)
     497      except (FileNotFoundError, PermissionError):
     498          if isfile(joinpath(real_executable_dir, BUILD_LANDMARK)):
     499              build_prefix = joinpath(real_executable_dir, VPATH)
     500              if os_name == 'nt':
     501                  # QUIRK: Windows builds need platstdlib_dir to be the executable
     502                  # dir. Normally the builddir marker handles this, but in this
     503                  # case we need to correct manually.
     504                  platstdlib_dir = real_executable_dir
     505  
     506      if build_prefix:
     507          if os_name == 'nt':
     508              # QUIRK: No searching for more landmarks on Windows
     509              build_stdlib_prefix = build_prefix
     510          else:
     511              build_stdlib_prefix = search_up(build_prefix, *BUILDSTDLIB_LANDMARKS)
     512          # Always use the build prefix for stdlib
     513          if build_stdlib_prefix:
     514              stdlib_dir = joinpath(build_stdlib_prefix, 'Lib')
     515          else:
     516              stdlib_dir = joinpath(build_prefix, 'Lib')
     517          # Only use the build prefix for prefix if it hasn't already been set
     518          if not prefix:
     519              prefix = build_stdlib_prefix
     520          # Do not warn, because 'prefix' never equals 'build_prefix' on POSIX
     521          #elif not venv_prefix and prefix != build_prefix:
     522          #    warn('Detected development environment but prefix is already set')
     523          if not exec_prefix:
     524              exec_prefix = build_prefix
     525          # Do not warn, because 'exec_prefix' never equals 'build_prefix' on POSIX
     526          #elif not venv_prefix and exec_prefix != build_prefix:
     527          #    warn('Detected development environment but exec_prefix is already set')
     528          config['_is_python_build'] = 1
     529  
     530  
     531  # ******************************************************************************
     532  # CALCULATE prefix AND exec_prefix
     533  # ******************************************************************************
     534  
     535  if py_setpath:
     536      # As documented, calling Py_SetPath will force both prefix
     537      # and exec_prefix to the empty string.
     538      prefix = exec_prefix = ''
     539  
     540  else:
     541      # Read prefix and exec_prefix from explicitly set home
     542      if home:
     543          # When multiple paths are listed with ':' or ';' delimiters,
     544          # split into prefix:exec_prefix
     545          prefix, had_delim, exec_prefix = home.partition(DELIM)
     546          if not had_delim:
     547              exec_prefix = prefix
     548          # Reset the standard library directory if it was already set
     549          stdlib_dir = None
     550  
     551  
     552      # First try to detect prefix by looking alongside our runtime library, if known
     553      if library and not prefix:
     554          library_dir = dirname(library)
     555          if ZIP_LANDMARK:
     556              if os_name == 'nt':
     557                  # QUIRK: Windows does not search up for ZIP file
     558                  if isfile(joinpath(library_dir, ZIP_LANDMARK)):
     559                      prefix = library_dir
     560              else:
     561                  prefix = search_up(library_dir, ZIP_LANDMARK)
     562          if STDLIB_SUBDIR and STDLIB_LANDMARKS and not prefix:
     563              if any(isfile(joinpath(library_dir, f)) for f in STDLIB_LANDMARKS):
     564                  prefix = library_dir
     565                  stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
     566  
     567  
     568      # Detect prefix by looking for zip file
     569      if ZIP_LANDMARK and executable_dir and not prefix:
     570          if os_name == 'nt':
     571              # QUIRK: Windows does not search up for ZIP file
     572              if isfile(joinpath(executable_dir, ZIP_LANDMARK)):
     573                  prefix = executable_dir
     574          else:
     575              prefix = search_up(executable_dir, ZIP_LANDMARK)
     576          if prefix:
     577              stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
     578              if not isdir(stdlib_dir):
     579                  stdlib_dir = None
     580  
     581  
     582      # Detect prefix by searching from our executable location for the stdlib_dir
     583      if STDLIB_SUBDIR and STDLIB_LANDMARKS and executable_dir and not prefix:
     584          prefix = search_up(executable_dir, *STDLIB_LANDMARKS)
     585          if prefix and not stdlib_dir:
     586              stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
     587  
     588      if PREFIX and not prefix:
     589          prefix = PREFIX
     590          if not any(isfile(joinpath(prefix, f)) for f in STDLIB_LANDMARKS):
     591              warn('Could not find platform independent libraries <prefix>')
     592  
     593      if not prefix:
     594          prefix = abspath('')
     595          warn('Could not find platform independent libraries <prefix>')
     596  
     597  
     598      # Detect exec_prefix by searching from executable for the platstdlib_dir
     599      if PLATSTDLIB_LANDMARK and not exec_prefix:
     600          if os_name == 'nt':
     601              # QUIRK: Windows always assumed these were the same
     602              # gh-100320: Our PYDs are assumed to be relative to the Lib directory
     603              # (that is, prefix) rather than the executable (that is, executable_dir)
     604              exec_prefix = prefix
     605          if not exec_prefix and executable_dir:
     606              exec_prefix = search_up(executable_dir, PLATSTDLIB_LANDMARK, test=isdir)
     607          if not exec_prefix and EXEC_PREFIX:
     608              exec_prefix = EXEC_PREFIX
     609          if not exec_prefix or not isdir(joinpath(exec_prefix, PLATSTDLIB_LANDMARK)):
     610              if os_name == 'nt':
     611                  # QUIRK: If DLLs is missing on Windows, don't warn, just assume
     612                  # that they're in exec_prefix
     613                  if not platstdlib_dir:
     614                      # gh-98790: We set platstdlib_dir here to avoid adding "DLLs" into
     615                      # sys.path when it doesn't exist in the platstdlib place, which
     616                      # would give Lib packages precedence over executable_dir where our
     617                      # PYDs *probably* live. Ideally, whoever changes our layout will tell
     618                      # us what the layout is, but in the past this worked, so it should
     619                      # keep working.
     620                      platstdlib_dir = exec_prefix
     621              else:
     622                  warn('Could not find platform dependent libraries <exec_prefix>')
     623  
     624  
     625      # Fallback: assume exec_prefix == prefix
     626      if not exec_prefix:
     627          exec_prefix = prefix
     628  
     629  
     630      if not prefix or not exec_prefix:
     631          warn('Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]')
     632  
     633  
     634  # For a venv, update the main prefix/exec_prefix but leave the base ones unchanged
     635  # XXX: We currently do not update prefix here, but it happens in site.py
     636  #if venv_prefix:
     637  #    base_prefix = prefix
     638  #    base_exec_prefix = exec_prefix
     639  #    prefix = exec_prefix = venv_prefix
     640  
     641  
     642  # ******************************************************************************
     643  # UPDATE pythonpath (sys.path)
     644  # ******************************************************************************
     645  
     646  if py_setpath:
     647      # If Py_SetPath was called then it overrides any existing search path
     648      config['module_search_paths'] = py_setpath.split(DELIM)
     649      config['module_search_paths_set'] = 1
     650  
     651  elif not pythonpath_was_set:
     652      # If pythonpath was already explicitly set or calculated, we leave it alone.
     653      # This won't matter in normal use, but if an embedded host is trying to
     654      # recalculate paths while running then we do not want to change it.
     655      pythonpath = []
     656  
     657      # First add entries from the process environment
     658      if use_environment and ENV_PYTHONPATH:
     659          for p in ENV_PYTHONPATH.split(DELIM):
     660              pythonpath.append(abspath(p))
     661  
     662      # Then add the default zip file
     663      if os_name == 'nt':
     664          # QUIRK: Windows uses the library directory rather than the prefix
     665          if library:
     666              library_dir = dirname(library)
     667          else:
     668              library_dir = executable_dir
     669          pythonpath.append(joinpath(library_dir, ZIP_LANDMARK))
     670      elif build_prefix:
     671          # QUIRK: POSIX uses the default prefix when in the build directory
     672          pythonpath.append(joinpath(PREFIX, ZIP_LANDMARK))
     673      else:
     674          pythonpath.append(joinpath(prefix, ZIP_LANDMARK))
     675  
     676      if os_name == 'nt' and use_environment and winreg:
     677          # QUIRK: Windows also lists paths in the registry. Paths are stored
     678          # as the default value of each subkey of
     679          # {HKCU,HKLM}\Software\Python\PythonCore\{winver}\PythonPath
     680          # where winver is sys.winver (typically '3.x' or '3.x-32')
     681          for hk in (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE):
     682              try:
     683                  key = winreg.OpenKeyEx(hk, WINREG_KEY)
     684                  try:
     685                      i = 0
     686                      while True:
     687                          try:
     688                              v = winreg.QueryValue(key, winreg.EnumKey(key, i))
     689                          except OSError:
     690                              break
     691                          if isinstance(v, str):
     692                              pythonpath.extend(v.split(DELIM))
     693                          i += 1
     694                      # Paths from the core key get appended last, but only
     695                      # when home was not set and we haven't found our stdlib
     696                      # some other way.
     697                      if not home and not stdlib_dir:
     698                          v = winreg.QueryValue(key, None)
     699                          if isinstance(v, str):
     700                              pythonpath.extend(v.split(DELIM))
     701                  finally:
     702                      winreg.CloseKey(key)
     703              except OSError:
     704                  pass
     705  
     706      # Then add any entries compiled into the PYTHONPATH macro.
     707      if PYTHONPATH:
     708          for p in PYTHONPATH.split(DELIM):
     709              pythonpath.append(joinpath(prefix, p))
     710  
     711      # Then add stdlib_dir and platstdlib_dir
     712      if not stdlib_dir and prefix:
     713          stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
     714      if not platstdlib_dir and exec_prefix:
     715          platstdlib_dir = joinpath(exec_prefix, PLATSTDLIB_LANDMARK)
     716  
     717      if os_name == 'nt':
     718          # QUIRK: Windows generates paths differently
     719          if platstdlib_dir:
     720              pythonpath.append(platstdlib_dir)
     721          if stdlib_dir:
     722              pythonpath.append(stdlib_dir)
     723          if executable_dir and executable_dir not in pythonpath:
     724              # QUIRK: the executable directory is on sys.path
     725              # We keep it low priority, so that properly installed modules are
     726              # found first. It may be earlier in the order if we found some
     727              # reason to put it there.
     728              pythonpath.append(executable_dir)
     729      else:
     730          if stdlib_dir:
     731              pythonpath.append(stdlib_dir)
     732          if platstdlib_dir:
     733              pythonpath.append(platstdlib_dir)
     734  
     735      config['module_search_paths'] = pythonpath
     736      config['module_search_paths_set'] = 1
     737  
     738  
     739  # ******************************************************************************
     740  # POSIX prefix/exec_prefix QUIRKS
     741  # ******************************************************************************
     742  
     743  # QUIRK: Non-Windows replaces prefix/exec_prefix with defaults when running
     744  # in build directory. This happens after pythonpath calculation.
     745  if os_name != 'nt' and build_prefix:
     746      prefix = config.get('prefix') or PREFIX
     747      exec_prefix = config.get('exec_prefix') or EXEC_PREFIX or prefix
     748  
     749  
     750  # ******************************************************************************
     751  # SET pythonpath FROM _PTH FILE
     752  # ******************************************************************************
     753  
     754  if pth:
     755      config['isolated'] = 1
     756      config['use_environment'] = 0
     757      config['site_import'] = 0
     758      config['safe_path'] = 1
     759      pythonpath = []
     760      for line in pth:
     761          line = line.partition('#')[0].strip()
     762          if not line:
     763              pass
     764          elif line == 'import site':
     765              config['site_import'] = 1
     766          elif line.startswith('import '):
     767              warn("unsupported 'import' line in ._pth file")
     768          else:
     769              pythonpath.append(joinpath(pth_dir, line))
     770      config['module_search_paths'] = pythonpath
     771      config['module_search_paths_set'] = 1
     772  
     773  # ******************************************************************************
     774  # UPDATE config FROM CALCULATED VALUES
     775  # ******************************************************************************
     776  
     777  config['program_name'] = program_name
     778  config['home'] = home
     779  config['executable'] = executable
     780  config['base_executable'] = base_executable
     781  config['prefix'] = prefix
     782  config['exec_prefix'] = exec_prefix
     783  config['base_prefix'] = base_prefix or prefix
     784  config['base_exec_prefix'] = base_exec_prefix or exec_prefix
     785  
     786  config['platlibdir'] = platlibdir
     787  # test_embed expects empty strings, not None
     788  config['stdlib_dir'] = stdlib_dir or ''
     789  config['platstdlib_dir'] = platstdlib_dir or ''