diff --git lib-python/3/ctypes/macholib/dyld.py lib-python/3/ctypes/macholib/dyld.py --- lib-python/3/ctypes/macholib/dyld.py +++ lib-python/3/ctypes/macholib/dyld.py @@ -6,6 +6,11 @@ import os from ctypes.macholib.framework import framework_info from ctypes.macholib.dylib import dylib_info from itertools import * +try: + from _ctypes import _dyld_shared_cache_contains_path +except ImportError: + def _dyld_shared_cache_contains_path(*args): + raise NotImplementedError __all__ = [ 'dyld_find', 'framework_find', @@ -122,8 +127,15 @@ def dyld_find(name, executable_path=None dyld_executable_path_search(name, executable_path), dyld_default_search(name, env), ), env): + if os.path.isfile(path): return path + try: + if _dyld_shared_cache_contains_path(path): + return path + except NotImplementedError: + pass + raise ValueError("dylib %s could not be found" % (name,)) def framework_find(fn, executable_path=None, env=None): diff --git lib-python/3/ctypes/test/test_macholib.py lib-python/3/ctypes/test/test_macholib.py --- lib-python/3/ctypes/test/test_macholib.py +++ lib-python/3/ctypes/test/test_macholib.py @@ -45,19 +45,22 @@ def find_lib(name): class MachOTest(unittest.TestCase): @unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test') def test_find(self): - - self.assertEqual(find_lib('pthread'), - '/usr/lib/libSystem.B.dylib') + # On Mac OS 11, system dylibs are only present in the shared cache, + # so symlinks like libpthread.dylib -> libSystem.B.dylib will not + # be resolved by dyld_find + self.assertIn(find_lib('pthread'), + ('/usr/lib/libSystem.B.dylib', '/usr/lib/libpthread.dylib')) result = find_lib('z') # Issue #21093: dyld default search path includes $HOME/lib and # /usr/local/lib before /usr/lib, which caused test failures if # a local copy of libz exists in one of them. Now ignore the head # of the path. - self.assertRegex(result, r".*/lib/libz\..*.*\.dylib") + self.assertRegex(result, r".*/lib/libz.*\.dylib") - self.assertEqual(find_lib('IOKit'), - '/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit') + self.assertIn(find_lib('IOKit'), + ('/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit', + '/System/Library/Frameworks/IOKit.framework/IOKit')) if __name__ == "__main__": unittest.main() diff --git lib_pypy/_ctypes/__init__.py lib_pypy/_ctypes/__init__.py --- lib_pypy/_ctypes/__init__.py +++ lib_pypy/_ctypes/__init__.py @@ -13,15 +13,15 @@ from _ctypes.builtin import ( _string_at_addr, _wstring_at_addr, set_conversion_mode) from _ctypes.union import Union +try: from __pypy__ import builtinify +except ImportError: builtinify = lambda f: f + import os as _os if _os.name in ("nt", "ce"): from _rawffi import FormatError from _rawffi import check_HRESULT as _check_HRESULT - try: from __pypy__ import builtinify - except ImportError: builtinify = lambda f: f - @builtinify def CopyComPointer(src, dst): from ctypes import c_void_p, cast @@ -32,8 +32,6 @@ if _os.name in ("nt", "ce"): dst[0] = cast(src, c_void_p).value return 0 - del builtinify - LoadLibrary = dlopen from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI @@ -43,6 +41,20 @@ from _ctypes.builtin import get_errno, s if _os.name in ("nt", "ce"): from _ctypes.builtin import get_last_error, set_last_error +import sys as _sys +if _sys.platform == 'darwin': + try: + from ._ctypes_cffi import ffi as _ffi, lib as _lib + @builtinify + def _dyld_shared_cache_contains_path(path): + if not hasattr(_lib, '_dyld_shared_cache_contains_path'): + raise NotImplementedError + return _lib._dyld_shared_cache_contains_path(path.encode()) + except ImportError: + pass + +del builtinify + __version__ = '1.1.0' #XXX platform dependant? RTLD_LOCAL = 0 diff --git lib_pypy/_ctypes/_ctypes_build.py lib_pypy/_ctypes/_ctypes_build.py new file mode 100644 --- /dev/null +++ lib_pypy/_ctypes/_ctypes_build.py @@ -0,0 +1,23 @@ +import os +import platform + +from cffi import FFI +ffi = FFI() + +def main(): + if platform.system() != 'Darwin': + return + + release, _, _ = platform.mac_ver() + release = tuple(map(int, release.split('.'))) + if release < (10, 16): + return + + ffi.cdef('bool _dyld_shared_cache_contains_path(const char* path);') + ffi.set_source('_ctypes_cffi', '#include ') + + os.chdir(os.path.dirname(__file__)) + ffi.compile() + +if __name__ == '__main__': + main() diff --git lib_pypy/pypy_tools/build_cffi_imports.py lib_pypy/pypy_tools/build_cffi_imports.py --- lib_pypy/pypy_tools/build_cffi_imports.py +++ lib_pypy/pypy_tools/build_cffi_imports.py @@ -1,5 +1,5 @@ from __future__ import print_function -import sys, shutil, os, tempfile, hashlib, time +import sys, shutil, os, tempfile, hashlib, time, collections import sysconfig from os.path import join @@ -22,22 +22,23 @@ class MissingDependenciesError(Exception pass -cffi_build_scripts = { - "_blake2": "_blake2/_blake2_build.py", - "_ssl": "_ssl_build.py", - "sqlite3": "_sqlite3_build.py", - "audioop": "_audioop_build.py", - "_tkinter": "_tkinter/tklib_build.py", - "curses": "_curses_build.py" if sys.platform != "win32" else None, - "syslog": "_syslog_build.py" if sys.platform != "win32" else None, - "_gdbm": "_gdbm_build.py" if sys.platform != "win32" else None, - "grp": "_pwdgrp_build.py" if sys.platform != "win32" else None, - "resource": "_resource_build.py" if sys.platform != "win32" else None, - "lzma": "_lzma_build.py", - # "_decimal": "_decimal_build.py", - "_sha3": "_sha3/_sha3_build.py", - "xx": None, # for testing: 'None' should be completely ignored - } +cffi_build_scripts = collections.OrderedDict([ + ("_ctypes._ctypes_cffi", "_ctypes/_ctypes_build.py" if sys.platform == "darwin" else None), + ("_blake2", "_blake2/_blake2_build.py"), + ("_ssl", "_ssl_build.py"), + ("sqlite3", "_sqlite3_build.py"), + ("audioop", "_audioop_build.py"), + ("_tkinter", "_tkinter/tklib_build.py"), + ("curses", "_curses_build.py" if sys.platform != "win32" else None), + ("syslog", "_syslog_build.py" if sys.platform != "win32" else None), + ("_gdbm", "_gdbm_build.py" if sys.platform != "win32" else None), + ("grp", "_pwdgrp_build.py" if sys.platform != "win32" else None), + ("resource", "_resource_build.py" if sys.platform != "win32" else None), + ("lzma", "_lzma_build.py"), + # "_decimal", "_decimal_build.py"), + ("_sha3", "_sha3/_sha3_build.py"), + ("xx", None), # for testing: 'None' should be completely ignored + ]) # for distribution, we may want to fetch dependencies not provided by # the OS, such as a recent openssl/libressl.