commit f6b905f93ad5d469c4983625fbe7f28aaa64b906
parent 3fbd50380ffc8175756f8decd961fa5f90e40c7c
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 17:05:15 -0700
Tighten tier1 kitchen sentinels
Diffstat:
15 files changed, 187 insertions(+), 65 deletions(-)
diff --git a/mk/test.mk b/mk/test.mk
@@ -253,7 +253,7 @@ test-t1-core-api:
test-t1-pp: bin
@$(T1_LOG) pp env KIT=$(abspath $(BIN)) test/tier1/frontend/run-kitchen.sh pp
-test-t1-c-front: bin $(PARSE_RUNNER) $(LINK_EXE_RUNNER) $(JIT_RUNNER)
+test-t1-c-front: bin
@$(T1_LOG) c-front env KIT=$(abspath $(BIN)) test/tier1/frontend/run-kitchen.sh c
test-t1-cg: bin
@@ -266,15 +266,15 @@ test-t1-opt:
test-t1-arch:
@$(T1_LOG) arch $(MAKE) --no-print-directory test-isa test-aa64-inline test-x64-inline test-rv64-inline test-arm32-inline
-test-t1-asm-disas: $(ASM_RUNNER)
- @$(T1_LOG) asm-disas test/tier1/objlink/asm.sh
+test-t1-asm-disas: bin
+ @$(T1_LOG) asm-disas env KIT=$(abspath $(BIN)) test/tier1/objlink/asm.sh
-test-t1-obj: $(ROUNDTRIP_BIN)
- @$(T1_LOG) obj test/tier1/objlink/object.sh
+test-t1-obj: bin
+ @$(T1_LOG) obj env KIT=$(abspath $(BIN)) test/tier1/objlink/object.sh
@$(T1_LOG) ar $(MAKE) --no-print-directory test-ar
-test-t1-link-jit: $(LINK_EXE_RUNNER)
- @$(T1_LOG) link test/tier1/objlink/link.sh
+test-t1-link-jit: bin
+ @$(T1_LOG) link env KIT=$(abspath $(BIN)) test/tier1/objlink/link.sh
@$(T1_LOG) jit-relax $(MAKE) --no-print-directory test-link-jit-tls-relax
@$(T1_LOG) interop env KIT=$(abspath $(BIN)) test/tier1/objlink/interop.sh
diff --git a/test/tier1/README.md b/test/tier1/README.md
@@ -14,8 +14,10 @@ Rules:
`test/TESTMAP.md`.
The cross sentinel is build/link-only. It covers the supported cross matrix and
-reports missing provisioned sysroots or SDKs as SKIP with exit 0. Narrow it with
-`T1_CROSS_TARGETS=<selector>` when needed.
+reports missing provisioned sysroots or SDKs as SKIP, which fails Tier 1 by
+default because it means the requested coverage did not run. Narrow it with
+`T1_CROSS_TARGETS=<selector>` when needed; use `KIT_TEST_ALLOW_SKIP=1` only for
+an explicitly permissive local probe.
`make test` runs Tier 1 in parallel. The previous broad default is available as
`make test-full`.
diff --git a/test/tier1/cross/README.md b/test/tier1/cross/README.md
@@ -3,8 +3,10 @@
`run.sh` is the Tier 1 cross-compile/link sentinel. It covers the portability
support set at build/link depth only; it does not execute target artifacts.
-Missing provisioned sysroots or SDKs are reported as `SKIP` and exit 0. Real
-compile/link failures are `FAIL`.
+Missing provisioned sysroots or SDKs are reported as `SKIP` and fail the run by
+default. Real compile/link failures are `FAIL`. Narrow local runs with
+`T1_CROSS_TARGETS=<selector>` when you only intend to cover one slice; use
+`KIT_TEST_ALLOW_SKIP=1` only when you explicitly want a permissive probe.
Covered lanes:
diff --git a/test/tier1/cross/run.sh b/test/tier1/cross/run.sh
@@ -13,7 +13,7 @@ mkdir -p "$WORK"
. "$ROOT/test/lib/kit_sh_report.sh"
kit_report_init
-KIT_SKIP_IS_FAILURE=0
+KIT_SKIP_IS_FAILURE=1
if [ ! -x "$KIT" ]; then
kit_fail "cross/setup" "kit not built at $KIT"
@@ -74,7 +74,7 @@ hosted_lane() {
triple="$(hosted_triple "$token")"
if [ -z "$triple" ]; then
- kit_skip "$label" "not in hosted support set"
+ kit_fail "$label" "not in hosted support set"
return 0
fi
@@ -163,6 +163,7 @@ linux_shared_lane() {
match_selector "$token" || return 0
sysroot="$(hosted_path "$token")"
if [ -z "$sysroot" ] || [ ! -d "$sysroot" ]; then
+ kit_skip "$label" "sysroot not provisioned; run: make provision TARGET=$token"
return 0
fi
dir="$WORK/$token-shared"
diff --git a/test/tier1/objlink/README.md b/test/tier1/objlink/README.md
@@ -5,12 +5,14 @@ asm sentinels. It does not sample the broader corpora.
Fixtures live under `test/tier1/kitchen/objlink/`:
-- `asm/`: direct `asm-runner` encode/decode checks for aa64, x64, and rv64.
+- `asm/`: direct `kit mc` / `kit disas` encode/decode checks for aa64, x64,
+ and rv64.
- `object/`: one C object with common symbols, weak/hidden symbols, data
relocations, and per-function/per-data sections; it is round-tripped with
- `kit-roundtrip` and compared through the ELF normalizer.
-- `link/`: a tiny multi-object program linked through `link-exe-runner` with an
- archive member and `--gc-sections`, then inspected as an executable image.
+ `kit objcopy` and compared through the ELF normalizer.
+- `link/`: a tiny multi-object program linked through `kit ar` and `kit ld`
+ with an archive member and `--gc-sections`, then inspected as an executable
+ image.
- `interop/`: a kit-produced object linked by clang/lld when available, and a
clang-produced object linked back through kit.
@@ -20,8 +22,8 @@ Run all:
test/tier1/objlink/run.sh
```
-Prerequisites are the same harness binaries used by the full suites:
+Prerequisite:
```sh
-make build/test/asm-runner build/test/kit-roundtrip build/test/link-exe-runner
+make bin
```
diff --git a/test/tier1/objlink/asm.sh b/test/tier1/objlink/asm.sh
@@ -7,27 +7,31 @@ ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
KITCHEN="$ROOT/test/tier1/kitchen/objlink/asm"
WORK="$(t1_work_dir "$ROOT" asm)"
LOG_DIR="$(t1_log_dir "$ROOT")"
-ASM_RUNNER="$ROOT/build/test/asm-runner"
+KIT="${KIT:-$ROOT/build/kit}"
mkdir -p "$WORK" "$LOG_DIR"
-t1_require_exe "$ASM_RUNNER" 'run: make build/test/asm-runner'
+t1_require_exe "$KIT" 'run: make bin'
echo "tier1 asm: aa64 encode"
-KIT_TEST_ARCH=aa64 t1_run "$LOG_DIR/asm-aa64-encode.log" \
- "$ASM_RUNNER" --encode "$KITCHEN/aa64_cond.s" "$WORK/aa64_cond.hex"
+KIT_TEST_ARCH=aa64 "$KIT" mc -target aarch64 -p - \
+ < "$KITCHEN/aa64_cond.s" > "$LOG_DIR/asm-aa64-encode.log" 2>&1
+tr -d '[:space:]' < "$LOG_DIR/asm-aa64-encode.log" > "$WORK/aa64_cond.hex"
+printf '\n' >> "$WORK/aa64_cond.hex"
t1_diff "$KITCHEN/aa64_cond.expected.hex" "$WORK/aa64_cond.hex" \
"$WORK/aa64_cond.diff"
echo "tier1 asm: x64 decode"
KIT_TEST_ARCH=x64 t1_run "$LOG_DIR/asm-x64-decode.log" \
- "$ASM_RUNNER" --decode "$KITCHEN/x64_mov_ret.hex" "$WORK/x64_mov_ret.txt"
-t1_diff "$KITCHEN/x64_mov_ret.expected.txt" "$WORK/x64_mov_ret.txt" \
- "$WORK/x64_mov_ret.diff"
+ "$KIT" disas -target x86_64 -x "$(cat "$KITCHEN/x64_mov_ret.hex")"
+t1_assert_grep "asm/x64-mov" '0:.*movl[[:space:]]+\$42, %eax' \
+ "$LOG_DIR/asm-x64-decode.log"
+t1_assert_grep "asm/x64-ret" '5:.*ret' "$LOG_DIR/asm-x64-decode.log"
echo "tier1 asm: rv64 decode"
KIT_TEST_ARCH=rv64 t1_run "$LOG_DIR/asm-rv64-decode.log" \
- "$ASM_RUNNER" --decode "$KITCHEN/rv64_li_ret.hex" "$WORK/rv64_li_ret.txt"
-t1_diff "$KITCHEN/rv64_li_ret.expected.txt" "$WORK/rv64_li_ret.txt" \
- "$WORK/rv64_li_ret.diff"
+ "$KIT" disas -target riscv64 -x "$(cat "$KITCHEN/rv64_li_ret.hex")"
+t1_assert_grep "asm/rv64-li" '0:.*li[[:space:]]+a0, 7' \
+ "$LOG_DIR/asm-rv64-decode.log"
+t1_assert_grep "asm/rv64-ret" '4:.*ret' "$LOG_DIR/asm-rv64-decode.log"
echo "tier1 asm: ok"
diff --git a/test/tier1/objlink/common.sh b/test/tier1/objlink/common.sh
@@ -42,3 +42,21 @@ t1_diff() {
local expected="$1" actual="$2" diff_file="$3"
diff -u "$expected" "$actual" >"$diff_file" 2>&1
}
+
+t1_assert_grep() {
+ local label="$1" pattern="$2" file="$3"
+ if ! grep -Eq "$pattern" "$file"; then
+ echo "$label: pattern not found: $pattern" >&2
+ sed -n '1,160p' "$file" >&2 || true
+ return 1
+ fi
+}
+
+t1_assert_not_grep() {
+ local label="$1" pattern="$2" file="$3"
+ if grep -Eq "$pattern" "$file"; then
+ echo "$label: unexpected pattern found: $pattern" >&2
+ grep -En "$pattern" "$file" >&2 || true
+ return 1
+ fi
+}
diff --git a/test/tier1/objlink/interop.sh b/test/tier1/objlink/interop.sh
@@ -10,7 +10,7 @@ mkdir -p "$WORK"
. "$ROOT/test/lib/kit_sh_report.sh"
kit_report_init
-KIT_SKIP_IS_FAILURE=0
+KIT_SKIP_IS_FAILURE=1
if [ ! -x "$KIT" ]; then
kit_fail "interop/setup" "kit not built at $KIT"
diff --git a/test/tier1/objlink/link.sh b/test/tier1/objlink/link.sh
@@ -9,13 +9,11 @@ TRIPLE="$(t1_clang_triple "$ARCH")"
KITCHEN="$ROOT/test/tier1/kitchen/objlink/link"
WORK="$(t1_work_dir "$ROOT" link)"
LOG_DIR="$(t1_log_dir "$ROOT")"
-LINK_EXE_RUNNER="$ROOT/build/test/link-exe-runner"
-AR_BIN="$(command -v llvm-ar 2>/dev/null || command -v ar 2>/dev/null || true)"
READELF_BIN="$(command -v llvm-readelf 2>/dev/null || command -v readelf 2>/dev/null || true)"
+KIT="${KIT:-$ROOT/build/kit}"
mkdir -p "$WORK" "$LOG_DIR"
-t1_require_exe "$LINK_EXE_RUNNER" 'run: make build/test/link-exe-runner'
-[ -n "$AR_BIN" ] || { echo "llvm-ar/ar not found" >&2; exit 2; }
+t1_require_exe "$KIT" 'run: make bin'
[ -n "$READELF_BIN" ] || { echo "llvm-readelf/readelf not found" >&2; exit 2; }
command -v clang >/dev/null 2>&1 || { echo "clang not found" >&2; exit 2; }
@@ -35,17 +33,28 @@ t1_run "$LOG_DIR/link-start-clang.log" \
clang "${CFLAGS[@]}" -c "$ROOT/test/link/harness/start.c" -o "$WORK/start.o"
echo "tier1 link: archive"
-t1_run "$LOG_DIR/link-ar.log" "$AR_BIN" rcs "$WORK/libtier1.a" "$WORK/archive_member.o"
+t1_run "$LOG_DIR/link-ar.log" "$KIT" ar rcs "$WORK/libtier1.a" "$WORK/archive_member.o"
echo "tier1 link: link executable"
-KIT_TEST_ARCH="$ARCH" KIT_TEST_OBJ=elf t1_run "$LOG_DIR/link-exe.log" \
- "$LINK_EXE_RUNNER" --gc-sections -o "$WORK/tier1.exe" \
- "$WORK/main.o" "$WORK/helper.o" "$WORK/start.o" \
- --archive "$WORK/libtier1.a"
+KIT_TEST_ARCH="$ARCH" t1_run "$LOG_DIR/link-exe.log" \
+ "$KIT" ld --gc-sections -e _start -o "$WORK/tier1.exe" \
+ "$WORK/main.o" "$WORK/helper.o" "$WORK/start.o" "$WORK/libtier1.a"
echo "tier1 link: inspect executable"
-"$READELF_BIN" -h "$WORK/tier1.exe" >"$WORK/tier1.readelf" 2>"$LOG_DIR/link-readelf.log"
+"$READELF_BIN" -aW "$WORK/tier1.exe" >"$WORK/tier1.readelf" 2>"$LOG_DIR/link-readelf.log"
grep -Eq 'Type:[[:space:]]+EXEC|Type:[[:space:]]+DYN' "$WORK/tier1.readelf"
grep -Eq 'Entry point address:[[:space:]]+0x[0-9a-fA-F]+' "$WORK/tier1.readelf"
+t1_assert_grep "link/archive-member-pulled" \
+ '[[:space:]]tier1_archive_value($|[[:space:]])' "$WORK/tier1.readelf"
+t1_assert_grep "link/helper-symbol" \
+ '[[:space:]]tier1_helper_value($|[[:space:]])' "$WORK/tier1.readelf"
+t1_assert_grep "link/live-data-relocated" \
+ '[[:space:]]tier1_live_data($|[[:space:]])' "$WORK/tier1.readelf"
+t1_assert_not_grep "link/gc-dead-archive-function" \
+ '[[:space:]]\.text\.tier1_archive_dead_value[[:space:]]+PROGBITS' \
+ "$WORK/tier1.readelf"
+t1_assert_not_grep "link/gc-dead-local-function" \
+ '[[:space:]]\.text\.tier1_dead_local[[:space:]]+PROGBITS' \
+ "$WORK/tier1.readelf"
echo "tier1 link: ok"
diff --git a/test/tier1/objlink/object.sh b/test/tier1/objlink/object.sh
@@ -9,14 +9,15 @@ TRIPLE="$(t1_clang_triple "$ARCH")"
KITCHEN="$ROOT/test/tier1/kitchen/objlink/object"
WORK="$(t1_work_dir "$ROOT" object)"
LOG_DIR="$(t1_log_dir "$ROOT")"
-ROUNDTRIP="$ROOT/build/test/kit-roundtrip"
NORMALIZE="$ROOT/test/elf/normalize.py"
+READELF_BIN="$(command -v llvm-readelf 2>/dev/null || command -v readelf 2>/dev/null || true)"
+KIT="${KIT:-$ROOT/build/kit}"
mkdir -p "$WORK" "$LOG_DIR"
-t1_require_exe "$ROUNDTRIP" 'run: make build/test/kit-roundtrip'
+t1_require_exe "$KIT" 'run: make bin'
command -v clang >/dev/null 2>&1 || { echo "clang not found" >&2; exit 2; }
command -v python3 >/dev/null 2>&1 || { echo "python3 not found" >&2; exit 2; }
-{ command -v llvm-readelf >/dev/null 2>&1 || command -v readelf >/dev/null 2>&1; } || {
+[ -n "$READELF_BIN" ] || {
echo "llvm-readelf/readelf not found" >&2
exit 2
}
@@ -27,12 +28,33 @@ t1_run "$LOG_DIR/object-clang.log" \
-fdata-sections "$KITCHEN/kitchen_object.c" -o "$WORK/kitchen.o"
echo "tier1 object: roundtrip"
-t1_run "$LOG_DIR/object-roundtrip.log" \
- "$ROUNDTRIP" "$WORK/kitchen.o" "$WORK/kitchen.rt.o"
+t1_run "$LOG_DIR/object-objcopy.log" \
+ "$KIT" objcopy "$WORK/kitchen.o" "$WORK/kitchen.rt.o"
+
+echo "tier1 object: inspect required ELF surface"
+"$READELF_BIN" -aW "$WORK/kitchen.o" >"$WORK/kitchen.raw.readelf" \
+ 2>"$LOG_DIR/object-raw-readelf.log"
+t1_assert_grep "object/common-symbol" \
+ '[[:space:]]COM[[:space:]]+tier1_common($|[[:space:]])' \
+ "$WORK/kitchen.raw.readelf"
+t1_assert_grep "object/weak-symbol" \
+ '[[:space:]]WEAK[[:space:]]+DEFAULT[[:space:]]+[A-Z0-9]+[[:space:]]+tier1_weak_hook($|[[:space:]])' \
+ "$WORK/kitchen.raw.readelf"
+t1_assert_grep "object/hidden-symbol" \
+ '[[:space:]]GLOBAL[[:space:]]+HIDDEN[[:space:]]+[A-Z0-9]+[[:space:]]+tier1_hidden_add($|[[:space:]])' \
+ "$WORK/kitchen.raw.readelf"
+t1_assert_grep "object/custom-data-section" \
+ '[[:space:]]\.data\.tier1[[:space:]]+PROGBITS' \
+ "$WORK/kitchen.raw.readelf"
+t1_assert_grep "object/data-relocation" \
+ 'Relocation section .*\.rela?\.(data|rodata).*' \
+ "$WORK/kitchen.raw.readelf"
echo "tier1 object: normalize diff"
-python3 "$NORMALIZE" readelf "$WORK/kitchen.o" >"$WORK/kitchen.readelf" 2>"$LOG_DIR/object-readelf-a.log" || true
-python3 "$NORMALIZE" readelf "$WORK/kitchen.rt.o" >"$WORK/kitchen.rt.readelf" 2>"$LOG_DIR/object-readelf-b.log" || true
+python3 "$NORMALIZE" readelf "$WORK/kitchen.o" >"$WORK/kitchen.readelf" \
+ 2>"$LOG_DIR/object-readelf-a.log"
+python3 "$NORMALIZE" readelf "$WORK/kitchen.rt.o" >"$WORK/kitchen.rt.readelf" \
+ 2>"$LOG_DIR/object-readelf-b.log"
t1_diff "$WORK/kitchen.readelf" "$WORK/kitchen.rt.readelf" "$WORK/kitchen.diff"
echo "tier1 object: ok"
diff --git a/test/tier1/system/README.md b/test/tier1/system/README.md
@@ -1,8 +1,8 @@
# Tier 1 System Sentinels
-These scripts are thin wrappers around existing cheap make targets or driver
-scripts. They are intended to catch broad system regressions quickly without
-pulling in cross-provisioning, VM, ecosystem, libc, or release suites.
+These scripts are manifest-driven wrappers around existing cheap make targets or
+driver scripts. They are intended to catch broad system regressions quickly
+without pulling in cross-provisioning, VM, ecosystem, libc, or release suites.
Each wrapper redirects command output into
`build/test/tier1/logs/system/<area>/` and prints the log path. On failure it
@@ -15,8 +15,9 @@ tails the captured log.
`hash`, `sha256sum`, `b2sum`, `crc32`, `disas`, `mc`, `compress`, `image`),
`test-driver-strings`, `test-driver-objdump`, `test-driver-objcopy`, and
`test-driver-strip`.
-- `runtime-headers.sh` runs `test-rt-headers`, compiling `test/rt/smoke.c`
- against the runtime headers for the cheap configured target triples.
+- `runtime-headers.sh` runs `test-rt-headers` for the triples listed in
+ `manifests/system/runtime-headers.txt`, then checks that every requested
+ smoke object was produced.
- `debug-dwarf.sh` runs DWARF reader and debug producer unit targets, one
committed `objdump --dwarf` golden, the lightweight `kit dbg` help transcript,
and the `addr2line`/`symbolize` backtrace smoke.
@@ -25,8 +26,7 @@ tails the captured log.
## Deferred
-The intentionally deferred suites are the heavier runtime execution and
-symbolization sweeps (`test-rt-runtime`, `test-rt-backtrace`), full debugger
-transcript matrix (`test-dbg`), self-distribution/update flow
-(`test-selfdist`), release artifact smoke, libc containers, ecosystem builds,
-and port/selfhost/cross-provisioning.
+The intentionally deferred suites are the heavier runtime execution sweep
+(`test-rt-runtime`), full debugger transcript matrix (`test-dbg`),
+self-distribution/update flow (`test-selfdist`), release artifact smoke, libc
+containers, ecosystem builds, and port/selfhost/cross-provisioning.
diff --git a/test/tier1/system/debug-dwarf.sh b/test/tier1/system/debug-dwarf.sh
@@ -56,10 +56,34 @@ if [ ! -f "$manifest" ]; then
exit 2
fi
-run_step bin make -C "$repo_root" bin || exit $?
-run_step test-dwarf make -C "$repo_root" test-dwarf || exit $?
-run_step test-debug make -C "$repo_root" test-debug || exit $?
-run_objdump_dwarf || exit $?
-run_step dbg-repl-help env KIT="$repo_root/build/kit" DBG_CASE=repl-help \
- sh "$repo_root/test/dbg/run.sh" || exit $?
-run_step addr2line-symbolize make -C "$repo_root" test-rt-backtrace
+count=0
+while IFS= read -r step || [ -n "$step" ]; do
+ step=${step%%#*}
+ step=$(printf '%s' "$step" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+ [ -n "$step" ] || continue
+ count=$((count + 1))
+ case "$step" in
+ make:bin)
+ run_step bin make -C "$repo_root" bin || exit $? ;;
+ make:test-dwarf)
+ run_step test-dwarf make -C "$repo_root" test-dwarf || exit $? ;;
+ make:test-debug)
+ run_step test-debug make -C "$repo_root" test-debug || exit $? ;;
+ driver:objdump-dwarf/01-dwarf-all)
+ run_objdump_dwarf || exit $? ;;
+ driver:dbg/repl-help)
+ run_step dbg-repl-help env KIT="$repo_root/build/kit" DBG_CASE=repl-help \
+ sh "$repo_root/test/dbg/run.sh" || exit $? ;;
+ driver:addr2line-symbolize)
+ run_step addr2line-symbolize make -C "$repo_root" test-rt-backtrace \
+ || exit $? ;;
+ *)
+ printf 'tier1/debug-dwarf: unknown manifest step: %s\n' "$step" >&2
+ exit 2 ;;
+ esac
+done < "$manifest"
+
+if [ "$count" -eq 0 ]; then
+ printf 'tier1/debug-dwarf: manifest has no runnable steps: %s\n' "$manifest" >&2
+ exit 2
+fi
diff --git a/test/tier1/system/dist.sh b/test/tier1/system/dist.sh
@@ -30,9 +30,16 @@ if [ ! -f "$manifest" ]; then
exit 2
fi
+count=0
while IFS= read -r target || [ -n "$target" ]; do
target=${target%%#*}
target=$(printf '%s' "$target" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[ -n "$target" ] || continue
+ count=$((count + 1))
run_step "$target" make -C "$repo_root" "$target" || exit $?
done < "$manifest"
+
+if [ "$count" -eq 0 ]; then
+ printf 'tier1/dist: manifest has no runnable targets: %s\n' "$manifest" >&2
+ exit 2
+fi
diff --git a/test/tier1/system/runtime-headers.sh b/test/tier1/system/runtime-headers.sh
@@ -30,4 +30,28 @@ if [ ! -f "$manifest" ]; then
exit 2
fi
-run_step test-rt-headers make -C "$repo_root" test-rt-headers
+targets=
+count=0
+while IFS= read -r target || [ -n "$target" ]; do
+ target=${target%%#*}
+ target=$(printf '%s' "$target" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+ [ -n "$target" ] || continue
+ targets="$targets $target"
+ count=$((count + 1))
+done < "$manifest"
+
+if [ "$count" -eq 0 ]; then
+ printf 'tier1/runtime-headers: manifest has no target triples: %s\n' "$manifest" >&2
+ exit 2
+fi
+
+run_step test-rt-headers make -C "$repo_root" \
+ RT_HEADER_TEST_TARGETS="$targets" test-rt-headers || exit $?
+
+for target in $targets; do
+ out="$repo_root/build/test/rt-headers/$target/smoke.o"
+ if [ ! -s "$out" ]; then
+ printf 'tier1/runtime-headers: missing compiled header smoke: %s\n' "$out" >&2
+ exit 1
+ fi
+done
diff --git a/test/tier1/system/tools.sh b/test/tier1/system/tools.sh
@@ -30,9 +30,16 @@ if [ ! -f "$manifest" ]; then
exit 2
fi
+count=0
while IFS= read -r target || [ -n "$target" ]; do
target=${target%%#*}
target=$(printf '%s' "$target" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[ -n "$target" ] || continue
+ count=$((count + 1))
run_step "$target" make -C "$repo_root" "$target" || exit $?
done < "$manifest"
+
+if [ "$count" -eq 0 ]; then
+ printf 'tier1/tools: manifest has no runnable targets: %s\n' "$manifest" >&2
+ exit 2
+fi