From 3a7cd861f523cd5a80b9ba1d452278cdc138cfd8 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 17 Feb 2025 14:38:25 +0800 Subject: [PATCH 1/6] More updates to USAGE and README (#250) * Adds details on `python-config` and `testbed` * Adds a bare bones interpreter instantiation example * Clarifies the difference between instantiating the interpreter, and accessing the Python API with PythonKit * Adds header exclusions to the modulemap to silence build warnings. --- README.rst | 35 ++++++-- USAGE.md | 113 ++++++++++++++++-------- patch/Python/module.modulemap | 160 ++++++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+), 43 deletions(-) diff --git a/README.rst b/README.rst index 94c0ae94..2317b749 100644 --- a/README.rst +++ b/README.rst @@ -83,15 +83,6 @@ Each support package contains: * ``VERSIONS``, a text file describing the specific versions of code used to build the support package; -* ``platform-site``, a folder that contains site customization scripts that can be used - to make your local Python install look like it is an on-device install for each of the - underlying target architectures supported by the platform. This is needed because when - you run ``pip`` you'll be on a macOS machine with a specific architecture; if ``pip`` - tries to install a binary package, it will install a macOS binary wheel (which won't - work on iOS/tvOS/watchOS). However, if you add the ``platform-site`` folder to your - ``PYTHONPATH`` when invoking pip, the site customization will make your Python install - return ``platform`` and ``sysconfig`` responses consistent with on-device behavior, - which will cause ``pip`` to install platform-appropriate packages. * ``Python.xcframework``, a multi-architecture build of the Python runtime library On iOS/tvOS/watchOS, the ``Python.xcframework`` contains a @@ -105,6 +96,32 @@ needed to build packages. This is required because Xcode uses the ``xcrun`` alias to dynamically generate the name of binaries, but a lot of C tooling expects that ``CC`` will not contain spaces. +Each slice of an iOS/tvOS/watchOS XCframework also contains a +``platform-config`` folder with a subfolder for each supported architecture in +that slice. These subfolders can be used to make a macOS Python environment +behave as if it were on an iOS/tvOS/watchOS device. This works in one of two +ways: + +1. **A sitecustomize.py script**. If the ``platform-config`` subfolder is on + your ``PYTHONPATH`` when a Python interpreter is started, a site + customization will be applied that patches methods in ``sys``, ``sysconfig`` + and ``platform`` that are used to identify the system. + +2. **A make_cross_venv.py script**. If you call ``make_cross_venv.py``, + providing the location of a virtual environment, the script will add some + files to the ``site-packages`` folder of that environment that will + automatically apply the same set of patches as the ``sitecustomize.py`` + script whenever the environment is activated, without any need to modify + ``PYTHONPATH``. If you use ``build`` to create an isolated PEP 517 + environment to build a wheel, these patches will also be applied to the + isolated build environment that is created. + +iOS distributions also contain a copy of the iOS ``testbed`` project - an Xcode +project that can be used to run test suites of Python code. See the `CPython +documentation on testing packages +`__ for +details on how to use this testbed. + For a detailed instructions on using the support package in your own project, see the `usage guide <./USAGE.md>`__ diff --git a/USAGE.md b/USAGE.md index 40bbcf80..096f71b0 100644 --- a/USAGE.md +++ b/USAGE.md @@ -25,6 +25,75 @@ guides: For tvOS and watchOS, you should be able to broadly follow the instructions in the iOS guide. +### Using Objective C + +Once you've added the Python XCframework to your project, you'll need to +initialize the Python runtime in your Objective C code (This is step 10 of the +iOS guide linked above). This initialization should generally be done as early +as possible in the application's lifecycle, but definitely needs to be done +before you invoke Python code. + +As a *bare minimum*, you can do the following: + +1. Import the Python C API headers: + ```objc + #include + ``` + +2. Initialize the Python interpreter: + ```objc + NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; + NSString *pythonHome = [NSString stringWithFormat:@"%@/python", resourcePath, nil]; + NSString *pythonPath = [NSString stringWithFormat:@"%@/lib/python3.13", python_home, nil]; + NSString *libDynloadPath = [NSString stringWithFormat:@"%@/lib/python3.13/lib-dynload", python_home, nil]; + NSString *appPath = [NSString stringWithFormat:@"%@/app", resourcePath, nil]; + + setenv("PYTHONHOME", pythonHome, 1); + setenv("PYTHONPATH", [NSString stringWithFormat:@"%@:%@:%@", pythonpath, libDynloadPath, appPath, nil]); + + Py_Initialize(); + + // we now have a Python interpreter ready to be used + ``` + References to a specific Python version should reflect the version of + Python you are using. + +Again - this is the *bare minimum* initialization. In practice, you will likely +need to configure other aspects of the Python interpreter using the +`PyPreConfig` and `PyConfig` mechanisms. Consult the [Python documentation on +interpreter configuration](https://docs.python.org/3/c-api/init_config.html) for +more details on the configuration options that are available. You may find the +[bootstrap mainline code used by +Briefcase](https://github.com/beeware/briefcase-iOS-Xcode-template/blob/main/%7B%7B%20cookiecutter.format%20%7D%7D/%7B%7B%20cookiecutter.class_name%20%7D%7D/main.m) +a helpful point of comparison. + +### Using Swift + +If you want to use Swift instead of Objective C, the bare minimum initialization +code will look something like this: + +1. Import the Python framework: + ```swift + import Python + ``` + +2. Initialize the Python interpreter: + ```swift + guard let pythonHome = Bundle.main.path(forResource: "python", ofType: nil) else { return } + guard let pythonPath = Bundle.main.path(forResource: "python/lib/python3.13", ofType: nil) else { return } + guard let libDynloadPath = Bundle.main.path(forResource: "python/lib/python3.13/lib-dynload", ofType: nil) else { return } + let appPath = Bundle.main.path(forResource: "app", ofType: nil) + + setenv("PYTHONHOME", pythonHome, 1) + setenv("PYTHONPATH", [pythonPath, libDynloadPath, appPath].compactMap { $0 }.joined(separator: ":"), 1) + Py_Initialize() + // we now have a Python interpreter ready to be used + ``` + + Again, references to a specific Python version should reflect the version of + Python you are using; and you will likely need to use `PyPreConfig` and + `PreConfig` APIs. + ## Accessing the Python runtime There are 2 ways to access the Python runtime in your project code. @@ -32,53 +101,29 @@ There are 2 ways to access the Python runtime in your project code. ### Embedded C API You can use the [Python Embedded C -API](https://docs.python.org/3/extending/embedding.html) to instantiate a Python -interpreter. This is the approach taken by Briefcase; you may find the bootstrap -mainline code generated by Briefcase a helpful guide to what is needed to start -an interpreter and run Python code. +API](https://docs.python.org/3/extending/embedding.html) to invoke Python code +and interact with Python objects. This is a raw C API that is accesible to both +Objective C and Swift. ### PythonKit -An alternate approach is to use +If you're using Swift, an alternate approach is to use [PythonKit](https://github.com/pvieito/PythonKit). PythonKit is a package that provides a Swift API to running Python code. To use PythonKit in your project, add the Python Apple Support package to your -project as described above; then: - -1. Add PythonKit to your project using the Swift Package manager. See the - PythonKit documentation for details. +project and instantiate a Python interpreter as described above; then add +PythonKit to your project using the Swift Package manager (see the [PythonKit +documentation](https://github.com/pvieito/PythonKit) for details). -2. In your Swift code, initialize the Python runtime. This should generally be - done as early as possible in the application's lifecycle, but definitely - needs to be done before you invoke Python code. References to a specific - Python version should reflect the version of Python you are using: +Once you've done this, you can import PythonKit: ```swift -import Python - -guard let pythonHome = Bundle.main.path(forResource: "python", ofType: nil) else { return } -guard let pythonPath = Bundle.main.path(forResource: "python/lib/python3.13", ofType: nil) else { return } -guard let libDynloadPath = Bundle.main.path(forResource: "python/lib/python3.13/lib-dynload", ofType: nil) else { return } -let appPath = Bundle.main.path(forResource: "app", ofType: nil) - -setenv("PYTHONHOME", pythonHome, 1) -setenv("PYTHONPATH", [pythonPath, libDynloadPath, appPath].compactMap { $0 }.joined(separator: ":"), 1) -Py_Initialize() -// we now have a Python interpreter ready to be used +import PythonKit ``` - -3. Invoke Python code in your app. For example: +and use the PythonKit Swift API to interact with Python code: ```swift -import PythonKit - let sys = Python.import("sys") print("Python Version: \(sys.version_info.major).\(sys.version_info.minor)") print("Python Encoding: \(sys.getdefaultencoding().upper())") print("Python Path: \(sys.path)") - -_ = Python.import("math") // verifies `lib-dynload` is found and signed successfully ``` - -To integrate 3rd party python code and dependencies, you will need to make sure -`PYTHONPATH` contains their paths; once this has been done, you can run -`Python.import("")`. to import that module from inside swift. diff --git a/patch/Python/module.modulemap b/patch/Python/module.modulemap index 9a4dcbb8..96b05fc6 100644 --- a/patch/Python/module.modulemap +++ b/patch/Python/module.modulemap @@ -2,4 +2,164 @@ module Python { umbrella header "Python.h" export * link "Python" + + exclude header "datetime.h" + exclude header "dynamic_annotations.h" + exclude header "errcode.h" + exclude header "frameobject.h" + exclude header "marshal.h" + exclude header "opcode_ids.h" + exclude header "opcode.h" + exclude header "osdefs.h" + exclude header "py_curses.h" + exclude header "pyconfig-arm32_64.h" + exclude header "pyconfig-arm64.h" + exclude header "pyconfig-x86_64.h" + exclude header "pydtrace.h" + exclude header "pyexpat.h" + exclude header "structmember.h" + + exclude header "cpython/frameobject.h" + exclude header "cpython/pthread_stubs.h" + exclude header "cpython/pyatomic_msc.h" + exclude header "cpython/pyatomic_std.h" + exclude header "cpython/pystats.h" + + exclude header "internal/mimalloc/mimalloc.h" + exclude header "internal/mimalloc/mimalloc/atomic.h" + exclude header "internal/mimalloc/mimalloc/internal.h" + exclude header "internal/mimalloc/mimalloc/prim.h" + exclude header "internal/mimalloc/mimalloc/track.h" + exclude header "internal/mimalloc/mimalloc/types.h" + + exclude header "internal/pycore_abstract.h" + exclude header "internal/pycore_asdl.h" + exclude header "internal/pycore_ast_state.h" + exclude header "internal/pycore_ast.h" + exclude header "internal/pycore_atexit.h" + exclude header "internal/pycore_audit.h" + exclude header "internal/pycore_backoff.h" + exclude header "internal/pycore_bitutils.h" + exclude header "internal/pycore_blocks_output_buffer.h" + exclude header "internal/pycore_brc.h" + exclude header "internal/pycore_bytes_methods.h" + exclude header "internal/pycore_bytesobject.h" + exclude header "internal/pycore_call.h" + exclude header "internal/pycore_capsule.h" + exclude header "internal/pycore_cell.h" + exclude header "internal/pycore_ceval_state.h" + exclude header "internal/pycore_ceval.h" + exclude header "internal/pycore_code.h" + exclude header "internal/pycore_codecs.h" + exclude header "internal/pycore_compile.h" + exclude header "internal/pycore_complexobject.h" + exclude header "internal/pycore_condvar.h" + exclude header "internal/pycore_context.h" + exclude header "internal/pycore_critical_section.h" + exclude header "internal/pycore_crossinterp_data_registry.h" + exclude header "internal/pycore_crossinterp.h" + exclude header "internal/pycore_debug_offsets.h" + exclude header "internal/pycore_descrobject.h" + exclude header "internal/pycore_dict_state.h" + exclude header "internal/pycore_dict.h" + exclude header "internal/pycore_dtoa.h" + exclude header "internal/pycore_emscripten_signal.h" + exclude header "internal/pycore_emscripten_trampoline.h" + exclude header "internal/pycore_exceptions.h" + exclude header "internal/pycore_faulthandler.h" + exclude header "internal/pycore_fileutils_windows.h" + exclude header "internal/pycore_fileutils.h" + exclude header "internal/pycore_floatobject.h" + exclude header "internal/pycore_flowgraph.h" + exclude header "internal/pycore_format.h" + exclude header "internal/pycore_frame.h" + exclude header "internal/pycore_freelist_state.h" + exclude header "internal/pycore_freelist.h" + exclude header "internal/pycore_function.h" + exclude header "internal/pycore_gc.h" + exclude header "internal/pycore_genobject.h" + exclude header "internal/pycore_getopt.h" + exclude header "internal/pycore_gil.h" + exclude header "internal/pycore_global_objects_fini_generated.h" + exclude header "internal/pycore_global_objects.h" + exclude header "internal/pycore_global_strings.h" + exclude header "internal/pycore_hamt.h" + exclude header "internal/pycore_hashtable.h" + exclude header "internal/pycore_identifier.h" + exclude header "internal/pycore_import.h" + exclude header "internal/pycore_importdl.h" + exclude header "internal/pycore_index_pool.h" + exclude header "internal/pycore_initconfig.h" + exclude header "internal/pycore_instruction_sequence.h" + exclude header "internal/pycore_instruments.h" + exclude header "internal/pycore_interp.h" + exclude header "internal/pycore_intrinsics.h" + exclude header "internal/pycore_jit.h" + exclude header "internal/pycore_list.h" + exclude header "internal/pycore_llist.h" + exclude header "internal/pycore_lock.h" + exclude header "internal/pycore_long.h" + exclude header "internal/pycore_magic_number.h" + exclude header "internal/pycore_memoryobject.h" + exclude header "internal/pycore_mimalloc.h" + exclude header "internal/pycore_modsupport.h" + exclude header "internal/pycore_moduleobject.h" + exclude header "internal/pycore_namespace.h" + exclude header "internal/pycore_object_alloc.h" + exclude header "internal/pycore_object_deferred.h" + exclude header "internal/pycore_object_stack.h" + exclude header "internal/pycore_object_state.h" + exclude header "internal/pycore_object.h" + exclude header "internal/pycore_obmalloc_init.h" + exclude header "internal/pycore_obmalloc.h" + exclude header "internal/pycore_opcode_metadata.h" + exclude header "internal/pycore_opcode_utils.h" + exclude header "internal/pycore_optimizer.h" + exclude header "internal/pycore_parking_lot.h" + exclude header "internal/pycore_parser.h" + exclude header "internal/pycore_pathconfig.h" + exclude header "internal/pycore_pyarena.h" + exclude header "internal/pycore_pyatomic_ft_wrappers.h" + exclude header "internal/pycore_pybuffer.h" + exclude header "internal/pycore_pyerrors.h" + exclude header "internal/pycore_pyhash.h" + exclude header "internal/pycore_pylifecycle.h" + exclude header "internal/pycore_pymath.h" + exclude header "internal/pycore_pymem_init.h" + exclude header "internal/pycore_pymem.h" + exclude header "internal/pycore_pystate.h" + exclude header "internal/pycore_pystats.h" + exclude header "internal/pycore_pythonrun.h" + exclude header "internal/pycore_pythread.h" + exclude header "internal/pycore_qsbr.h" + exclude header "internal/pycore_range.h" + exclude header "internal/pycore_runtime_init_generated.h" + exclude header "internal/pycore_runtime_init.h" + exclude header "internal/pycore_runtime.h" + exclude header "internal/pycore_semaphore.h" + exclude header "internal/pycore_setobject.h" + exclude header "internal/pycore_signal.h" + exclude header "internal/pycore_sliceobject.h" + exclude header "internal/pycore_stackref.h" + exclude header "internal/pycore_strhex.h" + exclude header "internal/pycore_structseq.h" + exclude header "internal/pycore_symtable.h" + exclude header "internal/pycore_sysmodule.h" + exclude header "internal/pycore_time.h" + exclude header "internal/pycore_token.h" + exclude header "internal/pycore_traceback.h" + exclude header "internal/pycore_tracemalloc.h" + exclude header "internal/pycore_tstate.h" + exclude header "internal/pycore_tuple.h" + exclude header "internal/pycore_typeobject.h" + exclude header "internal/pycore_typevarobject.h" + exclude header "internal/pycore_ucnhash.h" + exclude header "internal/pycore_unicodeobject_generated.h" + exclude header "internal/pycore_unicodeobject.h" + exclude header "internal/pycore_unionobject.h" + exclude header "internal/pycore_uniqueid.h" + exclude header "internal/pycore_uop_ids.h" + exclude header "internal/pycore_uop_metadata.h" + exclude header "internal/pycore_warnings.h" + exclude header "internal/pycore_weakref.h" } From 1158013c280b625e64db4470c528f03f61b48546 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 06:08:50 +0800 Subject: [PATCH 2/6] Bump ncipollo/release-action from 1.15.0 to 1.16.0 (#253) Bumps [ncipollo/release-action](https://github.com/ncipollo/release-action) from 1.15.0 to 1.16.0. - [Release notes](https://github.com/ncipollo/release-action/releases) - [Commits](https://github.com/ncipollo/release-action/compare/v1.15.0...v1.16.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4c0a16a4..0980fb50 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -47,7 +47,7 @@ jobs: merge-multiple: true - name: Create Release - uses: ncipollo/release-action@v1.15.0 + uses: ncipollo/release-action@v1.16.0 with: name: ${{ needs.ci.outputs.PYTHON_VER }}-${{ needs.config.outputs.BUILD_NUMBER }} tag: ${{ needs.ci.outputs.PYTHON_VER }}-${{ needs.config.outputs.BUILD_NUMBER }} From 832d39318cb752f0a0165ee2eeee263610fb12ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 06:09:14 +0800 Subject: [PATCH 3/6] Bump actions/upload-artifact from 4.6.0 to 4.6.1 (#254) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.0 to 4.6.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4.6.0...v4.6.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 44609a7a..ef7ad512 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -121,7 +121,7 @@ jobs: make ${{ matrix.target }} BUILD_NUMBER=${{ needs.config.outputs.BUILD_NUMBER }} - name: Upload build artefacts - uses: actions/upload-artifact@v4.6.0 + uses: actions/upload-artifact@v4.6.1 with: name: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz path: dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz From aa545e919535a3334cf17a79dc4acfdd512d9a41 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 26 Feb 2025 07:05:14 +0800 Subject: [PATCH 4/6] Add patch for handling empty simulator lists. --- patch/Python/Python.patch | 49 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index 910f33c2..139da995 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -1271,10 +1271,53 @@ index c3e261ecd9e..26ef7a95de4 100644 iPhoneOS diff --git a/iOS/testbed/__main__.py b/iOS/testbed/__main__.py -index b4499f5ac17..08fbe90a1c6 100644 +index b4499f5ac17..d12a5ab065b 100644 --- a/iOS/testbed/__main__.py +++ b/iOS/testbed/__main__.py -@@ -230,33 +230,69 @@ +@@ -82,19 +82,29 @@ + + # Return a list of UDIDs associated with booted simulators + async def list_devices(): +- # List the testing simulators, in JSON format +- raw_json = await async_check_output( +- "xcrun", "simctl", "--set", "testing", "list", "-j" +- ) +- json_data = json.loads(raw_json) +- +- # Filter out the booted iOS simulators +- return [ +- simulator["udid"] +- for runtime, simulators in json_data["devices"].items() +- for simulator in simulators +- if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" +- ] ++ try: ++ # List the testing simulators, in JSON format ++ raw_json = await async_check_output( ++ "xcrun", "simctl", "--set", "testing", "list", "-j" ++ ) ++ json_data = json.loads(raw_json) ++ ++ # Filter out the booted iOS simulators ++ return [ ++ simulator["udid"] ++ for runtime, simulators in json_data["devices"].items() ++ for simulator in simulators ++ if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" ++ ] ++ except subprocess.CalledProcessError as e: ++ # If there's no ~/Library/Developer/XCTestDevices folder (which is the ++ # case on fresh installs, and in some CI environments), `simctl list` ++ # returns error code 1, rather than an empty list. Handle that case, ++ # but raise all other errors. ++ if e.returncode == 1: ++ return [] ++ else: ++ raise + + + async def find_device(initial_devices): +@@ -230,33 +240,69 @@ shutil.copytree(source, target, symlinks=True) print(" done") @@ -1351,7 +1394,7 @@ index b4499f5ac17..08fbe90a1c6 100644 for app_src in apps: print(f" Installing app {app_src.name!r}...", end="", flush=True) -@@ -372,8 +408,8 @@ +@@ -372,8 +418,8 @@ if context.subcommand == "clone": clone_testbed( From c794b061d3092ea6716039b22118de85fd98aa27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 08:56:06 +0800 Subject: [PATCH 5/6] Bump actions/download-artifact from 4.1.8 to 4.1.9 (#255) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.1.8 to 4.1.9. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4.1.8...v4.1.9) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0980fb50..61da403c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -40,7 +40,7 @@ jobs: needs: [ config, ci ] steps: - name: Get build artifacts - uses: actions/download-artifact@v4.1.8 + uses: actions/download-artifact@v4.1.9 with: pattern: Python-* path: dist From 0013ca0bc85a38f21ca1c4c9f6c8b1e44ae6c400 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 18 Mar 2025 15:39:26 +0800 Subject: [PATCH 6/6] Update patch for Python 3.14.0a6 (#258) * Update patch for v3.14.0a6, * Automate the contents of the modulemap file. --- .github/workflows/ci.yaml | 7 +- Makefile | 24 +++- patch/Python/Python.patch | 171 +++------------------------ patch/Python/module.modulemap | 165 -------------------------- patch/Python/module.modulemap.prefix | 20 ++++ 5 files changed, 60 insertions(+), 327 deletions(-) delete mode 100644 patch/Python/module.modulemap create mode 100644 patch/Python/module.modulemap.prefix diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ef7ad512..6befbc46 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,10 +1,6 @@ name: CI on: pull_request: - push: - branches: - - main - - 3.* workflow_call: inputs: build-number: @@ -114,6 +110,9 @@ jobs: # Appending -dev ensures that we can always build the dev release. # It's a no-op for versions that have been published. python-version: ${{ needs.config.outputs.PYTHON_VER }}-dev + # Ensure that we *always* use the latest build, not a cached version. + # It's an edge case, but when a new alpha is released, we need to use it ASAP. + check-latest: true - name: Build ${{ matrix.target }} run: | diff --git a/Makefile b/Makefile index b0ba7299..7d3f6bfa 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ BUILD_NUMBER=custom # of a release cycle, as official binaries won't be published. # PYTHON_MICRO_VERSION is the full version number, without any alpha/beta/rc suffix. (e.g., 3.10.0) # PYTHON_VER is the major/minor version (e.g., 3.10) -PYTHON_VERSION=3.14.0a5 +PYTHON_VERSION=3.14.0a6 PYTHON_PKG_VERSION=$(PYTHON_VERSION) PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+") PYTHON_PKG_MICRO_VERSION=$(shell echo $(PYTHON_PKG_VERSION) | grep -Eo "\d+\.\d+\.\d+") @@ -426,6 +426,7 @@ PYTHON_FRAMEWORK-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/Python.framework PYTHON_INSTALL_VERSION-$(sdk)=$$(PYTHON_FRAMEWORK-$(sdk))/Versions/$(PYTHON_VER) PYTHON_LIB-$(sdk)=$$(PYTHON_INSTALL_VERSION-$(sdk))/Python PYTHON_INCLUDE-$(sdk)=$$(PYTHON_INSTALL_VERSION-$(sdk))/include/python$(PYTHON_VER) +PYTHON_MODULEMAP-$(sdk)=$$(PYTHON_INCLUDE-$(sdk))/module.modulemap PYTHON_STDLIB-$(sdk)=$$(PYTHON_INSTALL_VERSION-$(sdk))/lib/python$(PYTHON_VER) else @@ -436,6 +437,7 @@ else # The non-macOS frameworks don't use the versioning structure. PYTHON_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/python-$(PYTHON_VERSION) +PYTHON_MODULEMAP-$(sdk)=$$(PYTHON_INCLUDE-$(sdk))/module.modulemap PYTHON_FRAMEWORK-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/Python.framework PYTHON_LIB-$(sdk)=$$(PYTHON_FRAMEWORK-$(sdk))/Python PYTHON_BIN-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/bin @@ -466,8 +468,14 @@ $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h: $$(PYTHON_LIB-$(sdk)) # Copy headers as-is from the first target in the $(sdk) SDK cp -r $$(PYTHON_INCLUDE-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_INCLUDE-$(sdk)) - # Copy in the modulemap file - cp -r patch/Python/module.modulemap $$(PYTHON_INCLUDE-$(sdk)) + # Create the modulemap file + cp -r patch/Python/module.modulemap.prefix $$(PYTHON_MODULEMAP-$(sdk)) + echo "" >> $$(PYTHON_MODULEMAP-$(sdk)) + cd $$(PYTHON_SRCDIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/Include && \ + find cpython -name "*.h" | sort | sed -e 's/^/ exclude header "/' | sed 's/$$$$/"/' >> $$(PYTHON_MODULEMAP-$(sdk)) && \ + echo "" >> $$(PYTHON_MODULEMAP-$(sdk)) && \ + find internal -name "*.h" | sort | sed -e 's/^/ exclude header "/' | sed 's/$$$$/"/' >> $$(PYTHON_MODULEMAP-$(sdk)) + echo "\n}" >> $$(PYTHON_MODULEMAP-$(sdk)) # Link the PYTHONHOME version of the headers mkdir -p $$(PYTHON_INSTALL-$(sdk))/include @@ -585,8 +593,14 @@ $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \ # Rewrite the framework to make it standalone patch/make-relocatable.sh $$(PYTHON_INSTALL_VERSION-macosx) 2>&1 > /dev/null - # Copy in the modulemap file - cp -r patch/Python/module.modulemap $$(PYTHON_FRAMEWORK-macosx)/Headers + # Create the modulemap file + cp -r patch/Python/module.modulemap.prefix $$(PYTHON_MODULEMAP-macosx) + echo "" >> $$(PYTHON_MODULEMAP-macosx) + cd $$(PYTHON_INCLUDE-macosx) && \ + find cpython -name "*.h" | sort | sed -e 's/^/ exclude header "/' | sed 's/$$$$/"/' >> $$(PYTHON_MODULEMAP-macosx) && \ + echo "" >> $$(PYTHON_MODULEMAP-macosx) && \ + find internal -name "*.h" | sort | sed -e 's/^/ exclude header "/' | sed 's/$$$$/"/' >> $$(PYTHON_MODULEMAP-macosx) + echo "\n}" >> $$(PYTHON_MODULEMAP-macosx) # Re-apply the signature on the binaries. codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f $$(PYTHON_LIB-macosx) \ diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index 139da995..c9c0ef6f 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -113,7 +113,7 @@ index 1f6baed66d3..235dd98c60a 100644 macos_release = mac_ver()[0] if macos_release: diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py -index 69f72452c40..34ce643340b 100644 +index 18e6b8d25e5..4994c56778c 100644 --- a/Lib/sysconfig/__init__.py +++ b/Lib/sysconfig/__init__.py @@ -719,6 +719,14 @@ @@ -163,7 +163,7 @@ index ec0857a4a99..2350e9dc821 100644 # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX PLATFORM_TRIPLET=darwin diff --git a/configure b/configure -index d46bc563a67..d5cd81d16a8 100755 +index d0ae103014a..308124ef06d 100755 --- a/configure +++ b/configure @@ -974,6 +974,8 @@ @@ -588,7 +588,7 @@ index d46bc563a67..d5cd81d16a8 100755 fi ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" if test "x$ac_cv_func_pread" = xyes -@@ -19860,12 +19973,6 @@ +@@ -19866,12 +19979,6 @@ then : printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h @@ -601,7 +601,7 @@ index d46bc563a67..d5cd81d16a8 100755 fi ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" if test "x$ac_cv_func_sigfillset" = xyes -@@ -20134,11 +20241,11 @@ +@@ -20140,11 +20247,11 @@ fi @@ -615,7 +615,7 @@ index d46bc563a67..d5cd81d16a8 100755 ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" if test "x$ac_cv_func_getentropy" = xyes then : -@@ -20160,6 +20267,53 @@ +@@ -20166,6 +20273,53 @@ fi @@ -669,7 +669,7 @@ index d46bc563a67..d5cd81d16a8 100755 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} -@@ -23242,7 +23396,8 @@ +@@ -23248,7 +23402,8 @@ # check for openpty, login_tty, and forkpty @@ -679,7 +679,7 @@ index d46bc563a67..d5cd81d16a8 100755 for ac_func in openpty do : -@@ -23356,7 +23511,7 @@ +@@ -23362,7 +23517,7 @@ fi done @@ -688,7 +688,7 @@ index d46bc563a67..d5cd81d16a8 100755 printf %s "checking for library containing login_tty... " >&6; } if test ${ac_cv_search_login_tty+y} then : -@@ -23539,6 +23694,7 @@ +@@ -23545,6 +23700,7 @@ fi done @@ -696,7 +696,7 @@ index d46bc563a67..d5cd81d16a8 100755 # check for long file support functions ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" -@@ -23804,10 +23960,10 @@ +@@ -23810,10 +23966,10 @@ done @@ -709,7 +709,7 @@ index d46bc563a67..d5cd81d16a8 100755 then for ac_func in clock_settime -@@ -26146,8 +26302,8 @@ +@@ -26152,8 +26308,8 @@ LIBPYTHON="\$(BLDLIBRARY)" fi @@ -720,7 +720,7 @@ index d46bc563a67..d5cd81d16a8 100755 MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" fi -@@ -29017,7 +29173,7 @@ +@@ -29023,7 +29179,7 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 printf "%s\n" "$as_me: checking for device files" >&6;} @@ -729,7 +729,7 @@ index d46bc563a67..d5cd81d16a8 100755 ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no else -@@ -29510,7 +29666,7 @@ +@@ -29504,7 +29660,7 @@ with_ensurepip=no ;; #( WASI) : with_ensurepip=no ;; #( @@ -738,7 +738,7 @@ index d46bc563a67..d5cd81d16a8 100755 with_ensurepip=no ;; #( *) : with_ensurepip=upgrade -@@ -30490,7 +30646,7 @@ +@@ -30484,7 +30640,7 @@ ;; #( Darwin) : ;; #( @@ -747,7 +747,7 @@ index d46bc563a67..d5cd81d16a8 100755 -@@ -34493,6 +34649,8 @@ +@@ -34487,6 +34643,8 @@ "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;; "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;; "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; @@ -757,7 +757,7 @@ index d46bc563a67..d5cd81d16a8 100755 "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; diff --git a/configure.ac b/configure.ac -index faa89095303..9bd51f7da97 100644 +index 8bb0f1c6ef4..bfd67de48bb 100644 --- a/configure.ac +++ b/configure.ac @@ -330,6 +330,12 @@ @@ -1128,7 +1128,7 @@ index faa89095303..9bd51f7da97 100644 + pipe2 plock poll posix_fadvise posix_fallocate posix_openpt \ pread preadv preadv2 process_vm_readv \ pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \ - pthread_kill pthread_getname_np pthread_setname_np \ + pthread_kill pthread_getname_np pthread_setname_np pthread_getattr_np \ @@ -5153,7 +5283,7 @@ sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \ sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \ @@ -1232,7 +1232,7 @@ index faa89095303..9bd51f7da97 100644 ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no else -@@ -7187,7 +7327,7 @@ +@@ -7174,7 +7314,7 @@ AS_CASE([$ac_sys_system], [Emscripten], [with_ensurepip=no], [WASI], [with_ensurepip=no], @@ -1241,7 +1241,7 @@ index faa89095303..9bd51f7da97 100644 [with_ensurepip=upgrade] ) ]) -@@ -7598,7 +7738,7 @@ +@@ -7585,7 +7725,7 @@ [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])], dnl The _scproxy module is available on macOS [Darwin], [], @@ -1270,141 +1270,6 @@ index c3e261ecd9e..26ef7a95de4 100644 CFBundleSupportedPlatforms iPhoneOS -diff --git a/iOS/testbed/__main__.py b/iOS/testbed/__main__.py -index b4499f5ac17..d12a5ab065b 100644 ---- a/iOS/testbed/__main__.py -+++ b/iOS/testbed/__main__.py -@@ -82,19 +82,29 @@ - - # Return a list of UDIDs associated with booted simulators - async def list_devices(): -- # List the testing simulators, in JSON format -- raw_json = await async_check_output( -- "xcrun", "simctl", "--set", "testing", "list", "-j" -- ) -- json_data = json.loads(raw_json) -- -- # Filter out the booted iOS simulators -- return [ -- simulator["udid"] -- for runtime, simulators in json_data["devices"].items() -- for simulator in simulators -- if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" -- ] -+ try: -+ # List the testing simulators, in JSON format -+ raw_json = await async_check_output( -+ "xcrun", "simctl", "--set", "testing", "list", "-j" -+ ) -+ json_data = json.loads(raw_json) -+ -+ # Filter out the booted iOS simulators -+ return [ -+ simulator["udid"] -+ for runtime, simulators in json_data["devices"].items() -+ for simulator in simulators -+ if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" -+ ] -+ except subprocess.CalledProcessError as e: -+ # If there's no ~/Library/Developer/XCTestDevices folder (which is the -+ # case on fresh installs, and in some CI environments), `simctl list` -+ # returns error code 1, rather than an empty list. Handle that case, -+ # but raise all other errors. -+ if e.returncode == 1: -+ return [] -+ else: -+ raise - - - async def find_device(initial_devices): -@@ -230,33 +240,69 @@ - shutil.copytree(source, target, symlinks=True) - print(" done") - -+ xc_framework_path = target / "Python.xcframework" -+ sim_framework_path = xc_framework_path / "ios-arm64_x86_64-simulator" - if framework is not None: - if framework.suffix == ".xcframework": - print(" Installing XCFramework...", end="", flush=True) -- xc_framework_path = (target / "Python.xcframework").resolve() - if xc_framework_path.is_dir(): - shutil.rmtree(xc_framework_path) - else: -- xc_framework_path.unlink() -+ xc_framework_path.unlink(missing_ok=True) - xc_framework_path.symlink_to( - framework.relative_to(xc_framework_path.parent, walk_up=True) - ) - print(" done") - else: - print(" Installing simulator framework...", end="", flush=True) -- sim_framework_path = ( -- target / "Python.xcframework" / "ios-arm64_x86_64-simulator" -- ).resolve() - if sim_framework_path.is_dir(): - shutil.rmtree(sim_framework_path) - else: -- sim_framework_path.unlink() -+ sim_framework_path.unlink(missing_ok=True) - sim_framework_path.symlink_to( - framework.relative_to(sim_framework_path.parent, walk_up=True) - ) - print(" done") - else: -- print(" Using pre-existing iOS framework.") -+ if ( -+ xc_framework_path.is_symlink() -+ and not xc_framework_path.readlink().is_absolute() -+ ): -+ # XCFramework is a relative symlink. Rewrite the symlink relative -+ # to the new location. -+ print(" Rewriting symlink to XCframework...", end="", flush=True) -+ orig_xc_framework_path = ( -+ source -+ / xc_framework_path.readlink() -+ ).resolve() -+ xc_framework_path.unlink() -+ xc_framework_path.symlink_to( -+ orig_xc_framework_path.relative_to( -+ xc_framework_path.parent, walk_up=True -+ ) -+ ) -+ print(" done") -+ elif ( -+ sim_framework_path.is_symlink() -+ and not sim_framework_path.readlink().is_absolute() -+ ): -+ print(" Rewriting symlink to simulator framework...", end="", flush=True) -+ # Simulator framework is a relative symlink. Rewrite the symlink -+ # relative to the new location. -+ orig_sim_framework_path = ( -+ source -+ / "Python.XCframework" -+ / sim_framework_path.readlink() -+ ).resolve() -+ sim_framework_path.unlink() -+ sim_framework_path.symlink_to( -+ orig_sim_framework_path.relative_to( -+ sim_framework_path.parent, walk_up=True -+ ) -+ ) -+ print(" done") -+ else: -+ print(" Using pre-existing iOS framework.") - - for app_src in apps: - print(f" Installing app {app_src.name!r}...", end="", flush=True) -@@ -372,8 +418,8 @@ - - if context.subcommand == "clone": - clone_testbed( -- source=Path(__file__).parent, -- target=Path(context.location), -+ source=Path(__file__).parent.resolve(), -+ target=Path(context.location).resolve(), - framework=Path(context.framework).resolve() if context.framework else None, - apps=[Path(app) for app in context.apps], - ) --- /dev/null +++ b/tvOS/README.rst @@ -0,0 +1,108 @@ diff --git a/patch/Python/module.modulemap b/patch/Python/module.modulemap deleted file mode 100644 index 96b05fc6..00000000 --- a/patch/Python/module.modulemap +++ /dev/null @@ -1,165 +0,0 @@ -module Python { - umbrella header "Python.h" - export * - link "Python" - - exclude header "datetime.h" - exclude header "dynamic_annotations.h" - exclude header "errcode.h" - exclude header "frameobject.h" - exclude header "marshal.h" - exclude header "opcode_ids.h" - exclude header "opcode.h" - exclude header "osdefs.h" - exclude header "py_curses.h" - exclude header "pyconfig-arm32_64.h" - exclude header "pyconfig-arm64.h" - exclude header "pyconfig-x86_64.h" - exclude header "pydtrace.h" - exclude header "pyexpat.h" - exclude header "structmember.h" - - exclude header "cpython/frameobject.h" - exclude header "cpython/pthread_stubs.h" - exclude header "cpython/pyatomic_msc.h" - exclude header "cpython/pyatomic_std.h" - exclude header "cpython/pystats.h" - - exclude header "internal/mimalloc/mimalloc.h" - exclude header "internal/mimalloc/mimalloc/atomic.h" - exclude header "internal/mimalloc/mimalloc/internal.h" - exclude header "internal/mimalloc/mimalloc/prim.h" - exclude header "internal/mimalloc/mimalloc/track.h" - exclude header "internal/mimalloc/mimalloc/types.h" - - exclude header "internal/pycore_abstract.h" - exclude header "internal/pycore_asdl.h" - exclude header "internal/pycore_ast_state.h" - exclude header "internal/pycore_ast.h" - exclude header "internal/pycore_atexit.h" - exclude header "internal/pycore_audit.h" - exclude header "internal/pycore_backoff.h" - exclude header "internal/pycore_bitutils.h" - exclude header "internal/pycore_blocks_output_buffer.h" - exclude header "internal/pycore_brc.h" - exclude header "internal/pycore_bytes_methods.h" - exclude header "internal/pycore_bytesobject.h" - exclude header "internal/pycore_call.h" - exclude header "internal/pycore_capsule.h" - exclude header "internal/pycore_cell.h" - exclude header "internal/pycore_ceval_state.h" - exclude header "internal/pycore_ceval.h" - exclude header "internal/pycore_code.h" - exclude header "internal/pycore_codecs.h" - exclude header "internal/pycore_compile.h" - exclude header "internal/pycore_complexobject.h" - exclude header "internal/pycore_condvar.h" - exclude header "internal/pycore_context.h" - exclude header "internal/pycore_critical_section.h" - exclude header "internal/pycore_crossinterp_data_registry.h" - exclude header "internal/pycore_crossinterp.h" - exclude header "internal/pycore_debug_offsets.h" - exclude header "internal/pycore_descrobject.h" - exclude header "internal/pycore_dict_state.h" - exclude header "internal/pycore_dict.h" - exclude header "internal/pycore_dtoa.h" - exclude header "internal/pycore_emscripten_signal.h" - exclude header "internal/pycore_emscripten_trampoline.h" - exclude header "internal/pycore_exceptions.h" - exclude header "internal/pycore_faulthandler.h" - exclude header "internal/pycore_fileutils_windows.h" - exclude header "internal/pycore_fileutils.h" - exclude header "internal/pycore_floatobject.h" - exclude header "internal/pycore_flowgraph.h" - exclude header "internal/pycore_format.h" - exclude header "internal/pycore_frame.h" - exclude header "internal/pycore_freelist_state.h" - exclude header "internal/pycore_freelist.h" - exclude header "internal/pycore_function.h" - exclude header "internal/pycore_gc.h" - exclude header "internal/pycore_genobject.h" - exclude header "internal/pycore_getopt.h" - exclude header "internal/pycore_gil.h" - exclude header "internal/pycore_global_objects_fini_generated.h" - exclude header "internal/pycore_global_objects.h" - exclude header "internal/pycore_global_strings.h" - exclude header "internal/pycore_hamt.h" - exclude header "internal/pycore_hashtable.h" - exclude header "internal/pycore_identifier.h" - exclude header "internal/pycore_import.h" - exclude header "internal/pycore_importdl.h" - exclude header "internal/pycore_index_pool.h" - exclude header "internal/pycore_initconfig.h" - exclude header "internal/pycore_instruction_sequence.h" - exclude header "internal/pycore_instruments.h" - exclude header "internal/pycore_interp.h" - exclude header "internal/pycore_intrinsics.h" - exclude header "internal/pycore_jit.h" - exclude header "internal/pycore_list.h" - exclude header "internal/pycore_llist.h" - exclude header "internal/pycore_lock.h" - exclude header "internal/pycore_long.h" - exclude header "internal/pycore_magic_number.h" - exclude header "internal/pycore_memoryobject.h" - exclude header "internal/pycore_mimalloc.h" - exclude header "internal/pycore_modsupport.h" - exclude header "internal/pycore_moduleobject.h" - exclude header "internal/pycore_namespace.h" - exclude header "internal/pycore_object_alloc.h" - exclude header "internal/pycore_object_deferred.h" - exclude header "internal/pycore_object_stack.h" - exclude header "internal/pycore_object_state.h" - exclude header "internal/pycore_object.h" - exclude header "internal/pycore_obmalloc_init.h" - exclude header "internal/pycore_obmalloc.h" - exclude header "internal/pycore_opcode_metadata.h" - exclude header "internal/pycore_opcode_utils.h" - exclude header "internal/pycore_optimizer.h" - exclude header "internal/pycore_parking_lot.h" - exclude header "internal/pycore_parser.h" - exclude header "internal/pycore_pathconfig.h" - exclude header "internal/pycore_pyarena.h" - exclude header "internal/pycore_pyatomic_ft_wrappers.h" - exclude header "internal/pycore_pybuffer.h" - exclude header "internal/pycore_pyerrors.h" - exclude header "internal/pycore_pyhash.h" - exclude header "internal/pycore_pylifecycle.h" - exclude header "internal/pycore_pymath.h" - exclude header "internal/pycore_pymem_init.h" - exclude header "internal/pycore_pymem.h" - exclude header "internal/pycore_pystate.h" - exclude header "internal/pycore_pystats.h" - exclude header "internal/pycore_pythonrun.h" - exclude header "internal/pycore_pythread.h" - exclude header "internal/pycore_qsbr.h" - exclude header "internal/pycore_range.h" - exclude header "internal/pycore_runtime_init_generated.h" - exclude header "internal/pycore_runtime_init.h" - exclude header "internal/pycore_runtime.h" - exclude header "internal/pycore_semaphore.h" - exclude header "internal/pycore_setobject.h" - exclude header "internal/pycore_signal.h" - exclude header "internal/pycore_sliceobject.h" - exclude header "internal/pycore_stackref.h" - exclude header "internal/pycore_strhex.h" - exclude header "internal/pycore_structseq.h" - exclude header "internal/pycore_symtable.h" - exclude header "internal/pycore_sysmodule.h" - exclude header "internal/pycore_time.h" - exclude header "internal/pycore_token.h" - exclude header "internal/pycore_traceback.h" - exclude header "internal/pycore_tracemalloc.h" - exclude header "internal/pycore_tstate.h" - exclude header "internal/pycore_tuple.h" - exclude header "internal/pycore_typeobject.h" - exclude header "internal/pycore_typevarobject.h" - exclude header "internal/pycore_ucnhash.h" - exclude header "internal/pycore_unicodeobject_generated.h" - exclude header "internal/pycore_unicodeobject.h" - exclude header "internal/pycore_unionobject.h" - exclude header "internal/pycore_uniqueid.h" - exclude header "internal/pycore_uop_ids.h" - exclude header "internal/pycore_uop_metadata.h" - exclude header "internal/pycore_warnings.h" - exclude header "internal/pycore_weakref.h" -} diff --git a/patch/Python/module.modulemap.prefix b/patch/Python/module.modulemap.prefix new file mode 100644 index 00000000..e3b3aafb --- /dev/null +++ b/patch/Python/module.modulemap.prefix @@ -0,0 +1,20 @@ +module Python { + umbrella header "Python.h" + export * + link "Python" + + exclude header "datetime.h" + exclude header "dynamic_annotations.h" + exclude header "errcode.h" + exclude header "frameobject.h" + exclude header "marshal.h" + exclude header "opcode_ids.h" + exclude header "opcode.h" + exclude header "osdefs.h" + exclude header "py_curses.h" + exclude header "pyconfig-arm32_64.h" + exclude header "pyconfig-arm64.h" + exclude header "pyconfig-x86_64.h" + exclude header "pydtrace.h" + exclude header "pyexpat.h" + exclude header "structmember.h"