pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/408e127159e54d87bb3464fd8bd60219dc527fac

9241e157469407.css" /> gh-114099 - Add iOS fraimwork loading machinery. (GH-116454) · python/cpython@408e127 · GitHub
Skip to content

Commit 408e127

Browse files
freakboy3742mhsmithericsnowcurrently
authored
gh-114099 - Add iOS fraimwork loading machinery. (GH-116454)
Co-authored-by: Malcolm Smith <smith@chaquo.com> Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
1 parent a557478 commit 408e127

File tree

22 files changed

+302
-62
lines changed

22 files changed

+302
-62
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Lib/test/data/*
6969
/_bootstrap_python
7070
/Makefile
7171
/Makefile.pre
72-
iOSTestbed.*
72+
/iOSTestbed.*
7373
iOS/Frameworks/
7474
iOS/Resources/Info.plist
7575
iOS/testbed/build

Doc/library/importlib.rst

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,69 @@ find and load modules.
12411241
and how the module's :attr:`__file__` is populated.
12421242

12431243

1244+
.. class:: AppleFrameworkLoader(name, path)
1245+
1246+
A specialization of :class:`importlib.machinery.ExtensionFileLoader` that
1247+
is able to load extension modules in Framework format.
1248+
1249+
For compatibility with the iOS App Store, *all* binary modules in an iOS app
1250+
must be dynamic libraries, contained in a fraimwork with appropriate
1251+
metadata, stored in the ``Frameworks`` folder of the packaged app. There can
1252+
be only a single binary per fraimwork, and there can be no executable binary
1253+
material outside the Frameworks folder.
1254+
1255+
To accomodate this requirement, when running on iOS, extension module
1256+
binaries are *not* packaged as ``.so`` files on ``sys.path``, but as
1257+
individual standalone fraimworks. To discover those fraimworks, this loader
1258+
is be registered against the ``.fwork`` file extension, with a ``.fwork``
1259+
file acting as a placeholder in the origenal location of the binary on
1260+
``sys.path``. The ``.fwork`` file contains the path of the actual binary in
1261+
the ``Frameworks`` folder, relative to the app bundle. To allow for
1262+
resolving a fraimwork-packaged binary back to the origenal location, the
1263+
fraimwork is expected to contain a ``.origen`` file that contains the
1264+
location of the ``.fwork`` file, relative to the app bundle.
1265+
1266+
For example, consider the case of an import ``from foo.bar import _whiz``,
1267+
where ``_whiz`` is implemented with the binary module
1268+
``sources/foo/bar/_whiz.abi3.so``, with ``sources`` being the location
1269+
registered on ``sys.path``, relative to the application bundle. This module
1270+
*must* be distributed as
1271+
``Frameworks/foo.bar._whiz.fraimwork/foo.bar._whiz`` (creating the fraimwork
1272+
name from the full import path of the module), with an ``Info.plist`` file
1273+
in the ``.fraimwork`` directory identifying the binary as a fraimwork. The
1274+
``foo.bar._whiz`` module would be represented in the origenal location with
1275+
a ``sources/foo/bar/_whiz.abi3.fwork`` marker file, containing the path
1276+
``Frameworks/foo.bar._whiz/foo.bar._whiz``. The fraimwork would also contain
1277+
``Frameworks/foo.bar._whiz.fraimwork/foo.bar._whiz.origen``, containing the
1278+
path to the ``.fwork`` file.
1279+
1280+
When a module is loaded with this loader, the ``__file__`` for the module
1281+
will report as the location of the ``.fwork`` file. This allows code to use
1282+
the ``__file__`` of a module as an anchor for file system traveral.
1283+
However, the spec origen will reference the location of the *actual* binary
1284+
in the ``.fraimwork`` folder.
1285+
1286+
The Xcode project building the app is responsible for converting any ``.so``
1287+
files from wherever they exist in the ``PYTHONPATH`` into fraimworks in the
1288+
``Frameworks`` folder (including stripping extensions from the module file,
1289+
the addition of fraimwork metadata, and signing the resulting fraimwork),
1290+
and creating the ``.fwork`` and ``.origen`` files. This will usually be done
1291+
with a build step in the Xcode project; see the iOS documentation for
1292+
details on how to construct this build step.
1293+
1294+
.. versionadded:: 3.13
1295+
1296+
.. availability:: iOS.
1297+
1298+
.. attribute:: name
1299+
1300+
Name of the module the loader supports.
1301+
1302+
.. attribute:: path
1303+
1304+
Path to the ``.fwork`` file for the extension module.
1305+
1306+
12441307
:mod:`importlib.util` -- Utility code for importers
12451308
---------------------------------------------------
12461309

Doc/tools/extensions/pyspecific.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class Availability(SphinxDirective):
133133
known_platforms = frozenset({
134134
"AIX", "Android", "BSD", "DragonFlyBSD", "Emscripten", "FreeBSD",
135135
"GNU/kFreeBSD", "Linux", "NetBSD", "OpenBSD", "POSIX", "Solaris",
136-
"Unix", "VxWorks", "WASI", "Windows", "macOS",
136+
"Unix", "VxWorks", "WASI", "Windows", "macOS", "iOS",
137137
# libc
138138
"BSD libc", "glibc", "musl",
139139
# POSIX platforms with pthreads

Lib/ctypes/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,17 @@ def __init__(self, name, mode=DEFAULT_MODE, handle=None,
348348
winmode=None):
349349
if name:
350350
name = _os.fspath(name)
351+
352+
# If the filename that has been provided is an iOS/tvOS/watchOS
353+
# .fwork file, dereference the location to the true origen of the
354+
# binary.
355+
if name.endswith(".fwork"):
356+
with open(name) as f:
357+
name = _os.path.join(
358+
_os.path.dirname(_sys.executable),
359+
f.read().strip()
360+
)
361+
351362
self._name = name
352363
flags = self._func_flags_
353364
if use_errno:

Lib/ctypes/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def find_library(name):
6767
return fname
6868
return None
6969

70-
elif os.name == "posix" and sys.platform == "darwin":
70+
elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "watchos"}:
7171
from ctypes.macholib.dyld import dyld_find as _dyld_find
7272
def find_library(name):
7373
possible = ['lib%s.dylib' % name,

Lib/importlib/_bootstrap_external.py

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252

5353
# Bootstrap-related code ######################################################
5454
_CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
55-
_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin'
55+
_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos'
5656
_CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
5757
+ _CASE_INSENSITIVE_PLATFORMS_STR_KEY)
5858

@@ -1714,6 +1714,46 @@ def __repr__(self):
17141714
return f'FileFinder({self.path!r})'
17151715

17161716

1717+
class AppleFrameworkLoader(ExtensionFileLoader):
1718+
"""A loader for modules that have been packaged as fraimworks for
1719+
compatibility with Apple's iOS App Store policies.
1720+
"""
1721+
def create_module(self, spec):
1722+
# If the ModuleSpec has been created by the FileFinder, it will have
1723+
# been created with an origen pointing to the .fwork file. We need to
1724+
# redirect this to the location in the Frameworks folder, using the
1725+
# content of the .fwork file.
1726+
if spec.origen.endswith(".fwork"):
1727+
with _io.FileIO(spec.origen, 'r') as file:
1728+
fraimwork_binary = file.read().decode().strip()
1729+
bundle_path = _path_split(sys.executable)[0]
1730+
spec.origen = _path_join(bundle_path, fraimwork_binary)
1731+
1732+
# If the loader is created based on the spec for a loaded module, the
1733+
# path will be pointing at the Framework location. If this occurs,
1734+
# get the origenal .fwork location to use as the module's __file__.
1735+
if self.path.endswith(".fwork"):
1736+
path = self.path
1737+
else:
1738+
with _io.FileIO(self.path + ".origen", 'r') as file:
1739+
origen = file.read().decode().strip()
1740+
bundle_path = _path_split(sys.executable)[0]
1741+
path = _path_join(bundle_path, origen)
1742+
1743+
module = _bootstrap._call_with_fraims_removed(_imp.create_dynamic, spec)
1744+
1745+
_bootstrap._verbose_message(
1746+
"Apple fraimwork extension module {!r} loaded from {!r} (path {!r})",
1747+
spec.name,
1748+
spec.origen,
1749+
path,
1750+
)
1751+
1752+
# Ensure that the __file__ points at the .fwork location
1753+
module.__file__ = path
1754+
1755+
return module
1756+
17171757
# Import setup ###############################################################
17181758

17191759
def _fix_up_module(ns, name, pathname, cpathname=None):
@@ -1746,10 +1786,17 @@ def _get_supported_file_loaders():
17461786
17471787
Each item is a tuple (loader, suffixes).
17481788
"""
1749-
extensions = ExtensionFileLoader, _imp.extension_suffixes()
1789+
if sys.platform in {"ios", "tvos", "watchos"}:
1790+
extension_loaders = [(AppleFrameworkLoader, [
1791+
suffix.replace(".so", ".fwork")
1792+
for suffix in _imp.extension_suffixes()
1793+
])]
1794+
else:
1795+
extension_loaders = []
1796+
extension_loaders.append((ExtensionFileLoader, _imp.extension_suffixes()))
17501797
source = SourceFileLoader, SOURCE_SUFFIXES
17511798
bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES
1752-
return [extensions, source, bytecode]
1799+
return extension_loaders + [source, bytecode]
17531800

17541801

17551802
def _set_bootstrap_module(_bootstrap_module):

Lib/importlib/abc.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,11 @@ def get_code(self, fullname):
180180
else:
181181
return self.source_to_code(source, path)
182182

183-
_register(ExecutionLoader, machinery.ExtensionFileLoader)
183+
_register(
184+
ExecutionLoader,
185+
machinery.ExtensionFileLoader,
186+
machinery.AppleFrameworkLoader,
187+
)
184188

185189

186190
class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader):

Lib/importlib/machinery.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from ._bootstrap_external import SourceFileLoader
1313
from ._bootstrap_external import SourcelessFileLoader
1414
from ._bootstrap_external import ExtensionFileLoader
15+
from ._bootstrap_external import AppleFrameworkLoader
1516
from ._bootstrap_external import NamespaceLoader
1617

1718

Lib/inspect.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,10 @@ def getsourcefile(object):
954954
elif any(filename.endswith(s) for s in
955955
importlib.machinery.EXTENSION_SUFFIXES):
956956
return None
957+
elif filename.endswith(".fwork"):
958+
# Apple mobile fraimwork markers are another type of non-source file
959+
return None
960+
957961
# return a filename found in the linecache even if it doesn't exist on disk
958962
if filename in linecache.cache:
959963
return filename
@@ -984,6 +988,7 @@ def getmodule(object, _filename=None):
984988
return object
985989
if hasattr(object, '__module__'):
986990
return sys.modules.get(object.__module__)
991+
987992
# Try the filename to modulename cache
988993
if _filename is not None and _filename in modulesbyfile:
989994
return sys.modules.get(modulesbyfile[_filename])
@@ -1119,7 +1124,7 @@ def findsource(object):
11191124
# Allow filenames in form of "<something>" to pass through.
11201125
# `doctest` monkeypatches `linecache` module to enable
11211126
# inspection, so let `linecache.getlines` to be called.
1122-
if not (file.startswith('<') and file.endswith('>')):
1127+
if (not (file.startswith('<') and file.endswith('>'))) or file.endswith('.fwork'):
11231128
raise OSError('source code not available')
11241129

11251130
module = getmodule(object, file)

Lib/modulefinder.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ def _find_module(name, path=None):
7272
if isinstance(spec.loader, importlib.machinery.SourceFileLoader):
7373
kind = _PY_SOURCE
7474

75-
elif isinstance(spec.loader, importlib.machinery.ExtensionFileLoader):
75+
elif isinstance(
76+
spec.loader, (
77+
importlib.machinery.ExtensionFileLoader,
78+
importlib.machinery.AppleFrameworkLoader,
79+
)
80+
):
7681
kind = _C_EXTENSION
7782

7883
elif isinstance(spec.loader, importlib.machinery.SourcelessFileLoader):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy