mirror of
https://github.com/hathach/tinyusb.git
synced 2026-08-18 11:02:16 +00:00
HIL: replace build.flags_on with named build variants (#3687)
* test/hil: replace build.flags_on with named variant schema
Boards declare build variants as `variant: [{name, flags}]` instead of
`build.flags_on`. The variant `name` is the build dir (cmake-build-<name>) and
the HIL report row; `flags` is the raw CFLAGS string (-D...=1) injected via
CFLAGS_CLI. No `variant` => a single build named after the board.
- build.py: --build-name <name> (dir) + --cflag=<token> (raw CFLAGS, repeatable,
=form survives the matrix's shell word-splitting); drop -f1/CFLAGS wrapping.
- hil_ci_set_matrix.py: emit one build arg per variant.
- hil_test.py: iterate variants; report row + build dir = variant name.
- hil_ci.sh: copy all cmake-build-<board>* dirs for -b runs.
- get_deps.py: accept (ignore) --build-name/--cflag from matrix args.
- tinyusb.json: migrate all 6 flags_on boards to variant.
* board_test: park CI build with busy spin instead of wfe
This commit is contained in:
@ -15,6 +15,10 @@
|
||||
{
|
||||
"name": "stm32f746disco",
|
||||
"uid": "210041000C51343237303334",
|
||||
"variant": [
|
||||
{ "name": "stm32f746disco", "flags": "" },
|
||||
{ "name": "stm32f746disco-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" }
|
||||
],
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
|
||||
@ -66,14 +66,41 @@ copy_board_binaries() {
|
||||
}
|
||||
|
||||
if [ -n "$BOARD" ]; then
|
||||
BUILD_DIR="$ROOT_DIR/examples/cmake-build-$BOARD"
|
||||
if [ ! -d "$BUILD_DIR" ]; then
|
||||
echo "Error: build directory not found: $BUILD_DIR"
|
||||
echo "Build first with: cd examples && cmake -DBOARD=$BOARD -G Ninja -B cmake-build-$BOARD . && cmake --build cmake-build-$BOARD"
|
||||
# Copy the board's build dir plus its variant dirs. Variant names come from
|
||||
# $CONFIG (they are not required to be prefixed with the board name); the
|
||||
# cmake-build-<BOARD>-* glob is kept as a fallback for ad-hoc local builds.
|
||||
# Collect only dirs that actually exist, deduplicated.
|
||||
declare -A SEEN_DIRS=()
|
||||
BUILD_DIRS=()
|
||||
add_build_dir() {
|
||||
[[ -d "$1" && -z "${SEEN_DIRS[$1]:-}" ]] || return 0
|
||||
SEEN_DIRS[$1]=1
|
||||
BUILD_DIRS+=("$1")
|
||||
}
|
||||
shopt -s nullglob
|
||||
for d in "$ROOT_DIR"/examples/cmake-build-"$BOARD" "$ROOT_DIR"/examples/cmake-build-"$BOARD"-*; do
|
||||
add_build_dir "$d"
|
||||
done
|
||||
shopt -u nullglob
|
||||
while IFS= read -r v; do
|
||||
add_build_dir "$ROOT_DIR/examples/cmake-build-$v"
|
||||
done < <(python3 -c '
|
||||
import json, sys
|
||||
cfg = json.load(open(sys.argv[1]))
|
||||
for b in cfg.get("boards", []):
|
||||
if b["name"] == sys.argv[2]:
|
||||
for v in b.get("variant") or []:
|
||||
print(v["name"])
|
||||
' "$CONFIG" "$BOARD")
|
||||
if [ ${#BUILD_DIRS[@]} -eq 0 ]; then
|
||||
echo "Error: no build directory found for $BOARD under $ROOT_DIR/examples/"
|
||||
echo "Build first with: cd examples && cmake --preset $BOARD && cmake --build --preset $BOARD"
|
||||
exit 1
|
||||
fi
|
||||
echo "==> Copying binaries for $BOARD"
|
||||
copy_board_binaries "$BUILD_DIR"
|
||||
echo "==> Copying binaries for $BOARD (${#BUILD_DIRS[@]} build dir(s))"
|
||||
for d in "${BUILD_DIRS[@]}"; do
|
||||
copy_board_binaries "$d"
|
||||
done
|
||||
else
|
||||
echo "==> Copying all built binaries"
|
||||
# Use `%/` parameter expansion to strip the trailing slash from the glob —
|
||||
|
||||
@ -44,19 +44,19 @@ def main():
|
||||
toolchain = 'arm-gcc'
|
||||
|
||||
build_board = f'-b {name}'
|
||||
if 'build' in board:
|
||||
if 'args' in board['build']:
|
||||
build_board += ' ' + ' '.join(f'-D{a}' for a in board['build']['args'])
|
||||
if 'flags_on' in board['build']:
|
||||
for f in board['build']['flags_on']:
|
||||
if f == '':
|
||||
append_build_arg(toolchain, build_board)
|
||||
else:
|
||||
append_build_arg(toolchain, f'{build_board} -f1 {f.replace(" ", " -f1 ")}')
|
||||
else:
|
||||
append_build_arg(toolchain, build_board)
|
||||
else:
|
||||
append_build_arg(toolchain, build_board)
|
||||
if 'build' in board and 'args' in board['build']:
|
||||
build_board += ' ' + ' '.join(f'-D{a}' for a in board['build']['args'])
|
||||
|
||||
# Each variant builds into cmake-build-<variant.name> with its raw CFLAGS.
|
||||
# No 'variant' -> a single build named after the board.
|
||||
variants = board.get('variant') or [{'name': name, 'flags': ''}]
|
||||
for v in variants:
|
||||
arg = build_board
|
||||
if v['name'] != name:
|
||||
arg += f' --build-name {v["name"]}'
|
||||
for tok in v.get('flags', '').split():
|
||||
arg += f' --cflag={tok}'
|
||||
append_build_arg(toolchain, arg)
|
||||
|
||||
print(json.dumps(matrix))
|
||||
|
||||
|
||||
@ -122,16 +122,21 @@ class TestsCfg(TypedDict, total=False):
|
||||
|
||||
|
||||
class BuildCfg(TypedDict, total=False):
|
||||
flags_on: list[str]
|
||||
args: list[str]
|
||||
|
||||
|
||||
class VariantCfg(TypedDict, total=False):
|
||||
name: str # build dir (cmake-build-<name>) and HIL report row
|
||||
flags: str # raw CFLAGS, e.g. "-DCFG_TUD_DWC2_DMA_ENABLE=1"
|
||||
|
||||
|
||||
class Board(TypedDict):
|
||||
name: str
|
||||
uid: str
|
||||
tests: TestsCfg
|
||||
flasher: FlasherCfg
|
||||
build: NotRequired[BuildCfg]
|
||||
variant: NotRequired[list[VariantCfg]]
|
||||
|
||||
|
||||
class HilConfig(TypedDict):
|
||||
@ -223,7 +228,9 @@ def open_serial_dev(port: str):
|
||||
while timeout > 0:
|
||||
if os.path.exists(port):
|
||||
try:
|
||||
ser = serial.Serial(port, baudrate=115200, timeout=5)
|
||||
# write_timeout: a wedged device otherwise blocks ser.write() forever,
|
||||
# hanging the worker until the pool/job timeout kills the whole run
|
||||
ser = serial.Serial(port, baudrate=115200, timeout=5, write_timeout=5)
|
||||
break
|
||||
except serial.SerialException:
|
||||
print(f'serial {port} not reaady {timeout} sec')
|
||||
@ -976,9 +983,9 @@ def test_device_cdc_msc_throughput(board):
|
||||
pass
|
||||
|
||||
print(f' CDC read {cdc_r} write {cdc_w}, MSC read {msc_r} write {msc_w} ', end='')
|
||||
# compact read/write speed for the report cell, e.g. "C 652k/422k M 1.1M/783k"
|
||||
# compact read/write speed for the report cell, e.g. "✅ CDC 652k/422k MSC 1.1M/783k"
|
||||
short = lambda s: (s.split()[0].rstrip('0').rstrip('.') + s.split()[-1][0]) if ' ' in s else s
|
||||
return f'C {short(cdc_r)}/{short(cdc_w)} M {short(msc_r)}/{short(msc_w)}'
|
||||
return f'{REPORT_CELL["pass"]} CDC {short(cdc_r)}/{short(cdc_w)} MSC {short(msc_r)}/{short(msc_w)}'
|
||||
|
||||
|
||||
def test_device_dfu(board):
|
||||
@ -1502,17 +1509,12 @@ host_test = [
|
||||
]
|
||||
|
||||
|
||||
def f1_suffix(f1: str) -> str:
|
||||
"""Build dir / row-label suffix for a flags-on variant ('' for the default)."""
|
||||
return '-f1_' + f1.replace(' ', '_') if f1 else ''
|
||||
|
||||
|
||||
def find_firmware(name: str, f1: str, example: str):
|
||||
def find_firmware(variant: str, example: str):
|
||||
"""Locate a built example's firmware base path (no extension) under
|
||||
cmake-build-<board>[-f1_...]/<example>/. Accepts the single-config layout
|
||||
(firmware directly in the example dir) or Ninja Multi-Config (a per-config
|
||||
subdir like RelWithDebInfo/). Returns the base Path, or None if not built."""
|
||||
fw_dir = TINYUSB_ROOT / build_dir / f'cmake-build-{name}{f1_suffix(f1)}' / example
|
||||
cmake-build-<variant>/<example>/. Accepts the single-config layout (firmware
|
||||
directly in the example dir) or Ninja Multi-Config (a per-config subdir like
|
||||
RelWithDebInfo/). Returns the base Path, or None if not built."""
|
||||
fw_dir = TINYUSB_ROOT / build_dir / f'cmake-build-{variant}' / example
|
||||
base = Path(example).name
|
||||
if fw_dir.is_dir():
|
||||
for cand in [fw_dir / base, fw_dir / 'RelWithDebInfo' / base,
|
||||
@ -1522,25 +1524,24 @@ def find_firmware(name: str, f1: str, example: str):
|
||||
return None
|
||||
|
||||
|
||||
def test_example(board: Board, f1: str, example: str) -> tuple[int, str]:
|
||||
def test_example(board: Board, variant: str, example: str) -> tuple[int, str]:
|
||||
"""
|
||||
Test example firmware
|
||||
:param board: board dict
|
||||
:param f1: flags on
|
||||
:param variant: build variant name = build dir (cmake-build-<variant>) and report row
|
||||
:param example: example name
|
||||
:return: (err_count, status, metric) where err_count is 0 on success/skip or
|
||||
1 on failure, status is one of 'pass'/'fail'/'skip' (a missing binary
|
||||
counts as 'skip'), and metric is an optional string a test returns to
|
||||
show in its report cell instead of the pass symbol (e.g. speed)
|
||||
"""
|
||||
name = board['name']
|
||||
err_count = 0
|
||||
result_status = 'fail'
|
||||
metric = None
|
||||
|
||||
test_name = f'{name + f1_suffix(f1):40} {example:30} ...'
|
||||
test_name = f'{variant:40} {example:30} ...'
|
||||
|
||||
fw_name = find_firmware(name, f1, example)
|
||||
fw_name = find_firmware(variant, example)
|
||||
if fw_name is None:
|
||||
log_line(f'{test_name} Skip (no binary)')
|
||||
return 0, 'skip', None
|
||||
@ -1619,21 +1620,22 @@ def test_example(board: Board, f1: str, example: str) -> tuple[int, str]:
|
||||
|
||||
def build_board(board: Board) -> tuple[str, int]:
|
||||
"""Build firmware for this board via tools/build.py.
|
||||
Honors board config's build.flags_on variants and build.args defines.
|
||||
Output goes to cmake-build/cmake-build-BOARD[-f1_...]/ (tools/build.py layout)."""
|
||||
Honors board config's variant list and build.args defines.
|
||||
Output goes to cmake-build/cmake-build-<variant>/ (tools/build.py layout)."""
|
||||
name = board['name']
|
||||
bcfg = cast(BuildCfg, board.get('build', {}))
|
||||
flags_on_list = bcfg.get('flags_on', [''])
|
||||
extra_defs = bcfg.get('args', [])
|
||||
variants = board.get('variant') or [{'name': name, 'flags': ''}]
|
||||
|
||||
failed = 0
|
||||
for f1 in flags_on_list:
|
||||
for v in variants:
|
||||
cmd = [sys.executable, str(TINYUSB_ROOT / 'tools' / 'build.py'), '-b', name]
|
||||
for d in extra_defs:
|
||||
cmd += ['-D', d]
|
||||
if f1:
|
||||
for flag in f1.split():
|
||||
cmd += ['-f1', flag]
|
||||
if v['name'] != name:
|
||||
cmd += ['--build-name', v['name']]
|
||||
for tok in v.get('flags', '').split():
|
||||
cmd += [f'--cflag={tok}']
|
||||
if verbose:
|
||||
cmd.append('-v')
|
||||
print(f' + {" ".join(cmd)}')
|
||||
@ -1684,25 +1686,24 @@ def test_board(board: Board) -> tuple[str, int, list[str], list]:
|
||||
|
||||
err_count = 0
|
||||
failed_tests = []
|
||||
rows = [] # list of (row_label, {example: status}) — one row per board[-f1] variant
|
||||
flags_on_list = [""]
|
||||
if 'build' in board and 'flags_on' in board['build']:
|
||||
flags_on_list = board['build']['flags_on']
|
||||
rows = [] # list of (row_label, {example: status}) — one row per build variant
|
||||
variants = board.get('variant') or [{'name': name, 'flags': ''}]
|
||||
|
||||
for f1 in flags_on_list:
|
||||
for v in variants:
|
||||
vname = v['name']
|
||||
cells = {}
|
||||
for test in test_list:
|
||||
ec, status, metric = test_example(board, f1, test)
|
||||
ec, status, metric = test_example(board, vname, test)
|
||||
err_count += ec
|
||||
cells[test] = metric if metric else status
|
||||
if ec > 0:
|
||||
failed_tests.append(test)
|
||||
rows.append((name + f1_suffix(f1), cells))
|
||||
rows.append((vname, cells))
|
||||
|
||||
# flash board_test last to disable board's usb (skipped when --skip-flash is set);
|
||||
# this is teardown/park, not a test — not recorded in the report
|
||||
if not skip_flash:
|
||||
test_example(board, flags_on_list[0], 'device/board_test')
|
||||
test_example(board, variants[0]['name'], 'device/board_test')
|
||||
|
||||
return name, err_count, sorted(set(failed_tests)), rows
|
||||
|
||||
|
||||
@ -17,12 +17,10 @@
|
||||
{
|
||||
"name": "espressif_p4_function_ev",
|
||||
"uid": "6055F9F98715",
|
||||
"build": {
|
||||
"flags_on": [
|
||||
"",
|
||||
"CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"
|
||||
]
|
||||
},
|
||||
"variant": [
|
||||
{ "name": "espressif_p4_function_ev", "flags": "" },
|
||||
{ "name": "espressif_p4_function_ev-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" }
|
||||
],
|
||||
"tests": {
|
||||
"only": [
|
||||
"device/cdc_msc_freertos",
|
||||
@ -58,12 +56,10 @@
|
||||
{
|
||||
"name": "espressif_s3_devkitm",
|
||||
"uid": "84F703C084E4",
|
||||
"build": {
|
||||
"flags_on": [
|
||||
"",
|
||||
"CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"
|
||||
]
|
||||
},
|
||||
"variant": [
|
||||
{ "name": "espressif_s3_devkitm", "flags": "" },
|
||||
{ "name": "espressif_s3_devkitm-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" }
|
||||
],
|
||||
"tests": {
|
||||
"only": [
|
||||
"device/cdc_msc_freertos",
|
||||
@ -226,11 +222,9 @@
|
||||
{
|
||||
"name": "raspberry_pi_pico",
|
||||
"uid": "E6614C311B764A37",
|
||||
"build": {
|
||||
"flags_on": [
|
||||
"CFG_TUH_RPI_PIO_USB"
|
||||
]
|
||||
},
|
||||
"variant": [
|
||||
{ "name": "raspberry_pi_pico", "flags": "-DCFG_TUH_RPI_PIO_USB=1" }
|
||||
],
|
||||
"tests": {
|
||||
"device": true,
|
||||
"host": true,
|
||||
@ -374,12 +368,10 @@
|
||||
{
|
||||
"name": "stm32f723disco",
|
||||
"uid": "460029001951373031313335",
|
||||
"build": {
|
||||
"flags_on": [
|
||||
"",
|
||||
"CFG_TUH_DWC2_DMA_ENABLE"
|
||||
]
|
||||
},
|
||||
"variant": [
|
||||
{ "name": "stm32f723disco", "flags": "" },
|
||||
{ "name": "stm32f723disco-DMA", "flags": "-DCFG_TUH_DWC2_DMA_ENABLE=1" }
|
||||
],
|
||||
"tests": {
|
||||
"device": true,
|
||||
"host": true,
|
||||
@ -410,12 +402,10 @@
|
||||
{
|
||||
"name": "stm32h743nucleo",
|
||||
"uid": "110018000951383432343236",
|
||||
"build": {
|
||||
"flags_on": [
|
||||
"",
|
||||
"CFG_TUD_DWC2_DMA_ENABLE"
|
||||
]
|
||||
},
|
||||
"variant": [
|
||||
{ "name": "stm32h743nucleo", "flags": "" },
|
||||
{ "name": "stm32h743nucleo-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" }
|
||||
],
|
||||
"tests": {
|
||||
"device": true,
|
||||
"host": false,
|
||||
@ -474,12 +464,10 @@
|
||||
{
|
||||
"name": "stm32f769disco",
|
||||
"uid": "21002F000F51363531383437",
|
||||
"build": {
|
||||
"flags_on": [
|
||||
"",
|
||||
"CFG_TUD_DWC2_DMA_ENABLE"
|
||||
]
|
||||
},
|
||||
"variant": [
|
||||
{ "name": "stm32f769disco", "flags": "" },
|
||||
{ "name": "stm32f769disco-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" }
|
||||
],
|
||||
"tests": {
|
||||
"device": true,
|
||||
"host": false,
|
||||
|
||||
Reference in New Issue
Block a user