Skip to content

Commit e384b99

Browse files
committed
detect libs in dyld cache on macOS >= 11 (inspired by python/cpython@4176193 )
1 parent 61c337d commit e384b99

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ctypes/CtypesModuleBuiltins.java

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -163,6 +163,7 @@
163163
import com.oracle.truffle.api.dsl.UnsupportedSpecializationException;
164164
import com.oracle.truffle.api.frame.VirtualFrame;
165165
import com.oracle.truffle.api.interop.ArityException;
166+
import com.oracle.truffle.api.interop.InteropException;
166167
import com.oracle.truffle.api.interop.InteropLibrary;
167168
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
168169
import com.oracle.truffle.api.interop.TruffleObject;
@@ -799,6 +800,70 @@ Object py_dl_sym(VirtualFrame frame, Object obj, Object name,
799800
}
800801
}
801802

803+
@Builtin(name = "_dyld_shared_cache_contains_path", minNumOfPositionalArgs = 1)
804+
@GenerateNodeFactory
805+
protected abstract static class DyldSharedCacheConstainsPath extends PythonBinaryBuiltinNode {
806+
private static boolean hasDynamicLoaderCacheValue = false;
807+
private static boolean hasDynamicLoaderCacheInit = false;
808+
809+
private static boolean hasDynamicLoaderCache() {
810+
if (hasDynamicLoaderCacheInit) {
811+
return hasDynamicLoaderCacheValue;
812+
}
813+
814+
CompilerDirectives.transferToInterpreter();
815+
if (System.getProperty("os.name").contains("Mac")) {
816+
String osVersion = System.getProperty("os.version");
817+
// dynamic linker cache support on os.version >= 11.x
818+
int major = 11;
819+
int i = osVersion.indexOf('.');
820+
try {
821+
major = Integer.parseInt(i < 0 ? osVersion : osVersion.substring(0, i));
822+
} catch (NumberFormatException e) {
823+
}
824+
hasDynamicLoaderCacheValue = major >= 11;
825+
} else {
826+
hasDynamicLoaderCacheValue = false;
827+
}
828+
hasDynamicLoaderCacheInit = true;
829+
return hasDynamicLoaderCacheValue;
830+
}
831+
832+
@Specialization
833+
Object py_dyld_shared_pstring(VirtualFrame frame, PString ppath,
834+
@CachedLibrary(limit = "1") InteropLibrary ilib) {
835+
return py_dyld_shared_cache_contains_path(frame, ppath.getValue(), ilib);
836+
}
837+
838+
@CompilationFinal Object cachedFunction = null;
839+
840+
// TODO: 'path' might need to be processed using FSConverter.
841+
@Specialization
842+
Object py_dyld_shared_cache_contains_path(VirtualFrame frame, String path,
843+
@CachedLibrary(limit = "1") InteropLibrary ilib) {
844+
if (!hasDynamicLoaderCache()) {
845+
throw raise(NotImplementedError, "_dyld_shared_cache_contains_path symbol is missing");
846+
}
847+
848+
try {
849+
if (cachedFunction == null) {
850+
String name = "_dyld_shared_cache_contains_path";
851+
CompilerDirectives.transferToInterpreter();
852+
DLHandler handle = DlOpenNode.loadNFILibrary(getContext(), NFIBackend.NATIVE, "", RTLD_LOCAL.getValueIfDefined());
853+
Object sym = ilib.readMember(handle.getLibrary(), name);
854+
// bool _dyld_shared_cache_contains_path(const char* path)
855+
Source source = Source.newBuilder(NFI_LANGUAGE, "(string):sint32", name).build();
856+
Object nfiSignature = getContext().getEnv().parseInternal(source).call();
857+
cachedFunction = SignatureLibrary.getUncached().bind(nfiSignature, sym);
858+
assert ilib.isExecutable(cachedFunction);
859+
}
860+
return (int) ilib.execute(cachedFunction, path) != 0;
861+
} catch (InteropException e) {
862+
return false;
863+
}
864+
}
865+
}
866+
802867
@Builtin(name = "alignment", minNumOfPositionalArgs = 1)
803868
@GenerateNodeFactory
804869
protected abstract static class AlignmentNode extends PythonUnaryBuiltinNode {

graalpython/lib-python/3/ctypes/macholib/dyld.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
from ctypes.macholib.framework import framework_info
77
from ctypes.macholib.dylib import dylib_info
88
from itertools import *
9+
try:
10+
from _ctypes import _dyld_shared_cache_contains_path
11+
except ImportError:
12+
def _dyld_shared_cache_contains_path(*args):
13+
print("dyld_shared_cached_contains_path not implemented")
14+
raise NotImplementedError
915

1016
__all__ = [
1117
'dyld_find', 'framework_find',
@@ -122,8 +128,15 @@ def dyld_find(name, executable_path=None, env=None):
122128
dyld_executable_path_search(name, executable_path),
123129
dyld_default_search(name, env),
124130
), env):
131+
125132
if os.path.isfile(path):
126133
return path
134+
try:
135+
if _dyld_shared_cache_contains_path(path):
136+
return path
137+
except NotImplementedError:
138+
pass
139+
127140
raise ValueError("dylib %s could not be found" % (name,))
128141

129142
def framework_find(fn, executable_path=None, env=None):

0 commit comments

Comments
 (0)