Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
Description
Bug report
Bug description:
The current getpath.py code tries determining base_prefix/base_exec_prefix by searching the location of the libpython library loaded in the current process, falling back to the location of the Python interpreter executable.
Lines 559 to 594 in 7900a85
| # First try to detect prefix by looking alongside our runtime library, if known | |
| iflibraryandnotprefix: | |
| library_dir=dirname(library) | |
| ifZIP_LANDMARK: | |
| ifos_name=='nt': | |
| # QUIRK: Windows does not search up for ZIP file | |
| ifisfile(joinpath(library_dir, ZIP_LANDMARK)): | |
| prefix=library_dir | |
| else: | |
| prefix=search_up(library_dir, ZIP_LANDMARK) | |
| ifSTDLIB_SUBDIRandSTDLIB_LANDMARKSandnotprefix: | |
| ifany(isfile(joinpath(library_dir, f)) forfinSTDLIB_LANDMARKS): | |
| prefix=library_dir | |
| ifnotstdlib_dir_was_set_in_config: | |
| stdlib_dir=joinpath(prefix, STDLIB_SUBDIR) | |
| # Detect prefix by looking for zip file | |
| ifZIP_LANDMARKandexecutable_dirandnotprefix: | |
| ifos_name=='nt': | |
| # QUIRK: Windows does not search up for ZIP file | |
| ifisfile(joinpath(executable_dir, ZIP_LANDMARK)): | |
| prefix=executable_dir | |
| else: | |
| prefix=search_up(executable_dir, ZIP_LANDMARK) | |
| ifprefixandnotstdlib_dir_was_set_in_config: | |
| stdlib_dir=joinpath(prefix, STDLIB_SUBDIR) | |
| ifnotisdir(stdlib_dir): | |
| stdlib_dir=None | |
| # Detect prefix by searching from our executable location for the stdlib_dir | |
| ifSTDLIB_SUBDIRandSTDLIB_LANDMARKSandexecutable_dirandnotprefix: | |
| prefix=search_up(executable_dir, *STDLIB_LANDMARKS) | |
| ifprefixandnotstdlib_dir: | |
| stdlib_dir=joinpath(prefix, STDLIB_SUBDIR) |
Looking at the location of the libpython library in use first makes sense, as that is more reliable than looking at interpreter location — it works when embedding, where there isn't any interpreter executable, it works when the executable is not on base_prefix, etc. However, this is only currently supported on Windows and macOS framework builds.
Lines 802 to 837 in 7b8bd3b
| /* Add the runtime library's path to the dict */ | |
| staticint | |
| library_to_dict(PyObject*dict, constchar*key) | |
| { | |
| #ifdefMS_WINDOWS | |
| #ifdefPy_ENABLE_SHARED | |
| externHMODULEPyWin_DLLhModule; | |
| if (PyWin_DLLhModule){ | |
| returnwinmodule_to_dict(dict, key, PyWin_DLLhModule); | |
| } | |
| #endif | |
| #elif defined(WITH_NEXT_FRAMEWORK) | |
| staticcharmodPath[MAXPATHLEN+1]; | |
| staticintmodPathInitialized=-1; | |
| if (modPathInitialized<0){ | |
| modPathInitialized=0; | |
| /* On Mac OS X we have a special case if we're running from a framework. | |
| This is because the python home should be set relative to the library, | |
| which is in the framework, not relative to the executable, which may | |
| be outside of the framework. Except when we're in the build | |
| directory... */ | |
| Dl_infopythonInfo; | |
| if (dladdr(&Py_Initialize, &pythonInfo)){ | |
| if (pythonInfo.dli_fname){ | |
| strncpy(modPath, pythonInfo.dli_fname, MAXPATHLEN); | |
| modPathInitialized=1; | |
| } | |
| } | |
| } | |
| if (modPathInitialized>0){ | |
| returndecode_to_dict(dict, key, modPath); | |
| } | |
| #endif | |
| returnPyDict_SetItemString(dict, key, Py_None) ==0; | |
| } |
The spotty platform support stroke me as odd, especially on macOS, as I see no apparent reason for only supporting framework builds, so I looked traced back the origin of this code.
The macOS logic goes back to Python 2.0, having been introduced in 54ecc3d. At this time, we were determining base_prefix/base_exec_prefix based on the Python interpreter location, which was problematic on OS X Frameworks, as the Python interpreter is provided via a launcher. The comment traces back to 55070f5 and is unrelated to the change made by that commit, it just highlights the special case for macOS framework builds.
In GH-29041, which introduced getpath.py, rewriting the old path initialization C code in Python, the logic changed to purposefully search the libpython location before the executable location, also adding Windows support. I imagine the existing macOS code was kept as-is as a mistake, leaving it behind the WITH_NEXT_FRAMEWORK flag, maybe under the assumption it was needed for some reason.
Considering the clear intent in the code, I am treating this a bug.
cc @zooba
CPython versions tested on:
CPython main branch
Operating systems tested on:
No response