Skip to content

gh-156112: Load the ObjC runtime by name when find_library() cannot resolve it - #156113

Open
clementperon wants to merge 2 commits into
python:mainfrom
clementperon:ios-objc-fallback
Open

gh-156112: Load the ObjC runtime by name when find_library() cannot resolve it#156113
clementperon wants to merge 2 commits into
python:mainfrom
clementperon:ios-objc-fallback

Conversation

@clementperon

@clementperon clementperon commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

_ios_support raises ImportError at import when ctypes.util.find_library("objc") returns None. That happens whenever the dyld shared cache cannot be queried: dyld_find() falls back to _dyld_shared_cache_contains_path(), which Modules/_ctypes/callproc.c guards with __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *), so on iOS 13 it raises NotImplementedError and no path can be resolved for a library that exists only in the cache.

IPHONEOS_DEPLOYMENT_TARGET defaults to 13.0, so this sits inside the supported range, and it takes platform.platform() and platform.ios_ver() down with it.

dyld resolves a bare library name against the cache by itself, so this falls back to the name when find_library() comes up empty, and keeps reporting a real load failure as ImportError rather than letting OSError escape.

Verified on macOS, where the same cache mechanism applies — find_library("objc") names a path that is not a file, and a bare-name load works:

>>> util.find_library("objc"), os.path.isfile("/usr/lib/libobjc.dylib")
('/usr/lib/libobjc.dylib', False)
>>> cdll.LoadLibrary("libobjc.dylib")
<CDLL 'libobjc.dylib', handle ... at ...>

and with find_library patched to return None, the module loads the runtime and objc_getClass(b"NSProcessInfo") succeeds.

I do not have an iOS 13 device or simulator runtime available, so the import failure itself is derived from the source rather than reproduced on-device; the fallback is verified as above.

ctypes.util.find_library() resolves a system library through the dyld shared
cache, which requires _dyld_shared_cache_contains_path(). Modules/_ctypes/
callproc.c guards that symbol with __builtin_available(iOS 14.0), so on iOS 13 -
the oldest release CPython's iOS support targets - find_library() returns None
for any library that exists only in the cache, and importing _ios_support fails
outright rather than degrading.

dyld resolves a bare library name against the cache by itself, so use that when
find_library() comes up empty. A genuine load failure is still reported as
ImportError.
clementperon added a commit to clementperon/xbmc that referenced this pull request Aug 20, 2026
CPython appends -mios-version-min - the device flag - to every iOS build.
Against the simulator SDK the linker rejects the dylibs it resolves there, and
the first configure check that links one fails, taking the depends build with
it.

The local patch faked ac_sys_system=iOS by deleting CPython's host parsing,
because config.site.in pinned every package to the tree's darwin triplet. Python
now configures against its own iOS triplet, so CPython derives ac_sys_system,
the deployment target and the device/simulator split itself, and the 76 lines
that deleted that logic are gone.

What is left matches three patches under review upstream, so all three can be
dropped when python is next bumped:

  python/cpython#156110
  python/cpython#156116
  python/cpython#156113

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
clementperon added a commit to clementperon/xbmc that referenced this pull request Aug 20, 2026
CPython appends -mios-version-min - the device flag - to every iOS build.
Against the simulator SDK the linker rejects the dylibs it resolves there, and
the first configure check that links one fails, taking the depends build with
it.

The local patch faked ac_sys_system=iOS by deleting CPython's host parsing,
because config.site.in pinned every package to the tree's darwin triplet. Python
now configures against its own iOS triplet, so CPython derives ac_sys_system,
the deployment target and the device/simulator split itself, and the 76 lines
that deleted that logic are gone.

What is left matches three patches under review upstream, so all three can be
dropped when python is next bumped:

  python/cpython#156110
  python/cpython#156116
  python/cpython#156113

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
clementperon added a commit to clementperon/xbmc that referenced this pull request Aug 20, 2026
CPython appends -mios-version-min - the device flag - to every iOS build.
Against the simulator SDK the linker rejects the dylibs it resolves there, and
the first configure check that links one fails, taking the depends build with
it.

The local patch faked ac_sys_system=iOS by deleting CPython's host parsing,
because config.site.in pinned every package to the tree's darwin triplet. Python
now configures against its own iOS triplet, so CPython derives ac_sys_system,
the deployment target and the device/simulator split itself, and the 76 lines
that deleted that logic are gone.

What is left matches three patches under review upstream, so all three can be
dropped when python is next bumped:

  python/cpython#156110
  python/cpython#156116
  python/cpython#156113

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant