Files

83 lines
3.2 KiB
Diff
Raw Permalink Normal View History

As of macOS 12, dladdr, NSLibraryNameForModule, and similar functions
will resolve symlinks, which breaks virtualenv. This works around that
issue by not using those functions if at all possible.
Adapted from https://github.com/apple-oss-distributions/python/blob/python-136.120.2/2.7/fix/getpath.c.ed
--- Modules/getpath.c.orig 2022-01-08 05:08:48.000000000 +1100
+++ Modules/getpath.c 2022-01-08 05:13:34.000000000 +1100
@@ -7,7 +7,7 @@
#include <string.h>
#ifdef __APPLE__
-#include <mach-o/dyld.h>
+#include <dlfcn.h>
#include <AvailabilityMacros.h>
#endif
@@ -380,9 +380,10 @@ calculate_path(void)
size_t prefixsz;
char *defpath = pythonpath;
#ifdef WITH_NEXT_FRAMEWORK
- NSModule pythonModule;
+ Dl_info addrinfo;
+ int first_pass = 1;
#endif
-#ifdef __APPLE__
+#if 0
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
uint32_t nsexeclength = MAXPATHLEN;
#else
@@ -397,7 +398,7 @@ calculate_path(void)
*/
if (strchr(prog, SEP))
strncpy(progpath, prog, MAXPATHLEN);
-#ifdef __APPLE__
+#if 0
/* On Mac OS X, if a script uses an interpreter of the form
* "#!/opt/python2.3/bin/python", the kernel only passes "python"
* as argv[0], which falls through to the $PATH search below.
@@ -410,7 +411,7 @@ calculate_path(void)
*/
else if(0 == _NSGetExecutablePath(progpath, &nsexeclength) && progpath[0] == SEP)
;
-#endif /* __APPLE__ */
+#endif /* notdef */
else if (path) {
while (1) {
char *delim = strchr(path, DELIM);
@@ -449,9 +450,18 @@ calculate_path(void)
** which is in the framework, not relative to the executable, which ma
** be outside of the framework. Except when we're in the build directory...
*/
- pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize"));
- /* Use dylib functions to find out where the framework was loaded from */
- buf = (char *)NSLibraryNameForModule(pythonModule);
+ /* dladdr() now returns the real path of the dylib, instead of the
+ ** path of the symlink. This breaks virtualenv. To fix this, we
+ ** skip using dladdr() during a first pass, and if that fails, then
+ ** we go back and do the dladdr(). It turns out that since we moved
+ ** Python.app to inside the Python.framework bundle, the call to
+ ** search_for_prefix() will now succeed without needing dladdr().
+ ** However, virtualenv copies the wrong binary when the prefix is
+ ** /usr, so if progpath begins with /usr/bin/, we skip the first pass.
+ */
+ if (strncmp(progpath, "/usr/bin/", 9) == 0) first_pass = 0;
+return_here_for_second_pass:
+ buf = first_pass ? NULL : (dladdr("_Py_Initialize", &addrinfo) ? (char *)addrinfo.dli_fname : NULL);
if (buf != NULL) {
/* We're in a framework. */
/* See if we might be in the build directory. The framework in the
@@ -504,6 +514,12 @@ calculate_path(void)
*/
if (!(pfound = search_for_prefix(argv0_path, home))) {
+#ifdef WITH_NEXT_FRAMEWORK
+ if (first_pass) {
+ first_pass = 0;
+ goto return_here_for_second_pass;
+ }
+#endif
if (!Py_FrozenFlag)
fprintf(stderr,
"Could not find platform independent libraries <prefix>\n");