Skip to content
Open
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
337 changes: 337 additions & 0 deletions .github/workflows/build-home-assistant-chip-core.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on the `build_prepare`/`build_linux_python_lib` jobs of:
# https://github.com/home-assistant-libs/chip-wheels/blob/2025.7.0/.github/workflows/build.yaml
name: Build home-assistant-chip-core wheels (riscv64)

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

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

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

env:
# gn/gn git_revision pinned by the Pigweed submodule's cipd_setup/pigweed.json
GN_REVISION: 487f8353f15456474437df32bb186187b0940b45
# infra/3pp/tools/protoc version pinned by the same pigweed.json
PROTOC_VERSION: '28.2'
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: home-assistant-chip-core
version: ${{ inputs.version }}

# ZAP code generation has no riscv64 build (project-chip/zap ships prebuilt
# Electron/node binaries for x86_64/arm64 only), so it runs once here on a
# regular x86_64 runner, as in chip-wheels' own build_prepare, and
# build_wheels consumes it via chip_code_pre_generated_directory, which
# never invokes ZAP itself. Unlike chip-wheels, only zzz_pregenerated/ is
# handed over, not a tar of the whole SDK: the riscv64 runners download
# Actions artifacts at ~1 MB/s in one non-resumable stream, so that ~4 GB tar
# took over an hour and failed whenever the stream broke, while the same
# checkout and patches straight from GitHub take minutes there.
build_prepare:
name: Prepare home-assistant-chip-core ${{ matrix.version }}
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
runs-on: ubuntu-24.04
env:
CHIP_VERSION: ${{ matrix.version }}

