From 38f9184c17f30423e2e5fdfca3a4dc6a1e121a1a Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 26 Aug 2026 13:25:30 +0200 Subject: [PATCH 1/4] gevent: package the licences of the embedded libev, libuv and c-ares The wheels statically compile deps/libev, deps/libuv and deps/c-ares into the extension modules, but setup.py names only 'LICENSE' in license_files, so the wheel ships gevent's own MIT licence alone. All three dependencies require their copyright notice to travel with binary redistributions. The vendored c-ares tree carries no licence file at all, so the patch also restores LICENSE.md from c-ares 1.34.5, the version in deps/c-ares. --- ...nces-of-the-embedded-libev-libuv-and.patch | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 patches/gevent/26.8.0/0001-package-the-licences-of-the-embedded-libev-libuv-and.patch diff --git a/patches/gevent/26.8.0/0001-package-the-licences-of-the-embedded-libev-libuv-and.patch b/patches/gevent/26.8.0/0001-package-the-licences-of-the-embedded-libev-libuv-and.patch new file mode 100644 index 000000000..a110290b9 --- /dev/null +++ b/patches/gevent/26.8.0/0001-package-the-licences-of-the-embedded-libev-libuv-and.patch @@ -0,0 +1,77 @@ +From c85027ca757d661635d7c02f1b60e73eb9b19187 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Wed, 26 Aug 2026 13:24:02 +0200 +Subject: [PATCH] package the licences of the embedded libev, libuv and c-ares + +Upstream-Status: To upstream [not yet submitted; the same gap exists in every gevent wheel on PyPI, so this needs a maintainer discussion rather than a drive-by PR] + +The wheels statically compile the bundled deps/libev, deps/libuv and +deps/c-ares sources into gevent.libev.corecext, gevent.libev._corecffi, +gevent.libuv._corecffi and gevent.resolver.cares. libev is BSD 2-clause +(or GPL 2+), libuv and c-ares are MIT; all three require the copyright +notice to travel with binary redistributions, but setup.py names only +'LICENSE' in license_files, so the wheel ships gevent's own licence alone. + +The vendored c-ares tree carries no licence file at all -- the notice +appears only in the per-file headers -- so restore LICENSE.md from the +vendored release (c-ares 1.34.5). + +NOTICE is added for the same reason: it carries the PSF licence covering +the stdlib test files copied under gevent/tests and the guv copyright of +gevent/libuv/_corecffi_*.c, both of which do ship in the wheel. + +Signed-off-by: Ludovic Henry +--- + deps/c-ares/LICENSE.md | 24 ++++++++++++++++++++++++ + setup.py | 7 +++++++ + 2 files changed, 31 insertions(+) + create mode 100644 deps/c-ares/LICENSE.md + +diff --git a/deps/c-ares/LICENSE.md b/deps/c-ares/LICENSE.md +new file mode 100644 +index 0000000..910ddde +--- /dev/null ++++ b/deps/c-ares/LICENSE.md +@@ -0,0 +1,24 @@ ++MIT License ++ ++Copyright (c) 1998 Massachusetts Institute of Technology ++Copyright (c) 2007 - 2023 Daniel Stenberg with many contributors, see AUTHORS ++file. ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy of ++this software and associated documentation files (the "Software"), to deal in ++the Software without restriction, including without limitation the rights to ++use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ++the Software, and to permit persons to whom the Software is furnished to do so, ++subject to the following conditions: ++ ++The above copyright notice and this permission notice (including the next ++paragraph) shall be included in all copies or substantial portions of the ++Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. +diff --git a/setup.py b/setup.py +index 878a360..22ef420 100755 +--- a/setup.py ++++ b/setup.py +@@ -349,6 +349,13 @@ def run_setup(ext_modules): + license='MIT', # pep 639, use SPDX license identifiers + license_files=[ + 'LICENSE', ++ 'NOTICE', ++ # Embedded and statically linked into the extension modules; their ++ # BSD/MIT terms require the copyright notice to ship with the binary. ++ 'deps/c-ares/LICENSE.md', ++ 'deps/libev/LICENSE', ++ 'deps/libuv/LICENSE', ++ 'deps/libuv/LICENSE-extra', + ], + project_urls={ + 'Bug Tracker': 'https://github.com/gevent/gevent/issues', From 07e28902435987befad528ef15ebe16a6a15de53 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 26 Aug 2026 13:25:30 +0200 Subject: [PATCH 2/4] gevent: add build-gevent.yml for riscv64 wheels Mirrors the `manylinux` job of gevent's ci.yml and the scripts/releases/make-manylinux script it runs, narrowed to riscv64 and driven through cibuildwheel instead of make-manylinux's own docker run and per-interpreter loop. The matrix is cp312/cp313/cp314; make-manylinux skips free-threaded builds ("The GIL is required") and PyPI carries no cp3XXt gevent wheel. Testing is upstream's: the per-interpreter sanity checks for the libev-cext, libuv and libev-cffi loops and for gevent.ares, then the full `python -m gevent.tests --second-chance` suite with the same GEVENT_MANYLINUX, GEVENT_LOOP, GEVENTTEST_USE_RESOURCES and PYTHONHASHSEED settings make-manylinux exports. --- .github/workflows/build-gevent.yml | 139 +++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 .github/workflows/build-gevent.yml diff --git a/.github/workflows/build-gevent.yml b/.github/workflows/build-gevent.yml new file mode 100644 index 000000000..b3d0c78b6 --- /dev/null +++ b/.github/workflows/build-gevent.yml @@ -0,0 +1,139 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `manylinux` job of +# https://github.com/gevent/gevent/blob/26.8.0/.github/workflows/ci.yml and the +# scripts/releases/make-manylinux script it runs. +name: Build gevent wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'gevent version to build (git tag, e.g. 26.8.0)' + required: true + default: '26.8.0' + pull_request: + paths: + - '.github/workflows/build-gevent.yml' + +concurrency: + group: ${{ github.workflow }}-${{ inputs.version || '26.8.0' }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + GEVENT_VERSION: ${{ inputs.version || '26.8.0' }} + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + build_wheels: + name: Build gevent ${{ inputs.version || '26.8.0' }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + strategy: + fail-fast: false + matrix: + python: + # make-manylinux skips free-threaded builds: "The GIL is required". + - "cp312" + - "cp313" + - "cp314" + + steps: + - name: Checkout gevent ${{ env.GEVENT_VERSION }} + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + repository: gevent/gevent + ref: ${{ env.GEVENT_VERSION }} + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + path: python-wheels + persist-credentials: false + + # The wheel statically compiles libev, libuv and c-ares but ships only gevent's + # own LICENSE. + - name: Patch gevent source + run: | + git apply python-wheels/patches/gevent/${{ env.GEVENT_VERSION }}/00*.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_BEFORE_ALL_LINUX: yum -y install libffi-devel + # Cython has no riscv64 wheel, so it builds from sdist; NO_CYTHON_COMPILE + # keeps that from compiling Cython's own accelerators (as make-manylinux does). + # TRAVIS is what make-manylinux uses to tell setup.py it is on CI, which makes + # the c-ares extension required instead of optional. + CIBW_ENVIRONMENT: >- + NO_CYTHON_COMPILE=true + CI=1 + TRAVIS=true + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + CIBW_TEST_EXTRAS: test + # GEVENT_MANYLINUX is test-only: during the build it makes setup.py assume + # c-ares was already configured by a separate step, which we don't have. + CIBW_TEST_ENVIRONMENT: >- + GEVENT_MANYLINUX=1 + GEVENT_MANYLINUX_NAME=manylinux_2_39_riscv64 + GEVENT_LOOP=libev-cext + GEVENTTEST_USE_RESOURCES=-network + PYTHONHASHSEED=8675309 + CIBW_TEST_COMMAND: >- + python -c "import gevent; print(gevent, gevent.__version__)" && + python -c "import gevent.core; print('default loop', gevent.core.loop)" && + GEVENT_LOOP=libuv python -c "import gevent.core; print('libuv loop', gevent.core.loop)" && + GEVENT_LOOP=libev-cffi python -c "import gevent.core; print('libev-cffi loop', gevent.core.loop)" && + python -c "import gevent.ares; print('ares', gevent.ares)" && + python -c "import importlib.metadata as m; f=[str(p) for p in m.files('gevent')]; missing=[n for n in ('licenses/LICENSE','licenses/NOTICE','licenses/deps/c-ares/LICENSE.md','licenses/deps/libev/LICENSE','licenses/deps/libuv/LICENSE','licenses/deps/libuv/LICENSE-extra') if not any(s.endswith(n) for s in f)]; assert not missing, missing" && + python -m gevent.tests --second-chance + + - name: Check the compiled extensions made it into the wheel + run: | + python3 - wheelhouse/*.whl <<'EOF' + import sys, zipfile + # gevent.resolver.cares is declared optional unless setup.py detects it is + # running on CI from a checkout, so a failed build silently drops it. + expected = ( + 'gevent/libev/corecext', 'gevent/libev/_corecffi', + 'gevent/libuv/_corecffi', 'gevent/resolver/cares', + 'gevent/_gevent_cgreenlet', 'gevent/_gevent_cqueue', + ) + for whl in sys.argv[1:]: + sos = [n for n in zipfile.ZipFile(whl).namelist() if n.endswith('.so')] + missing = [e for e in expected if not any(n.startswith(e) for n in sos)] + assert not missing, (whl, missing, sos) + print(whl, len(sos), 'extension modules ok') + EOF + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: gevent-${{ env.GEVENT_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish gevent ${{ inputs.version || '26.8.0' }} to GitLab + needs: [build_wheels] + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Publish wheels and open docs PR + uses: riseproject-dev/python-wheels/actions/publish-wheels@main + with: + artifact-pattern: gevent-${{ env.GEVENT_VERSION }}-*-manylinux_riscv64 + gitlab-username: ${{ vars.GITLAB_DEPLOY_USER }} + gitlab-token: ${{ secrets.GITLAB_DEPLOY_TOKEN }} + gitlab-project-id: ${{ vars.GITLAB_PROJECT_ID }} + gh-token: ${{ secrets.GITHUB_TOKEN }} From 3385c1f9aeb1a8f22ffad07416e6c8f225f9bcba Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 26 Aug 2026 13:29:30 +0200 Subject: [PATCH 3/4] gevent: reword the NO_CYTHON_COMPILE/TRAVIS note --- .github/workflows/build-gevent.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-gevent.yml b/.github/workflows/build-gevent.yml index b3d0c78b6..9be3d215f 100644 --- a/.github/workflows/build-gevent.yml +++ b/.github/workflows/build-gevent.yml @@ -69,10 +69,9 @@ jobs: env: CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} CIBW_BEFORE_ALL_LINUX: yum -y install libffi-devel - # Cython has no riscv64 wheel, so it builds from sdist; NO_CYTHON_COMPILE - # keeps that from compiling Cython's own accelerators (as make-manylinux does). - # TRAVIS is what make-manylinux uses to tell setup.py it is on CI, which makes - # the c-ares extension required instead of optional. + # As in make-manylinux: NO_CYTHON_COMPILE keeps Cython, which has no riscv64 + # binary wheel, from compiling its own accelerators here; TRAVIS is how it tells + # setup.py it is on CI, which makes the c-ares extension required, not optional. CIBW_ENVIRONMENT: >- NO_CYTHON_COMPILE=true CI=1 From 7c00c0eed1cfae5388bb26afe0889c038373f3a3 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 26 Aug 2026 13:34:33 +0200 Subject: [PATCH 4/4] gevent: stage src/greentest so the monkey-patched stdlib tests run cibuildwheel runs test-command in an empty directory, where gevent's test runner cannot climb to setup.py and therefore warns and skips the whole monkey-patched stdlib suite -- 17 of its 86 test commands. Staging setup.py, src/greentest and examples (but not src/gevent) brings them back while leaving the installed wheel as the only importable gevent. --- .github/workflows/build-gevent.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build-gevent.yml b/.github/workflows/build-gevent.yml index 9be3d215f..e142b219b 100644 --- a/.github/workflows/build-gevent.yml +++ b/.github/workflows/build-gevent.yml @@ -78,6 +78,10 @@ jobs: TRAVIS=true PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ CIBW_TEST_EXTRAS: test + # The monkey-patched stdlib tests live in src/greentest and are found by climbing + # to setup.py, so both have to be staged or the runner just warns and skips them + # (17 of 86 test commands). src/gevent stays out so the wheel is what is imported. + CIBW_TEST_SOURCES: setup.py src/greentest examples # GEVENT_MANYLINUX is test-only: during the build it makes setup.py assume # c-ares was already configured by a separate step, which we don't have. CIBW_TEST_ENVIRONMENT: >-