Repository navigation
release: the openipc.org push succeeds on a 200 and nothing else #120
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: PR Build Check | |
| on: | |
| pull_request: | |
| branches: [master] | |
| jobs: | |
| build: | |
| name: Build ${{ matrix.target }} (musl static) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: arm32 | |
| toolchain_url: https://github.com/OpenIPC/firmware/releases/download/toolchain/toolchain.hisilicon-hi3516cv100.tgz | |
| toolchain_dir: arm-openipc-linux-musleabi_sdk-buildroot | |
| cc: arm-openipc-linux-musleabi-gcc | |
| - target: mips32 | |
| toolchain_url: https://github.com/OpenIPC/firmware/releases/download/toolchain/toolchain.ingenic-t31.tgz | |
| toolchain_dir: mipsel-openipc-linux-musl_sdk-buildroot | |
| cc: mipsel-openipc-linux-musl-gcc | |
| - target: arm64 | |
| # Bootlin's prebuilt aarch64 musl cross toolchain. Switch | |
| # to an OpenIPC-hosted tarball once one is published. | |
| toolchain_url: https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64/tarballs/aarch64--musl--stable-2025.08-1.tar.xz | |
| toolchain_dir: aarch64--musl--stable-2025.08-1 | |
| cc: aarch64-buildroot-linux-musl-gcc | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| # The size step below builds the PR's base commit as well as its | |
| # head, so the history has to be there to check out. | |
| fetch-depth: 0 | |
| - name: Fetch toolchain | |
| run: | | |
| # Download to file (with retries) before extracting — piping | |
| # wget -> tar makes transient stream truncations look like | |
| # corrupt archives; the wget retry only helps with discrete | |
| # files. | |
| wget --tries=3 --timeout=60 -O /tmp/toolchain.tar "${{ matrix.toolchain_url }}" | |
| # `tar xf` autodetects gzip/bzip2/xz so the matrix entries | |
| # can mix archive formats freely. | |
| tar xf /tmp/toolchain.tar -C /opt | |
| rm /tmp/toolchain.tar | |
| - name: Build | |
| run: | | |
| export PATH=/opt/${{ matrix.toolchain_dir }}/bin:$PATH | |
| cmake -H. -Bbuild -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_BUILD_TYPE=Release | |
| cmake --build build | |
| - name: ipcinfo size | |
| # ipcinfo ships on all but three of the OpenIPC firmware tree's board | |
| # configs, onto cameras whose rootfs cap leaves tens of KB spare, and | |
| # nothing here measured it until now -- the job above builds a static | |
| # binary, which is not what those images carry. | |
| # | |
| # The configure below reproduces the firmware package's: shared libs | |
| # (which is what drops the global -static), SKIP_VERSION, and | |
| # CMAKE_C_FLAGS_RELEASE cleared. That last one matters. CMake appends | |
| # its own "-O3 -DNDEBUG" after CMAKE_C_FLAGS, so a plain Release | |
| # configure silently measures -O3; Buildroot's toolchain file clears | |
| # the variable, which is why the firmware genuinely gets the -Os this | |
| # file asks for. | |
| # | |
| # The comparison is against the PR's base commit, not a number written | |
| # down here. This job's toolchain is not one any camera is built with | |
| # -- it is whatever toolchain.hisilicon-hi3516cv100.tgz ships, and it | |
| # produces an ipcinfo some 12 KB larger than the gcc 13.3 toolchains | |
| # the boards use -- so an absolute ceiling here would describe no | |
| # shipped binary and would go stale the moment that URL moves. A | |
| # delta does not care which compiler measured it. | |
| if: matrix.target == 'arm32' | |
| run: | | |
| export PATH=/opt/${{ matrix.toolchain_dir }}/bin:$PATH | |
| measure() { | |
| out=$(mktemp -d) | |
| cmake -H"$1" -B"$out" -DCMAKE_C_COMPILER=${{ matrix.cc }} \ | |
| -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE=" -DNDEBUG" \ | |
| -DBUILD_SHARED_LIBS=ON -DSKIP_VERSION=ON \ | |
| -DIPCHW_VENDORS="$2" > /dev/null | |
| cmake --build "$out" --target ipcinfo > /dev/null | |
| stat -c %s "$out/ipcinfo" | |
| } | |
| git worktree add -f /tmp/ipcinfo-base \ | |
| "${{ github.event.pull_request.base.sha }}" > /dev/null | |
| status=0 | |
| # "all" is what the firmware tree builds today; "none" is what it | |
| # builds once its ipctool.mk passes the knob added in #178. | |
| for vendors in all none; do | |
| base=$(measure /tmp/ipcinfo-base "$vendors") | |
| head=$(measure . "$vendors") | |
| delta=$((head - base)) | |
| echo "ipcinfo, IPCHW_VENDORS=$vendors: $base -> $head ($delta bytes)" | |
| if [ "$delta" -gt 1024 ]; then | |
| echo "::error::ipcinfo (IPCHW_VENDORS=$vendors) grows $delta bytes. Over the 1024-byte budget: say in the PR why the camera should carry it." | |
| status=1 | |
| elif [ "$delta" -gt 0 ]; then | |
| echo "::warning::ipcinfo (IPCHW_VENDORS=$vendors) grows $delta bytes." | |
| fi | |
| done | |
| exit $status | |
| test-extraction-pipeline: | |
| name: Test sensor extraction pipeline | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Run end-to-end pipeline smoke test | |
| run: tools/test_pipeline.sh | |
| - name: Check the HiSilicon sensor-clock suite is still wired in | |
| # In this job and not in unit-tests, for the reason that job's own | |
| # guard gives: a check that runs only once the thing it protects has | |
| # run protects nothing. Anchored to a bare invocation line so this | |
| # step's own text cannot satisfy it. | |
| run: | | |
| grep -qE '^[[:space:]]*\./build/hal_hisi_test[[:space:]]*$' \ | |
| .github/workflows/pr-build-check.yml \ | |
| || { echo "no job in this workflow runs hal_hisi_test"; exit 1; } | |
| unit-tests: | |
| name: Unit tests (native) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Check the pipeline suite is still wired in | |
| # Deliberately NOT inside test_pipeline.sh: a check that only runs | |
| # once the thing it protects has already run protects nothing. | |
| # It lives in this job rather than test-extraction-pipeline for the | |
| # same reason -- both jobs are required, so dropping that job's step | |
| # leaves this one still failing. | |
| # Matches a run: line and nothing else. A bare grep for the script | |
| # name finds this very step's own text and can never fail. | |
| run: | | |
| grep -qE '^[[:space:]]*run:[[:space:]]*tools/test_pipeline\.sh[[:space:]]*$' \ | |
| .github/workflows/pr-build-check.yml \ | |
| || { echo "no job in this workflow runs tools/test_pipeline.sh"; exit 1; } | |
| - name: Build and run | |
| run: | | |
| cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release | |
| cmake --build build --target cYAML_test reginfo_test longse_test \ | |
| sensors_test anyka_test hal_hisi_test \ | |
| report_test | |
| ./build/cYAML_test | |
| ./build/report_test | |
| ./build/reginfo_test | |
| ./build/longse_test | |
| ./build/anyka_test | |
| ./build/hal_hisi_test | |
| # Run from the tree root: the fingerprint it compares against is | |
| # src/sensors_golden.txt, and a sensor that stopped being identified | |
| # has to fail here rather than be noticed on a camera in a ceiling. | |
| ./build/sensors_test src/sensors_golden.txt | |
| - name: Build trimmed, and run again | |
| # The pad tables are the largest thing in libipchw and a consumer | |
| # picks the families it targets. Prove the trimmed configure | |
| # compiles and that reginfo_test still passes when most of the | |
| # tables are not there. | |
| run: | | |
| cmake -H. -Bbuild-trimmed -DCMAKE_BUILD_TYPE=Release \ | |
| -DIPCHW_VENDORS=none -DIPCHW_PADMUX=v1 -DIPCHW_HISI=v4 | |
| cmake --build build-trimmed --target reginfo_test | |
| ./build-trimmed/reginfo_test | |
| - name: Every IPCHW_HISI selection compiles | |
| # Each generation guards a different set of arms -- a chip-ID case, a | |
| # temperature formula, a sensor-bus back-end, a die-ID reader -- and a | |
| # guard that swallows a #define or leaves a dangling else only shows up | |
| # in the one selection that needs it. Three of these broke while the | |
| # knob was being written, each in a different generation, so sweep all | |
| # of them rather than trusting the two that a person happens to build. | |
| # libipchw alone, natively: it is the target that carries the guards, | |
| # and it keeps the sweep to a few seconds. | |
| run: | | |
| status=0 | |
| for gen in all none v1 v2 v2a "v2;v2a" v3 v3a v4 v4a v5 3536c 3536d; do | |
| dir=build-hisi-$(echo "$gen" | tr -d ';') | |
| if cmake -H. -B"$dir" -DCMAKE_BUILD_TYPE=Release \ | |
| -DIPCHW_VENDORS=none -DIPCHW_HISI="$gen" > "$dir.log" 2>&1 \ | |
| && cmake --build "$dir" --target ipchw >> "$dir.log" 2>&1; then | |
| echo "IPCHW_HISI=$gen ok" | |
| else | |
| echo "::error::IPCHW_HISI=$gen does not build" | |
| tail -30 "$dir.log" | |
| status=1 | |
| fi | |
| done | |
| exit $status | |
| - name: The interned pad names are current | |
| # src/padmux_names.{h,c} are generated from the MUXCTRL tables, and | |
| # nothing at build time regenerates them: a cross build must not need | |
| # python3 in the toolchain container. So the staleness check is here. | |
| # A row that names a function the table does not carry fails to | |
| # compile, which is the loud half; a name left in the blob after its | |
| # last row went is the quiet half, and this is what catches it. | |
| run: python3 tools/gen_padmux_names.py --check | |
| - name: Every IPCHW_PADMUX selection compiles, and its tables still read | |
| # Same shape as the IPCHW_HISI sweep above and the same reason, only | |
| # sharper since the names were interned: each family's entries in | |
| # struct padmux_names sit behind that family's #if, so a guard that | |
| # names the wrong family builds everywhere except the one selection | |
| # that needs it. reginfo_test is built as well as ipchw because a | |
| # table that compiles and reads back the wrong name is the failure | |
| # this is really for. | |
| run: | | |
| status=0 | |
| for fam in all none v1 v2 v2a v3 v3a v4 v4a v5 3536c 3536d \ | |
| sstar ingenic "v4;sstar"; do | |
| dir=build-padmux-$(echo "$fam" | tr -d ';') | |
| if cmake -H. -B"$dir" -DCMAKE_BUILD_TYPE=Release \ | |
| -DIPCHW_PADMUX="$fam" > "$dir.log" 2>&1 \ | |
| && cmake --build "$dir" --target reginfo_test >> "$dir.log" 2>&1 \ | |
| && ./"$dir"/reginfo_test >> "$dir.log" 2>&1; then | |
| echo "IPCHW_PADMUX=$fam ok" | |
| else | |
| echo "::error::IPCHW_PADMUX=$fam does not build or does not pass" | |
| tail -30 "$dir.log" | |
| status=1 | |
| fi | |
| done | |
| exit $status | |
| - name: IPCHW_HISI's default follows IPCHW_VENDORS | |
| # A default is the kind of thing that drifts without anyone noticing, | |
| # and the two spellings that must NOT move are the two ipcinfo is | |
| # built as: its own "all", and the firmware package's "none", which | |
| # means only the always-in vendors and so IS a HiSilicon build. A | |
| # silently HiSi-blind ipcinfo would be worse than a large one. | |
| # | |
| # Configure only -- this asserts the cache value, not a binary. | |
| run: | | |
| status=0 | |
| check() { # <vendors|-> <hisi|-> <expected> | |
| d=$(mktemp -d) | |
| args=(-H. -B"$d" -DSKIP_VERSION=ON -DONLY_LIBRARY=ON) | |
| [ "$1" != "-" ] && args+=(-DIPCHW_VENDORS="$1") | |
| [ "$2" != "-" ] && args+=(-DIPCHW_HISI="$2") | |
| if ! cmake "${args[@]}" > "$d/log" 2>&1; then | |
| echo "::error::configure failed for VENDORS=$1 HISI=$2" | |
| tail -20 "$d/log"; status=1; rm -rf "$d"; return | |
| fi | |
| got=$(grep '^IPCHW_HISI:STRING=' "$d/CMakeCache.txt" | cut -d= -f2-) | |
| if [ "$got" = "$3" ]; then | |
| printf 'ok VENDORS=%-16s HISI=%-8s -> %s\n' "$1" "$2" "$got" | |
| else | |
| echo "::error::VENDORS=$1 HISI=$2 gave IPCHW_HISI=$got, wanted $3" | |
| status=1 | |
| fi | |
| rm -rf "$d" | |
| } | |
| check - - all # ipctool's own default | |
| check all - all # ipcinfo's default: must not move | |
| check none - all # firmware's ipcinfo: a HiSi build | |
| check ingenic - none # a narrowing implies no HiSilicon | |
| check sstar - none | |
| check "ingenic;sstar" - none | |
| check ingenic all all # an explicit value always wins | |
| check ingenic v4 v4 | |
| check all none none | |
| # And the same question asked of ONE build directory, reconfigured. | |
| # This is where the first cut of this was wrong: the derived value | |
| # lands in the cache, and on the next configure it is | |
| # indistinguishable from one the user typed -- so a tree first | |
| # configured with a narrowed vendor kept IPCHW_HISI=none when it was | |
| # later broadened to `all`, and that build could not identify a | |
| # HiSilicon camera. Build directories are reused across boards. | |
| d=$(mktemp -d) | |
| step() { # <cmake args...> <expected> | |
| exp="${!#}"; set -- "${@:1:$#-1}" | |
| if ! cmake -H. -B"$d" -DSKIP_VERSION=ON -DONLY_LIBRARY=ON "$@" \ | |
| > "$d/log" 2>&1; then | |
| echo "::error::reconfigure failed: $*"; tail -20 "$d/log" | |
| status=1; return | |
| fi | |
| got=$(grep '^IPCHW_HISI:' "$d/CMakeCache.txt" | cut -d= -f2-) | |
| if [ "$got" = "$exp" ]; then | |
| printf 'ok reconfigure %-38s -> %s\n' "$*" "$got" | |
| else | |
| echo "::error::reconfigure $* gave IPCHW_HISI=$got, wanted $exp" | |
| status=1 | |
| fi | |
| } | |
| step -DIPCHW_VENDORS=ingenic none # narrowed | |
| step -DIPCHW_VENDORS=all all # broadened: must follow | |
| step -DIPCHW_VENDORS=sstar none # narrowed again | |
| step -DIPCHW_VENDORS=none all # a HiSilicon build | |
| rm -rf "$d"; d=$(mktemp -d) | |
| step -DIPCHW_VENDORS=all -DIPCHW_HISI=v4 v4 # explicit | |
| step -DIPCHW_VENDORS=ingenic v4 # and it survives a vendor change | |
| rm -rf "$d"; d=$(mktemp -d) | |
| step -DIPCHW_VENDORS=ingenic none | |
| step -DIPCHW_HISI=all all # explicit on a LATER configure | |
| step -DIPCHW_VENDORS=sstar all # still theirs | |
| rm -rf "$d" | |
| exit $status |