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
174platlibdir = config.get('platlibdir') or PLATLIBDIR
175
176if 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
189elif 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
208def 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
219program_name = config.get('program_name')
220home = config.get('home')
221executable = config.get('executable')
222base_executable = config.get('base_executable')
223prefix = config.get('prefix')
224exec_prefix = config.get('exec_prefix')
225base_prefix = config.get('base_prefix')
226base_exec_prefix = config.get('base_exec_prefix')
227ENV_PYTHONPATH = config['pythonpath_env']
228use_environment = config.get('use_environment', 1)
229
230pythonpath = config.get('module_search_paths')
231pythonpath_was_set = config.get('module_search_paths_set')
232
233real_executable_dir = None
234stdlib_dir = None
235platstdlib_dir = None
236
237# ******************************************************************************
238# CALCULATE program_name
239# ******************************************************************************
240
241program_name_was_set = bool(program_name)
242
243if not program_name:
244    try:
245        program_name = config.get('orig_argv', [])[0]
246    except IndexError:
247        pass
248
249if not program_name:
250    program_name = DEFAULT_PROGRAM_NAME
251
252if 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
260if 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
266if not executable and SEP in program_name:
267    # Resolve partial path program_name against current directory
268    executable = abspath(program_name)
269
270if 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
274elif 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
282if 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
292if 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
302if 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
329home_was_set = False
330
331if home:
332    home_was_set = True
333elif use_environment and ENV_PYTHONHOME and not py_setpath:
334    home = ENV_PYTHONHOME
335
336
337# ******************************************************************************
338# READ pyvenv.cfg
339# ******************************************************************************
340
341venv_prefix = None
342
343# Calling Py_SetPythonHome(), Py_SetPath() or
344# setting $PYTHONHOME will override venv detection.
345if 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
406if not base_executable:
407    base_executable = executable or real_executable or ''
408
409if not real_executable:
410    real_executable = base_executable
411
412try:
413    real_executable = realpath(real_executable)
414except 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
420if 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.
431if 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.
436if 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 calcualation. Its presence also implies isolated mode and
445# no-site (unless explicitly requested)
446pth = None
447pth_dir = None
448
449# Calling Py_SetPythonHome() or Py_SetPath() will override ._pth search,
450# but environment variables and command-line options cannot.
451if 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
481build_prefix = None
482
483if ((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
535if 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
540else:
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
646if 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
651elif 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.
745if 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
754if 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
777config['program_name'] = program_name
778config['home'] = home
779config['executable'] = executable
780config['base_executable'] = base_executable
781config['prefix'] = prefix
782config['exec_prefix'] = exec_prefix
783config['base_prefix'] = base_prefix or prefix
784config['base_exec_prefix'] = base_exec_prefix or exec_prefix
785
786config['platlibdir'] = platlibdir
787# test_embed expects empty strings, not None
788config['stdlib_dir'] = stdlib_dir or ''
789config['platstdlib_dir'] = platstdlib_dir or ''
790