gh-114099 - Add iOS framework loading machinery. (GH-116454)

Co-authored-by: Malcolm Smith <smith@chaquo.com>
Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
This commit is contained in:
Russell Keith-Magee 2024-03-19 20:36:19 +08:00 committed by GitHub
parent a557478987
commit 408e127159
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 302 additions and 62 deletions

View file

@ -52,7 +52,7 @@ _pathseps_with_colon = {f':{s}' for s in path_separators}
# Bootstrap-related code ######################################################
_CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin'
_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos'
_CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
+ _CASE_INSENSITIVE_PLATFORMS_STR_KEY)
@ -1714,6 +1714,46 @@ class FileFinder:
return f'FileFinder({self.path!r})'
class AppleFrameworkLoader(ExtensionFileLoader):
"""A loader for modules that have been packaged as frameworks for
compatibility with Apple's iOS App Store policies.
"""
def create_module(self, spec):
# If the ModuleSpec has been created by the FileFinder, it will have
# been created with an origin pointing to the .fwork file. We need to
# redirect this to the location in the Frameworks folder, using the
# content of the .fwork file.
if spec.origin.endswith(".fwork"):
with _io.FileIO(spec.origin, 'r') as file:
framework_binary = file.read().decode().strip()
bundle_path = _path_split(sys.executable)[0]
spec.origin = _path_join(bundle_path, framework_binary)
# If the loader is created based on the spec for a loaded module, the
# path will be pointing at the Framework location. If this occurs,
# get the original .fwork location to use as the module's __file__.
if self.path.endswith(".fwork"):
path = self.path
else:
with _io.FileIO(self.path + ".origin", 'r') as file:
origin = file.read().decode().strip()
bundle_path = _path_split(sys.executable)[0]
path = _path_join(bundle_path, origin)
module = _bootstrap._call_with_frames_removed(_imp.create_dynamic, spec)
_bootstrap._verbose_message(
"Apple framework extension module {!r} loaded from {!r} (path {!r})",
spec.name,
spec.origin,
path,
)
# Ensure that the __file__ points at the .fwork location
module.__file__ = path
return module
# Import setup ###############################################################
def _fix_up_module(ns, name, pathname, cpathname=None):
@ -1746,10 +1786,17 @@ def _get_supported_file_loaders():
Each item is a tuple (loader, suffixes).
"""
extensions = ExtensionFileLoader, _imp.extension_suffixes()
if sys.platform in {"ios", "tvos", "watchos"}:
extension_loaders = [(AppleFrameworkLoader, [
suffix.replace(".so", ".fwork")
for suffix in _imp.extension_suffixes()
])]
else:
extension_loaders = []
extension_loaders.append((ExtensionFileLoader, _imp.extension_suffixes()))
source = SourceFileLoader, SOURCE_SUFFIXES
bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES
return [extensions, source, bytecode]
return extension_loaders + [source, bytecode]
def _set_bootstrap_module(_bootstrap_module):

View file

@ -180,7 +180,11 @@ class ExecutionLoader(InspectLoader):
else:
return self.source_to_code(source, path)
_register(ExecutionLoader, machinery.ExtensionFileLoader)
_register(
ExecutionLoader,
machinery.ExtensionFileLoader,
machinery.AppleFrameworkLoader,
)
class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader):

View file

@ -12,6 +12,7 @@ from ._bootstrap_external import FileFinder
from ._bootstrap_external import SourceFileLoader
from ._bootstrap_external import SourcelessFileLoader
from ._bootstrap_external import ExtensionFileLoader
from ._bootstrap_external import AppleFrameworkLoader
from ._bootstrap_external import NamespaceLoader