Repository navigation
313 lines (303 loc) · 15.4 KB
/
Copy pathpr-build-check.yml
File metadata and controls
313 lines (303 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
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.
#
# The quantity is text + data + bss from size(1), not the file size.
# The file is page-quantised: the RW segment's file offset must equal
# its address modulo 4096, so it moves a whole page the moment the
# code before it crosses a boundary. On 5d678de the code segment ended
# exactly where the data segment began (both 0xae68), and a PR adding
# 12 bytes of code grew the file by 4096 and failed the budget.
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
cc=${{ matrix.cc }}
"${cc%gcc}size" "$out/ipcinfo" | awk 'NR == 2 { print $4 }'
}
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 http_test mtd_alias_test \
nand_layout_test upgrade_env_test \
jffs2_test
./build/cYAML_test
./build/report_test
./build/http_test
./build/mtd_alias_test
./build/upgrade_env_test
./build/jffs2_test
./build/nand_layout_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