From 46c418e699878ebf467c9caa150a8f5ed477b25e Mon Sep 17 00:00:00 2001 From: ihb2032 Date: Thu, 27 Aug 2026 15:47:46 +0800 Subject: [PATCH 1/2] ci: add riscv64 RVV cross-compile workflow ported from faiss Port faiss's linux-riscv64-DD-cmake job (build-pull-request.yml) so PRs get riscv64 coverage without native hardware: - .github/workflows/08-linux-riscv64-rvv-cross.yml: cross-compile with gcc-14-riscv64-linux-gnu using faiss's proven multiarch apt setup (minus libopenblas-dev/libgomp1: no BLAS, ENABLE_OPENMP=OFF), then build and run the whole ailego unit test suite (61 targets) under qemu-user-static with -cpu rv64,v=true,zihintpause=true. - cmake/toolchains/riscv64-linux-gnu.cmake: riscv64-linux-gnu toolchain file ported from faiss, with overridable compiler names. - .github/workflows/01-ci-pipeline.yml: wire the new workflow into the main pipeline. - .github/workflows/10-cmake-subproject-integration.yml: renumbered from 08 to free the slot (standalone nightly, no references by filename). The job passes -DENABLE_RISCV64/-DENABLE_RISCV_VECTOR/ -DENABLE_RISCV_ZIHINTPAUSE; until the RISC-V platform support lands on main these are unused warnings and the job runs as a plain rv64gc cross-compile smoke test. Co-authored-by: lyd1992 Co-authored-by: YuanSheng --- .github/workflows/01-ci-pipeline.yml | 10 + .../workflows/08-linux-riscv64-rvv-cross.yml | 174 ++++++++++++++++++ ...ml => 10-cmake-subproject-integration.yml} | 0 cmake/toolchains/riscv64-linux-gnu.cmake | 39 ++++ 4 files changed, 223 insertions(+) create mode 100644 .github/workflows/08-linux-riscv64-rvv-cross.yml rename .github/workflows/{08-cmake-subproject-integration.yml => 10-cmake-subproject-integration.yml} (100%) create mode 100644 cmake/toolchains/riscv64-linux-gnu.cmake diff --git a/.github/workflows/01-ci-pipeline.yml b/.github/workflows/01-ci-pipeline.yml index 6a0395600..c900f40e0 100644 --- a/.github/workflows/01-ci-pipeline.yml +++ b/.github/workflows/01-ci-pipeline.yml @@ -121,3 +121,13 @@ jobs: name: Build & Test (musllinux) needs: [lint, clang-tidy] uses: ./.github/workflows/09-musllinux-build.yml + + # RISC-V Vector (RVV) smoke test: cross-compile for riscv64 and run the + # ailego unit tests under qemu-user (ported from faiss's + # linux-riscv64-DD-cmake job). Complements the weekly native riscv + # build (07-linux-riscv-build.yml) with per-PR coverage. + build-and-test-linux-riscv64-rvv-cross: + if: github.event_name != 'push' || github.ref != 'refs/heads/main' + name: Build & Test (linux-riscv64 RVV cross) + needs: [lint, clang-tidy] + uses: ./.github/workflows/08-linux-riscv64-rvv-cross.yml diff --git a/.github/workflows/08-linux-riscv64-rvv-cross.yml b/.github/workflows/08-linux-riscv64-rvv-cross.yml new file mode 100644 index 000000000..3b82d8540 --- /dev/null +++ b/.github/workflows/08-linux-riscv64-rvv-cross.yml @@ -0,0 +1,174 @@ +name: Linux riscv64 RVV Cross Compile + +# Ported from faiss's linux-riscv64-DD-cmake job (build-pull-request.yml): +# cross-compile on an x86_64 runner with gcc-14-riscv64-linux-gnu, then run +# the unit tests under qemu-user. +# +# zvec specifics: +# - The apt setup follows faiss (multiarch :riscv64 packages + +# ubuntu-ports repo + sysroot symlink) because that package set is +# proven to work upstream; only libopenblas-dev and libgomp1 are +# dropped (zvec has no BLAS dependency and builds with +# ENABLE_OPENMP=OFF). +# - Test scope: the whole ailego unit test suite (tests/ailego/**/*_test.cc, +# 61 targets). Those cover the RVV-relevant code paths (CpuFeatures +# runtime detection + math kernels) while staying cheap: every target +# links only the static zvec_ailego + gtest, so no heavy thirdparty +# (arrow/rocksdb/...) cross builds are needed. Like faiss, the full test +# suite is not run under qemu — that would take hours under emulation. +# - ENABLE_RISCV64 / ENABLE_RISCV_VECTOR / ENABLE_RISCV_ZIHINTPAUSE are the +# RVV build options from the RISC-V platform support. Until that support +# lands on main, CMake warns about the unused variables and the job runs +# as a plain rv64gc cross-compile smoke test. +# - ENABLE_RISCV_ZVFH is intentionally left off: the test asserts +# CpuFeatures::RISCV_ZVFH() when compiled with Zvfh, but qemu-user's +# riscv_hwprobe emulation may not report ZVFH, which would fail the run +# spuriously. +# - QEMU gets an explicit -cpu with the extensions the binary is built +# with, instead of relying on the (version-dependent) default CPU. + +on: + workflow_call: + workflow_dispatch: + +permissions: + contents: read + +jobs: + build-and-test: + name: Linux riscv64 RVV cross-compile (cmake) + runs-on: ubuntu-24.04 + timeout-minutes: 60 + + steps: + - name: Checkout code + uses: actions/checkout@v7 + with: + submodules: recursive + + # Apt setup follows faiss's linux-riscv64-DD-cmake job (proven + # upstream): enable the riscv64 multiarch architecture, add the + # ubuntu-ports repo, install the target libraries, and symlink the + # multiarch lib dir into the cross sysroot for CMake's ONLY find-root + # mode and the qemu -L runtime lookup. faiss's libopenblas-dev and + # libgomp1 are dropped: zvec has no BLAS dependency and builds with + # ENABLE_OPENMP=OFF. + - name: Set up riscv64 cross-compilation environment + run: | + sudo dpkg --add-architecture riscv64 + + # Ubuntu 24.04 deb822 sources: keep host packages amd64/i386 only. + if [ -f /etc/apt/sources.list.d/ubuntu.sources ]; then + sudo sed -i '/^Types: deb$/a Architectures: amd64 i386' \ + /etc/apt/sources.list.d/ubuntu.sources + fi + + if grep -q '^deb http' /etc/apt/sources.list 2>/dev/null; then + sudo sed -i 's|^deb http|deb [arch=amd64,i386] http|g' \ + /etc/apt/sources.list + fi + + CODENAME=$(. /etc/os-release && echo "$VERSION_CODENAME") + + echo "deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports ${CODENAME} main restricted universe multiverse" \ + | sudo tee /etc/apt/sources.list.d/riscv64-ports.list + + echo "deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports ${CODENAME}-updates main restricted universe multiverse" \ + | sudo tee -a /etc/apt/sources.list.d/riscv64-ports.list + + sudo apt-get update -qq + + sudo apt-get install -y -qq \ + cmake \ + gcc-14-riscv64-linux-gnu \ + g++-14-riscv64-linux-gnu \ + libc6:riscv64 \ + libc6-dev:riscv64 \ + libstdc++6:riscv64 \ + libgcc-s1:riscv64 \ + qemu-user-static + + echo "Checking GCC version:" + riscv64-linux-gnu-gcc-14 --version + riscv64-linux-gnu-g++-14 --version + + # Prepare sysroot library lookup + sudo mkdir -p /usr/riscv64-linux-gnu/usr/lib + + sudo ln -sfn /usr/lib/riscv64-linux-gnu \ + /usr/riscv64-linux-gnu/usr/lib/riscv64-linux-gnu + shell: bash + + - name: Setup ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: linux-riscv64-rvv-cross-${{ runner.os }}-gcc + max-size: 150M + + - name: Configure (cmake) + run: | + cmake -B build \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_C_COMPILER=riscv64-linux-gnu-gcc-14 \ + -DCMAKE_CXX_COMPILER=riscv64-linux-gnu-g++-14 \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TOOLS=OFF \ + -DBUILD_PYTHON_BINDINGS=OFF \ + -DENABLE_RISCV64=ON \ + -DENABLE_RISCV_VECTOR=ON \ + -DENABLE_RISCV_ZIHINTPAUSE=ON \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + . + shell: bash + + # Test target names are the *_test.cc file stems + # (see tests/ailego/CMakeLists.txt: get_filename_component(... NAME_WE)). + - name: Build ailego unit tests + run: | + mapfile -t AILEGO_TESTS < <(find tests/ailego -name '*_test.cc' -exec basename {} .cc \;) + echo "Building ${#AILEGO_TESTS[@]} ailego test targets:" + printf ' %s\n' "${AILEGO_TESTS[@]}" + cmake --build build --target "${AILEGO_TESTS[@]}" -j"$(nproc)" + shell: bash + + - name: Verify binary with ldd (via qemu) + run: | + file build/bin/cpu_features_test + + file build/bin/cpu_features_test | grep -q "RISC-V" || \ + { echo "ERROR: not a RISC-V binary"; exit 1; } + + RISCV64_LD=$(find /usr/riscv64-linux-gnu/lib \ + -name "ld-linux-riscv64-*.so.1" | head -1) + + qemu-riscv64-static \ + -L /usr/riscv64-linux-gnu \ + "$RISCV64_LD" \ + --list \ + build/bin/cpu_features_test + shell: bash + + # Mirrors how ctest runs these tests: each in its own + # build/test_tmp/ working directory (created at configure time). + # Run everything and report all failures instead of stopping at the + # first one. + - name: Run ailego unit tests (via QEMU) + run: | + FAILED=() + for t in $(find tests/ailego -name '*_test.cc' -exec basename {} .cc \;); do + echo "=== $t ===" + ( cd "build/test_tmp/$t" && \ + qemu-riscv64-static \ + -L /usr/riscv64-linux-gnu \ + -cpu rv64,v=true,zihintpause=true \ + "$GITHUB_WORKSPACE/build/bin/$t" ) || FAILED+=("$t") + done + + if [ ${#FAILED[@]} -ne 0 ]; then + echo "FAILED tests (${#FAILED[@]}):" + printf ' %s\n' "${FAILED[@]}" + exit 1 + fi + echo "All ailego unit tests passed." + shell: bash diff --git a/.github/workflows/08-cmake-subproject-integration.yml b/.github/workflows/10-cmake-subproject-integration.yml similarity index 100% rename from .github/workflows/08-cmake-subproject-integration.yml rename to .github/workflows/10-cmake-subproject-integration.yml diff --git a/cmake/toolchains/riscv64-linux-gnu.cmake b/cmake/toolchains/riscv64-linux-gnu.cmake new file mode 100644 index 000000000..92633a0ab --- /dev/null +++ b/cmake/toolchains/riscv64-linux-gnu.cmake @@ -0,0 +1,39 @@ +## Cross-compilation toolchain for RISC-V 64-bit (lp64d ABI) on Ubuntu/Debian. +## +## Ported from faiss (cmake/toolchains/riscv64-linux-gnu.cmake) for the +## riscv64 RVV cross-compile CI job (.github/workflows/08-linux-riscv64-rvv-cross.yml). +## +## Required host packages (Ubuntu 24.04), same as faiss's CI: +## gcc-14-riscv64-linux-gnu g++-14-riscv64-linux-gnu +## libc6:riscv64 libc6-dev:riscv64 libstdc++6:riscv64 libgcc-s1:riscv64 +## +## Target libraries are installed via apt multiarch to +## /usr/lib/riscv64-linux-gnu/. CMake's ONLY find-root mode searches +## ${CMAKE_FIND_ROOT_PATH}/usr/lib/riscv64-linux-gnu/ (via the compiler's +## multiarch tuple), so the CI job creates this symlink before configuring: +## /usr/riscv64-linux-gnu/usr/lib/riscv64-linux-gnu +## -> /usr/lib/riscv64-linux-gnu +## +## Pin a specific GCC version from the command line if needed: +## cmake -DCMAKE_C_COMPILER=riscv64-linux-gnu-gcc-14 \ +## -DCMAKE_CXX_COMPILER=riscv64-linux-gnu-g++-14 ... + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR riscv64) + +if(NOT DEFINED CMAKE_C_COMPILER) + set(CMAKE_C_COMPILER riscv64-linux-gnu-gcc) +endif() +if(NOT DEFINED CMAKE_CXX_COMPILER) + set(CMAKE_CXX_COMPILER riscv64-linux-gnu-g++) +endif() + +# Cross-compiler sysroot provided by the gcc-riscv64-linux-gnu packages. +set(CMAKE_FIND_ROOT_PATH /usr/riscv64-linux-gnu) + +# Never look for host-side tools (cmake, python, ...) inside the sysroot. +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# Look for target libraries/headers/packages only inside the sysroot. +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) From 8ee9c35a36dfeecb235b2790587a24a143e4bfb6 Mon Sep 17 00:00:00 2001 From: ihb2032 Date: Thu, 27 Aug 2026 16:06:55 +0800 Subject: [PATCH 2/2] ci: enable RISCV_ZVFH and install qemu-user-static >= 9.2 Ubuntu 24.04 ships qemu-user-static 8.2, which does not emulate the riscv_hwprobe syscall (emulation added in qemu 9.2, reporting V and ZVFH from the -cpu config), so the hwprobe-based CpuFeatures detection would always report false once the RISC-V platform support lands. Install the newest static qemu build from the Ubuntu package pool (currently 9.2.1), enable ENABLE_RISCV_ZVFH, and run the tests with -cpu rv64,v=true,zvfh=true,zihintpause=true. Co-authored-by: lyd1992 Co-authored-by: YuanSheng --- .../workflows/08-linux-riscv64-rvv-cross.yml | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/.github/workflows/08-linux-riscv64-rvv-cross.yml b/.github/workflows/08-linux-riscv64-rvv-cross.yml index 3b82d8540..963e70b29 100644 --- a/.github/workflows/08-linux-riscv64-rvv-cross.yml +++ b/.github/workflows/08-linux-riscv64-rvv-cross.yml @@ -16,14 +16,16 @@ name: Linux riscv64 RVV Cross Compile # links only the static zvec_ailego + gtest, so no heavy thirdparty # (arrow/rocksdb/...) cross builds are needed. Like faiss, the full test # suite is not run under qemu — that would take hours under emulation. -# - ENABLE_RISCV64 / ENABLE_RISCV_VECTOR / ENABLE_RISCV_ZIHINTPAUSE are the -# RVV build options from the RISC-V platform support. Until that support -# lands on main, CMake warns about the unused variables and the job runs -# as a plain rv64gc cross-compile smoke test. -# - ENABLE_RISCV_ZVFH is intentionally left off: the test asserts -# CpuFeatures::RISCV_ZVFH() when compiled with Zvfh, but qemu-user's -# riscv_hwprobe emulation may not report ZVFH, which would fail the run -# spuriously. +# - ENABLE_RISCV64 / ENABLE_RISCV_VECTOR / ENABLE_RISCV_ZVFH / +# ENABLE_RISCV_ZIHINTPAUSE are the RVV build options from the RISC-V +# platform support. Until that support lands on main, CMake warns about +# the unused variables and the job runs as a plain rv64gc cross-compile +# smoke test. +# - The runtime detection behind CpuFeatures::RISCV_VECTOR()/RISCV_ZVFH() +# uses the riscv_hwprobe syscall, which qemu-user only emulates since +# 9.2 (V and ZVFH are both reported from the -cpu config there). Ubuntu +# 24.04 ships qemu 8.2, so a newer qemu-user-static is installed from +# the Ubuntu package pool. # - QEMU gets an explicit -cpu with the extensions the binary is built # with, instead of relying on the (version-dependent) default CPU. @@ -85,8 +87,7 @@ jobs: libc6:riscv64 \ libc6-dev:riscv64 \ libstdc++6:riscv64 \ - libgcc-s1:riscv64 \ - qemu-user-static + libgcc-s1:riscv64 echo "Checking GCC version:" riscv64-linux-gnu-gcc-14 --version @@ -99,6 +100,24 @@ jobs: /usr/riscv64-linux-gnu/usr/lib/riscv64-linux-gnu shell: bash + # Ubuntu 24.04's qemu-user-static is 8.2, which predates qemu-user's + # riscv_hwprobe emulation (added in 9.2) — CpuFeatures::RISCV_VECTOR()/ + # RISCV_ZVFH() would always report false. Install the newest static + # build from the Ubuntu pool instead; the -static package is + # self-contained, so it installs fine on 24.04. + - name: Install qemu-user-static >= 9.2 + run: | + QEMU_DEB=$( + curl -sL http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu/ \ + | grep -oE 'qemu-user-static_(9\.[2-9]|[1-9][0-9]+\.)[^"]*_amd64\.deb' \ + | sort -uV | tail -1 + ) + echo "Selected ${QEMU_DEB}" + curl -sLO "http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu/${QEMU_DEB}" + sudo apt-get install -y "./${QEMU_DEB}" + qemu-riscv64-static --version + shell: bash + - name: Setup ccache uses: hendrikmuhs/ccache-action@v1.2 with: @@ -116,6 +135,7 @@ jobs: -DBUILD_PYTHON_BINDINGS=OFF \ -DENABLE_RISCV64=ON \ -DENABLE_RISCV_VECTOR=ON \ + -DENABLE_RISCV_ZVFH=ON \ -DENABLE_RISCV_ZIHINTPAUSE=ON \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ @@ -161,7 +181,7 @@ jobs: ( cd "build/test_tmp/$t" && \ qemu-riscv64-static \ -L /usr/riscv64-linux-gnu \ - -cpu rv64,v=true,zihintpause=true \ + -cpu rv64,v=true,zvfh=true,zihintpause=true \ "$GITHUB_WORKSPACE/build/bin/$t" ) || FAILED+=("$t") done