Template
feat: self-host configure generation for stupidtools
Wire the full pipeline into the binary: parse + validate the KDL buildfile, discover extensions, bridge Lua, detect the C toolchain, and emit ./configure. Adds the project's own stupid.kdl build file and a temp-dir-isolated self-host integration test proving the generated configure + make rebuild the tool with -std=c23. tests/run.sh tests 6+8 re-pin the interim 'accepted, no read' CLI assertions to the wired 'missing buildfile -> exit 1' behavior.
This commit is contained in:
+11
-7
@@ -98,11 +98,13 @@ else
|
||||
fail "no arguments exited rc=$noargs_rc (want 1): $noargs_out"
|
||||
fi
|
||||
|
||||
# --- 6. one positional buildfile must be accepted (exit 0, no read) ------
|
||||
if "$BIN" buildfile.kdl >/dev/null 2>&1; then
|
||||
pass "one positional buildfile is accepted (exit 0)"
|
||||
# --- 6. a missing buildfile is a runtime error (exit 1) -------------------
|
||||
"$BIN" buildfile.kdl >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ "$rc" -eq 1 ]; then
|
||||
pass "missing buildfile exits 1 (runtime error)"
|
||||
else
|
||||
fail "one positional buildfile was rejected (rc=$?)"
|
||||
fail "missing buildfile exited rc=$rc (want 1)"
|
||||
fi
|
||||
|
||||
# --- 7. --version=1 is an unknown option form -> exit 2 -------------------
|
||||
@@ -115,10 +117,12 @@ else
|
||||
fi
|
||||
|
||||
# --- 8. -- ends option parsing; following text is positional --------------
|
||||
if "$BIN" -- --bogus >/dev/null 2>&1; then
|
||||
pass "-- terminates option parsing (--bogus taken as buildfile)"
|
||||
"$BIN" -- --bogus >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ "$rc" -eq 1 ]; then
|
||||
pass "-- terminates option parsing (--bogus taken as a missing buildfile: rc=1, not 2)"
|
||||
else
|
||||
fail "-- --bogus exited non-zero (rc=$?)"
|
||||
fail "-- --bogus exited rc=$rc (want 1, proving --bogus was a buildfile not an option)"
|
||||
fi
|
||||
|
||||
# --- 9. two positionals are a usage error -> exit 2 -----------------------
|
||||
|
||||
Executable
+181
@@ -0,0 +1,181 @@
|
||||
#!/bin/sh
|
||||
# tests/selfhost.sh - self-host integration test (plan todo 23).
|
||||
#
|
||||
# Proves stupidtools generates its OWN ./configure end to end: the tool
|
||||
# (already built by `make`) reads the repo's stupid.kdl, emits ./configure
|
||||
# into a TEMP dir, that configure produces a Makefile, and `make` builds a
|
||||
# working stupidtools whose compile line used -std=c23. The generated
|
||||
# configure/Makefile/binary live in the temp dir ONLY - the repo's own
|
||||
# autotools bootstrap (configure.ac + Makefile.am) is never touched, and no
|
||||
# in-tree residue is produced.
|
||||
#
|
||||
# POSIX sh only (dash/bash/zsh safe); no [[ ]], arrays, local, ==, <<<, &>.
|
||||
# Exit 0 = pass, non-zero = fail. Fails fast on a hard setup error.
|
||||
|
||||
TOP_DIR=$(cd "$(dirname "$0")/.." && pwd) || {
|
||||
echo "FAIL: cannot resolve project root" >&2
|
||||
exit 1
|
||||
}
|
||||
BIN="$TOP_DIR/src/stupidtools"
|
||||
|
||||
TESTS_RUN=0
|
||||
TESTS_FAILED=0
|
||||
|
||||
pass() {
|
||||
TESTS_RUN=$((TESTS_RUN + 1))
|
||||
printf 'ok %d - %s\n' "$TESTS_RUN" "$1"
|
||||
}
|
||||
|
||||
fail() {
|
||||
TESTS_RUN=$((TESTS_RUN + 1))
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
printf 'not ok %d - %s\n' "$TESTS_RUN" "$1" >&2
|
||||
}
|
||||
|
||||
# --- 1. the built binary must exist --------------------------------------
|
||||
if [ -x "$BIN" ]; then
|
||||
pass "binary exists and is executable: $BIN"
|
||||
else
|
||||
fail "binary missing: $BIN (run 'make' first)"
|
||||
printf 'FAILED: %d/%d checks failed\n' "$TESTS_FAILED" "$TESTS_RUN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- temp dir (isolated; cleaned on every exit path) ---------------------
|
||||
WORK=$(mktemp -d "${TMPDIR:-/tmp}/stupidtools-selfhost.XXXXXX") || {
|
||||
fail "cannot create temp dir"
|
||||
exit 1
|
||||
}
|
||||
cleanup() { rm -rf "$WORK"; }
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
# --- 2. copy stupid.kdl + write a Makefile.in into the temp dir ----------
|
||||
cp "$TOP_DIR/stupid.kdl" "$WORK/stupid.kdl" || {
|
||||
fail "cannot copy stupid.kdl into temp dir"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# The tool's own source list (repo-relative, kept in sync with stupid.kdl's
|
||||
# `target` and src/Makefile.am). Prefixed with $TOP_DIR so the self-hosted
|
||||
# build compiles the REAL sources from the isolated temp dir. The `\$(...)`
|
||||
# escapes keep CC/CFLAGS/LIBS as MAKE variables (substituted by configure);
|
||||
# `$SRCS` expands here (shell) into the absolute path list.
|
||||
SRCS="$TOP_DIR/src/main.c $TOP_DIR/src/cli.c $TOP_DIR/src/error.c $TOP_DIR/src/span.c \
|
||||
$TOP_DIR/src/kdl/lexer.c $TOP_DIR/src/kdl/parser.c $TOP_DIR/src/kdl/value.c $TOP_DIR/src/kdl/schema.c \
|
||||
$TOP_DIR/src/detect/check_registry.c $TOP_DIR/src/detect/checks.c $TOP_DIR/src/detect/probe.c $TOP_DIR/src/detect/resolve.c \
|
||||
$TOP_DIR/src/gen/sh_emit.c $TOP_DIR/src/gen/configure.c $TOP_DIR/src/gen/config.c $TOP_DIR/src/gen/args.c \
|
||||
$TOP_DIR/src/ext/discovery.c $TOP_DIR/src/ext/lua.c $TOP_DIR/src/ext/abi.c $TOP_DIR/src/ext/api.c \
|
||||
$TOP_DIR/src/ext/lang_c.c $TOP_DIR/src/ext/lang_cpp.c \
|
||||
$TOP_DIR/thirdparty/lua/lapi.c $TOP_DIR/thirdparty/lua/lauxlib.c \
|
||||
$TOP_DIR/thirdparty/lua/lbaselib.c $TOP_DIR/thirdparty/lua/lcode.c \
|
||||
$TOP_DIR/thirdparty/lua/lctype.c $TOP_DIR/thirdparty/lua/ldebug.c \
|
||||
$TOP_DIR/thirdparty/lua/ldo.c $TOP_DIR/thirdparty/lua/ldump.c \
|
||||
$TOP_DIR/thirdparty/lua/lfunc.c $TOP_DIR/thirdparty/lua/lgc.c \
|
||||
$TOP_DIR/thirdparty/lua/llex.c $TOP_DIR/thirdparty/lua/lmem.c \
|
||||
$TOP_DIR/thirdparty/lua/lobject.c $TOP_DIR/thirdparty/lua/lopcodes.c \
|
||||
$TOP_DIR/thirdparty/lua/lparser.c $TOP_DIR/thirdparty/lua/lstate.c \
|
||||
$TOP_DIR/thirdparty/lua/lstring.c $TOP_DIR/thirdparty/lua/ltable.c \
|
||||
$TOP_DIR/thirdparty/lua/ltm.c $TOP_DIR/thirdparty/lua/lundump.c \
|
||||
$TOP_DIR/thirdparty/lua/lvm.c $TOP_DIR/thirdparty/lua/lzio.c \
|
||||
$TOP_DIR/thirdparty/lua/lstrlib.c $TOP_DIR/thirdparty/lua/ltablib.c"
|
||||
|
||||
cat > "$WORK/Makefile.in" <<EOF
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ -std=c23 -Wall -Wextra -Wpedantic -I$TOP_DIR/src
|
||||
LIBS = @LIBS@
|
||||
prefix = @prefix@
|
||||
|
||||
all: stupidtools
|
||||
|
||||
stupidtools: $SRCS
|
||||
\$(CC) \$(CFLAGS) $SRCS -o stupidtools \$(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f stupidtools
|
||||
EOF
|
||||
pass "copied stupid.kdl + wrote Makefile.in"
|
||||
|
||||
# --- 3. generate ./configure from stupid.kdl ------------------------------
|
||||
# Isolate from the dev environment's extensions (XDG_DATA_HOME to a
|
||||
# nonexistent dir, STUPIDTOOLS_EXT emptied) so only the builtin modules
|
||||
# load. The binary writes ./configure to the CWD (the temp dir).
|
||||
if (cd "$WORK" && XDG_DATA_HOME="$WORK/xdg" STUPIDTOOLS_EXT= \
|
||||
"$BIN" stupid.kdl >gen.log 2>&1); then
|
||||
if [ -s "$WORK/configure" ]; then
|
||||
pass "stupidtools generated a non-empty ./configure"
|
||||
else
|
||||
fail "stupidtools exited 0 but wrote no ./configure (see $WORK/gen.log)"
|
||||
fi
|
||||
else
|
||||
rc=$?
|
||||
fail "stupidtools failed on stupid.kdl (rc=$rc): $(cat "$WORK/gen.log" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
# --- 4. run ./configure -> Makefile --------------------------------------
|
||||
if [ -s "$WORK/configure" ]; then
|
||||
if sh -n "$WORK/configure" 2>"$WORK/configure.n.err"; then
|
||||
pass "generated ./configure passes sh -n (POSIX syntax)"
|
||||
else
|
||||
fail "generated ./configure fails sh -n: $(cat "$WORK/configure.n.err" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
if (cd "$WORK" && sh ./configure >config.log 2>&1); then
|
||||
if [ -s "$WORK/Makefile" ]; then
|
||||
pass "./configure ran and wrote a non-empty Makefile"
|
||||
else
|
||||
fail "./configure exited 0 but wrote no Makefile (see $WORK/config.log)"
|
||||
fi
|
||||
else
|
||||
rc=$?
|
||||
fail "./configure failed (rc=$rc): $(cat "$WORK/config.log" 2>/dev/null)"
|
||||
fi
|
||||
else
|
||||
fail "skipping configure run (no ./configure was generated)"
|
||||
fi
|
||||
|
||||
# --- 5+6. build with make V=1 and assert -std=c23 ------------------------
|
||||
if [ -s "$WORK/Makefile" ]; then
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 300 make -C "$WORK" V=1 >"$WORK/make.log" 2>&1
|
||||
make_rc=$?
|
||||
else
|
||||
make -C "$WORK" V=1 >"$WORK/make.log" 2>&1
|
||||
make_rc=$?
|
||||
fi
|
||||
if [ "$make_rc" -eq 0 ] && [ -x "$WORK/stupidtools" ]; then
|
||||
pass "make built a stupidtools binary in the temp dir"
|
||||
else
|
||||
fail "make failed (rc=$make_rc): $(tail -n 5 "$WORK/make.log" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
if grep -q -- '-std=c23' "$WORK/make.log"; then
|
||||
pass "self-hosted compile line used -std=c23"
|
||||
else
|
||||
fail "compile line did NOT contain -std=c23 (see $WORK/make.log)"
|
||||
fi
|
||||
else
|
||||
fail "skipping make (no Makefile was written)"
|
||||
fi
|
||||
|
||||
# --- 7. the self-hosted binary must run ----------------------------------
|
||||
if [ -x "$WORK/stupidtools" ]; then
|
||||
if version_out=$("$WORK/stupidtools" --version 2>&1); then
|
||||
if [ "$version_out" = "stupidtools 1.0.0" ]; then
|
||||
pass "self-hosted binary --version reports: $version_out"
|
||||
else
|
||||
fail "self-hosted --version unexpected: '$version_out'"
|
||||
fi
|
||||
else
|
||||
rc=$?
|
||||
fail "self-hosted --version exited non-zero (rc=$rc): $version_out"
|
||||
fi
|
||||
else
|
||||
fail "skipping --version check (no self-hosted binary was built)"
|
||||
fi
|
||||
|
||||
# --- summary -------------------------------------------------------------
|
||||
if [ "$TESTS_FAILED" -ne 0 ]; then
|
||||
printf 'FAILED: %d/%d checks failed\n' "$TESTS_FAILED" "$TESTS_RUN" >&2
|
||||
exit 1
|
||||
fi
|
||||
printf 'All %d self-host checks passed.\n' "$TESTS_RUN"
|
||||
Reference in New Issue
Block a user