mirror of
https://github.com/python/cpython.git
synced 2024-12-01 03:01:36 +01:00
99fcf15052
The getpath.py file is frozen at build time and executed as code over a namespace. It is never imported, nor is it meant to be importable or reusable. However, it should be easier to read, modify, and patch than the previous code. This commit attempts to preserve every previously tested quirk, but these may be changed in the future to better align platforms.
728 lines
30 KiB
Python
728 lines
30 KiB
Python
# ******************************************************************************
|
|
# getpath.py
|
|
# ******************************************************************************
|
|
|
|
# This script is designed to be precompiled to bytecode, frozen into the
|
|
# main binary, and then directly evaluated. It is not an importable module,
|
|
# and does not import any other modules (besides winreg on Windows).
|
|
# Rather, the values listed below must be specified in the globals dict
|
|
# used when evaluating the bytecode.
|
|
|
|
# See _PyConfig_InitPathConfig in Modules/getpath.c for the execution.
|
|
|
|
# ******************************************************************************
|
|
# REQUIRED GLOBALS
|
|
# ******************************************************************************
|
|
|
|
# ** Helper functions **
|
|
# abspath(path) -- make relative paths absolute against CWD
|
|
# basename(path) -- the filename of path
|
|
# dirname(path) -- the directory name of path
|
|
# hassuffix(path, suffix) -- returns True if path has suffix
|
|
# isabs(path) -- path is absolute or not
|
|
# isdir(path) -- path exists and is a directory
|
|
# isfile(path) -- path exists and is a file
|
|
# isxfile(path) -- path exists and is an executable file
|
|
# joinpath(*paths) -- combine the paths
|
|
# readlines(path) -- a list of each line of text in the UTF-8 encoded file
|
|
# realpath(path) -- resolves symlinks in path
|
|
# warn(message) -- print a warning (if enabled)
|
|
|
|
# ** Values known at compile time **
|
|
# os_name -- [in] one of 'nt', 'posix', 'darwin'
|
|
# PREFIX -- [in] sysconfig.get_config_var(...)
|
|
# EXEC_PREFIX -- [in] sysconfig.get_config_var(...)
|
|
# PYTHONPATH -- [in] sysconfig.get_config_var(...)
|
|
# VPATH -- [in] sysconfig.get_config_var(...)
|
|
# PLATLIBDIR -- [in] sysconfig.get_config_var(...)
|
|
# PYDEBUGEXT -- [in, opt] '_d' on Windows for debug builds
|
|
# EXE_SUFFIX -- [in, opt] '.exe' on Windows/Cygwin/similar
|
|
# VERSION_MAJOR -- [in] sys.version_info.major
|
|
# VERSION_MINOR -- [in] sys.version_info.minor
|
|
# PYWINVER -- [in] the Windows platform-specific version (e.g. 3.8-32)
|
|
|
|
# ** Values read from the environment **
|
|
# There is no need to check the use_environment flag before reading
|
|
# these, as the flag will be tested in this script.
|
|
# Also note that ENV_PYTHONPATH is read from config['pythonpath_env']
|
|
# to allow for embedders who choose to specify it via that struct.
|
|
# ENV_PATH -- [in] getenv(...)
|
|
# ENV_PYTHONHOME -- [in] getenv(...)
|
|
# ENV_PYTHONEXECUTABLE -- [in] getenv(...)
|
|
# ENV___PYVENV_LAUNCHER__ -- [in] getenv(...)
|
|
|
|
# ** Values calculated at runtime **
|
|
# config -- [in/out] dict of the PyConfig structure
|
|
# real_executable -- [in, optional] resolved path to main process
|
|
# On Windows and macOS, read directly from the running process
|
|
# Otherwise, leave None and it will be calculated from executable
|
|
# executable_dir -- [in, optional] real directory containing binary
|
|
# If None, will be calculated from real_executable or executable
|
|
# py_setpath -- [in] argument provided to Py_SetPath
|
|
# If None, 'prefix' and 'exec_prefix' may be updated in config
|
|
# library -- [in, optional] path of dylib/DLL/so
|
|
# Only used for locating ._pth files
|
|
# winreg -- [in, optional] the winreg module (only on Windows)
|
|
|
|
# ******************************************************************************
|
|
# HIGH-LEVEL ALGORITHM
|
|
# ******************************************************************************
|
|
|
|
# IMPORTANT: The code is the actual specification at time of writing.
|
|
# This prose description is based on the original comment from the old
|
|
# getpath.c to help capture the intent, but should not be considered
|
|
# a specification.
|
|
|
|
# Search in some common locations for the associated Python libraries.
|
|
|
|
# Two directories must be found, the platform independent directory
|
|
# (prefix), containing the common .py and .pyc files, and the platform
|
|
# dependent directory (exec_prefix), containing the shared library
|
|
# modules. Note that prefix and exec_prefix can be the same directory,
|
|
# but for some installations, they are different.
|
|
|
|
# This script carries out separate searches for prefix and exec_prefix.
|
|
# Each search tries a number of different locations until a ``landmark''
|
|
# file or directory is found. If no prefix or exec_prefix is found, a
|
|
# warning message is issued and the preprocessor defined PREFIX and
|
|
# EXEC_PREFIX are used (even though they will not work); python carries on
|
|
# as best as is possible, but most imports will fail.
|
|
|
|
# Before any searches are done, the location of the executable is
|
|
# determined. If Py_SetPath() was called, or if we are running on
|
|
# Windows, the 'real_executable' path is used (if known). Otherwise,
|
|
# we use the config-specified program name or default to argv[0].
|
|
# If this has one or more slashes in it, it is made absolute against
|
|
# the current working directory. If it only contains a name, it must
|
|
# have been invoked from the shell's path, so we search $PATH for the
|
|
# named executable and use that. If the executable was not found on
|
|
# $PATH (or there was no $PATH environment variable), the original
|
|
# argv[0] string is used.
|
|
|
|
# At this point, provided Py_SetPath was not used, the
|
|
# __PYVENV_LAUNCHER__ variable may override the executable (on macOS,
|
|
# the PYTHON_EXECUTABLE variable may also override). This allows
|
|
# certain launchers that run Python as a subprocess to properly
|
|
# specify the executable path. They are not intended for users.
|
|
|
|
# Next, the executable location is examined to see if it is a symbolic
|
|
# link. If so, the link is realpath-ed and the directory of the link
|
|
# target is used for the remaining searches. The same steps are
|
|
# performed for prefix and for exec_prefix, but with different landmarks.
|
|
|
|
# Step 1. Are we running in a virtual environment? Unless 'home' has
|
|
# been specified another way, check for a pyvenv.cfg and use its 'home'
|
|
# property to override the executable dir used later for prefix searches.
|
|
# We do not activate the venv here - that is performed later by site.py.
|
|
|
|
# Step 2. Is there a ._pth file? A ._pth file lives adjacent to the
|
|
# runtime library (if any) or the actual executable (not the symlink),
|
|
# and contains precisely the intended contents of sys.path as relative
|
|
# paths (to its own location). Its presence also enables isolated mode
|
|
# and suppresses other environment variable usage. Unless already
|
|
# specified by Py_SetHome(), the directory containing the ._pth file is
|
|
# set as 'home'.
|
|
|
|
# Step 3. Are we running python out of the build directory? This is
|
|
# checked by looking for the BUILDDIR_TXT file, which contains the
|
|
# relative path to the platlib dir. The executable_dir value is
|
|
# derived from joining the VPATH preprocessor variable to the
|
|
# directory containing pybuilddir.txt. If it is not found, the
|
|
# BUILD_LANDMARK file is found, which is part of the source tree.
|
|
# prefix is then found by searching up for a file that should only
|
|
# exist in the source tree, and the stdlib dir is set to prefix/Lib.
|
|
|
|
# Step 4. If 'home' is set, either by Py_SetHome(), ENV_PYTHONHOME,
|
|
# a pyvenv.cfg file, ._pth file, or by detecting a build directory, it
|
|
# is assumed to point to prefix and exec_prefix. $PYTHONHOME can be a
|
|
# single directory, which is used for both, or the prefix and exec_prefix
|
|
# directories separated by DELIM (colon on POSIX; semicolon on Windows).
|
|
|
|
# Step 5. Try to find prefix and exec_prefix relative to executable_dir,
|
|
# backtracking up the path until it is exhausted. This is the most common
|
|
# step to succeed. Note that if prefix and exec_prefix are different,
|
|
# exec_prefix is more likely to be found; however if exec_prefix is a
|
|
# subdirectory of prefix, both will be found.
|
|
|
|
# Step 6. Search the directories pointed to by the preprocessor variables
|
|
# PREFIX and EXEC_PREFIX. These are supplied by the Makefile but can be
|
|
# passed in as options to the configure script.
|
|
|
|
# That's it!
|
|
|
|
# Well, almost. Once we have determined prefix and exec_prefix, the
|
|
# preprocessor variable PYTHONPATH is used to construct a path. Each
|
|
# relative path on PYTHONPATH is prefixed with prefix. Then the directory
|
|
# containing the shared library modules is appended. The environment
|
|
# variable $PYTHONPATH is inserted in front of it all. On POSIX, if we are
|
|
# in a build directory, both prefix and exec_prefix are reset to the
|
|
# corresponding preprocessor variables (so sys.prefix will reflect the
|
|
# installation location, even though sys.path points into the build
|
|
# directory). This seems to make more sense given that currently the only
|
|
# known use of sys.prefix and sys.exec_prefix is for the ILU installation
|
|
# process to find the installed Python tree.
|
|
|
|
# An embedding application can use Py_SetPath() to override all of
|
|
# these automatic path computations.
|
|
|
|
|
|
# ******************************************************************************
|
|
# PLATFORM CONSTANTS
|
|
# ******************************************************************************
|
|
|
|
platlibdir = config.get('platlibdir') or PLATLIBDIR
|
|
|
|
if os_name == 'posix' or os_name == 'darwin':
|
|
BUILDDIR_TXT = 'pybuilddir.txt'
|
|
BUILD_LANDMARK = 'Modules/Setup.local'
|
|
DEFAULT_PROGRAM_NAME = f'python{VERSION_MAJOR}'
|
|
STDLIB_SUBDIR = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}'
|
|
STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}/os.py', f'{STDLIB_SUBDIR}/os.pyc']
|
|
PLATSTDLIB_LANDMARK = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}/lib-dynload'
|
|
BUILDSTDLIB_LANDMARKS = ['Lib/os.py']
|
|
VENV_LANDMARK = 'pyvenv.cfg'
|
|
ZIP_LANDMARK = f'{platlibdir}/python{VERSION_MAJOR}{VERSION_MINOR}.zip'
|
|
DELIM = ':'
|
|
SEP = '/'
|
|
|
|
elif os_name == 'nt':
|
|
BUILDDIR_TXT = 'pybuilddir.txt'
|
|
BUILD_LANDMARK = r'..\..\Modules\Setup.local'
|
|
DEFAULT_PROGRAM_NAME = f'python'
|
|
STDLIB_SUBDIR = 'Lib'
|
|
STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}\\os.py', f'{STDLIB_SUBDIR}\\os.pyc']
|
|
PLATSTDLIB_LANDMARK = f'{platlibdir}'
|
|
BUILDSTDLIB_LANDMARKS = ['Lib\\os.py']
|
|
VENV_LANDMARK = 'pyvenv.cfg'
|
|
ZIP_LANDMARK = f'python{VERSION_MAJOR}{VERSION_MINOR}{PYDEBUGEXT or ""}.zip'
|
|
WINREG_KEY = f'SOFTWARE\\Python\\PythonCore\\{PYWINVER}\\PythonPath'
|
|
DELIM = ';'
|
|
SEP = '\\'
|
|
|
|
|
|
# ******************************************************************************
|
|
# HELPER FUNCTIONS (note that we prefer C functions for performance)
|
|
# ******************************************************************************
|
|
|
|
def search_up(prefix, *landmarks, test=isfile):
|
|
while prefix:
|
|
if any(test(joinpath(prefix, f)) for f in landmarks):
|
|
return prefix
|
|
prefix = dirname(prefix)
|
|
|
|
|
|
# ******************************************************************************
|
|
# READ VARIABLES FROM config
|
|
# ******************************************************************************
|
|
|
|
program_name = config.get('program_name')
|
|
home = config.get('home')
|
|
executable = config.get('executable')
|
|
base_executable = config.get('base_executable')
|
|
prefix = config.get('prefix')
|
|
exec_prefix = config.get('exec_prefix')
|
|
base_prefix = config.get('base_prefix')
|
|
base_exec_prefix = config.get('base_exec_prefix')
|
|
ENV_PYTHONPATH = config['pythonpath_env']
|
|
use_environment = config.get('use_environment', 1)
|
|
|
|
pythonpath = config.get('module_search_paths')
|
|
|
|
real_executable_dir = None
|
|
stdlib_dir = None
|
|
platstdlib_dir = None
|
|
|
|
# ******************************************************************************
|
|
# CALCULATE program_name
|
|
# ******************************************************************************
|
|
|
|
program_name_was_set = bool(program_name)
|
|
|
|
if not program_name:
|
|
try:
|
|
program_name = config.get('orig_argv', [])[0]
|
|
except IndexError:
|
|
pass
|
|
|
|
if not program_name:
|
|
program_name = DEFAULT_PROGRAM_NAME
|
|
|
|
if EXE_SUFFIX and not hassuffix(program_name, EXE_SUFFIX) and isxfile(program_name + EXE_SUFFIX):
|
|
program_name = program_name + EXE_SUFFIX
|
|
|
|
|
|
# ******************************************************************************
|
|
# CALCULATE executable
|
|
# ******************************************************************************
|
|
|
|
if py_setpath:
|
|
# When Py_SetPath has been called, executable defaults to
|
|
# the real executable path.
|
|
if not executable:
|
|
executable = real_executable
|
|
|
|
if not executable and SEP in program_name:
|
|
# Resolve partial path program_name against current directory
|
|
executable = abspath(program_name)
|
|
|
|
if not executable:
|
|
# All platforms default to real_executable if known at this
|
|
# stage. POSIX does not set this value.
|
|
executable = real_executable
|
|
elif os_name == 'darwin':
|
|
# QUIRK: On macOS we may know the real executable path, but
|
|
# if our caller has lied to us about it (e.g. most of
|
|
# test_embed), we need to use their path in order to detect
|
|
# whether we are in a build tree. This is true even if the
|
|
# executable path was provided in the config.
|
|
real_executable = executable
|
|
|
|
if not executable and program_name:
|
|
# Resolve names against PATH.
|
|
# NOTE: The use_environment value is ignored for this lookup.
|
|
# To properly isolate, launch Python with a full path.
|
|
for p in ENV_PATH.split(DELIM):
|
|
p = joinpath(p, program_name)
|
|
if isxfile(p):
|
|
executable = p
|
|
break
|
|
|
|
if not executable:
|
|
executable = ''
|
|
# When we cannot calculate the executable, subsequent searches
|
|
# look in the current working directory. Here, we emulate that
|
|
# (the former getpath.c would do it apparently by accident).
|
|
executable_dir = abspath('.')
|
|
# Also need to set this fallback in case we are running from a
|
|
# build directory with an invalid argv0 (i.e. test_sys.test_executable)
|
|
real_executable_dir = executable_dir
|
|
|
|
if ENV_PYTHONEXECUTABLE or ENV___PYVENV_LAUNCHER__:
|
|
# If set, these variables imply that we should be using them as
|
|
# sys.executable and when searching for venvs. However, we should
|
|
# use the argv0 path for prefix calculation
|
|
base_executable = executable
|
|
if not real_executable:
|
|
real_executable = executable
|
|
executable = ENV_PYTHONEXECUTABLE or ENV___PYVENV_LAUNCHER__
|
|
executable_dir = dirname(executable)
|
|
|
|
|
|
# ******************************************************************************
|
|
# CALCULATE (default) home
|
|
# ******************************************************************************
|
|
|
|
# Used later to distinguish between Py_SetPythonHome and other
|
|
# ways that it may have been set
|
|
home_was_set = False
|
|
|
|
if home:
|
|
home_was_set = True
|
|
elif use_environment and ENV_PYTHONHOME and not py_setpath:
|
|
home = ENV_PYTHONHOME
|
|
|
|
|
|
# ******************************************************************************
|
|
# READ pyvenv.cfg
|
|
# ******************************************************************************
|
|
|
|
venv_prefix = None
|
|
|
|
# Calling Py_SetPythonHome(), Py_SetPath() or
|
|
# setting $PYTHONHOME will override venv detection.
|
|
if not home and not py_setpath:
|
|
try:
|
|
# prefix2 is just to avoid calculating dirname again later,
|
|
# as the path in venv_prefix is the more common case.
|
|
venv_prefix2 = executable_dir or dirname(executable)
|
|
venv_prefix = dirname(venv_prefix2)
|
|
try:
|
|
# Read pyvenv.cfg from one level above executable
|
|
pyvenvcfg = readlines(joinpath(venv_prefix, VENV_LANDMARK))
|
|
except FileNotFoundError:
|
|
# Try the same directory as executable
|
|
pyvenvcfg = readlines(joinpath(venv_prefix2, VENV_LANDMARK))
|
|
venv_prefix = venv_prefix2
|
|
except FileNotFoundError:
|
|
venv_prefix = None
|
|
pyvenvcfg = []
|
|
|
|
for line in pyvenvcfg:
|
|
key, had_equ, value = line.partition('=')
|
|
if had_equ and key.strip().lower() == 'home':
|
|
executable_dir = real_executable_dir = value.strip()
|
|
base_executable = joinpath(executable_dir, basename(executable))
|
|
break
|
|
else:
|
|
venv_prefix = None
|
|
|
|
|
|
# ******************************************************************************
|
|
# CALCULATE base_executable, real_executable AND executable_dir
|
|
# ******************************************************************************
|
|
|
|
if not base_executable:
|
|
base_executable = executable or real_executable or ''
|
|
|
|
if not real_executable:
|
|
real_executable = base_executable
|
|
|
|
try:
|
|
real_executable = realpath(real_executable)
|
|
except OSError as ex:
|
|
# Only warn if the file actually exists and was unresolvable
|
|
# Otherwise users who specify a fake executable may get spurious warnings.
|
|
if isfile(real_executable):
|
|
warn(f'Failed to find real location of {base_executable}')
|
|
|
|
if not executable_dir and os_name == 'darwin' and library:
|
|
# QUIRK: macOS checks adjacent to its library early
|
|
library_dir = dirname(library)
|
|
if any(isfile(joinpath(library_dir, p)) for p in STDLIB_LANDMARKS):
|
|
# Exceptions here should abort the whole process (to match
|
|
# previous behavior)
|
|
executable_dir = realpath(library_dir)
|
|
real_executable_dir = executable_dir
|
|
|
|
# If we do not have the executable's directory, we can calculate it.
|
|
# This is the directory used to find prefix/exec_prefix if necessary.
|
|
if not executable_dir:
|
|
executable_dir = real_executable_dir = dirname(real_executable)
|
|
|
|
# If we do not have the real executable's directory, we calculate it.
|
|
# This is the directory used to detect build layouts.
|
|
if not real_executable_dir:
|
|
real_executable_dir = dirname(real_executable)
|
|
|
|
# ******************************************************************************
|
|
# DETECT _pth FILE
|
|
# ******************************************************************************
|
|
|
|
# The contents of an optional ._pth file are used to totally override
|
|
# sys.path calcualation. Its presence also implies isolated mode and
|
|
# no-site (unless explicitly requested)
|
|
pth = None
|
|
pth_dir = None
|
|
|
|
# Calling Py_SetPythonHome() or Py_SetPath() will override ._pth search,
|
|
# but environment variables and command-line options cannot.
|
|
if not py_setpath and not home_was_set:
|
|
# Check adjacent to the main DLL/dylib/so
|
|
if library:
|
|
try:
|
|
pth = readlines(library.rpartition('.')[0] + '._pth')
|
|
pth_dir = dirname(library)
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
# Check adjacent to the original executable, even if we
|
|
# redirected to actually launch Python. This may allow a
|
|
# venv to override the base_executable's ._pth file, but
|
|
# it cannot override the library's one.
|
|
if not pth_dir:
|
|
try:
|
|
pth = readlines(executable.rpartition('.')[0] + '._pth')
|
|
pth_dir = dirname(executable)
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
# If we found a ._pth file, disable environment and home
|
|
# detection now. Later, we will do the rest.
|
|
if pth_dir:
|
|
use_environment = 0
|
|
home = pth_dir
|
|
pythonpath = []
|
|
|
|
|
|
# ******************************************************************************
|
|
# CHECK FOR BUILD DIRECTORY
|
|
# ******************************************************************************
|
|
|
|
build_prefix = None
|
|
|
|
if not home_was_set and real_executable_dir and not py_setpath:
|
|
# Detect a build marker and use it to infer prefix, exec_prefix,
|
|
# stdlib_dir and the platstdlib_dir directories.
|
|
try:
|
|
platstdlib_dir = joinpath(
|
|
real_executable_dir,
|
|
readlines(joinpath(real_executable_dir, BUILDDIR_TXT))[0],
|
|
)
|
|
build_prefix = joinpath(real_executable_dir, VPATH)
|
|
except FileNotFoundError:
|
|
if isfile(joinpath(real_executable_dir, BUILD_LANDMARK)):
|
|
build_prefix = joinpath(real_executable_dir, VPATH)
|
|
if os_name == 'nt':
|
|
# QUIRK: Windows builds need platstdlib_dir to be the executable
|
|
# dir. Normally the builddir marker handles this, but in this
|
|
# case we need to correct manually.
|
|
platstdlib_dir = real_executable_dir
|
|
|
|
if build_prefix:
|
|
if os_name == 'nt':
|
|
# QUIRK: No searching for more landmarks on Windows
|
|
build_stdlib_prefix = build_prefix
|
|
else:
|
|
build_stdlib_prefix = search_up(build_prefix, *BUILDSTDLIB_LANDMARKS)
|
|
# Always use the build prefix for stdlib
|
|
if build_stdlib_prefix:
|
|
stdlib_dir = joinpath(build_stdlib_prefix, 'Lib')
|
|
else:
|
|
stdlib_dir = joinpath(build_prefix, 'Lib')
|
|
# Only use the build prefix for prefix if it hasn't already been set
|
|
if not prefix:
|
|
prefix = build_stdlib_prefix
|
|
# Do not warn, because 'prefix' never equals 'build_prefix' on POSIX
|
|
#elif not venv_prefix and prefix != build_prefix:
|
|
# warn('Detected development environment but prefix is already set')
|
|
if not exec_prefix:
|
|
exec_prefix = build_prefix
|
|
# Do not warn, because 'exec_prefix' never equals 'build_prefix' on POSIX
|
|
#elif not venv_prefix and exec_prefix != build_prefix:
|
|
# warn('Detected development environment but exec_prefix is already set')
|
|
config['_is_python_build'] = 1
|
|
|
|
|
|
# ******************************************************************************
|
|
# CALCULATE prefix AND exec_prefix
|
|
# ******************************************************************************
|
|
|
|
if py_setpath:
|
|
# As documented, calling Py_SetPath will force both prefix
|
|
# and exec_prefix to the empty string.
|
|
prefix = exec_prefix = ''
|
|
|
|
else:
|
|
# Read prefix and exec_prefix from explicitly set home
|
|
if home:
|
|
# When multiple paths are listed with ':' or ';' delimiters,
|
|
# split into prefix:exec_prefix
|
|
prefix, had_delim, exec_prefix = home.partition(DELIM)
|
|
if not had_delim:
|
|
exec_prefix = prefix
|
|
|
|
|
|
# First try to detect prefix by looking alongside our runtime library, if known
|
|
if library and not prefix:
|
|
library_dir = dirname(library)
|
|
if ZIP_LANDMARK:
|
|
if os_name == 'nt':
|
|
# QUIRK: Windows does not search up for ZIP file
|
|
if isfile(joinpath(library_dir, ZIP_LANDMARK)):
|
|
prefix = library_dir
|
|
else:
|
|
prefix = search_up(library_dir, ZIP_LANDMARK)
|
|
if STDLIB_SUBDIR and STDLIB_LANDMARKS and not prefix:
|
|
if any(isfile(joinpath(library_dir, f)) for f in STDLIB_LANDMARKS):
|
|
prefix = library_dir
|
|
stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
|
|
|
|
|
|
# Detect prefix by looking for zip file
|
|
if ZIP_LANDMARK and executable_dir and not prefix:
|
|
if os_name == 'nt':
|
|
# QUIRK: Windows does not search up for ZIP file
|
|
if isfile(joinpath(executable_dir, ZIP_LANDMARK)):
|
|
prefix = executable_dir
|
|
else:
|
|
prefix = search_up(executable_dir, ZIP_LANDMARK)
|
|
if prefix:
|
|
stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
|
|
if not isdir(stdlib_dir):
|
|
stdlib_dir = None
|
|
|
|
|
|
# Detect prefix by searching from our executable location for the stdlib_dir
|
|
if STDLIB_SUBDIR and STDLIB_LANDMARKS and executable_dir and not prefix:
|
|
prefix = search_up(executable_dir, *STDLIB_LANDMARKS)
|
|
if prefix:
|
|
stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
|
|
|
|
if PREFIX and not prefix:
|
|
prefix = PREFIX
|
|
if not any(isfile(joinpath(prefix, f)) for f in STDLIB_LANDMARKS):
|
|
warn('Could not find platform independent libraries <prefix>')
|
|
|
|
if not prefix:
|
|
prefix = abspath('')
|
|
warn('Could not find platform independent libraries <prefix>')
|
|
|
|
|
|
# Detect exec_prefix by searching from executable for the platstdlib_dir
|
|
if PLATSTDLIB_LANDMARK and not exec_prefix:
|
|
if executable_dir:
|
|
exec_prefix = search_up(executable_dir, PLATSTDLIB_LANDMARK, test=isdir)
|
|
if not exec_prefix:
|
|
if EXEC_PREFIX:
|
|
exec_prefix = EXEC_PREFIX
|
|
if not isdir(joinpath(exec_prefix, PLATSTDLIB_LANDMARK)):
|
|
warn('Could not find platform dependent libraries <exec_prefix>')
|
|
else:
|
|
warn('Could not find platform dependent libraries <exec_prefix>')
|
|
|
|
# Fallback: assume exec_prefix == prefix
|
|
if not exec_prefix:
|
|
exec_prefix = prefix
|
|
|
|
|
|
if not prefix or not exec_prefix:
|
|
warn('Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]')
|
|
|
|
|
|
# If we haven't set [plat]stdlib_dir already, set them now
|
|
if not stdlib_dir:
|
|
if prefix:
|
|
stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
|
|
else:
|
|
stdlib_dir = ''
|
|
|
|
if not platstdlib_dir:
|
|
if exec_prefix:
|
|
platstdlib_dir = joinpath(exec_prefix, PLATSTDLIB_LANDMARK)
|
|
else:
|
|
platstdlib_dir = ''
|
|
|
|
|
|
# For a venv, update the main prefix/exec_prefix but leave the base ones unchanged
|
|
# XXX: We currently do not update prefix here, but it happens in site.py
|
|
#if venv_prefix:
|
|
# base_prefix = prefix
|
|
# base_exec_prefix = exec_prefix
|
|
# prefix = exec_prefix = venv_prefix
|
|
|
|
|
|
# ******************************************************************************
|
|
# UPDATE pythonpath (sys.path)
|
|
# ******************************************************************************
|
|
|
|
if py_setpath:
|
|
# If Py_SetPath was called then it overrides any existing search path
|
|
config['module_search_paths'] = py_setpath.split(DELIM)
|
|
config['module_search_paths_set'] = 1
|
|
|
|
elif not pythonpath:
|
|
# If pythonpath was already set, we leave it alone.
|
|
# This won't matter in normal use, but if an embedded host is trying to
|
|
# recalculate paths while running then we do not want to change it.
|
|
pythonpath = []
|
|
|
|
# First add entries from the process environment
|
|
if use_environment and ENV_PYTHONPATH:
|
|
for p in ENV_PYTHONPATH.split(DELIM):
|
|
pythonpath.append(abspath(p))
|
|
|
|
# Then add the default zip file
|
|
if os_name == 'nt':
|
|
# QUIRK: Windows uses the library directory rather than the prefix
|
|
if library:
|
|
library_dir = dirname(library)
|
|
else:
|
|
library_dir = executable_dir
|
|
pythonpath.append(joinpath(library_dir, ZIP_LANDMARK))
|
|
elif build_prefix or venv_prefix:
|
|
# QUIRK: POSIX uses the default prefix when in the build directory
|
|
# or a venv
|
|
pythonpath.append(joinpath(PREFIX, ZIP_LANDMARK))
|
|
else:
|
|
pythonpath.append(joinpath(prefix, ZIP_LANDMARK))
|
|
|
|
if os_name == 'nt' and use_environment and winreg:
|
|
# QUIRK: Windows also lists paths in the registry. Paths are stored
|
|
# as the default value of each subkey of
|
|
# {HKCU,HKLM}\Software\Python\PythonCore\{winver}\PythonPath
|
|
# where winver is sys.winver (typically '3.x' or '3.x-32')
|
|
for hk in (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE):
|
|
try:
|
|
key = winreg.OpenKeyEx(hk, WINREG_KEY)
|
|
try:
|
|
i = 0
|
|
while True:
|
|
try:
|
|
keyname = winreg.EnumKey(key, i)
|
|
subkey = winreg.OpenKeyEx(key, keyname)
|
|
if not subkey:
|
|
continue
|
|
try:
|
|
v = winreg.QueryValue(subkey)
|
|
finally:
|
|
winreg.CloseKey(subkey)
|
|
if isinstance(v, str):
|
|
pythonpath.append(v)
|
|
i += 1
|
|
except OSError:
|
|
break
|
|
finally:
|
|
winreg.CloseKey(key)
|
|
except OSError:
|
|
pass
|
|
|
|
# Then add any entries compiled into the PYTHONPATH macro.
|
|
if PYTHONPATH:
|
|
for p in PYTHONPATH.split(DELIM):
|
|
pythonpath.append(joinpath(prefix, p))
|
|
|
|
# Then add stdlib_dir and platstdlib_dir
|
|
if stdlib_dir:
|
|
pythonpath.append(stdlib_dir)
|
|
if platstdlib_dir:
|
|
if os_name == 'nt' and venv_prefix:
|
|
# QUIRK: Windows appends executable_dir instead of platstdlib_dir
|
|
# when in a venv
|
|
pythonpath.append(executable_dir)
|
|
else:
|
|
pythonpath.append(platstdlib_dir)
|
|
|
|
config['module_search_paths'] = pythonpath
|
|
config['module_search_paths_set'] = 1
|
|
|
|
|
|
# ******************************************************************************
|
|
# POSIX prefix/exec_prefix QUIRKS
|
|
# ******************************************************************************
|
|
|
|
# QUIRK: Non-Windows replaces prefix/exec_prefix with defaults when running
|
|
# in build directory. This happens after pythonpath calculation.
|
|
if os_name != 'nt' and build_prefix:
|
|
prefix = config.get('prefix') or PREFIX
|
|
exec_prefix = config.get('exec_prefix') or EXEC_PREFIX or prefix
|
|
|
|
|
|
# ******************************************************************************
|
|
# SET pythonpath FROM _PTH FILE
|
|
# ******************************************************************************
|
|
|
|
if pth:
|
|
config['isolated'] = 1
|
|
config['use_environment'] = 0
|
|
config['site_import'] = 0
|
|
pythonpath = []
|
|
for line in pth:
|
|
line = line.partition('#')[0].strip()
|
|
if not line:
|
|
pass
|
|
elif line == 'import site':
|
|
config['site_import'] = 1
|
|
elif line.startswith('import '):
|
|
warn("unsupported 'import' line in ._pth file")
|
|
else:
|
|
pythonpath.append(joinpath(pth_dir, line))
|
|
config['module_search_paths'] = pythonpath
|
|
config['module_search_paths_set'] = 1
|
|
|
|
# ******************************************************************************
|
|
# UPDATE config FROM CALCULATED VALUES
|
|
# ******************************************************************************
|
|
|
|
config['program_name'] = program_name
|
|
config['home'] = home
|
|
config['executable'] = executable
|
|
config['base_executable'] = base_executable
|
|
config['prefix'] = prefix
|
|
config['exec_prefix'] = exec_prefix
|
|
config['base_prefix'] = base_prefix or prefix
|
|
config['base_exec_prefix'] = base_exec_prefix or exec_prefix
|
|
|
|
config['platlibdir'] = platlibdir
|
|
config['stdlib_dir'] = stdlib_dir
|
|
config['platstdlib_dir'] = platstdlib_dir
|