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
155 changes: 155 additions & 0 deletions .github/workflows/build-pyrnnoise.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# Based on upstream's own wheel build at this commit:
# https://github.com/pengzhendong/pyrnnoise/blob/a4edc69/.github/workflows/release.yml
name: Build pyrnnoise wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/pyrnnoise.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-pyrnnoise.yml'
- 'docs/packages/pyrnnoise.yaml'
- 'patches/pyrnnoise/**'
push:
branches: [main]
paths:
- '.github/workflows/build-pyrnnoise.yml'
- 'docs/packages/pyrnnoise.yaml'
- 'patches/pyrnnoise/**'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
# Upstream cuts releases from a workflow_dispatch that stamps VERSION at
# build time (never committed) and tags no commit at all. This is the
# commit whose tree (pyrnnoise/pyrnnoise.py, requirements.txt) is
# byte-identical to the released 0.4.3 sdist/wheel contents.
PYRNNOISE_REF: a4edc697a2f475dcdac14c453d7c06eebbd06b33
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

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

build_wheels:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build pyrnnoise ${{ matrix.version }} py3-none-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 90

env:
PYRNNOISE_VERSION: ${{ matrix.version }}

steps:
- name: Checkout pyrnnoise ${{ env.PYRNNOISE_REF }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: pengzhendong/pyrnnoise
ref: ${{ env.PYRNNOISE_REF }}
submodules: true
persist-credentials: false

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

- name: Patch pyrnnoise source
run: git apply python-wheels/patches/pyrnnoise/${{ env.PYRNNOISE_VERSION }}/*.patch

# Matches release.yml's own `echo "$RELEASE_VERSION" > VERSION` step;
# setup.py reads VERSION verbatim and the checkout above carries
# whatever placeholder was last committed to it.
- name: Stamp VERSION
run: echo "${{ env.PYRNNOISE_VERSION }}" > VERSION

- uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
output-dir: wheelhouse/
# setup.py ships no ext_modules and forces root_is_pure = False
# (the C library is loaded via ctypes), so setuptools tags the
# wheel py3-none and one build serves every interpreter.
only: cp312-manylinux_riscv64
env:
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
# Mirrors release.yml's own `cmake --build ... --target install`
# step, run here instead since setup.py does not invoke cmake
# itself. The image ships no cmake or wget (gotcha 289); the
# CMakeLists.txt wget call fetches the pretrained model weights
# that rnnoise_data.c/.h are generated from.
CIBW_BEFORE_ALL_LINUX: >-
dnf install -y cmake wget &&
cmake -B build -DCMAKE_BUILD_TYPE=Release &&
cmake --build build --target install --parallel
# matplotlib, an unconditional runtime dependency, has no
# musllinux_riscv64 wheel on this registry, so musllinux is
# dropped (same outcome as build-keystone-engine.yml).
CIBW_ENVIRONMENT: PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
CIBW_TEST_ENVIRONMENT: PIP_ONLY_BINARY=numpy,matplotlib,av,soundfile,soxr
CIBW_TEST_COMMAND: >-
python -c "import numpy as np;
from pyrnnoise.rnnoise import create, destroy, process_frame, FRAME_SIZE;
state = create();
frame = np.zeros(FRAME_SIZE, dtype=np.int16);
out, prob = process_frame(state, frame);
assert out.shape == (FRAME_SIZE,), out.shape;
destroy(state);
print('pyrnnoise OK')"

- name: Check the wheel carries librnnoise and RNNoise's licence
run: |
python3 - wheelhouse/*.whl <<'EOF'
import sys, zipfile

for whl in sys.argv[1:]:
names = zipfile.ZipFile(whl).namelist()
assert any(n.endswith("pyrnnoise/librnnoise.so") for n in names), whl
licences = {n.rsplit("/", 1)[-1] for n in names if "dist-info/licenses/" in n and not n.endswith("/")}
assert licences == {"LICENSE", "LICENSE.rnnoise"}, (whl, licences)
print(whl, "ok")
EOF

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: pyrnnoise-${{ env.PYRNNOISE_VERSION }}-py3-none-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish pyrnnoise ${{ 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: pyrnnoise-${{ matrix.version }}-*riscv64
5 changes: 5 additions & 0 deletions docs/packages/pyrnnoise.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package-name: pyrnnoise
source-code: https://github.com/pengzhendong/pyrnnoise
license: Apache-2.0
versions:
- version: 0.4.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 5 Oct 2026 00:00:00 +0000
Subject: [PATCH] Add RNNoise's LICENSE at project root

librnnoise.so is built from the xiph/rnnoise git submodule and statically
linked into every pyrnnoise wheel, but setup.py ships no license_files
list and the submodule's own COPYING (BSD-3-Clause) lives outside the
project root, so setuptools' default LICEN[CS]E*/COPYING*/NOTICE*/
AUTHORS* glob never picks it up. Every wheel on PyPI currently ships
only pyrnnoise's own Apache-2.0 LICENSE.

Copy rnnoise/COPYING to the root as LICENSE.rnnoise, which the existing
default glob already matches with no setup.py change.

Upstream-Status: To upstream [not submitted from this automated port run; needs a pull request against pengzhendong/pyrnnoise]
---
LICENSE.rnnoise | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 LICENSE.rnnoise

diff --git a/LICENSE.rnnoise b/LICENSE.rnnoise
new file mode 100644
index 0000000..59d7d09
--- /dev/null
+++ b/LICENSE.rnnoise
@@ -0,0 +1,32 @@
+Copyright (c) 2007-2017, 2024 Jean-Marc Valin
+Copyright (c) 2023 Amazon
+Copyright (c) 2017, Mozilla
+Copyright (c) 2005-2017, Xiph.Org Foundation
+Copyright (c) 2003-2004, Mark Borgerding
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.Org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
2.43.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 5 Oct 2026 00:00:00 +0000
Subject: [PATCH] setup.py: force platlib placement for auditwheel

custom_bdist_wheel.finalize_options sets root_is_pure = False to get a
platform-specific wheel tag, but setup.py declares no ext_modules, so
distutils' install_lib command still treats the build as pure and
installs every file (including librnnoise.so) under the wheel's
purelib data category. auditwheel's manylinux/musllinux repair step
refuses to process a shared library placed there: "Invalid binary
wheel, found the following shared library/libraries in purelib
folder: librnnoise.so. The wheel has to be platlib compliant in order
to be repaired by auditwheel."

Overriding has_ext_modules() to True makes install_lib install the
whole package to platlib instead, which lands it at the wheel root
with no .data split and lets auditwheel repair the wheel normally.

Upstream-Status: Inappropriate [upstream's own release.yml never runs auditwheel on any platform, so this only matters for a build pipeline like this one's]
---
setup.py | 1 +
1 file changed, 1 insertion(+)

diff --git a/setup.py b/setup.py
index a6fba1b..ca22400 100644
--- a/setup.py
+++ b/setup.py
@@ -23,6 +23,7 @@ class custom_bdist_wheel(bdist_wheel):
def finalize_options(self):
bdist_wheel.finalize_options(self)
self.root_is_pure = False
+ self.distribution.has_ext_modules = lambda: True

def get_tag(self):
python, abi, plat = bdist_wheel.get_tag(self)
--
2.43.0
Loading