-
Notifications
You must be signed in to change notification settings - Fork 1
229 lines (217 loc) · 10.9 KB
/
Copy path_cppcheck.yml
File metadata and controls
229 lines (217 loc) · 10.9 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
# Reusable cppcheck gate — called by BOTH build.yml (commit / PR) and
# release.yml (tag push) via `uses:`. Single source of the static-analysis
# baseline so the two callers can never drift.
#
# V2.5.31: extracted from the two near-identical inline copies that had ALREADY
# drifted — only release.yml's copy passed `--std=c11`, so a commit-push run and
# the tag-push run for the SAME commit evaluated slightly different baselines,
# the exact failure the old "keep in sync" comments warned against. Tune flags
# or suppressions HERE, once.
#
# V2.6.8 MAX review: this job used to hardcode -DBOARD_HELTEC_V2=1 only, which
# has HAL_HAS_NEOPIXEL=0 and HAL_HAS_FUEL_GAUGE=0 — so cppcheck had NEVER
# analyzed the real neopixel.c (WS2812/RMT) or fuel_gauge.c (MAX17048) driver
# code on ANY board, only their HAL_HAS_*==0 stub branches, since every board
# with those flags set to 1 postdates the single-macro design. Matrixed across
# one leg per real build target (mirrors _build-boards.yml's board list and
# CMakeLists.txt's exact per-board add_compile_definitions) so every hal.h
# branch and every HAL_HAS_*-gated file actually gets checked somewhere.
name: cppcheck (reusable)
on:
workflow_call:
inputs:
ref:
description: "Git ref to check out (default: the caller's triggering ref)."
type: string
default: ''
required: false
# Reusable workflows do NOT inherit the caller's env, so the Node 20→24
# deprecation opt-in (see build.yml) must be repeated here.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
# Builds cppcheck 2.21.0 from source ONCE and hands it to every matrix leg
# below via artifact, instead of each of the 10 legs building it in
# parallel. The first cut of this (single build step inlined into the
# matrix job, cached via actions/cache) had all 10 legs race to build AND
# save the same cache key simultaneously — cache save failed for the 9
# losers ("Unable to reserve cache... another job may be creating this
# cache") and, worse, all 10 still paid the full from-source build cost
# every run since the cache write hadn't landed yet when they started.
# This job runs once; the matrix below downloads its output instead of
# rebuilding.
build-cppcheck:
name: build cppcheck 2.21.0
runs-on: ubuntu-latest
steps:
# Ubuntu's apt package is frozen at whatever shipped with the runner's
# Ubuntu release (2.13.0 on ubuntu-latest as of this writing) and never
# rolls forward within that release. Build from source instead, pinned
# to 2.21.0 by commit SHA (mirroring the espressif/esp-idf-ci-action
# SHA-pin convention in build.yml) for a reproducible baseline. Local
# pre-build gating in _build.cmd points at whatever cppcheck is
# installed on the dev machine — currently 2.21.0, in sync with this
# pin as of 2026-07-11; bump the local install again if this pin moves.
# Cached by version so only the first run after a version bump pays the
# build cost at all.
# Build with prefix /usr/local (cmake's default) — the SAME prefix the
# matrix jobs below install the downloaded artifact into. cppcheck's
# FILESDIR (where it looks up std.cfg etc.) is baked into the binary
# at compile time from CMAKE_INSTALL_PREFIX — it is NOT relocatable, so
# building with one prefix and deploying to another breaks the
# library-config lookup even though the binary itself still runs
# ("Failed to load library configuration file 'std.cfg'... FILESDIR set
# to <build-time prefix>"). A prior cut here built with prefix
# runner.temp to dodge the cache-restore permission bug described below
# and broke every matrix leg this way — don't repeat that.
#
# The actual cache-restore bug: caching /usr/local directly (root-owned
# via `sudo cmake --install`) made SAVING work (reading root-owned-but-
# world-readable files needs no privilege) but broke RESTORING on a
# fresh runner VM — /usr/local/bin is pre-opened for the runner user on
# GitHub-hosted runners, but /usr/local/share is not, so the
# unprivileged cache-restore step couldn't `mkdir` a fresh share/Cppcheck
# ("Cannot mkdir: Permission denied") and silently fell back to a full
# rebuild every run — cache-hit was reported true but never actually
# saved any time. Fix: cache the workspace-relative cppcheck-dist/ copy
# instead (always runner-owned, no permission boundary to cross on
# restore) rather than /usr/local itself; keep the real
# `sudo cmake --install` into /usr/local (only paid on a cache miss)
# purely so the binary's baked-in FILESDIR matches where matrix jobs
# deploy it.
- name: Cache cppcheck 2.21.0 build
id: cppcheck_cache
uses: actions/cache@v6
with:
path: cppcheck-dist
key: cppcheck-2.21.0-e73bf44-${{ runner.os }}
- name: Build cppcheck 2.21.0
if: steps.cppcheck_cache.outputs.cache-hit != 'true'
run: |
sudo apt-get update -qq && sudo apt-get install -y -qq cmake build-essential
git clone --depth 1 https://github.com/danmar/cppcheck.git /tmp/cppcheck-src
git -C /tmp/cppcheck-src fetch --depth 1 origin e73bf44c3e49686b7495fab352d03a6c6075516b # tag 2.21.0
git -C /tmp/cppcheck-src checkout e73bf44c3e49686b7495fab352d03a6c6075516b
cmake -S /tmp/cppcheck-src -B /tmp/cppcheck-build -DCMAKE_BUILD_TYPE=Release
cmake --build /tmp/cppcheck-build -j"$(nproc)"
sudo cmake --install /tmp/cppcheck-build
mkdir -p cppcheck-dist/bin cppcheck-dist/share
cp /usr/local/bin/cppcheck cppcheck-dist/bin/
cp -r /usr/local/share/Cppcheck cppcheck-dist/share/
- name: Verify cppcheck version
run: cppcheck-dist/bin/cppcheck --version
- name: Upload cppcheck build
uses: actions/upload-artifact@v7
with:
name: cppcheck-2.21.0-build
path: cppcheck-dist
retention-days: 1
cppcheck:
name: cppcheck / ${{ matrix.board }}
needs: build-cppcheck
runs-on: ubuntu-latest
strategy:
# Keep checking every board even if one already has findings, so a
# single run shows the full breakage matrix (mirrors _build-boards.yml).
fail-fast: false
matrix:
# One leg per real build target — same list and same per-board
# defines as CMakeLists.txt's add_compile_definitions() calls, so a
# define added there without a matching leg here silently goes
# unanalyzed again (see the V2.6.8 note above).
include:
- board: heltec_v2
defines: -DBOARD_HELTEC_V2=1
- board: heltec_v2_4mb
defines: -DBOARD_HELTEC_V2=1 -DBOARD_HELTEC_V2_4MB=1
- board: feathers3_d
defines: -DBOARD_FEATHERS3_D=1 -DMQTT_RICH_STATE=1
- board: adafruit_qtpy_esp32_pico
defines: -DBOARD_ADAFRUIT_QTPY_ESP32_PICO=1 -DMQTT_RICH_STATE=1
- board: seeed_xiao_esp32s3
defines: -DBOARD_SEEED_XIAO_ESP32S3=1 -DMQTT_RICH_STATE=1
- board: heltec_wifi_lora32_v4_r2
defines: -DBOARD_HELTEC_WIFI_LORA32_V4_R2=1 -DMQTT_RICH_STATE=1 -DCONFIG_GEIGER_LORAWAN=1
- board: sparkfun_thing_plus_esp32s3
defines: -DBOARD_SPARKFUN_THING_PLUS_ESP32S3=1 -DMQTT_RICH_STATE=1
- board: sparkfun_thing_plus_esp32c5
defines: -DBOARD_SPARKFUN_THING_PLUS_ESP32C5=1 -DMQTT_RICH_STATE=1
- board: adafruit_esp32s3_tft_feather
defines: -DBOARD_ADAFRUIT_ESP32S3_TFT_FEATHER=1 -DMQTT_RICH_STATE=1
- board: adafruit_esp32_feather_v2
defines: -DBOARD_ADAFRUIT_ESP32_FEATHER_V2=1 -DMQTT_RICH_STATE=1
- board: adafruit_esp32s3_feather_4mb_2mbpsram
defines: -DBOARD_ADAFRUIT_ESP32S3_FEATHER_4MB_2MBPSRAM=1 -DMQTT_RICH_STATE=1
steps:
- name: Checkout
uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
- name: Download cppcheck 2.21.0 build
uses: actions/download-artifact@v8
with:
name: cppcheck-2.21.0-build
path: /tmp/cppcheck-dist
- name: Install cppcheck from downloaded build
run: |
sudo cp /tmp/cppcheck-dist/bin/cppcheck /usr/local/bin/cppcheck
sudo chmod +x /usr/local/bin/cppcheck
sudo cp -r /tmp/cppcheck-dist/share/Cppcheck /usr/local/share/Cppcheck
- name: Verify cppcheck version
run: cppcheck --version
- name: Run cppcheck on main/
run: |
set +e
# --enable: include warning/style/performance/portability findings.
# Suppressions:
# missingIncludeSystem — we don't ship IDF headers in this check
# unusedFunction — many entry points are IDF/FreeRTOS
# callbacks cppcheck can't see being called
# unusedStructMember — struct members read via memcpy or by
# external IDF code
# internalAstError — known cppcheck issue with some macros
# unknownMacro — IDF-defined macros (MACSTR, IP2STR, ...)
# that cppcheck has no header for
# -DESP_PLATFORM=1 + this leg's board defines mirror the real build
# so hal.h enters the same branch this board actually compiles,
# instead of the fallback #error (or, pre-V2.6.8, always the same
# one board's branch regardless of what changed).
cppcheck \
--enable=warning,style,performance,portability \
--inline-suppr \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
--suppress=unusedStructMember \
--suppress=internalAstError \
--suppress=unknownMacro \
--error-exitcode=1 \
--quiet \
--std=c11 \
-DESP_PLATFORM=1 \
${{ matrix.defines }} \
-I main \
main/ 2>&1 | tee cppcheck.out
RC=${PIPESTATUS[0]}
{
echo "## cppcheck findings — ${{ matrix.board }}"
if [ -s cppcheck.out ]; then
echo '```'
cat cppcheck.out
echo '```'
else
echo "_(clean — no findings at warning/style/performance/portability levels)_"
fi
echo ""
echo "cppcheck exit code: $RC (0=clean)"
} >> "$GITHUB_STEP_SUMMARY"
# Hard gate: fix new findings at source, or add an inline
# `// cppcheck-suppress <id>` with a reason for a false positive.
exit $RC
- name: Upload cppcheck output as artifact
if: always()
uses: actions/upload-artifact@v7
with:
name: cppcheck-${{ matrix.board }}-${{ github.sha }}
path: cppcheck.out
if-no-files-found: ignore
retention-days: 14