Add the shared pull-request template (taphouse sync) #208
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| pull_request: | |
| concurrency: | |
| # Superseded pushes cancel their own in-flight runs: the ratchet stack | |
| # (three QEMU targets, a toolchain download, minutes of runner time) was | |
| # piling up once per push during baseline harvests. | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| build-and-test: | |
| name: ${{ matrix.name }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: Linux GCC | |
| os: ubuntu-latest | |
| cc: gcc | |
| cxx: g++ | |
| werror: ON | |
| - name: Linux Clang | |
| os: ubuntu-latest | |
| cc: clang | |
| cxx: clang++ | |
| werror: ON | |
| - name: macOS AppleClang | |
| os: macos-latest | |
| werror: ON | |
| # Warnings stay non-fatal on MSVC until /W4 output has been | |
| # triaged (docs/PERFORMANCE.md "Known debt"). | |
| - name: Windows MSVC | |
| os: windows-latest | |
| werror: OFF | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Configure | |
| env: | |
| CC: ${{ matrix.cc }} | |
| CXX: ${{ matrix.cxx }} | |
| run: > | |
| cmake -B build | |
| -DCMAKE_BUILD_TYPE=Release | |
| -DSRT_WERROR=${{ matrix.werror }} | |
| - name: Build | |
| run: cmake --build build --config Release -j 4 | |
| - name: Test | |
| run: ctest --test-dir build -C Release --output-on-failure | |
| sanitizers: | |
| name: ${{ matrix.name }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: ASan + UBSan | |
| flags: -fsanitize=address,undefined -fno-sanitize-recover=all | |
| - name: TSan | |
| flags: -fsanitize=thread | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Configure | |
| env: | |
| CC: clang | |
| CXX: clang++ | |
| run: > | |
| cmake -B build | |
| -DCMAKE_BUILD_TYPE=RelWithDebInfo | |
| -DSRT_BUILD_EXAMPLES=OFF | |
| -DCMAKE_CXX_FLAGS="${{ matrix.flags }}" | |
| - name: Build | |
| run: cmake --build build -j 4 | |
| - name: Test | |
| env: | |
| TSAN_OPTIONS: halt_on_error=1 | |
| UBSAN_OPTIONS: print_stacktrace=1 | |
| run: ctest --test-dir build --output-on-failure | |
| # Cross-compile for Qualcomm Hexagon (Linux/musl) with the open-source | |
| # toolchain and run a subset of the suite under qemu-hexagon user-mode | |
| # emulation. Validates ISA-level correctness on a 32-bit audio DSP target | |
| # (size_t width, atomics lowering, musl libc, soft-float doubles); the | |
| # long-running quality/lock simulations and the 10M-element thread stress | |
| # are excluded — they prove DSP math and concurrency, which emulation | |
| # neither speeds up nor measures meaningfully. | |
| hexagon-qemu: | |
| name: Hexagon cross (QEMU) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| env: | |
| # Prebuilt open-source toolchain (BSD-3) published by Qualcomm/Quicinc; | |
| # binary artifacts are hosted on CodeLinaro and linked from the | |
| # quic/toolchain_for_hexagon release notes. | |
| HEXAGON_TOOLCHAIN_URL: https://artifacts.codelinaro.org/artifactory/codelinaro-toolchain-for-hexagon/19.1.5/clang+llvm-19.1.5-cross-hexagon-unknown-linux-musl.tar.zst | |
| # Hard pin, taken from the "toolchain sha256:" line of run #13 (which | |
| # also matched the published SHA256SUMS). | |
| HEXAGON_TOOLCHAIN_SHA256: "55b41922318f6331590ab7baa7f5dbdd99c109327a9c44a52c5e9878fab148c1" | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Cache toolchain | |
| id: cache | |
| uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: ~/hexagon | |
| # Keyed on the pinned digest: every job that can write this key | |
| # verifies its download against the same pin, so no unverified | |
| # writer can poison the trusted entry. | |
| key: hexagon-toolchain-${{ env.HEXAGON_TOOLCHAIN_SHA256 }}-1 | |
| - name: Download toolchain | |
| if: steps.cache.outputs.cache-hit != 'true' | |
| run: | | |
| mkdir -p ~/hexagon && cd ~/hexagon | |
| curl -sfLo toolchain.tar.zst "$HEXAGON_TOOLCHAIN_URL" | |
| # Integrity check against the published SHA256SUMS, plus the hard | |
| # pin when set. The SUMS file catches corruption and | |
| # cache-poisoning; only the pin catches an origin compromise. | |
| curl -sfLo SHA256SUMS "$(dirname "$HEXAGON_TOOLCHAIN_URL")/SHA256SUMS" | |
| expected=$(grep "$(basename "$HEXAGON_TOOLCHAIN_URL")" SHA256SUMS | awk '{print $1}' | head -1) | |
| actual=$(sha256sum toolchain.tar.zst | cut -d' ' -f1) | |
| echo "toolchain sha256: $actual (pin this in HEXAGON_TOOLCHAIN_SHA256)" | |
| if [ -z "$expected" ] || [ "$actual" != "$expected" ]; then | |
| echo "::error::toolchain does not match published SHA256SUMS"; exit 1 | |
| fi | |
| if [ -n "${HEXAGON_TOOLCHAIN_SHA256:-}" ] && \ | |
| [ "$actual" != "$HEXAGON_TOOLCHAIN_SHA256" ]; then | |
| echo "::error::toolchain checksum mismatch against pinned value"; exit 1 | |
| fi | |
| tar --zstd -xf toolchain.tar.zst | |
| rm toolchain.tar.zst SHA256SUMS | |
| - name: Set up toolchain and QEMU paths | |
| run: | | |
| # No -type f (symlinks count); dirname of an empty find result is | |
| # ".", so assert on the find output itself. | |
| clangxx=$(find "$HOME/hexagon" -name 'hexagon-unknown-linux-musl-clang++' | head -1) | |
| test -n "$clangxx" | |
| echo "$(dirname "$clangxx")" >> "$GITHUB_PATH" | |
| # Prefer a qemu-hexagon bundled with the toolchain; else use distro qemu. | |
| qemu=$(find "$HOME/hexagon" -name 'qemu-hexagon' -type f | head -1 || true) | |
| if [ -n "$qemu" ]; then | |
| echo "$(dirname "$qemu")" >> "$GITHUB_PATH" | |
| else | |
| sudo apt-get update -q && sudo apt-get install -y -q qemu-user | |
| fi | |
| - name: Verify tools | |
| run: | | |
| hexagon-unknown-linux-musl-clang++ --version | |
| qemu-hexagon --version | |
| - name: Configure | |
| run: > | |
| cmake -B build | |
| -DCMAKE_BUILD_TYPE=Release | |
| -DCMAKE_TOOLCHAIN_FILE=cmake/hexagon-linux-musl.cmake | |
| -DSRT_BUILD_EXAMPLES=OFF | |
| - name: Build | |
| run: cmake --build build -j 4 | |
| - name: Test under emulation | |
| run: > | |
| ctest --test-dir build --output-on-failure | |
| -E 'AsrcQuality|AsrcLock|TwoThreadStress|TransparentPrototypeMeetsSpec|MultiChannel\.|Feasibility|Reset\.|ConfigValidation' | |
| # ConfigValidation: this static-musl toolchain cannot unwind across | |
| # frames — the constructor throws correctly but EXPECT_THROW never | |
| # catches and libc++abi terminates. Validation is target-independent | |
| # and covered on every other leg; limitation tracked in | |
| # docs/PERFORMANCE.md "Known debt". | |
| # Cross-compile for Arm Cortex-M55 (bare metal, newlib + semihosting) and | |
| # run the emulation-sized test subset on QEMU's MPS3 AN547 board model. | |
| # Validates the library on a 32-bit MCU-class target with no OS, no | |
| # threads and no double-precision FPU; the fixed-point datapaths are the | |
| # performance-appropriate formats here. | |
| cortex-m55-qemu: | |
| name: Cortex-M55 cross (QEMU) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Install toolchain and QEMU | |
| run: > | |
| sudo apt-get update -q && | |
| sudo apt-get install -y -q gcc-arm-none-eabi qemu-system-arm | |
| - name: Configure | |
| run: > | |
| cmake -B build | |
| -DCMAKE_BUILD_TYPE=MinSizeRel | |
| -DCMAKE_TOOLCHAIN_FILE=cmake/arm-cortex-m55-mps3.cmake | |
| -DSRT_BUILD_EXAMPLES=OFF | |
| - name: Build | |
| run: cmake --build build -j 4 | |
| - name: Test under emulation | |
| run: ctest --test-dir build --output-on-failure | |
| # Cortex-M33 (Raspberry Pi Pico 2 / RP2350 class: single-precision FPU, | |
| # no FP64, no MVE) on QEMU's MPS2+ AN505 model. Shares the Armv8-M | |
| # startup with the M55 target; quantifies the soft-double float path and | |
| # anchors the Q15/Q31 budgets for Pico-class parts. | |
| cortex-m33-qemu: | |
| name: Cortex-M33 cross (QEMU) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Install toolchain and QEMU | |
| run: > | |
| sudo apt-get update -q && | |
| sudo apt-get install -y -q gcc-arm-none-eabi qemu-system-arm | |
| - name: Configure | |
| run: > | |
| cmake -B build | |
| -DCMAKE_BUILD_TYPE=MinSizeRel | |
| -DCMAKE_TOOLCHAIN_FILE=cmake/arm-cortex-m33-mps2.cmake | |
| -DSRT_BUILD_EXAMPLES=OFF | |
| - name: Build | |
| run: cmake --build build -j 4 | |
| - name: Test under emulation | |
| run: ctest --test-dir build --output-on-failure | |
| # ------------------------------------------------------------------------ | |
| # Template: genuine Tensilica HiFi4/HiFi5 coverage. The HiFi audio ISA, | |
| # xt-clang compiler and xt-run instruction-set simulator are proprietary | |
| # (FlexLM-licensed Cadence tools), so this must run on a self-hosted | |
| # runner with access to the license server. Uncomment and adapt once such | |
| # a runner is registered (suggested labels: [self-hosted, cadence-xtensa]). | |
| # | |
| # hifi-iss: | |
| # name: HiFi ISS (self-hosted) | |
| # runs-on: [self-hosted, cadence-xtensa] | |
| # env: | |
| # XTENSA_CORE: <your HiFi core name> | |
| # steps: | |
| # - uses: actions/checkout@v4 | |
| # - name: Configure | |
| # run: > | |
| # cmake -B build | |
| # -DCMAKE_BUILD_TYPE=Release | |
| # -DCMAKE_SYSTEM_NAME=Generic | |
| # -DCMAKE_C_COMPILER=xt-clang | |
| # -DCMAKE_CXX_COMPILER=xt-clang++ | |
| # "-DCMAKE_CROSSCOMPILING_EMULATOR=xt-run;--xtensa-core=$XTENSA_CORE" | |
| # -DSRT_BUILD_EXAMPLES=OFF | |
| # - name: Build | |
| # run: cmake --build build -j | |
| # - name: Test on ISS | |
| # run: > | |
| # ctest --test-dir build --output-on-failure | |
| # -E 'AsrcQuality|AsrcLock|TwoThreadStress|TransparentPrototypeMeetsSpec' | |
| # ------------------------------------------------------------------------ | |
| # Deterministic instruction-count ratchet (docs/PERFORMANCE.md): fixed | |
| # workloads under QEMU with a counting plugin, gated against | |
| # bench/baselines.json. Unlike wall-clock numbers these are noise-free, | |
| # so a hard >3% gate is safe on shared runners. | |
| icount-ratchet: | |
| name: Instruction-count ratchet | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| env: | |
| # Commit the v8.2.2 tag pointed at when pinned (tags are movable; | |
| # commit SHAs are not), with the header's digest verified on download. | |
| QEMU_PLUGIN_HEADER_URL: https://raw.githubusercontent.com/qemu/qemu/11aa0b1ff115b86160c4d37e7c37e6a6b13b77ea/include/qemu/qemu-plugin.h | |
| QEMU_PLUGIN_HEADER_SHA256: "c53a2af163e80e3f4bc6c60dbdfc84003db329d757e37cd8a16a77e1d82606ff" | |
| QEMU_SRC_URL: https://download.qemu.org/qemu-8.2.2.tar.xz | |
| # Hard pin from the "qemu source sha256:" line of run #24. | |
| QEMU_SRC_SHA256: "847346c1b82c1a54b2c38f6edbd85549edeb17430b7d4d3da12620e2962bc4f3" | |
| HEXAGON_TOOLCHAIN_URL: https://artifacts.codelinaro.org/artifactory/codelinaro-toolchain-for-hexagon/19.1.5/clang+llvm-19.1.5-cross-hexagon-unknown-linux-musl.tar.zst | |
| # Same hard pin as the hexagon-qemu job: this job also writes the | |
| # shared toolchain cache, so it must verify against the same digest. | |
| HEXAGON_TOOLCHAIN_SHA256: "55b41922318f6331590ab7baa7f5dbdd99c109327a9c44a52c5e9878fab148c1" | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Install toolchains and QEMU | |
| run: > | |
| sudo apt-get update -q && | |
| sudo apt-get install -y -q gcc-arm-none-eabi qemu-system-arm | |
| libglib2.0-dev ninja-build meson flex bison | |
| - name: Build counting plugin | |
| run: | | |
| curl -sfLo /tmp/qemu-plugin.h "$QEMU_PLUGIN_HEADER_URL" | |
| actual=$(sha256sum /tmp/qemu-plugin.h | cut -d' ' -f1) | |
| if [ "$actual" != "$QEMU_PLUGIN_HEADER_SHA256" ]; then | |
| echo "::error::qemu-plugin.h checksum mismatch"; exit 1 | |
| fi | |
| gcc -shared -fPIC $(pkg-config --cflags glib-2.0) -I/tmp \ | |
| -o /tmp/libinsncount.so tools/qemu_insn_plugin/insn_count.c | |
| # Release (-O2), matching how the baselines were recorded. | |
| - name: Build M55 workloads | |
| run: > | |
| cmake -B build-m55 | |
| -DCMAKE_BUILD_TYPE=Release | |
| -DCMAKE_TOOLCHAIN_FILE=cmake/arm-cortex-m55-mps3.cmake | |
| -DSRT_BUILD_TESTS=OFF -DSRT_BUILD_EXAMPLES=OFF | |
| -DSRT_BUILD_ICOUNT_BENCH=ON | |
| && cmake --build build-m55 -j 4 | |
| - name: Ratchet M55 | |
| run: > | |
| python3 scripts/icount.py --target m55 | |
| --build-dir build-m55 --plugin /tmp/libinsncount.so | |
| - name: Build M33 workloads | |
| if: ${{ !cancelled() }} | |
| run: > | |
| cmake -B build-m33 | |
| -DCMAKE_BUILD_TYPE=Release | |
| -DCMAKE_TOOLCHAIN_FILE=cmake/arm-cortex-m33-mps2.cmake | |
| -DSRT_BUILD_TESTS=OFF -DSRT_BUILD_EXAMPLES=OFF | |
| -DSRT_BUILD_ICOUNT_BENCH=ON | |
| && cmake --build build-m33 -j 4 | |
| - name: Ratchet M33 | |
| if: ${{ !cancelled() }} | |
| run: > | |
| python3 scripts/icount.py --target m33 | |
| --build-dir build-m33 --plugin /tmp/libinsncount.so | |
| # Neither Debian's nor the CodeLinaro toolchain's qemu-hexagon enables | |
| # TCG plugins, so the Hexagon leg builds its own from the pinned QEMU | |
| # release (linux-user target only, ~4 min, cached thereafter). | |
| # The remaining ratchet steps run even if an earlier target failed | |
| # (each target's numbers are independent evidence; stopping at the | |
| # first failure forces a serial harvest when baselines legitimately | |
| # move). The job still fails if any step failed. | |
| - name: Cache plugin-enabled qemu-hexagon | |
| if: ${{ !cancelled() }} | |
| id: qemu-hex | |
| uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: ~/qemu-hexagon-plugins | |
| key: qemu-hexagon-plugins-${{ env.QEMU_SRC_URL }}-1 | |
| - name: Build plugin-enabled qemu-hexagon | |
| if: ${{ !cancelled() && steps.qemu-hex.outputs.cache-hit != 'true' }} | |
| run: | | |
| curl -sfLo /tmp/qemu-src.tar.xz "$QEMU_SRC_URL" | |
| actual=$(sha256sum /tmp/qemu-src.tar.xz | cut -d' ' -f1) | |
| echo "qemu source sha256: $actual (pin this in QEMU_SRC_SHA256)" | |
| if [ -n "${QEMU_SRC_SHA256:-}" ] && [ "$actual" != "$QEMU_SRC_SHA256" ]; then | |
| echo "::error::qemu source checksum mismatch"; exit 1 | |
| fi | |
| tar -xJf /tmp/qemu-src.tar.xz -C /tmp | |
| cd /tmp/qemu-*/ | |
| ./configure --target-list=hexagon-linux-user --enable-plugins \ | |
| --disable-docs --disable-tools --disable-system | |
| ninja -C build qemu-hexagon | |
| mkdir -p ~/qemu-hexagon-plugins | |
| cp build/qemu-hexagon ~/qemu-hexagon-plugins/ | |
| - name: Cache Hexagon toolchain | |
| if: ${{ !cancelled() }} | |
| id: cache | |
| uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: ~/hexagon | |
| # Same digest-keyed name as the hexagon-qemu job; the download | |
| # below verifies the same pin before anything is saved under it. | |
| key: hexagon-toolchain-${{ env.HEXAGON_TOOLCHAIN_SHA256 }}-1 | |
| - name: Ratchet Hexagon | |
| if: ${{ !cancelled() }} | |
| run: | | |
| if [ "${{ steps.cache.outputs.cache-hit }}" != "true" ]; then | |
| mkdir -p ~/hexagon && cd ~/hexagon | |
| curl -sfLo toolchain.tar.zst "$HEXAGON_TOOLCHAIN_URL" | |
| actual=$(sha256sum toolchain.tar.zst | cut -d' ' -f1) | |
| if [ "$actual" != "$HEXAGON_TOOLCHAIN_SHA256" ]; then | |
| echo "::error::toolchain checksum mismatch against pinned value" | |
| exit 1 | |
| fi | |
| tar --zstd -xf toolchain.tar.zst && rm toolchain.tar.zst | |
| cd "$GITHUB_WORKSPACE" | |
| fi | |
| # No -type f: the compiler may be a symlink in the restored tree. | |
| clangxx=$(find "$HOME/hexagon" -name 'hexagon-unknown-linux-musl-clang++' | head -1) | |
| if [ -z "$clangxx" ]; then | |
| echo "contents of ~/hexagon:" | |
| ls -la "$HOME/hexagon" 2>&1 | head -20 | |
| find "$HOME/hexagon" -maxdepth 3 | head -40 | |
| echo "::error::hexagon cross compiler not found under ~/hexagon" | |
| exit 1 | |
| fi | |
| bindir=$(dirname "$clangxx") | |
| export PATH="$HOME/qemu-hexagon-plugins:$bindir:$PATH" | |
| test -x "$HOME/qemu-hexagon-plugins/qemu-hexagon" || { | |
| echo "::error::plugin-enabled qemu-hexagon missing"; exit 1; } | |
| # qemu exits 1 with or without plugin support here (no guest binary | |
| # was given), so probe by the error text, not the exit code. | |
| if qemu-hexagon -plugin help 2>&1 | grep -q "unknown option"; then | |
| echo "::error::built qemu-hexagon lacks plugin support"; exit 1 | |
| fi | |
| cmake -B build-hex -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_TOOLCHAIN_FILE=cmake/hexagon-linux-musl.cmake \ | |
| -DSRT_BUILD_TESTS=OFF -DSRT_BUILD_EXAMPLES=OFF \ | |
| -DSRT_BUILD_ICOUNT_BENCH=ON | |
| cmake --build build-hex -j 4 | |
| python3 scripts/icount.py --target hexagon \ | |
| --build-dir build-hex --plugin /tmp/libinsncount.so | |
| # The README instruction-count table derives 1:1 from the committed | |
| # baselines; regenerating it must produce no diff. | |
| - name: Docs freshness | |
| run: | | |
| python3 scripts/update_icount_docs.py | |
| git diff --exit-code README.md || { | |
| echo "::error::README icount table is stale; run scripts/update_icount_docs.py"; exit 1; } | |
| # Keeps the benchmarks compiling and runnable; never a performance gate | |
| # (shared runners are noise — see docs/PERFORMANCE.md). | |
| bench-smoke: | |
| name: Benchmark smoke | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Configure | |
| run: > | |
| cmake -B build | |
| -DCMAKE_BUILD_TYPE=Release | |
| -DSRT_BUILD_BENCHMARKS=ON | |
| -DSRT_BUILD_TESTS=OFF | |
| -DSRT_BUILD_EXAMPLES=OFF | |
| - name: Build | |
| run: cmake --build build -j 4 | |
| - name: Run (smoke) | |
| run: ./build/bench/srt_bench --benchmark_min_time=0.01s | |
| # Keeps the manually-triggered comparison paths (compare.yml, | |
| # bench/compare) compiling per push; build-only — the measured numbers | |
| # come from the manual workflow, never from here. | |
| compare-smoke: | |
| name: Comparison build smoke | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Install dependencies | |
| run: > | |
| sudo apt-get update -q && | |
| sudo apt-get install -y -q libsamplerate0-dev libsoxr-dev | |
| gcc-arm-none-eabi | |
| - name: Build host comparison bench | |
| run: > | |
| cmake -B build-host | |
| -DCMAKE_BUILD_TYPE=Release | |
| -DSRT_BUILD_BENCHMARKS=ON | |
| -DSRT_BUILD_COMPARE_BENCH=ON | |
| && cmake --build build-host -j 4 --target srt_bench_compare | |
| - name: Build M55 comparison workload | |
| run: > | |
| cmake -B build-m55 | |
| -DCMAKE_BUILD_TYPE=Release | |
| -DCMAKE_TOOLCHAIN_FILE=cmake/arm-cortex-m55-mps3.cmake | |
| -DSRT_BUILD_TESTS=OFF -DSRT_BUILD_EXAMPLES=OFF | |
| -DSRT_BUILD_ICOUNT_BENCH=ON -DSRT_ICOUNT_COMPARE=ON | |
| && cmake --build build-m55 -j 4 --target cmp_icount_lsr_medium | |
| clang-format: | |
| name: clang-format | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| # Run the TapHouse pre-commit hook — the same pinned clang-format | |
| # developers get from `pre-commit install` (.pre-commit-config.yaml), so | |
| # local and CI share one version AND one file scope (all C/C++ minus | |
| # third_party) by construction. pipx is preinstalled on the runner. | |
| - name: Check formatting (pre-commit) | |
| run: | | |
| pipx install pre-commit | |
| pre-commit run --all-files --show-diff-on-failure | |
| # The book (book/) quotes library code via mdBook anchor includes; this | |
| # gate makes a refactor that orphans an excerpt fail CI, the same | |
| # freshness contract as the README's generated tables. Warnings are | |
| # errors: a missing anchor is a warning, and a missing anchor is rot. | |
| book: | |
| name: Book build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| env: | |
| MDBOOK_URL: https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz | |
| MDBOOK_SHA256: "9ef07fd288ba58ff3b99d1c94e6d414d431c9a61fdb20348e5beb74b823d546b" | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| submodules: recursive | |
| - name: Install mdBook (pinned) | |
| run: | | |
| curl -sfLo /tmp/mdbook.tar.gz "$MDBOOK_URL" | |
| actual=$(sha256sum /tmp/mdbook.tar.gz | cut -d' ' -f1) | |
| if [ "$actual" != "$MDBOOK_SHA256" ]; then | |
| echo "::error::mdbook checksum mismatch"; exit 1 | |
| fi | |
| tar -xzf /tmp/mdbook.tar.gz -C /tmp | |
| - name: Build (warnings are errors) | |
| run: | | |
| /tmp/mdbook build book 2>&1 | tee /tmp/book-build.log | |
| if grep -qiE 'warning|error' /tmp/book-build.log; then | |
| echo "::error::mdbook reported warnings/errors (stale anchor or broken include?)" | |
| exit 1 | |
| fi | |
| # mdBook does not fail on a missing image, so check every relative | |
| # image reference resolves. (The SVGs are committed, generated by | |
| # scripts/book_figures.py; regeneration is not gated because | |
| # matplotlib's SVG output is not byte-stable across versions.) | |
| - name: Check image references resolve | |
| run: | | |
| python3 - <<'EOF' | |
| import pathlib, re, sys | |
| src = pathlib.Path("book/src") | |
| missing = [] | |
| for md in src.rglob("*.md"): | |
| for target in re.findall(r"!\[[^\]]*\]\(([^)#?]+)", md.read_text()): | |
| if target.startswith(("http://", "https://")): | |
| continue | |
| if not (md.parent / target).resolve().exists(): | |
| missing.append(f"{md}: {target}") | |
| if missing: | |
| print("::error::broken image reference(s):") | |
| print("\n".join(missing)) | |
| sys.exit(1) | |
| EOF |