From 5430680e706511531c115c792a7450e018644886 Mon Sep 17 00:00:00 2001 From: ffgan Date: Sun, 27 Jul 2025 21:33:49 +0800 Subject: [PATCH 1/5] Add support for RISC-V architecture in manylinux and update compatibility checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: nijincheng@iscas.ac.cn; --- .github/workflows/release.yml | 7 +++++-- .github/workflows/test.yml | 38 +++++++++++++++++++++++++++++++++++ src/target/legacy_py.rs | 2 +- src/target/mod.rs | 2 +- src/target/pypi_tags.rs | 25 +++++++++++++++++------ tests/common/errors.rs | 4 ++-- 6 files changed, 66 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 939a9b1b1..180742f46 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -168,6 +168,9 @@ jobs: - target: "loongarch64-unknown-linux-gnu" image: "manylinux_2_36-cross:loongarch64" compatibility: "manylinux_2_36" + - target: "riscv64gc-unknown-linux-gnu" + image: "manylinux_2_39-cross:riscv64" + compatibility: "manylinux_2_39" container: image: docker://ghcr.io/rust-cross/${{ matrix.platform.image }} env: @@ -178,9 +181,9 @@ jobs: - uses: actions/checkout@v4 # powerpc64le-unknown-linux-musl doesn't have official std library release - run: rustup target add --toolchain stable ${{ matrix.platform.target }} - if: ${{ !contains(fromJson('["powerpc64le-unknown-linux-musl", "s390x-unknown-linux-gnu", "loongarch64-unknown-linux-gnu"]'), matrix.platform.target) }} + if: ${{ !contains(fromJson('["powerpc64le-unknown-linux-musl", "s390x-unknown-linux-gnu", "loongarch64-unknown-linux-gnu", "riscv64gc-unknown-linux-gnu"]'), matrix.platform.target) }} - uses: dtolnay/rust-toolchain@stable - if: contains(fromJson('["s390x-unknown-linux-gnu", "loongarch64-unknown-linux-gnu"]'), matrix.platform.target) + if: contains(fromJson('["s390x-unknown-linux-gnu", "loongarch64-unknown-linux-gnu", "riscv64gc-unknown-linux-gnu"]'), matrix.platform.target) with: targets: ${{ matrix.platform.target }} - name: Build wheel diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b8cdd25ba..e22960560 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -420,7 +420,45 @@ jobs: # --find-interpreter bin/maturin build --find-interpreter --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml + test-riscv64-compile: + name: Test Cross Compile + needs: build-maturin + runs-on: ubuntu-latest + container: ${{ matrix.platform.container }} + strategy: + fail-fast: false + matrix: + platform: + - target: riscv64gc-unknown-linux-gnu + abi: cp310-cp310 + python: python3.10 + container: ghcr.io/rust-cross/manylinux_2_39-cross:riscv64 + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: maturin-build + path: bin + - run: chmod +x bin/maturin + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.platform.target }} + - name: Build wheels + run: | + set -ex + # Use bundled sysconfig + bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml --manylinux 2_39 + # Use PYO3_CROSS_LIB_DIR + export PYO3_CROSS_LIB_DIR=/opt/python/${{ matrix.platform.abi }} + bin/maturin build -i python3.9 --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml --manylinux 2_39 + unset PYO3_CROSS_LIB_DIR + + # Test abi3 + bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-pure/Cargo.toml --manylinux 2_39 + + # --find-interpreter + bin/maturin build --find-interpreter --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml --manylinux 2_39 test-bootstrap: name: Test Bootstrap runs-on: ${{ matrix.os }} diff --git a/src/target/legacy_py.rs b/src/target/legacy_py.rs index 436e5733e..97c09e554 100644 --- a/src/target/legacy_py.rs +++ b/src/target/legacy_py.rs @@ -57,7 +57,7 @@ pub(super) static IOS_ARCHES: &[&str] = &["arm64", "x86_64"]; pub(super) static ANDROID_ARCHES: &[&str] = &["armeabi_v7a", "arm64_v8a", "x86", "x86_64"]; pub(super) static MANYLINUX_ARCHES: &[&str] = &[ - "x86_64", "i686", "aarch64", "armv7l", "ppc64le", "s390x", "ppc64", + "x86_64", "i686", "aarch64", "armv7l", "ppc64le", "s390x", "ppc64", "riscv64", ]; pub(super) static MUSLLINUX_ARCHES: &[&str] = diff --git a/src/target/mod.rs b/src/target/mod.rs index f8d97a9c9..dbc31facb 100644 --- a/src/target/mod.rs +++ b/src/target/mod.rs @@ -483,7 +483,7 @@ impl Target { } Arch::Riscv64 => PlatformTag::Manylinux { major: 2, - minor: 31, + minor: 39, // 2_39 is the minimum version supported uploaded to PyPI }, Arch::LoongArch64 => PlatformTag::Manylinux { major: 2, diff --git a/src/target/pypi_tags.rs b/src/target/pypi_tags.rs index 509d49681..f1173c829 100644 --- a/src/target/pypi_tags.rs +++ b/src/target/pypi_tags.rs @@ -78,6 +78,7 @@ pub fn is_arch_supported_by_pypi(target: &Target) -> bool { /// Validates that a wheel platform tag is allowed by PyPI. /// /// Based on PyPI warehouse platform tag validation logic. +/// fn is_platform_tag_allowed_by_pypi(platform_tag: &str) -> bool { // Covers old Windows and old manylinux tags. if ALLOWED_PLATFORMS.contains(&platform_tag) { @@ -96,6 +97,17 @@ fn is_platform_tag_allowed_by_pypi(platform_tag: &str) -> bool { if let Some(captures) = LINUX_PLATFORM_RE.captures(platform_tag) { let libc = captures.name("libc").unwrap().as_str(); let arch = captures.name("arch").unwrap().as_str(); + // please see https://github.com/pypi/warehouse/pull/18390 + if arch == "riscv64" && libc == "many" { + let parts: Vec<&str> = platform_tag.split('_').collect(); + let major: u8 = parts[1].parse().expect("parse major failed"); + let minor: u8 = parts[2].parse().expect("parse minor failed"); + // pypi now support manylinux_2_39_riscv64 + if major == 2 && minor >= 39 { + return true; + } + return false; + } return match libc { "musl" => MUSLLINUX_ARCHES.contains(&arch), @@ -171,6 +183,7 @@ mod tests { ("manylinux2014_x86_64", true), ("manylinux_2_17_aarch64", true), ("manylinux_2_17_riscv64", false), + ("manylinux_2_39_riscv64", true), // musllinux platforms ("musllinux_1_1_x86_64", true), ("musllinux_1_1_riscv64", false), @@ -222,12 +235,12 @@ mod tests { ("x86_64-unknown-linux-gnu", true), ("aarch64-linux-android", true), ("armv7-linux-androideabi", true), - ("riscv64gc-unknown-linux-gnu", false), // Unsupported - ("x86_64-unknown-freebsd", false), // Now unsupported (no lazy validation) - ("powerpc64-unknown-linux-gnu", true), // PPC64 on Linux is supported - ("s390x-unknown-linux-gnu", true), // s390x on Linux is supported - ("wasm32-unknown-emscripten", false), // Emscripten is unsupported - ("i686-pc-windows-msvc", true), // i686 Windows is supported + ("riscv64gc-unknown-linux-gnu", true), + ("x86_64-unknown-freebsd", false), // Now unsupported (no lazy validation) + ("powerpc64-unknown-linux-gnu", true), // PPC64 on Linux is supported + ("s390x-unknown-linux-gnu", true), // s390x on Linux is supported + ("wasm32-unknown-emscripten", false), // Emscripten is unsupported + ("i686-pc-windows-msvc", true), // i686 Windows is supported ]; for (triple, expected) in targets { diff --git a/tests/common/errors.rs b/tests/common/errors.rs index e842be0be..a8a790efa 100644 --- a/tests/common/errors.rs +++ b/tests/common/errors.rs @@ -158,7 +158,7 @@ pub fn pypi_compatibility_unsupported_target() -> Result<()> { "--compatibility", "pypi", "--target", - "riscv64gc-unknown-linux-gnu", // Unsupported by PyPI + "riscv32gc-unknown-linux-gnu", // Unsupported by PyPI "--target-dir", "test-crates/targets/pypi_compatibility_unsupported_target", "--out", @@ -178,7 +178,7 @@ pub fn pypi_compatibility_unsupported_target() -> Result<()> { let err_string = err.to_string(); assert!( err_string.contains( - "Target riscv64gc-unknown-linux-gnu architecture is not supported by PyPI" + "Target riscv32gc-unknown-linux-gnu architecture is not supported by PyPI" ), "{err_string}", ); From 7319dc6043ecf21006158a6540f7bd9111cf8947 Mon Sep 17 00:00:00 2001 From: ffgan <114909534+ffgan@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:36:40 +0800 Subject: [PATCH 2/5] Update src/target/mod.rs Co-authored-by: messense --- src/target/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/mod.rs b/src/target/mod.rs index dbc31facb..f8d97a9c9 100644 --- a/src/target/mod.rs +++ b/src/target/mod.rs @@ -483,7 +483,7 @@ impl Target { } Arch::Riscv64 => PlatformTag::Manylinux { major: 2, - minor: 39, // 2_39 is the minimum version supported uploaded to PyPI + minor: 31, }, Arch::LoongArch64 => PlatformTag::Manylinux { major: 2, From 60411311e15dd9ae57ebcb937df91a11c9e914c4 Mon Sep 17 00:00:00 2001 From: ffgan <114909534+ffgan@users.noreply.github.com> Date: Mon, 28 Jul 2025 10:01:33 +0800 Subject: [PATCH 3/5] Update src/target/pypi_tags.rs Co-authored-by: messense --- src/target/pypi_tags.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/target/pypi_tags.rs b/src/target/pypi_tags.rs index f1173c829..b659c7534 100644 --- a/src/target/pypi_tags.rs +++ b/src/target/pypi_tags.rs @@ -97,17 +97,6 @@ fn is_platform_tag_allowed_by_pypi(platform_tag: &str) -> bool { if let Some(captures) = LINUX_PLATFORM_RE.captures(platform_tag) { let libc = captures.name("libc").unwrap().as_str(); let arch = captures.name("arch").unwrap().as_str(); - // please see https://github.com/pypi/warehouse/pull/18390 - if arch == "riscv64" && libc == "many" { - let parts: Vec<&str> = platform_tag.split('_').collect(); - let major: u8 = parts[1].parse().expect("parse major failed"); - let minor: u8 = parts[2].parse().expect("parse minor failed"); - // pypi now support manylinux_2_39_riscv64 - if major == 2 && minor >= 39 { - return true; - } - return false; - } return match libc { "musl" => MUSLLINUX_ARCHES.contains(&arch), From 26cc19bd4e37503d81d0869100ee7196f8463e6c Mon Sep 17 00:00:00 2001 From: ffgan Date: Mon, 28 Jul 2025 10:10:48 +0800 Subject: [PATCH 4/5] merge test-riscv64-compile to test-cross --- .github/workflows/test.yml | 53 +++++++------------------------------- src/target/pypi_tags.rs | 2 +- 2 files changed, 11 insertions(+), 44 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e22960560..8e58b2857 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -389,6 +389,11 @@ jobs: abi: cp310-cp310 python: python3.10 container: ghcr.io/rust-cross/manylinux_2_36-cross:loongarch64 + - target: riscv64gc-unknown-linux-gnu + abi: cp310-cp310 + python: python3.10 + container: ghcr.io/rust-cross/manylinux_2_39-cross:riscv64 + extra-args: --manylinux 2_39 # PyPy - target: aarch64-unknown-linux-gnu abi: pp310-pypy310_pp73 @@ -408,57 +413,19 @@ jobs: run: | set -ex # Use bundled sysconfig - bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml - - # Use PYO3_CROSS_LIB_DIR - export PYO3_CROSS_LIB_DIR=/opt/python/${{ matrix.platform.abi }} - bin/maturin build -i python3.9 --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml - unset PYO3_CROSS_LIB_DIR - - # Test abi3 - bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-pure/Cargo.toml - - # --find-interpreter - bin/maturin build --find-interpreter --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml - test-riscv64-compile: - name: Test Cross Compile - needs: build-maturin - runs-on: ubuntu-latest - container: ${{ matrix.platform.container }} - strategy: - fail-fast: false - matrix: - platform: - - target: riscv64gc-unknown-linux-gnu - abi: cp310-cp310 - python: python3.10 - container: ghcr.io/rust-cross/manylinux_2_39-cross:riscv64 - steps: - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: - name: maturin-build - path: bin - - run: chmod +x bin/maturin - - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.platform.target }} - - name: Build wheels - run: | - set -ex - # Use bundled sysconfig - bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml --manylinux 2_39 + bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml ${{ matrix.platform.extra-args }} # Use PYO3_CROSS_LIB_DIR export PYO3_CROSS_LIB_DIR=/opt/python/${{ matrix.platform.abi }} - bin/maturin build -i python3.9 --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml --manylinux 2_39 + bin/maturin build -i python3.9 --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml ${{ matrix.platform.extra-args }} unset PYO3_CROSS_LIB_DIR # Test abi3 - bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-pure/Cargo.toml --manylinux 2_39 + bin/maturin build -i ${{ matrix.platform.python }} --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-pure/Cargo.toml ${{ matrix.platform.extra-args }} # --find-interpreter - bin/maturin build --find-interpreter --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml --manylinux 2_39 + bin/maturin build --find-interpreter --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml ${{ matrix.platform.extra-args }} + test-bootstrap: name: Test Bootstrap runs-on: ${{ matrix.os }} diff --git a/src/target/pypi_tags.rs b/src/target/pypi_tags.rs index b659c7534..db4097e6a 100644 --- a/src/target/pypi_tags.rs +++ b/src/target/pypi_tags.rs @@ -171,7 +171,7 @@ mod tests { // manylinux platforms ("manylinux2014_x86_64", true), ("manylinux_2_17_aarch64", true), - ("manylinux_2_17_riscv64", false), + ("manylinux_2_17_riscv64", true), ("manylinux_2_39_riscv64", true), // musllinux platforms ("musllinux_1_1_x86_64", true), From aad2dc99914371b93bf1e4d091577db5cd88ac95 Mon Sep 17 00:00:00 2001 From: ffgan Date: Mon, 28 Jul 2025 10:26:49 +0800 Subject: [PATCH 5/5] Fix formatting in test workflow --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8e58b2857..379f743ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -425,7 +425,7 @@ jobs: # --find-interpreter bin/maturin build --find-interpreter --release --out dist --target ${{ matrix.platform.target }} -m test-crates/pyo3-mixed/Cargo.toml ${{ matrix.platform.extra-args }} - + test-bootstrap: name: Test Bootstrap runs-on: ${{ matrix.os }}