steps:
- name: Checkout home-assistant-libs/chip-wheels ${{ env.CHIP_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: home-assistant-libs/chip-wheels
ref: ${{ env.CHIP_VERSION }}
submodules: true
persist-credentials: false

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

- name: Checkout connectedhomeip submodules
working-directory: connectedhomeip
run: scripts/checkout_submodules.py --shallow --platform linux

- name: Apply riscv64 patches
working-directory: connectedhomeip
run: git apply ../python-wheels/patches/home-assistant-chip-core/${{ env.CHIP_VERSION }}/*.patch

- name: Apply chip-wheels patches
working-directory: connectedhomeip
run: |
for patch in ../*.patch; do
echo "Applying ${patch}"
patch -p1 < "$patch"
done

- name: Bootstrap
working-directory: connectedhomeip
run: bash scripts/bootstrap.sh -p all,linux

- name: ZAP code pre-generation
working-directory: connectedhomeip
run: scripts/run_in_build_env.sh "scripts/codepregen.py ./zzz_pregenerated/"

- name: Create ZAP pre-generated code tar
run: tar -caf zzz_pregenerated-${{ env.CHIP_VERSION }}.tar.zst --use-compress-program=zstdmt -C connectedhomeip zzz_pregenerated

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: home-assistant-chip-core-${{ env.CHIP_VERSION }}-zap-pregenerated
path: zzz_pregenerated-${{ env.CHIP_VERSION }}.tar.zst
if-no-files-found: error

build_wheels:
needs: [setup, build_prepare]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build home-assistant-chip-core ${{ matrix.version }} cp37-abi3-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 1440 # full Pigweed/GN/Ninja CHIP SDK compile from source
# container.image can't read the env context, so the image is repeated
# literally here; MANYLINUX_RISCV64_IMAGE below still pins gpl_sources to
# the same one.
container:
image: quay.io/pypa/manylinux_2_39_riscv64

defaults:
run:
working-directory: connectedhomeip

env:
CHIP_VERSION: ${{ matrix.version }}
# CHIP's constraints.txt pins protobuf==5.28.3, which ships binary (upb)
# wheels for x86_64/aarch64 only, so on riscv64 pip picks its
# py3-none-any wheel: the pure-Python backend. That backend has no
# FieldOptions.RegisterExtension, which the extensions_pb2.py bundled in
# the pinned mypy-protobuf 3.5.0 calls, so every protoc --mypy_out step
# in Bootstrap fails. Build protobuf from its sdist instead, which
# compiles the same upb extension the other platforms get.
PIP_NO_BINARY: protobuf
# Pigweed pip-installs its own package with --no-build-isolation, so a
# dependency with no riscv64 wheel is built in the Pigweed venv, which
# has no maturin (or Rust) for cryptography's sdist. Take cryptography
# (pinned to 43.0.1 by patch 0004) and its cffi from our registry.
# Patch 0005 also moves that venv's pip off CHIP's 23.2.1, which lists
# no manylinux_*_riscv64 tags and so can't see these wheels at all
# (gotchas 234/640).
PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/
PIP_ONLY_BINARY: cryptography,cffi

steps:
- name: Checkout home-assistant-libs/chip-wheels ${{ env.CHIP_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: home-assistant-libs/chip-wheels
ref: ${{ env.CHIP_VERSION }}
submodules: true
persist-credentials: false

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

- name: Install system dependencies
working-directory: ./
run: |
# cairo-gobject-devel ships cairo-gobject.h; chip-repl's pygobject==3.50.0
# dependency needs it for its pygi-foreign-cairo.c Cairo integration.
dnf install -y --enablerepo=crb zstd \
openssl-devel glib2-devel libnl3-devel cairo-devel \
cairo-gobject-devel gobject-introspection-devel dbus-devel \
python3-devel libstdc++-static
git config --global --add safe.directory '*'
echo "/opt/python/cp312-cp312/bin" >> "$GITHUB_PATH"

- name: Checkout connectedhomeip submodules
run: scripts/checkout_submodules.py --shallow --platform linux

- name: Apply riscv64 patches
run: git apply ../python-wheels/patches/home-assistant-chip-core/${{ env.CHIP_VERSION }}/*.patch

- name: Apply chip-wheels patches
run: |
for patch in ../*.patch; do
echo "Applying ${patch}"
patch -p1 < "$patch"
done

- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: home-assistant-chip-core-${{ env.CHIP_VERSION }}-zap-pregenerated

- name: Extract ZAP pre-generated code
run: tar -xaf ../zzz_pregenerated-${{ env.CHIP_VERSION }}.tar.zst --use-compress-program=zstdmt

# Rocky 10's riscv64 CIPD backend has no fuchsia/third_party/ninja build
# at all, and gn_gen.sh's own gn/ninja fetch goes through the CIPD
# client this job's patched pigweed wrapper.py bootstraps -- same "no
# CIPD gn/ninja on riscv64" situation build-skia-python.yml/
# build-skia-pathops.yml already solved: build gn from source and get
# ninja from its own riscv64 PyPI wheel, ahead of bootstrap.sh.
#
# gn's own link step passes -static-libstdc++, which needs
# libstdc++.a -- the riscv64 manylinux image doesn't ship it by
# default (CLAUDE.md gotcha 77), hence libstdc++-static above.
- name: Install gn and ninja
run: |
set -e
python3 -m pip install ninja
git clone https://gn.googlesource.com/gn /tmp/gn
git -C /tmp/gn checkout "${GN_REVISION}"
(cd /tmp/gn && CXX=g++ python3 build/gen.py --allow-warnings && ninja -C out gn)
install -m 0755 /tmp/gn/out/gn /usr/local/bin/gn

# Pigweed's bootstrap runs a bare `protoc` from PATH to generate the
# Python protos, and infra/3pp/tools/protoc has no linux-riscv64 CIPD
# build. CRB's protobuf-compiler (3.19.6) rejects --experimental_editions
# and the riscv64 grpcio-tools bundles protoc 35, whose output won't load
# under CHIP's protobuf==5.28.3, so build Pigweed's own version. The
# well-known .protos go in /opt/protoc/include, found relative to the binary.
- name: Install protoc
run: |
set -e
git clone --depth 1 --branch "v${PROTOC_VERSION}" https://github.com/protocolbuffers/protobuf /tmp/protobuf
git -C /tmp/protobuf submodule update --init --depth 1 third_party/abseil-cpp
cmake -S /tmp/protobuf -B /tmp/protobuf/build -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/protoc \
-Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_BUILD_LIBUPB=OFF -Dprotobuf_WITH_ZLIB=OFF
cmake --build /tmp/protobuf/build --target protoc
cmake --install /tmp/protobuf/build --component protoc
cmake --install /tmp/protobuf/build --component protobuf-headers
ln -s /opt/protoc/bin/protoc /usr/local/bin/protoc
protoc --version

- name: Bootstrap
run: bash scripts/bootstrap.sh -p linux

- name: Setup build and run build
run: |
scripts/build/gn_gen.sh --args=" \
chip_project_config_include_dirs=[\"//..\"] \
chip_crypto=\"boringssl\" \
enable_rtti=true \
chip_config_memory_debug_checks=false \
chip_config_memory_debug_dmalloc=false \
chip_exchange_node_id_logging=true \
chip_mdns=\"minimal\" \
chip_minmdns_default_policy=\"libnl\" \
chip_python_version=\"${{ env.CHIP_VERSION }}\" \
chip_python_package_prefix=\"home-assistant-chip\" \
chip_python_platform_tag=\"manylinux_2_39\" \
chip_code_pre_generated_directory=\"$(pwd)/zzz_pregenerated\" \
"
scripts/run_in_build_env.sh "ninja -C ./out chip-repl"

- name: Run Python library specific unit tests
run: |
scripts/run_in_build_env.sh 'pip3 install ./out/controller/python/home_assistant_chip_core-${{ env.CHIP_VERSION }}-cp37-abi3-manylinux_2_39_riscv64.whl'
scripts/run_in_build_env.sh 'pip3 install ./out/controller/python/home_assistant_chip_clusters-${{ env.CHIP_VERSION }}-py3-none-any.whl'
scripts/run_in_build_env.sh 'pip3 install ./out/controller/python/home_assistant_chip_repl-${{ env.CHIP_VERSION }}-py3-none-any.whl'
scripts/run_in_build_env.sh '(cd src/controller/python/test/unit_tests/ && python3 -m unittest -v)'

# Only chip-core goes in the wheelhouse. The build also emits
# home_assistant_chip_clusters and home_assistant_chip_repl, which the
# unit tests above install, but those are separate PyPI projects that
# upstream already ships as pure-Python py3-none-any wheels (no
# extension, Root-Is-Purelib), so riscv64 installs them from PyPI as is.
# _publish-wheel.yml also publishes exactly one project per run and
# rejects a wheelhouse mixing project names.
- name: Repair wheel
run: |
mkdir -p ../wheelhouse
pip3 install auditwheel
auditwheel repair -w ../wheelhouse --plat manylinux_2_39_riscv64 \
out/controller/python/home_assistant_chip_core-${{ env.CHIP_VERSION }}-cp37-abi3-manylinux_2_39_riscv64.whl

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: home-assistant-chip-core-${{ env.CHIP_VERSION }}-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error

gpl_sources:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Collect GPL sources (glib2, libnl3) for home-assistant-chip-core ${{ matrix.version }}
runs-on: ubuntu-24.04-riscv
env:
CHIP_VERSION: ${{ matrix.version }}

steps:
# auditwheel vendors the image's libglib-2.0/libgobject-2.0/libgio-2.0
# (glib2, LGPL) and libnl-3/libnl-route-3 (libnl3, LGPL) into the wheel.
- name: Collect glib2/libnl3 source RPMs from manylinux_riscv64
uses: riseproject-dev/python-wheels/actions/collect-gpl-sources@main
with:
image: ${{ env.MANYLINUX_RISCV64_IMAGE }}
packages: glib2 libnl3
output: gpl-sources.tar

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: home-assistant-chip-core-${{ env.CHIP_VERSION }}-gpl-sources
path: gpl-sources.tar
if-no-files-found: error

publish:
name: Publish home-assistant-chip-core ${{ matrix.version }}
needs: [setup, build_wheels, gpl_sources]
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: home-assistant-chip-core-${{ matrix.version }}-manylinux_riscv64
gpl-sources-artifact: home-assistant-chip-core-${{ matrix.version }}-gpl-sources
gpl-sources-description: glib2, libnl3
5 changes: 5 additions & 0 deletions docs/packages/home-assistant-chip-core.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package-name: home-assistant-chip-core
source-code: https://github.com/home-assistant-libs/chip-wheels
license: Apache-2.0
versions:
- version: 2025.7.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Thu, 15 Oct 2026 00:00:00 +0000
Subject: [PATCH] pigweed: cipd_setup/wrapper.py: support linux-riscv64

Upstream-Status: To upstream [not yet submitted to google/pigweed]

cipd_setup/wrapper.py bootstraps the standalone `cipd` client binary
used by Pigweed's env setup. Two separate bugs there make it reject
riscv64 entirely, even though the CIPD backend itself already serves a
linux-riscv64 client (chrome-infra-packages.appspot.com, and
.cipd_version.digests lists a linux-riscv64 sha256 for the pinned
client version):

- arch_normalized() only special-cases arm/aarch64; everything else
falls through to `machine.endswith('64')`, which maps the literal
string "riscv64" to "amd64" because it also ends in "64".
- SUPPORTED_PLATFORMS is a hardcoded tuple that never listed
"linux-riscv64" to begin with, so client_bytes() would raise
UnsupportedPlatform even with the arch mapping fixed.

Neither function used by this wheel's actual package-selection logic
(cipd_setup/update.py:platform(), which already falls back to the
literal "riscv64" string) needs a patch; only the client bootstrap
path in this file does.

Signed-off-by: Ludovic Henry <git@ludovic.dev>
---
third_party/pigweed/repo/pw_env_setup/py/pw_env_setup/cipd_setup/wrapper.py | 3 +++
1 file changed, 3 insertions(+)

diff --git a/third_party/pigweed/repo/pw_env_setup/py/pw_env_setup/cipd_setup/wrapper.py b/third_party/pigweed/repo/pw_env_setup/py/pw_env_setup/cipd_setup/wrapper.py
index 151745d..75228bc 100644
--- a/third_party/pigweed/repo/pw_env_setup/py/pw_env_setup/cipd_setup/wrapper.py
+++ b/third_party/pigweed/repo/pw_env_setup/py/pw_env_setup/cipd_setup/wrapper.py
@@ -51,6 +51,7 @@ SUPPORTED_PLATFORMS = (
'linux-mipsle',
'linux-ppc64',
'linux-ppc64le',
+ 'linux-riscv64',
'linux-s390x',
'mac-amd64',
'mac-arm64',
@@ -135,6 +136,8 @@ def arch_normalized(rosetta=False):
if machine == 'arm64':
return machine
return 'armv6l'
+ if machine == 'riscv64':
+ return machine
if machine.endswith('64'):
return 'amd64'
if machine.endswith('86'):
--
2.50.1
Loading
Loading