From 9d11ea355ab8d592192eec48a2a80f0f64d798fa Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 15 Oct 2026 21:00:50 +0000 Subject: [PATCH 1/2] Add pyre2 build (riscv64) Cython/pybind11 wrapper around Google's RE2 regex engine. Upstream ships manylinux x86_64/aarch64 wheels via EPEL's re2-devel, which isn't available on riscv64 (gotcha 51); abseil-cpp and re2 are built from source instead, reusing the recipe the already-published google-re2 build proved on this image. --- .github/workflows/build-pyre2.yml | 152 ++++++++++++++++++ docs/packages/pyre2.yaml | 5 + ...icense-files-to-cover-re2-and-abseil.patch | 33 ++++ 3 files changed, 190 insertions(+) create mode 100644 .github/workflows/build-pyre2.yml create mode 100644 docs/packages/pyre2.yaml create mode 100644 patches/pyre2/0.3.14/0001-pyproject-widen-license-files-to-cover-re2-and-abseil.patch diff --git a/.github/workflows/build-pyre2.yml b/.github/workflows/build-pyre2.yml new file mode 100644 index 000000000000..d9488093cbf5 --- /dev/null +++ b/.github/workflows/build-pyre2.yml @@ -0,0 +1,152 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `cibw_wheels` job of +# https://github.com/andreasvc/pyre2/blob/v0.3.14/.github/workflows/release.yml +name: Build pyre2 wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/pyre2.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-pyre2.yml' + - 'docs/packages/pyre2.yaml' + push: + branches: [main] + paths: + - '.github/workflows/build-pyre2.yml' + - 'docs/packages/pyre2.yaml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + # abseil-cpp version and re2 tag the already-published google-re2 build + # proved on this image; reused here for the same reason (gotcha 51 below). + ABSEIL_VERSION: '20250512.1' + RE2_TAG: '2025-11-05' + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: pyre2 + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build pyre2 ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + python: ["cp312", "cp313", "cp314", "cp314t"] + + env: + PYRE2_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout pyre2 v${{ env.PYRE2_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: andreasvc/pyre2 + ref: v${{ env.PYRE2_VERSION }} + fetch-depth: 0 # setuptools_scm derives the version from the tag + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch pyre2 source + run: git apply python-wheels/patches/pyre2/${{ env.PYRE2_VERSION }}/0001-pyproject-widen-license-files-to-cover-re2-and-abseil.patch + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + output-dir: wheelhouse/ + only: ${{ matrix.python }}-manylinux_riscv64 + env: + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + CIBW_ENVIRONMENT_PASS_LINUX: ABSEIL_VERSION RE2_TAG + # Upstream's before-all installs EPEL's re2-devel, unavailable on + # riscv64 (gotcha 51 - no EPEL there); build abseil-cpp + re2 from + # source instead, installed so CMakeLists.txt's own + # find_package(re2 CONFIG) picks them up unmodified. + CIBW_BEFORE_ALL: >- + mkdir -p /tmp/abseil-cpp && + curl -sSLf "https://github.com/abseil/abseil-cpp/archive/refs/tags/${ABSEIL_VERSION}.tar.gz" + | tar -xz -C /tmp/abseil-cpp --strip-components=1 && + cmake -S /tmp/abseil-cpp -B /tmp/abseil-cpp/build -DCMAKE_BUILD_TYPE=Release + -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_CXX_STANDARD=17 + -DABSL_PROPAGATE_CXX_STD=ON -DABSL_ENABLE_INSTALL=ON -DCMAKE_INSTALL_LIBDIR=lib && + cmake --build /tmp/abseil-cpp/build --parallel --target install && + mkdir -p /tmp/re2 && + curl -sSLf "https://github.com/google/re2/archive/refs/tags/${RE2_TAG}.tar.gz" + | tar -xz -C /tmp/re2 --strip-components=1 && + cmake -S /tmp/re2 -B /tmp/re2/build -DCMAKE_BUILD_TYPE=Release + -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_LIBDIR=lib && + cmake --build /tmp/re2/build --parallel --target install && + ldconfig && + cp /tmp/re2/LICENSE {project}/LICENSE.re2 && + cp /tmp/abseil-cpp/LICENSE {project}/LICENSE.abseil-cpp + CIBW_ENVIRONMENT: LIBRARY_PATH=/usr/local/lib LD_LIBRARY_PATH=/usr/local/lib + CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" + CIBW_BEFORE_BUILD: >- + pip install setuptools "setuptools_scm>=8" "Cython>=0.20" "pybind11>=2.12" ninja "cmake>=3.18,<4.0.0" + CIBW_REPAIR_WHEEL_COMMAND: auditwheel repair --strip -w {dest_dir} {wheel} + CIBW_TEST_REQUIRES: pytest + CIBW_TEST_SOURCES: tests pyproject.toml + CIBW_TEST_COMMAND: pytest -v . + + - name: Check the extension and licences made it into the wheel + run: | + python3 - wheelhouse/*.whl <<'EOF' + import sys, zipfile + for whl in sys.argv[1:]: + names = zipfile.ZipFile(whl).namelist() + assert any(n.startswith("re2") and n.endswith(".so") for n in names), whl + assert any(n.endswith(".dist-info/licenses/LICENSE") for n in names), whl + assert any(n.endswith("licenses/LICENSE.re2") for n in names), whl + assert any(n.endswith("licenses/LICENSE.abseil-cpp") for n in names), whl + print(whl, "ok") + EOF + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pyre2-${{ env.PYRE2_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish pyre2 ${{ matrix.version }} + needs: [setup, build_wheels] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + secrets: + app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} + with: + artifact-pattern: pyre2-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/pyre2.yaml b/docs/packages/pyre2.yaml new file mode 100644 index 000000000000..6c975fe10b79 --- /dev/null +++ b/docs/packages/pyre2.yaml @@ -0,0 +1,5 @@ +package-name: pyre2 +source-code: https://github.com/andreasvc/pyre2 +license: BSD-3-Clause +versions: +- version: 0.3.14 diff --git a/patches/pyre2/0.3.14/0001-pyproject-widen-license-files-to-cover-re2-and-abseil.patch b/patches/pyre2/0.3.14/0001-pyproject-widen-license-files-to-cover-re2-and-abseil.patch new file mode 100644 index 000000000000..6b34ba93dc40 --- /dev/null +++ b/patches/pyre2/0.3.14/0001-pyproject-widen-license-files-to-cover-re2-and-abseil.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] pyproject: widen license-files to cover re2 and abseil-cpp + +`license-files = ["LICENSE"]` is an explicit PEP 639 list, so it has no +default glob behind it. On riscv64, the manylinux image has no EPEL +`re2-devel` to link against (gotcha 51), so the wheel instead builds +and statically links abseil-cpp (Apache-2.0) and re2 (BSD-3-Clause) +from source, with their upstream LICENSE files copied next to this +one as LICENSE.re2 and LICENSE.abseil-cpp. Widening the glob to +`LICENSE*` picks both up in dist-info/licenses without changing what a +clean checkout's sdist ships (still just LICENSE). + +Upstream-Status: Inappropriate [riscv64-only build detail; upstream's own CI links a system re2-devel package, never ships these extra notices] +--- + pyproject.toml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pyproject.toml b/pyproject.toml +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -16,7 +16,7 @@ + readme = { file = "README.rst", content-type = "text/x-rst" } + requires-python = ">=3.10" + license = "BSD-3-Clause" +-license-files = ["LICENSE"] ++license-files = ["LICENSE*"] + dynamic = ["version"] + classifiers = [ + "Programming Language :: Cython", +-- +2.43.0 From 898be7fe1cde78c55dd40b3c0556b648af7a3df3 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 25 Oct 2026 18:04:44 +0000 Subject: [PATCH 2/2] pyre2: install openssl-devel before building pip cmake (gotcha 608) No riscv64 wheel exists for the pinned cmake version, so CIBW_BEFORE_BUILD's pip install builds it from source as a build dependency. That build runs CMake's own bootstrap CMakeLists, whose Utilities/cmcurl/CMakeLists.txt calls find_package(OpenSSL); the manylinux_riscv64 image ships openssl-libs but no -devel headers, so all 4 build legs failed identically with: CMake Error at Utilities/cmcurl/CMakeLists.txt:772 (message): Could not find OpenSSL. Install openssl-devel in CIBW_BEFORE_ALL before cmake gets pip installed, same fix as build-executorch.yml. --- .github/workflows/build-pyre2.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build-pyre2.yml b/.github/workflows/build-pyre2.yml index d9488093cbf5..60a585d98279 100644 --- a/.github/workflows/build-pyre2.yml +++ b/.github/workflows/build-pyre2.yml @@ -89,7 +89,13 @@ jobs: # riscv64 (gotcha 51 - no EPEL there); build abseil-cpp + re2 from # source instead, installed so CMakeLists.txt's own # find_package(re2 CONFIG) picks them up unmodified. + # + # No riscv64 cmake wheel exists, so CIBW_BEFORE_BUILD's pip install + # builds it from source as a build dependency; its own CMake + # bootstrap needs OpenSSL's dev headers to find libcrypto for + # Utilities/cmcurl (gotcha 608). CIBW_BEFORE_ALL: >- + dnf -y install openssl-devel && mkdir -p /tmp/abseil-cpp && curl -sSLf "https://github.com/abseil/abseil-cpp/archive/refs/tags/${ABSEIL_VERSION}.tar.gz" | tar -xz -C /tmp/abseil-cpp --strip-components=1 &&