Skip to content

Commit 2001213

Browse files
authored
pylibmc: add build-pylibmc.yml for riscv64 wheels (#1504)
* **Package**: `pylibmc` * **Version**: `1.6.3` * **Source**: https://github.com/lericson/pylibmc * **Docs**: https://sendapatch.se/projects/pylibmc/ C extension binding libmemcached, a client library for memcached. Upstream publishes no riscv64 wheel. Mirrors [upstream's `cd.yml`](https://github.com/lericson/pylibmc/blob/1.6.3/.github/workflows/cd.yml) cibuildwheel build. **Differs from upstream** - Builds libmemcached-awesome from source in `CIBW_BEFORE_ALL` - Rocky 10 has no `libmemcached-devel` for riscv64 (no EPEL), unlike upstream's `yum install`. - SASL support left at its (off) CMake default - untested by pylibmc's own suite, and avoids a large transitive Kerberos/GSSAPI dependency chain. **Testing** - same as upstream (`runtests.py`-equivalent `pytest tests`), against a real `memcached` server started in `CIBW_BEFORE_TEST`. **License**: Wheel bundles libmemcached-awesome (BSD-3-Clause); upstream ships no licence text for it, so the build adds one. Not yet build-tested locally this session (no working container runtime available); relies on the `pull_request` CI run for the actual riscv64 build/test/publish-dry-run verification.
1 parent 1ea448b commit 2001213

2 files changed

Lines changed: 212 additions & 0 deletions

File tree

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# SPDX-FileCopyrightText: 2026 The RISE Project
2+
# SPDX-License-Identifier: MIT
3+
---
4+
# This workflow is based on: https://github.com/lericson/pylibmc/blob/1.6.3/.github/workflows/cd.yml
5+
name: Build pylibmc wheels (riscv64)
6+
7+
on:
8+
workflow_dispatch:
9+
inputs:
10+
version:
11+
description: 'pylibmc version to build (git tag, e.g. 1.6.3)'
12+
required: true
13+
default: '1.6.3'
14+
pull_request:
15+
paths:
16+
- '.github/workflows/build-pylibmc.yml'
17+
- 'patches/pylibmc/**'
18+
19+
concurrency:
20+
group: ${{ github.workflow }}-${{ inputs.version || '1.6.3' }}-${{ github.head_ref || github.run_id }}
21+
cancel-in-progress: true
22+
23+
permissions:
24+
contents: read # to fetch code (actions/checkout)
25+
26+
env:
27+
# `inputs.version` is empty on pull_request events; default to 1.6.3 there.
28+
PYLIBMC_VERSION: ${{ inputs.version || '1.6.3' }}
29+
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
30+
# Rocky 10's repos carry no libmemcached-devel at all (EPEL is absent on
31+
# riscv64, gotcha 51, and it isn't in baseos/appstream/CRB either), unlike
32+
# upstream's `yum install -y libmemcached-devel` on x86_64/aarch64. Original
33+
# libmemcached 1.0.18 is largely unmaintained and not proven to build under
34+
# the image's GCC 14; libmemcached-awesome is the community-maintained fork
35+
# (used by PHP's own memcached extension for the same reason) that keeps the
36+
# same public headers/API/SONAME, built from source instead.
37+
LIBMEMCACHED_VERSION: '1.1.4'
38+
39+
jobs:
40+
setup:
41+
uses: $/.github/workflows/_setup.yml
42+
43+
build_wheels:
44+
needs: [setup]
45+
name: Build pylibmc ${{ inputs.version || '1.6.3' }} ${{ matrix.python }}-manylinux_riscv64
46+
runs-on: ubuntu-24.04-riscv
47+
timeout-minutes: 90
48+
strategy:
49+
fail-fast: false
50+
matrix:
51+
python:
52+
- "cp312"
53+
- "cp313"
54+
- "cp314"
55+
- "cp314t"
56+
57+
steps:
58+
- name: Checkout pylibmc ${{ env.PYLIBMC_VERSION }}
59+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
60+
with:
61+
repository: lericson/pylibmc
62+
ref: ${{ env.PYLIBMC_VERSION }}
63+
persist-credentials: false
64+
65+
- name: Checkout python-wheels
66+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
67+
with:
68+
path: python-wheels
69+
persist-credentials: false
70+
71+
- name: Patch pylibmc source
72+
run: git apply python-wheels/patches/pylibmc/${{ env.PYLIBMC_VERSION }}/*.patch
73+
74+
- name: Build wheels
75+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
76+
with:
77+
output-dir: wheelhouse/
78+
only: ${{ matrix.python }}-manylinux_riscv64
79+
env:
80+
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
81+
# Mirrors upstream's install_libaec/install_hdf5-style before-all
82+
# (build-h5py.yml): fetch, configure and install the dependency into
83+
# the container instead of yum-installing a devel package. SASL and
84+
# OpenSSL-crypto support are left at their (off) CMake defaults --
85+
# pylibmc's own tests exercise neither, and upstream's official
86+
# wheel pulls in a large Kerberos/GSSAPI stack for SASL that isn't
87+
# worth the added scope for an untested feature.
88+
CIBW_BEFORE_ALL_LINUX: |
89+
set -ex
90+
dnf -y install zlib-devel flex
91+
mkdir -p /tmp/libmemcached
92+
curl -fsSL "https://github.com/awesomized/libmemcached/archive/refs/tags/$LIBMEMCACHED_VERSION.tar.gz" | tar xz --strip-components=1 -C /tmp/libmemcached
93+
cmake -S /tmp/libmemcached -B /tmp/libmemcached/build \
94+
-D CMAKE_BUILD_TYPE=Release \
95+
-D CMAKE_INSTALL_PREFIX=/usr \
96+
-D BUILD_TESTING=OFF \
97+
-D ENABLE_HASH_HSIEH=ON \
98+
-D ENABLE_HASH_FNV64=ON \
99+
-D ENABLE_HASH_MURMUR=ON
100+
cmake --build /tmp/libmemcached/build -j "$(nproc)"
101+
cmake --install /tmp/libmemcached/build
102+
ldconfig
103+
# LIBMEMCACHED_VERSION must be restated here: CIBW_BEFORE_ALL_LINUX
104+
# runs inside the manylinux container via `sh -c`, which does not
105+
# inherit the job's plain `env:` (only what CIBW_ENVIRONMENT passes
106+
# through).
107+
CIBW_ENVIRONMENT: >-
108+
LIBMEMCACHED_VERSION=${{ env.LIBMEMCACHED_VERSION }}
109+
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
110+
CIBW_TEST_REQUIRES: pytest
111+
# Rocky 10's `memcached` package (appstream, no EPEL needed) stands
112+
# in for upstream's CI service container; it refuses to start as
113+
# root without an explicit -u.
114+
CIBW_BEFORE_TEST_LINUX: |
115+
dnf -y install memcached
116+
memcached -d -u root
117+
# src-layout checkout (package_dir={'': 'src'}) has no top-level
118+
# pylibmc/ to shadow the installed wheel (gotcha territory:
119+
# testing-and-shadowing.md), so testing straight from {project} is
120+
# safe -- mirrors upstream's `runtests.py -v tests --with-doctest`.
121+
CIBW_TEST_COMMAND: >-
122+
python -c "import importlib.metadata as m;
123+
f = sorted(p.name for p in m.files('pylibmc') if '.dist-info/licenses/' in str(p));
124+
assert f == ['LICENSE', 'LICENSE.libmemcached'], f" &&
125+
cd {project} && python -m pytest -v tests
126+
127+
- name: Check the wheel is a compiled extension
128+
run: |
129+
python3 - wheelhouse/*.whl <<'EOF'
130+
import sys, zipfile
131+
for whl in sys.argv[1:]:
132+
names = zipfile.ZipFile(whl).namelist()
133+
assert any(n.startswith("_pylibmc") and n.endswith(".so") for n in names), names
134+
print(whl, "ok")
135+
EOF
136+
137+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
138+
with:
139+
name: pylibmc-${{ env.PYLIBMC_VERSION }}-${{ matrix.python }}-manylinux_riscv64
140+
path: wheelhouse/*.whl
141+
if-no-files-found: error
142+
143+
publish:
144+
name: Publish pylibmc ${{ inputs.version || '1.6.3' }}
145+
needs: [setup, build_wheels]
146+
permissions:
147+
contents: write
148+
pull-requests: write
149+
uses: $/.github/workflows/_publish-wheel.yml
150+
with:
151+
artifact-pattern: pylibmc-${{ inputs.version || '1.6.3' }}-*-manylinux_riscv64
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
From 95c7a802a09df3cf3fe795a950555bb339c0eaa1 Mon Sep 17 00:00:00 2001
2+
From: Ludovic Henry <git@ludovic.dev>
3+
Date: Tue, 8 Sep 2026 06:58:17 +0200
4+
Subject: [PATCH] Package the libmemcached-awesome licence with the wheels
5+
6+
The riscv64 wheels build libmemcached-awesome (https://github.com/
7+
awesomized/libmemcached) from source in CIBW_BEFORE_ALL and auditwheel
8+
vendors the resulting libmemcached.so into pylibmc.libs/, but the wheel
9+
only ships pylibmc's own LICENSE. libmemcached-awesome is BSD-3-Clause,
10+
which requires the copyright notice to be reproduced in binary
11+
redistributions.
12+
13+
Add its licence text as LICENSE.libmemcached at the project root --
14+
setuptools' default license_files glob (LICEN[CS]E*) picks it up with
15+
no setup.py/setup.cfg change and lands it in dist-info/licenses/
16+
beside the project's own LICENSE.
17+
18+
Upstream-Status: Inappropriate [riscv64-specific build dependency, not part of upstream's own build]
19+
---
20+
LICENSE.libmemcached | 29 +++++++++++++++++++++++++++++
21+
1 file changed, 29 insertions(+)
22+
create mode 100644 LICENSE.libmemcached
23+
24+
diff --git a/LICENSE.libmemcached b/LICENSE.libmemcached
25+
new file mode 100644
26+
index 0000000..1d50957
27+
--- /dev/null
28+
+++ b/LICENSE.libmemcached
29+
@@ -0,0 +1,29 @@
30+
+Copyright (c) 2006-2014 Brian Aker, DataDifferential, https://datadifferential.com/
31+
+Copyright (c) 2020-2021 Michael Wallner, Awesome Inc, https://awesome.co/
32+
+
33+
+All rights reserved.
34+
+
35+
+Redistribution and use in source and binary forms, with or without modification,
36+
+are permitted provided that the following conditions are met:
37+
+
38+
+1. Redistributions of source code must retain the above copyright notice, this
39+
+ list of conditions and the following disclaimer.
40+
+
41+
+2. Redistributions in binary form must reproduce the above copyright notice,
42+
+ this list of conditions and the following disclaimer in the documentation
43+
+ and/or other materials provided with the distribution.
44+
+
45+
+3. Neither the name of the copyright holder nor the names of its contributors
46+
+ may be used to endorse or promote products derived from this software
47+
+ without specific prior written permission.
48+
+
49+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
50+
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
51+
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
52+
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
53+
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
54+
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
55+
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
56+
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57+
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
58+
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59+
--
60+
2.50.1 (Apple Git-155)
61+

0 commit comments

Comments
 (0)