Skip to main content

build

The project build contract. Use when a change must be verified by building, when an agent needs the boards a diff affects, or when a workflow asks for "the project's build". Resolves scope to boards, builds in a private dir, reports pass/fail with the first error.

معلومات المصدر

المستودع
hathach/tinyusb
آخر نشاط في المصدر
٨ أكتوبر ٢٠٢٦ في ٠٩:٠٧
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٧٬٢١٠
التفرعات
١٬٥٥٨

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
3 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
build
description
The project build contract. Use when a change must be verified by building, when an agent needs the boards a diff affects, or when a workflow asks for "the project's build". Resolves scope to boards, builds in a private dir, reports pass/fail with the first error.
# Build contract `scripts/check_build.py` is the entry point for verifying a change; every agent and workflow that does so calls it rather than composing cmake lines. Two builds are not verification and stay on `tools/build.py` directly: the debug build below, and the PVS compile-database build for the `pvs-studio` agent, which needs one configured tree for the analyser, not a sweep. ```bash B=.claude/skills/build/scripts/check_build.py python3 $B --scope <changed paths or dirs> # boards a change affects, one per family python3 $B --base master # same, from the branch diff python3 $B --base master --worktree # same, plus uncommitted and untracked changes python3 $B --select-only (--scope ... | --base REF [--worktree] | --endpoints A..B) [--config <roster>]... # the selection alone python3 $B --board stm32f407disco [-e device/cdc_msc] [-T target] python3 $B --board stm32f407disco -e host/cdc_msc_hid --cflag=-DCFG_TUH_CDC_FTDI_LATENCY=16 python3 $B ... --shared # canonical cmake-build-<board>, the dir HIL flashes from python3 $B --board <b> --shared --variants <hil config> # one cmake-build-<variant> per roster variant python3 $B --board <b> --shared --variants <hil config> --receipt .hil-remote/<name>.json # plus the build receipt a delegated HIL run checks (hil skill) python3 $B ... --fetch-deps # fetch a family's missing deps instead of failing ``` The last stdout line is JSON: `pass`, per-board `status` (`ok`, `failed`, `skipped`, `error`), `built` (elf files this run wrote), `firstError`, `buildDir`, how the boards were resolved, and the scope paths nothing builds, split into `nothingToBuild` and `uncovered`. Exit 0 pass, 1 a board failed, 2 usage or resolution error with the message in `error` (a missing dependency names its remedy there) or a refused receipt with its reason in `receipt.error`, 3 an uncovered path. `-v` streams the build to stderr. `--select-only` is the selection contract: CI and any agent that needs "what does this change affect" read its manifest rather than calling `tools/change_impact.py` or parsing its log. It prints one JSON line and stops before any dependency check or build, under an isolated stdlib-only interpreter: - `version` 1. `input`: `mode` (`paths`, `base`, `worktree`, `endpoints`), the ref as given, and the SHAs it resolved to (`base_sha`, `merge_base`, `head`, `deps_base`). Committed modes classify the checked-out tree, so `--endpoints A..B` refuses a `B` that is not HEAD. - `build`: `full` and `needed` (booleans); `families` maps each selected family to `examples` (`"all"` or a non-empty list), and is empty when `full`; `required_boards` (changed `hw/bsp/<f>/boards/<b>` still in the tree); `required_targets` (`examples-membrowse-upload` for `tools/membrowse_cli.py`); `dropped` (families pruned away, each with its line); `paths`, one record per changed path: `rule`, `effect` (`none` nothing to verify, `gap` firmware no build compiles, `select`, `full`), the `families` and `examples` the rule names (`null` means every one), `port`, `targets`, and the human `reason`. `effect` is what the path contributes to the selection, not a coverage verdict. - `hil`: `full`, `needed`, `boards`, and the per-roster `args`, `args_flasher` and `hil_examples`. A selector error is exit 2 with the message: a consumer that falls back to the full matrix decides so itself. ## Judgment - **Full example set by default.** `-e` narrows to named examples for a quick check; a change in `src/` or a class driver is verified by the full set on every resolved board before it is called green. - **Scope, not guesswork.** `--scope` takes changed paths, expanding a directory into its tracked files first, and runs `tools/change_impact.py`: one board per affected family; a board whose own `hw/bsp/<family>/boards/<board>/` files changed is built itself, else a rig-roster board of the family, else the first in the family. A full-matrix answer (core or unclassified paths) builds `stm32f407disco` and `raspberry_pi_pico`, plus any board whose own files changed, plus one board per family a port, bsp or mcu path in the scope names: the pair stands in for the matrix on core code, not on a port it does not contain. A changed driver under `src/portable/` adds, per family it maps to, a board whose `hw/bsp/family.json` row lists the driver and, where the host preprocessor can say, selects the USB IPs its guard names: `stm32l412nucleo` for fsdev next to a DWC2 pick on stm32l4, `feather_rp2040_max3421` for `hcd_max3421.c`. A special target the changed path needs (the manifest's `required_targets`: `examples-membrowse-upload` for `tools/membrowse_cli.py`) is `-T`; a default sweep is no evidence for it. `tools/code_size.py` is validated by CI's code-size step, which no local build runs, so it always stays `uncovered` here. - **A path nothing builds** is one of two kinds, in `change_impact`'s words, and the script sorts them so that a mixed change gets the stricter answer: - `nothingToBuild` (docs, `.claude/`, `*.md`, unit tests, HIL harness): there is nothing a build could verify, which is not a failure. A scope of only such paths is `pass` true with no boards, exit 0; quote the reason in your notes so nobody mistakes it for a build that ran. - `uncovered` (a class or typec no example config enables, a lib nothing builds, a port mapping to no board family, a family the selector pruned because nothing in it builds, an example or class no built board wrote an elf for, a port driver no built board of its families kept a line of after preprocessing): firmware this run did not compile, judged against the boards and elfs it actually produced. The port test is the driver's own compile command run with `-E` on every instance in an example this run built, so a board whose configuration guards the driver away (`dcd_nrf5x.c` on NRF54, `hcd_rp2040.c` under MAX3421) is not coverage whatever else went green; the reason names each board's verdict. `-e` or `-T` hands coverage to you: the script then does not report what you chose to leave out, and a `-T` target that writes no elf is not a verified build of anything. Exit 3 and `pass` false, even when every other path in the scope built green — a class driver plus the core file that registers it is the common shape, and the green boards say nothing about the driver. The verdict is false and the `uncovered` reason, quoted verbatim, is the finding: a human adds coverage (the next bullet) or accepts the gap. - **Private dirs for parallel agents.** Builds land in `cmake-build/cmake-build-agent-<pid>-<board>`; remove yours when done. `--shared` writes `cmake-build/cmake-build-<board>`, the dir `hil_test.py` flashes from by default, and needs exclusive ownership of that board: never while a HIL run or another agent is on it. `--variants <hil config>` builds instead each variant that roster gives a named board, into the `cmake-build-<variant>` `hil_test.py` runs it from, with your own defines and flags followed by the variant's, so a repeated `-D` takes the variant's value; a `--cflag` macro the variant's flags also set is a `-Werror` redefinition, not an override (a board without a variant list as itself); it refuses a board the roster lacks. - **`hw/bsp/family.json`** is what a board's default configure compiles: its `mcu`, the tested defines, `family_mcus`, the `MAX3421_HOST` option and its drivers under `src/portable/`, one row per cmake board, `null` for the two Make-only pic32mz boards. `tools/build.py` rewrites the row whenever it runs a default configure (cmake, gcc, no `-D`, no `--cflag`, into a dir that did not exist yet, which every private dir is; `--configure-only` does just that), so a change that moves a board's configuration leaves the catalog modified: the run's JSON says so in `familyJsonChanged` and per board in `familyJson`, and the row is committed with the change. The pre-commit hook `family-json` repairs the catalog in place, like codespell: it configures each board without a row once into a fresh private dir, drops rows of boards that are gone, rewrites the file canonical, and fails the commit when it changed anything, so you stage the file and commit again (`python3 tools/family_json.py fix` by hand does the same). A board this machine cannot configure (no toolchain, ESP-IDF not exported) stays reported with tools/build.py's reason. - **Dependencies.** The family's entries in `tools/get_deps.py` must exist. In a worktree, symlink them from the primary checkout (`CLAUDE.md`, Working Rules); `--fetch-deps` is for a fresh clone. The script never fetches on its own. - **Code no example enables.** A branch behind a `CFG_*` option no board sets is not compiled by any sweep, so a change there is unverified until you build it with the option on: `--cflag=-D<OPTION>=<value>` (repeatable), narrowed with `-e` to one example that reaches the code. `-D` passes a build-system define (`LOG=2`) the same way. Never hand-roll a cmake line for this. - **Espressif** boards go through `tools/build.py`'s ESP-IDF path; `. "$IDF_PATH/export.sh"` must be in the environment first, and only ESP-IDF examples build for them. - **Debug builds**: `-DCMAKE_BUILD_TYPE=Debug -DLOG=2 -DLOGGER=rtt` via `tools/build.py -D` directly; this script builds MinSizeRel. ETM trace builds add `-DTRACE_ETM=1` the same way. `python3 tools/build_utils.py board-info <board>` prints the board's J-Link device name and its reference Ozone project. With several J-Links attached, `-DJLINK_OPTION="-USB <serial>"` pins the `<example>-jlink` flash target. rp2350 at a non-default core clock: pass `SYS_CLK_KHZ` together with `PLL_SYS_VCO_FREQ_HZ`/`PLL_SYS_POSTDIV1`/`PLL_SYS_POSTDIV2` from the SDK's `scripts/vcocalc.py` as compile definitions; 240 MHz also needs `SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST=1` and `SYS_CLK_VREG_VOLTAGE_MIN=VREG_VOLTAGE_1_15`. - **Printing a command is not verification.** A verdict is the JSON of a run that happened; an agent that cannot run the script reports the build as not run.
عرض على GitHub