From 0d7e5e018808ce810262627a2f463bb4eb9f7fb0 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Thu, 26 Sep 2024 18:23:02 -0500 Subject: [PATCH] Add support for freethreaded builds of Python 3.13 (#326) * Add support for freethreaded builds of Python 3.13 * Split the 3.13 matrix into another job to get past the 256 matrix item limit * Add `build_options` to the JSON schema * Expect version 8 in the JSON schema * Allow freethreaded libpython during validation on macOS * Allow freethreaded libpython during validation on Linux * Enable mimalloc * Include `t` in abiflags patch for free-threaded builds * Fix mistaken toggle of `CPYTHON_OPTIMIZED` for LTO builds * Disable freethreaded musl builds We will work on these separately --- .github/workflows/apple.yml | 101 ++-- .github/workflows/linux.yml | 938 +++++++++++++++++++++------------- .github/workflows/windows.yml | 15 +- cpython-unix/Makefile | 8 +- cpython-unix/build-cpython.sh | 29 +- cpython-unix/build-main.py | 23 +- cpython-unix/build.py | 80 +-- cpython-windows/build.py | 38 +- docs/building.rst | 12 +- docs/distributions.rst | 11 +- pythonbuild/buildenv.py | 8 +- src/json.rs | 1 + src/validation.rs | 22 +- 13 files changed, 810 insertions(+), 476 deletions(-) diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index d7ed9d8c..bb2f6125 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -47,80 +47,93 @@ jobs: - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.8' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.8' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.8' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.9' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.9' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.10' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.10' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.11' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.11' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.12' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.12' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.13' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.13' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'aarch64-apple-darwin' runner: macos-14 py: 'cpython-3.13' - optimizations: 'pgo+lto' + options: 'pgo+lto' + + - target_triple: 'aarch64-apple-darwin' + runner: macos-14 + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 'aarch64-apple-darwin' + runner: macos-14 + py: 'cpython-3.13' + options: 'freethreaded+pgo' + - target_triple: 'aarch64-apple-darwin' + runner: macos-14 + py: 'cpython-3.13' + options: 'freethreaded+pgo+lto' # macOS on Intel hardware. This is pretty straightforward. We exclude # noopt because it doesn't provide any compelling advantages over PGO @@ -128,80 +141,92 @@ jobs: - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.8' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.8' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.8' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.9' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.9' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.10' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.10' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.11' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.11' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.12' - optimizations: 'pgo' + options: 'pgo' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.12' - optimizations: 'pgo+lto' + options: 'pgo+lto' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.13' - optimizations: 'debug' + options: 'debug' + - target_triple: 'x86_64-apple-darwin' + runner: macos-13 + py: 'cpython-3.13' + options: 'pgo' + - target_triple: 'x86_64-apple-darwin' + runner: macos-13 + py: 'cpython-3.13' + options: 'pgo+lto' + - target_triple: 'x86_64-apple-darwin' + runner: macos-13 + py: 'cpython-3.13' + options: 'freethreaded+debug' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.13' - optimizations: 'pgo' + options: 'freethreaded+pgo' - target_triple: 'x86_64-apple-darwin' runner: macos-13 py: 'cpython-3.13' - optimizations: 'pgo+lto' + options: 'freethreaded+pgo+lto' needs: - pythonbuild runs-on: ${{ matrix.build.runner }} @@ -232,12 +257,12 @@ jobs: exit 1 fi - ./build-macos.py --target-triple ${{ matrix.build.target_triple }} --python ${{ matrix.build.py }} --optimizations ${{ matrix.build.optimizations }} + ./build-macos.py --target-triple ${{ matrix.build.target_triple }} --python ${{ matrix.build.py }} --options ${{ matrix.build.options }} - name: Upload Distributions uses: actions/upload-artifact@v4 with: - name: ${{ matrix.build.py }}-${{ matrix.build.target_triple }}-${{ matrix.build.optimizations }} + name: ${{ matrix.build.py }}-${{ matrix.build.target_triple }}-${{ matrix.build.options }} path: dist/* - uses: actions/checkout@v4 diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index aa9689fb..4b283309 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -122,894 +122,1128 @@ jobs: # Cross-compiles can't do PGO. - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.8' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.8' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.8' - optimizations: 'lto' + options: 'lto' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'aarch64-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'lto' - - - target_triple: 'aarch64-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - - target_triple: 'aarch64-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'noopt' - - target_triple: 'aarch64-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.12' - optimizations: 'lto' - - - target_triple: 'armv7-unknown-linux-gnueabi' - py: 'cpython-3.13' - optimizations: 'debug' - - target_triple: 'armv7-unknown-linux-gnueabi' - py: 'cpython-3.13' - optimizations: 'noopt' - - target_triple: 'armv7-unknown-linux-gnueabi' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.12' - optimizations: 'lto' - - - target_triple: 'armv7-unknown-linux-gnueabihf' - py: 'cpython-3.13' - optimizations: 'debug' - - target_triple: 'armv7-unknown-linux-gnueabihf' - py: 'cpython-3.13' - optimizations: 'noopt' - - target_triple: 'armv7-unknown-linux-gnueabihf' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'lto' - - - target_triple: 'mips-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - - target_triple: 'mips-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'noopt' - - target_triple: 'mips-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'lto' - - - target_triple: 'mipsel-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - - target_triple: 'mipsel-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'noopt' - - target_triple: 'mipsel-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'lto' - - - target_triple: 's390x-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - - target_triple: 's390x-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'noopt' - - target_triple: 's390x-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'lto' - - - target_triple: 'ppc64le-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - - target_triple: 'ppc64le-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'noopt' - - target_triple: 'ppc64le-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' # We don't publish noopt builds when PGO is available. - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.8' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.8' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.8' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'pgo+lto' - run: true - - - target_triple: 'x86_64-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - run: true - - target_triple: 'x86_64-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'pgo' - run: true - - target_triple: 'x86_64-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'pgo+lto' - run: true - - - target_triple: 'x86_64_v2-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - run: true - - target_triple: 'x86_64_v2-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'pgo' - run: true - - target_triple: 'x86_64_v2-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'pgo' + options: 'pgo' run: true - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'pgo+lto' - run: true - - - target_triple: 'x86_64_v3-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - run: true - - target_triple: 'x86_64_v3-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'pgo' - run: true - - target_triple: 'x86_64_v3-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'pgo+lto' + options: 'pgo+lto' run: true # GitHub Actions runners don't support x86-64-v4 so we can't PGO. - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' # GitHub Actions runners don't support x86-64-v4 so we can't PGO. - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.12' - optimizations: 'lto' - - - target_triple: 'x86_64_v4-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'debug' - - target_triple: 'x86_64_v4-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'noopt' - - target_triple: 'x86_64_v4-unknown-linux-gnu' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' # musl doesn't support PGO. - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.8' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.8' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.8' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'lto' - run: true - - - target_triple: 'x86_64-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'debug' - run: true - - target_triple: 'x86_64-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'noopt' - run: true - - target_triple: 'x86_64-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'lto' - run: true - - - target_triple: 'x86_64_v2-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'debug' - run: true - - target_triple: 'x86_64_v2-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'noopt' - run: true - - target_triple: 'x86_64_v2-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' run: true - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'lto' - run: true - - - target_triple: 'x86_64_v3-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'debug' - run: true - - target_triple: 'x86_64_v3-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'noopt' - run: true - - target_triple: 'x86_64_v3-unknown-linux-musl' - py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' run: true - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.9' - optimizations: 'lto' + options: 'lto' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.10' - optimizations: 'lto' + options: 'lto' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.11' - optimizations: 'lto' + options: 'lto' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.12' - optimizations: 'lto' + options: 'lto' + + needs: + - pythonbuild + - image + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Download pythonbuild + uses: actions/download-artifact@v4 + with: + name: pythonbuild + path: build + + - name: Download images + uses: actions/download-artifact@v4 + with: + pattern: image-* + path: build + merge-multiple: true + + - name: Load Docker Images + run: | + for f in build/image-*.tar.zst; do + echo "decompressing $f" + zstd -d --rm ${f} + done + + for f in build/image-*.tar; do + echo "loading $f" + docker load --input $f + done + + - name: Build + run: | + # Do empty target so all generated files are touched. + ./build-linux.py --make-target empty + + # Touch mtimes of all images so they are newer than autogenerated files above. + touch build/image-* + + ./build-linux.py --target-triple ${{ matrix.build.target_triple }} --python ${{ matrix.build.py }} --options ${{ matrix.build.options }} + + - name: Validate Distribution + run: | + chmod +x build/pythonbuild + + if [ -n "${{matrix.build.run}}" ]; then + EXTRA_ARGS="--run" + fi + + build/pythonbuild validate-distribution ${EXTRA_ARGS} dist/*.tar.zst + + - name: Upload Distribution + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.build.py }}-${{ matrix.build.target_triple }}-${{ matrix.build.options }} + path: dist/* + + + + # GitHub enforces a limit of 256 entries per matrix, which we exceeded above + # so the CPytho 3.13 jobs are split out + build-313: + strategy: + fail-fast: false + matrix: + build: + + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'noopt' + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'lto' + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+noopt' + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+lto' + + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + options: 'debug' + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + options: 'noopt' + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + options: 'lto' + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + options: 'freethreaded+noopt' + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + options: 'freethreaded+lto' + + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + options: 'debug' + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + options: 'noopt' + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + options: 'lto' + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + options: 'freethreaded+noopt' + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + options: 'freethreaded+lto' + + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'noopt' + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'lto' + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+noopt' + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+lto' + + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'noopt' + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'lto' + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+noopt' + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+lto' + + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'noopt' + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'lto' + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+noopt' + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+lto' + + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'noopt' + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'lto' + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+noopt' + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+lto' + + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + run: true + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'pgo' + run: true + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'pgo+lto' + run: true + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + run: true + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+pgo' + run: true + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+pgo+lto' + run: true + + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'pgo' + run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'pgo+lto' + run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+pgo' + run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+pgo+lto' + run: true + + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'pgo' + run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'pgo+lto' + run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+pgo' + run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+pgo+lto' + run: true + + - target_triple: 'x86_64-unknown-linux-musl' + py: 'cpython-3.13' + options: 'debug' + run: true + - target_triple: 'x86_64-unknown-linux-musl' + py: 'cpython-3.13' + options: 'noopt' + run: true + - target_triple: 'x86_64-unknown-linux-musl' + py: 'cpython-3.13' + options: 'lto' + run: true + # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18. + # - target_triple: 'x86_64-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+debug' + # run: true + # - target_triple: 'x86_64-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+noopt' + # run: true + # - target_triple: 'x86_64-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+lto' + # run: true + + - target_triple: 'x86_64_v2-unknown-linux-musl' + py: 'cpython-3.13' + options: 'debug' + run: true + - target_triple: 'x86_64_v2-unknown-linux-musl' + py: 'cpython-3.13' + options: 'noopt' + run: true + - target_triple: 'x86_64_v2-unknown-linux-musl' + py: 'cpython-3.13' + options: 'lto' + run: true + # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18. + # - target_triple: 'x86_64_v2-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+debug' + # run: true + # - target_triple: 'x86_64_v2-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+noopt' + # run: true + # - target_triple: 'x86_64_v2-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+lto' + # run: true + + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'debug' + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'noopt' + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'lto' + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+debug' + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+noopt' + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + options: 'freethreaded+lto' + + - target_triple: 'x86_64_v3-unknown-linux-musl' + py: 'cpython-3.13' + options: 'debug' + run: true + - target_triple: 'x86_64_v3-unknown-linux-musl' + py: 'cpython-3.13' + options: 'noopt' + run: true + - target_triple: 'x86_64_v3-unknown-linux-musl' + py: 'cpython-3.13' + options: 'lto' + run: true + # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18. + # - target_triple: 'x86_64_v3-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+debug' + # run: true + # - target_triple: 'x86_64_v3-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+noopt' + # run: true + # - target_triple: 'x86_64_v3-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+lto' + # run: true - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.13' - optimizations: 'debug' + options: 'debug' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.13' - optimizations: 'noopt' + options: 'noopt' - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.13' - optimizations: 'lto' + options: 'lto' + # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18. + # - target_triple: 'x86_64_v4-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+debug' + # - target_triple: 'x86_64_v4-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+noopt' + # - target_triple: 'x86_64_v4-unknown-linux-musl' + # py: 'cpython-3.13' + # options: 'freethreaded+lto' needs: - pythonbuild - image runs-on: ubuntu-22.04 + + # The above should remain an exact duplicate of the `build` job steps: - uses: actions/checkout@v4 with: @@ -1053,7 +1287,7 @@ jobs: # Touch mtimes of all images so they are newer than autogenerated files above. touch build/image-* - ./build-linux.py --target-triple ${{ matrix.build.target_triple }} --python ${{ matrix.build.py }} --optimizations ${{ matrix.build.optimizations }} + ./build-linux.py --target-triple ${{ matrix.build.target_triple }} --python ${{ matrix.build.py }} --options ${{ matrix.build.options }} - name: Validate Distribution run: | @@ -1068,5 +1302,5 @@ jobs: - name: Upload Distribution uses: actions/upload-artifact@v4 with: - name: ${{ matrix.build.py }}-${{ matrix.build.target_triple }}-${{ matrix.build.optimizations }} + name: ${{ matrix.build.py }}-${{ matrix.build.target_triple }}-${{ matrix.build.options }} path: dist/* diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c4a18790..31618b0f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -53,8 +53,17 @@ jobs: vcvars: - 'vcvars32.bat' - 'vcvars64.bat' - profile: + options: - 'pgo' + + include: + - py: 'cpython-3.13' + vcvars: 'vcvars32.bat' + options: 'freethreaded+pgo' + - py: 'cpython-3.13' + vcvars: 'vcvars64.bat' + options: 'freethreaded+pgo' + needs: pythonbuild runs-on: 'windows-2019' steps: @@ -87,7 +96,7 @@ jobs: shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\${{ matrix.vcvars }}" - py.exe -3.9 build-windows.py --python ${{ matrix.py }} --sh c:\cygwin\bin\sh.exe --profile ${{ matrix.profile }} + py.exe -3.9 build-windows.py --python ${{ matrix.py }} --sh c:\cygwin\bin\sh.exe --options ${{ matrix.options }} - name: Validate Distribution run: | @@ -97,5 +106,5 @@ jobs: - name: Upload Distributions uses: actions/upload-artifact@v4 with: - name: ${{ matrix.py }}-${{ matrix.vcvars }}-${{ matrix.profile }} + name: ${{ matrix.py }}-${{ matrix.vcvars }}-${{ matrix.options }} path: dist/* diff --git a/cpython-unix/Makefile b/cpython-unix/Makefile index d3225451..11dd1557 100644 --- a/cpython-unix/Makefile +++ b/cpython-unix/Makefile @@ -9,8 +9,8 @@ ifndef PYBUILD_TARGET_TRIPLE $(error PYBUILD_TARGET_TRIPLE not defined) endif -ifndef PYBUILD_OPTIMIZATIONS - $(error PYBUILD_OPTIMIZATIONS not defined) +ifndef PYBUILD_BUILD_OPTIONS + $(error PYBUILD_BUILD_OPTIONS not defined) endif ifndef PYBUILD_HOST_PLATFORM @@ -31,12 +31,12 @@ endif TARGET_TRIPLE := $(PYBUILD_TARGET_TRIPLE) HOST_PLATFORM := $(PYBUILD_HOST_PLATFORM) -PACKAGE_SUFFIX := $(TARGET_TRIPLE)-$(PYBUILD_OPTIMIZATIONS) +PACKAGE_SUFFIX := $(TARGET_TRIPLE)-$(PYBUILD_BUILD_OPTIONS) RUN_BUILD = $(BUILD) \ --host-platform $(HOST_PLATFORM) \ --target-triple $(TARGET_TRIPLE) \ - --optimizations $(PYBUILD_OPTIMIZATIONS) \ + --options $(PYBUILD_BUILD_OPTIONS) \ --python-source $(PYBUILD_PYTHON_SOURCE) \ --dest-archive $@ \ $(NULL) diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh index 8c555956..eb1fe7b7 100755 --- a/cpython-unix/build-cpython.sh +++ b/cpython-unix/build-cpython.sh @@ -355,6 +355,10 @@ if [ -n "${CPYTHON_DEBUG}" ]; then CONFIGURE_FLAGS="${CONFIGURE_FLAGS} --with-pydebug" fi +if [ -n "${CPYTHON_FREETHREADED}" ]; then + CONFIGURE_FLAGS="${CONFIGURE_FLAGS} --disable-gil --with-mimalloc" +fi + if [ -n "${CPYTHON_OPTIMIZED}" ]; then CONFIGURE_FLAGS="${CONFIGURE_FLAGS} --enable-optimizations" if [[ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" && -n "${BOLT_CAPABLE}" ]]; then @@ -493,10 +497,16 @@ make -j ${NUM_CPUS} make -j ${NUM_CPUS} sharedinstall DESTDIR=${ROOT}/out/python make -j ${NUM_CPUS} install DESTDIR=${ROOT}/out/python -if [ -n "${CPYTHON_DEBUG}" ]; then - PYTHON_BINARY_SUFFIX=d + +if [ -n "${CPYTHON_FREETHREADED}" ]; then + PYTHON_BINARY_SUFFIX=t + PYTHON_LIB_SUFFIX=t else PYTHON_BINARY_SUFFIX= + PYTHON_LIB_SUFFIX= +fi +if [ -n "${CPYTHON_DEBUG}" ]; then + PYTHON_BINARY_SUFFIX="${PYTHON_BINARY_SUFFIX}d" fi # Python interpreter to use during the build. When cross-compiling, @@ -515,10 +525,10 @@ fi # LD_LIBRARY_PATH pointing to the directory containing libpython. if [ "${PYBUILD_SHARED}" = "1" ]; then if [ "${PYBUILD_PLATFORM}" = "macos" ]; then + # There's only 1 dylib produced on macOS and it has the binary suffix. LIBPYTHON_SHARED_LIBRARY_BASENAME=libpython${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}.dylib LIBPYTHON_SHARED_LIBRARY=${ROOT}/out/python/install/lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} - # There's only 1 dylib produced on macOS and it has the binary suffix. install_name_tool \ -change /install/lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} @executable_path/../lib/${LIBPYTHON_SHARED_LIBRARY_BASENAME} \ ${ROOT}/out/python/install/bin/python${PYTHON_MAJMIN_VERSION} @@ -594,7 +604,9 @@ import sysconfig ROOT = sys.argv[1] +FREETHREADED = sysconfig.get_config_var("Py_GIL_DISABLED") MAJMIN = ".".join([str(sys.version_info[0]), str(sys.version_info[1])]) +LIB_SUFFIX = "t" if FREETHREADED else "" PYTHON_CONFIG = os.path.join(ROOT, "install", "bin", "python%s-config" % MAJMIN) PLATFORM_CONFIG = os.path.join(ROOT, sysconfig.get_config_var("LIBPL").lstrip("/")) MAKEFILE = os.path.join(PLATFORM_CONFIG, "Makefile") @@ -602,7 +614,7 @@ SYSCONFIGDATA = os.path.join( ROOT, "install", "lib", - "python%s" % MAJMIN, + "python%s%s" % (MAJMIN, LIB_SUFFIX), "%s.py" % sysconfig._get_sysconfigdata_name(), ) @@ -654,7 +666,10 @@ import sys import sysconfig # When doing cross builds, sysconfig still picks up abiflags from the -# host Python, which is never built in debug mode. Patch abiflags accordingly. +# host Python, which is never built in debug or free-threaded mode. Patch abiflags accordingly. +if os.environ.get("CPYTHON_FREETHREADED") and "t" not in sysconfig.get_config_var("abiflags"): + sys.abiflags += "t" + sysconfig._CONFIG_VARS["abiflags"] += "t" if os.environ.get("CPYTHON_DEBUG") and "d" not in sysconfig.get_config_var("abiflags"): sys.abiflags += "d" sysconfig._CONFIG_VARS["abiflags"] += "d" @@ -739,7 +754,7 @@ fi find ${ROOT}/out/python/install -type d -name __pycache__ -print0 | xargs -0 rm -rf # Ensure lib-dynload exists, or Python complains on startup. -LIB_DYNLOAD=${ROOT}/out/python/install/lib/python${PYTHON_MAJMIN_VERSION}/lib-dynload +LIB_DYNLOAD=${ROOT}/out/python/install/lib/python${PYTHON_MAJMIN_VERSION}${PYTHON_LIB_SUFFIX}/lib-dynload mkdir -p "${LIB_DYNLOAD}" touch "${LIB_DYNLOAD}/.empty" @@ -793,7 +808,7 @@ esac LIBPYTHON=libpython${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}.a ln -sf \ - python${PYTHON_MAJMIN_VERSION}/config-${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}-${PYTHON_ARCH}/${LIBPYTHON} \ + python${PYTHON_MAJMIN_VERSION}${PYTHON_LIB_SUFFIX}/config-${PYTHON_MAJMIN_VERSION}${PYTHON_BINARY_SUFFIX}-${PYTHON_ARCH}/${LIBPYTHON} \ ${ROOT}/out/python/install/lib/${LIBPYTHON} if [ -n "${PYTHON_BINARY_SUFFIX}" ]; then diff --git a/cpython-unix/build-main.py b/cpython-unix/build-main.py index 34a90d19..c6d59bc0 100755 --- a/cpython-unix/build-main.py +++ b/cpython-unix/build-main.py @@ -41,7 +41,7 @@ def main(): else: raise Exception("unhandled macOS machine value: %s" % machine) else: - print("unsupport build platform: %s" % sys.platform) + print("Unsupported build platform: %s" % sys.platform) return 1 parser = argparse.ArgumentParser() @@ -53,11 +53,12 @@ def main(): help="Target host triple to build for", ) + optimizations = {"debug", "noopt", "pgo", "lto", "pgo+lto"} parser.add_argument( - "--optimizations", - choices={"debug", "noopt", "pgo", "lto", "pgo+lto"}, + "--options", + choices=optimizations.union({f"freethreaded+{o}" for o in optimizations}), default="noopt", - help="Optimizations to apply when compiling Python", + help="Build options to apply when compiling Python", ) parser.add_argument( "--python", @@ -136,7 +137,7 @@ def main(): env["PYBUILD_HOST_PLATFORM"] = host_platform env["PYBUILD_TARGET_TRIPLE"] = target_triple - env["PYBUILD_OPTIMIZATIONS"] = args.optimizations + env["PYBUILD_BUILD_OPTIONS"] = args.options env["PYBUILD_PYTHON_SOURCE"] = python_source if musl: env["PYBUILD_MUSL"] = "1" @@ -163,10 +164,20 @@ def main(): else: release_tag = release_tag_from_git() + # Guard against accidental misuse of the free-threaded flag with older versions + if "freethreaded" in args.options and env["PYBUILD_PYTHON_MAJOR_VERSION"] not in ( + "3.13" + ): + print( + "Invalid build option: 'freethreaded' is only compatible with CPython 3.13+ (got %s)" + % env["PYBUILD_PYTHON_MAJOR_VERSION"] + ) + return 1 + archive_components = [ "cpython-%s" % cpython_version, target_triple, - args.optimizations, + args.options, ] build_basename = "-".join(archive_components) + ".tar" diff --git a/cpython-unix/build.py b/cpython-unix/build.py index d2adb9d4..7d61a918 100755 --- a/cpython-unix/build.py +++ b/cpython-unix/build.py @@ -231,7 +231,7 @@ def simple_build( entry, host_platform, target_triple, - optimizations, + build_options, dest_archive, extra_archives=None, tools_path="deps", @@ -250,7 +250,7 @@ def simple_build( ) for a in extra_archives or []: - build_env.install_artifact_archive(BUILD, a, target_triple, optimizations) + build_env.install_artifact_archive(BUILD, a, target_triple, build_options) build_env.copy_file(archive) build_env.copy_file(SUPPORT / ("build-%s.sh" % entry)) @@ -335,7 +335,7 @@ def build_musl(client, image, host_platform: str, target_triple: str): def build_libedit( - settings, client, image, host_platform, target_triple, optimizations, dest_archive + settings, client, image, host_platform, target_triple, build_options, dest_archive ): libedit_archive = download_entry("libedit", DOWNLOADS_PATH) @@ -351,7 +351,7 @@ def build_libedit( ) build_env.install_artifact_archive( - BUILD, "ncurses", target_triple, optimizations + BUILD, "ncurses", target_triple, build_options ) build_env.copy_file(libedit_archive) build_env.copy_file(SUPPORT / "build-libedit.sh") @@ -367,7 +367,7 @@ def build_libedit( def build_tix( - settings, client, image, host_platform, target_triple, optimizations, dest_archive + settings, client, image, host_platform, target_triple, build_options, dest_archive ): tcl_archive = download_entry("tcl", DOWNLOADS_PATH) tk_archive = download_entry("tk", DOWNLOADS_PATH) @@ -389,7 +389,7 @@ def build_tix( depends |= {"libX11", "xorgproto"} for p in sorted(depends): - build_env.install_artifact_archive(BUILD, p, target_triple, optimizations) + build_env.install_artifact_archive(BUILD, p, target_triple, build_options) for p in (tcl_archive, tk_archive, tix_archive, SUPPORT / "build-tix.sh"): build_env.copy_file(p) @@ -413,7 +413,7 @@ def build_cpython_host( entry, host_platform: str, target_triple: str, - optimizations: str, + build_options: list[str], dest_archive, ): """Build binutils in the Docker image.""" @@ -446,7 +446,7 @@ def build_cpython_host( "m4", } for p in sorted(packages): - build_env.install_artifact_archive(BUILD, p, target_triple, optimizations) + build_env.install_artifact_archive(BUILD, p, target_triple, build_options) env = { "PYTHON_VERSION": python_version, @@ -478,7 +478,7 @@ def python_build_info( platform, target_triple, musl, - optimizations, + lto, extensions, extra_metadata, ): @@ -503,7 +503,7 @@ def python_build_info( binary_suffix, ) - if optimizations in ("lto", "pgo+lto"): + if lto: llvm_version = DOWNLOADS[clang_toolchain(platform, target_triple)][ "version" ] @@ -524,7 +524,7 @@ def python_build_info( binary_suffix, ) - if optimizations in ("lto", "pgo+lto"): + if lto: object_file_format = ( "llvm-bitcode:%s" % DOWNLOADS["llvm-aarch64-macos"]["version"] ) @@ -682,12 +682,13 @@ def build_cpython( image, host_platform, target_triple, - optimizations, + build_options, dest_archive, version=None, python_source=None, ): """Build CPython in a Docker image'""" + parsed_build_options = set(build_options.split("+")) entry_name = "cpython-%s" % version entry = DOWNLOADS[entry_name] if not python_source: @@ -735,7 +736,7 @@ def build_cpython( packages.discard("musl") for p in sorted(packages): - build_env.install_artifact_archive(BUILD, p, target_triple, optimizations) + build_env.install_artifact_archive(BUILD, p, target_triple, build_options) build_env.install_toolchain_archive( BUILD, entry_name, host_platform, version=python_version @@ -792,11 +793,14 @@ def build_cpython( if meets_python_maximum_version(python_version, v): env[f"PYTHON_MEETS_MAXIMUM_VERSION_{normal_version}"] = "1" - if optimizations == "debug": + if "freethreaded" in parsed_build_options: + env["CPYTHON_FREETHREADED"] = "1" + + if "debug" in parsed_build_options: env["CPYTHON_DEBUG"] = "1" - if optimizations in ("pgo", "pgo+lto"): + if "pgo" in parsed_build_options: env["CPYTHON_OPTIMIZED"] = "1" - if optimizations in ("lto", "pgo+lto"): + if "lto" in parsed_build_options: env["CPYTHON_LTO"] = "1" add_target_env(env, host_platform, target_triple, build_env) @@ -832,11 +836,16 @@ def build_cpython( extra_metadata = json.loads(build_env.get_file("metadata.json")) + # TODO: Remove `optimizations` in the future, deprecated in favor of + # `build_options` in metadata version 8. + optimizations = build_options.replace("freethreaded+", "") + # Create PYTHON.json file describing this distribution. python_info = { - "version": "7", + "version": "8", "target_triple": target_triple, "optimizations": optimizations, + "build_options": build_options, "python_tag": entry["python_tag"], "python_version": python_version, "python_stdlib_test_packages": sorted(STDLIB_TEST_PACKAGES), @@ -851,7 +860,7 @@ def build_cpython( host_platform, target_triple, "musl" in target_triple, - optimizations, + "lto" in parsed_build_options, enabled_extensions, extra_metadata, ), @@ -923,11 +932,12 @@ def main(): required=True, help="Host triple that we are building Python for", ) + optimizations = {"debug", "noopt", "pgo", "lto", "pgo+lto"} parser.add_argument( - "--optimizations", - choices={"debug", "noopt", "pgo", "lto", "pgo+lto"}, - required=True, - help="Optimization profile to use", + "--options", + choices=optimizations.union({f"freethreaded+{o}" for o in optimizations}), + default="noopt", + help="Build options to apply when compiling Python", ) parser.add_argument( "--toolchain", @@ -951,7 +961,7 @@ def main(): target_triple = args.target_triple host_platform = args.host_platform - optimizations = args.optimizations + build_options = args.options python_source = ( pathlib.Path(args.python_source) if args.python_source != "null" else None ) @@ -976,7 +986,7 @@ def main(): action, entry["version"], target_triple, - optimizations, + build_options, ) log_path = BUILD / "logs" / ("build.%s.log" % log_name) @@ -1027,7 +1037,7 @@ def main(): action, host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, tools_path="host", extra_archives=["m4"], @@ -1040,7 +1050,7 @@ def main(): get_image(client, ROOT, BUILD, docker_image), host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, ) @@ -1079,7 +1089,7 @@ def main(): action, host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, tools_path=tools_path, ) @@ -1092,7 +1102,7 @@ def main(): action, host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, extra_archives={ "inputproto", @@ -1116,7 +1126,7 @@ def main(): action, host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, extra_archives={"x11-util-macros", "xproto"}, ) @@ -1129,7 +1139,7 @@ def main(): action, host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, ) @@ -1141,7 +1151,7 @@ def main(): action, host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, extra_archives={"libpthread-stubs", "libXau", "xcb-proto", "xproto"}, ) @@ -1153,7 +1163,7 @@ def main(): get_image(client, ROOT, BUILD, docker_image), host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, ) @@ -1175,7 +1185,7 @@ def main(): action, host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, extra_archives=extra_archives, ) @@ -1187,7 +1197,7 @@ def main(): action[:-5], host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, ) @@ -1205,7 +1215,7 @@ def main(): get_image(client, ROOT, BUILD, docker_image), host_platform=host_platform, target_triple=target_triple, - optimizations=optimizations, + build_options=build_options, dest_archive=dest_archive, version=action.split("-")[1], python_source=python_source, diff --git a/cpython-windows/build.py b/cpython-windows/build.py index 7be485aa..e65a459d 100644 --- a/cpython-windows/build.py +++ b/cpython-windows/build.py @@ -877,7 +877,6 @@ def build_openssl_for_arch( openssl_version: str, nasm_archive, build_root: pathlib.Path, - profile: str, *, jom_archive, ): @@ -969,7 +968,6 @@ def build_openssl( entry: str, perl_path: pathlib.Path, arch: str, - profile: str, dest_archive: pathlib.Path, ): """Build OpenSSL from sources using the Perl executable specified.""" @@ -996,7 +994,6 @@ def build_openssl( openssl_version, nasm_archive, root_32, - profile, jom_archive=jom_archive, ) elif arch == "amd64": @@ -1008,7 +1005,6 @@ def build_openssl( openssl_version, nasm_archive, root_64, - profile, jom_archive=jom_archive, ) else: @@ -1389,14 +1385,15 @@ def build_cpython( python_entry_name: str, target_triple: str, arch: str, - profile, + build_options: str, msvc_version: str, windows_sdk_version: str, openssl_archive, libffi_archive, openssl_entry: str, ) -> pathlib.Path: - pgo = profile == "pgo" + parsed_build_options = set(build_options.split("+")) + pgo = "pgo" in parsed_build_options msbuild = find_msbuild(msvc_version) log("found MSBuild at %s" % msbuild) @@ -1753,16 +1750,17 @@ def build_cpython( crt_features = ["vcruntime:140"] - if profile == "pgo": + if pgo: optimizations = "pgo" else: optimizations = "noopt" # Create PYTHON.json file describing this distribution. python_info = { - "version": "7", + "version": "8", "target_triple": target_triple, "optimizations": optimizations, + "build_options": build_options, "python_tag": entry["python_tag"], "python_version": python_version, "python_symbol_visibility": python_symbol_visibility, @@ -1816,7 +1814,7 @@ def build_cpython( % ( entry["version"], target_triple, - profile, + build_options, ) ) @@ -1869,11 +1867,13 @@ def main() -> None: default="cpython-3.11", help="Python distribution to build", ) + # TODO: Rename this to `--options` to match the Unix build script + optimizations = {"debug", "noopt", "pgo", "lto", "pgo+lto"} parser.add_argument( - "--profile", - choices={"noopt", "pgo"}, + "--options", + choices=optimizations.union({f"freethreaded+{o}" for o in optimizations}), default="noopt", - help="How to compile Python", + help="Build options to apply when compiling Python", ) parser.add_argument( "--sh", required=True, help="Path to sh.exe in a cygwin or mingw installation" @@ -1885,6 +1885,7 @@ def main() -> None: ) args = parser.parse_args() + build_options = args.options log_path = BUILD / "build.log" @@ -1909,7 +1910,7 @@ def main() -> None: openssl_entry = "openssl-3.0" openssl_archive = BUILD / ( - "%s-%s-%s.tar" % (openssl_entry, target_triple, args.profile) + "%s-%s-%s.tar" % (openssl_entry, target_triple, build_options) ) if not openssl_archive.exists(): perl_path = fetch_strawberry_perl() / "perl" / "bin" / "perl.exe" @@ -1918,11 +1919,10 @@ def main() -> None: openssl_entry, perl_path, arch, - profile=args.profile, dest_archive=openssl_archive, ) - libffi_archive = BUILD / ("libffi-%s-%s.tar" % (target_triple, args.profile)) + libffi_archive = BUILD / ("libffi-%s-%s.tar" % (target_triple, build_options)) if not libffi_archive.exists(): build_libffi( args.python, @@ -1937,7 +1937,7 @@ def main() -> None: args.python, target_triple, arch, - profile=args.profile, + build_options=build_options, msvc_version=args.vs, windows_sdk_version=args.windows_sdk_version, openssl_archive=openssl_archive, @@ -1961,10 +1961,10 @@ def main() -> None: # The 'shared-' prefix is no longer needed, but we're double-publishing under # both names during the transition period. filename: str = dest_path.name - if not filename.endswith("-%s-%s.tar.zst" % (args.profile, release_tag)): + if not filename.endswith("-%s-%s.tar.zst" % (args.options, release_tag)): raise ValueError("expected filename to end with profile: %s" % filename) - filename = filename.removesuffix("-%s-%s.tar.zst" % (args.profile, release_tag)) - filename = filename + "-shared-%s-%s.tar.zst" % (args.profile, release_tag) + filename = filename.removesuffix("-%s-%s.tar.zst" % (args.options, release_tag)) + filename = filename + "-shared-%s-%s.tar.zst" % (args.options, release_tag) shutil.copy2(dest_path, dest_path.with_name(filename)) diff --git a/docs/building.rst b/docs/building.rst index f6931680..9db309f8 100644 --- a/docs/building.rst +++ b/docs/building.rst @@ -16,9 +16,11 @@ To build a Python distribution for Linux x64:: $ ./build-linux.py # With profile-guided optimizations (generated code should be faster): - $ ./build-linux.py --optimizations pgo + $ ./build-linux.py --options pgo # Produce a debug build. - $ ./build-linux.py --optimizations debug + $ ./build-linux.py --options debug + # Produce a free-threaded build without extra optimizations + $ ./build-linux.py --options freethreaded+noopt You can also build another version of Python. e.g.:: @@ -94,16 +96,16 @@ If building CPython 3.8+, there are the following additional requirements: To build a dynamically linked Python distribution for Windows x64:: - $ py.exe build-windows.py --profile noopt + $ py.exe build-windows.py --options noopt It's also possible to build with optional PGO optimizations:: - $ py.exe build-windows.py --profile pgo + $ py.exe build-windows.py --options pgo If building CPython 3.8+, you will need to specify the path to a ``sh.exe`` installed from cygwin. e.g. - $ py.exe build-windows.py --python cpython-3.8 --sh c:\cygwin\bin\sh.exe --profile noopt + $ py.exe build-windows.py --python cpython-3.8 --sh c:\cygwin\bin\sh.exe --options noopt To build a 32-bit x86 binary, simply use an ``x86 Native Tools Command Prompt`` instead of ``x64``. diff --git a/docs/distributions.rst b/docs/distributions.rst index 8fe1d345..9e45523a 100644 --- a/docs/distributions.rst +++ b/docs/distributions.rst @@ -58,7 +58,16 @@ optimizations Known values include ``debug``, ``noopt``, ``pgo``, ``lto``, and ``pgo+lto``. - (Version 5 or above only.) + (Deprecated in version 8 in favor of ``build_options``.) + +build_options + String indicating what build options were used. Options are separated + by a ``+``. + + Known values include ``debug``, ``noopt``, ``pgo``, ``lto``, and + ``freethreading``. + + (Version 8 or above only.) os Target operating system for the distribution. e.g. ``linux``, ``macos``, diff --git a/pythonbuild/buildenv.py b/pythonbuild/buildenv.py index 0ce3cd03..65da541a 100644 --- a/pythonbuild/buildenv.py +++ b/pythonbuild/buildenv.py @@ -53,14 +53,14 @@ def install_toolchain_archive( self.run(["/bin/tar", "-C", "/tools", "-xf", "/build/%s" % p.name]) def install_artifact_archive( - self, build_dir, package_name, target_triple, optimizations + self, build_dir, package_name, target_triple, build_options ): entry = DOWNLOADS[package_name] basename = "%s-%s-%s-%s.tar" % ( package_name, entry["version"], target_triple, - optimizations, + build_options, ) p = build_dir / basename @@ -174,14 +174,14 @@ def install_toolchain_archive( extract_tar_to_directory(p, dest_path) def install_artifact_archive( - self, build_dir, package_name, target_triple, optimizations + self, build_dir, package_name, target_triple, build_options ): entry = DOWNLOADS[package_name] basename = "%s-%s-%s-%s.tar" % ( package_name, entry["version"], target_triple, - optimizations, + build_options, ) p = build_dir / basename diff --git a/src/json.rs b/src/json.rs index 7c27f46b..d51a6216 100644 --- a/src/json.rs +++ b/src/json.rs @@ -62,6 +62,7 @@ pub struct PythonJsonMain { pub apple_sdk_platform: Option, pub apple_sdk_version: Option, pub build_info: PythonBuildInfo, + pub build_options: String, pub crt_features: Vec, pub libpython_link_mode: String, pub licenses: Option>, diff --git a/src/validation.rs b/src/validation.rs index cbbf3665..3b8a81d4 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -298,6 +298,16 @@ static DARWIN_ALLOWED_DYLIBS: Lazy> = Lazy::new(|| { max_compatibility_version: "3.13.0".try_into().unwrap(), required: false, }, + MachOAllowedDylib { + name: "@executable_path/../lib/libpython3.13t.dylib".to_string(), + max_compatibility_version: "3.13.0".try_into().unwrap(), + required: false, + }, + MachOAllowedDylib { + name: "@executable_path/../lib/libpython3.13td.dylib".to_string(), + max_compatibility_version: "3.13.0".try_into().unwrap(), + required: false, + }, MachOAllowedDylib { name: "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit".to_string(), max_compatibility_version: "45.0.0".try_into().unwrap(), @@ -891,6 +901,14 @@ fn validate_elf>( "$ORIGIN/../lib/libpython{}d.so.1.0", python_major_minor )); + allowed_libraries.push(format!( + "$ORIGIN/../lib/libpython{}t.so.1.0", + python_major_minor + )); + allowed_libraries.push(format!( + "$ORIGIN/../lib/libpython{}td.so.1.0", + python_major_minor + )); // Allow the _crypt extension module - and only it - to link against libcrypt, // which is no longer universally present in Linux distros. @@ -1575,9 +1593,9 @@ fn validate_extension_modules( fn validate_json(json: &PythonJsonMain, triple: &str, is_debug: bool) -> Result> { let mut errors = vec![]; - if json.version != "7" { + if json.version != "8" { errors.push(format!( - "expected version 7 in PYTHON.json; got {}", + "expected version 8 in PYTHON.json; got {}", json.version )); }