Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions .github/workflows/build-couchbase.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on upstream's documented wheel build:
# https://github.com/couchbase/couchbase-python-client/blob/4.6.3/BUILDING.md
name: Build couchbase wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/couchbase.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-couchbase.yml'
- 'docs/packages/couchbase.yaml'
push:
branches: [main]
paths:
- '.github/workflows/build-couchbase.yml'
- 'docs/packages/couchbase.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

jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: couchbase
version: ${{ inputs.version }}

build_sdist:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
name: Build couchbase ${{ matrix.version }} sdist
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
env:
COUCHBASE_VERSION: ${{ matrix.version }}

steps:
- name: Checkout couchbase ${{ env.COUCHBASE_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: couchbase/couchbase-python-client
ref: ${{ env.COUCHBASE_VERSION }}
submodules: recursive
persist-credentials: false

- name: Install Python
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: '3.12'
activate-environment: true
enable-cache: false

# configure_ext populates deps/couchbase-cxx-cache, which MANIFEST.in bundles
# into the sdist; without it the riscv job would have to fetch the C++ core's
# dependencies from inside the build container.
- name: Build sdist
run: |
uv pip install build setuptools twine wheel
PYCBC_SET_CPM_CACHE=ON PYCBC_USE_OPENSSL=OFF python setup.py configure_ext
python setup.py sdist
twine check dist/*
env:
CMAKE_POLICY_VERSION_MINIMUM: '3.5'

- name: Upload sdist artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: couchbase-${{ env.COUCHBASE_VERSION }}-sdist
path: dist/*.tar.gz
if-no-files-found: error

build_wheels:
needs: [setup, build_sdist]
if: needs.setup.outputs.versions != '[]'
name: Build couchbase ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 1440
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
python: ["cp312", "cp313", "cp314", "cp314t"]
env:
COUCHBASE_VERSION: ${{ matrix.version }}

steps:
- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false

- name: Download sdist
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: couchbase-${{ env.COUCHBASE_VERSION }}-sdist
path: dist/

# The patches reach files the git checkout does not have in a patchable
# shape: one lives in the CPM cache only the sdist carries, the other
# inside the couchbase-cxx-client submodule.
- name: Extract and patch couchbase source
run: |
mkdir couchbase-src
tar zxf dist/couchbase-*.tar.gz -C couchbase-src --strip-components=1
git apply --directory=couchbase-src python-wheels/patches/couchbase/"${COUCHBASE_VERSION}"/00*.patch

- name: Build wheels
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
package-dir: couchbase-src
output-dir: wheelhouse/
only: ${{ matrix.python }}-manylinux_riscv64
env:
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
# PYCBC_USE_OPENSSL=OFF is how upstream builds its own wheels: the C++ core
# statically links the vendored BoringSSL instead of the image's OpenSSL.
# CMAKE_POLICY_VERSION_MINIMUM covers the vendored GSL's cmake_minimum_required.
CIBW_ENVIRONMENT: >-
PYCBC_USE_OPENSSL=OFF
PYCBC_CMAKE_PARALLEL_THREADS=$(nproc)
CMAKE_POLICY_VERSION_MINIMUM=3.5
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
CIBW_TEST_REQUIRES: pytest
# Upstream's own suite needs a live Couchbase Server, which has no riscv64
# build, so this drives the C++ core directly instead: a bootstrap against an
# unroutable address has to surface as a Couchbase error, not a crash.
CIBW_TEST_COMMAND: >-
python -c "import importlib.metadata as m; f=[str(p) for p in m.files('couchbase')]; assert any(s.endswith('licenses/LICENSE') for s in f), f; import couchbase; from couchbase.logic.pycbc_core import _core; assert _core.__file__.endswith('.so'), _core.__file__; md = couchbase.get_metadata(); assert md['version'], md; assert 'BoringSSL' in md['openssl_runtime'], md; print(md['version'], md['openssl_runtime'])" &&
python -c "import pytest; from datetime import timedelta; from couchbase.auth import PasswordAuthenticator; from couchbase.cluster import Cluster; from couchbase.exceptions import CouchbaseException; from couchbase.options import ClusterOptions, ClusterTimeoutOptions; opts = ClusterOptions(PasswordAuthenticator('u', 'p'), timeout_options=ClusterTimeoutOptions(bootstrap_timeout=timedelta(seconds=15), resolve_timeout=timedelta(seconds=5))); pytest.raises(CouchbaseException, lambda: Cluster.connect('couchbase://192.0.2.1', opts).ping()); print('bootstrap failure surfaced as CouchbaseException')"

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: couchbase-${{ env.COUCHBASE_VERSION }}-${{ matrix.python }}-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish couchbase ${{ 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: couchbase-${{ matrix.version }}-*-manylinux_riscv64
6 changes: 6 additions & 0 deletions docs/packages/couchbase.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package-name: couchbase
source-code: https://github.com/couchbase/couchbase-python-client
license: Apache-2.0
versions:
- version: 4.6.3
patched: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 21 Sep 2026 19:40:00 +0000
Subject: [PATCH] Detect riscv64 as a correct-double-operations target

taocpp/json vendors Google's double-conversion, whose architecture list decides
whether the target evaluates doubles at exactly 64 bits (x86's 80-bit x87 stack
is the reason the list exists). The list ends in an #error, so an architecture
it does not name fails the build outright:

deps/couchbase-cxx-cache/json/4c7c/json/include/tao/json/external/double.hpp:78:2:
error: #error Target architecture was not detected as supported by Double-Conversion.

riscv64's F/D extensions operate on true IEEE-754 binary32/binary64 with no
extended-precision stack, so it belongs in the first branch. taocpp/json fixed
this on main in 91a480ff36259ed077545a64c04696062916bcbe; the couchbase-cxx-client
CPM cache pins 1.0.0-beta.14, which predates it, and no release carries the fix
yet.

Upstream-Status: Backport [https://github.com/taocpp/json/commit/91a480ff36259ed077545a64c04696062916bcbe]
---
.../json/4c7c/json/include/tao/json/external/double.hpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/deps/couchbase-cxx-cache/json/4c7c/json/include/tao/json/external/double.hpp b/deps/couchbase-cxx-cache/json/4c7c/json/include/tao/json/external/double.hpp
--- a/deps/couchbase-cxx-cache/json/4c7c/json/include/tao/json/external/double.hpp
+++ b/deps/couchbase-cxx-cache/json/4c7c/json/include/tao/json/external/double.hpp
@@ -63,7 +63,8 @@
defined(__SH4__) || defined(__alpha__) || \
defined(_MIPS_ARCH_MIPS32R2) || \
defined(__AARCH64EL__) || defined(__aarch64__) || \
- defined(__EMSCRIPTEN__)
+ defined(__EMSCRIPTEN__) || \
+ (defined(__riscv) && __riscv_xlen == 64)
#define TAO_JSON_DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#elif defined(__mc68000__)
#undef TAO_JSON_DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 21 Sep 2026 20:10:00 +0000
Subject: [PATCH] Do not make cast-align fatal on strict-alignment targets

GCC only emits -Wcast-align on targets it considers strict-alignment, so the
C++ core's casts from byte buffers to protocol header layouts are silent on
x86_64 and aarch64 and fatal on riscv64:

core/io/mcbp_session.cxx:141:26: error: cast from 'const std::byte*' to
'const mcbp_header_layout*' increases required alignment of target type
[-Werror=cast-align]

-Wcast-align is a performance diagnostic, not a correctness one, and the
casts it flags here are the protocol decoding the core is built around. Demote
it the same way the GCC block below already demotes the four warnings asio
trips, so every other warning stays fatal.

Upstream-Status: To upstream [not yet submitted; this port may only touch riseproject-dev/python-wheels]
---
deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake b/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake
--- a/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake
+++ b/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake
@@ -55,7 +55,9 @@
-Wno-compound-token-split-by-macro)

if(WARNINGS_AS_ERRORS)
- set(COMMON_WARNINGS ${COMMON_WARNINGS} -Werror)
+ # -Wcast-align is only emitted on strict-alignment targets such as riscv64,
+ # where it flags the byte-buffer-to-header casts the protocol code is built on.
+ set(COMMON_WARNINGS ${COMMON_WARNINGS} -Werror -Wno-error=cast-align)
set(MSVC_WARNINGS ${MSVC_WARNINGS} /WX)
endif()

Loading