feat(build): add --incremental flag to xce-build.sh (bug-1565)

setup_build() unconditionally rm -rf'd the whole profile build
directory on every single-component invocation -- running
/xce-build xceadmin after /xce-build controller silently deleted
xce_controller/xce_test/etc. from the same build dir.

Added an opt-in --incremental flag (meson setup --reconfigure in
place instead of wiping) rather than changing the default: this
project's capnp-generation custom_target has known missing-
dependency-edge races that a full wipe currently papers over as a
loud, retry-fixable failure. Making incremental the default risked
turning that same gap into silent stale-generated-code instead, so
the safer full-wipe behavior is preserved unless explicitly opted
into.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-08-17 10:20:36 +00:00
parent 986a330472
commit 1c943e98fe
Signed by: rshen
SSH key fingerprint: SHA256:8Vf2pZ3h6rJa7EhGK+WaAQ9Mta/apZvteW6g9U/WKKk

View file

@ -1,6 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
# --incremental (bug-1565 escape hatch): opt-in, NOT the default. Every
# invocation normally does a full `rm -rf "$BUILD_DIR"` + fresh `meson
# setup` (see setup_build below) -- correct in isolation, but since
# `meson compile` afterward only rebuilds the ONE requested component, a
# single-component build silently deletes any OTHER already-built binary
# sharing that same dir (e.g. `/xce-build xceadmin` after `/xce-build
# controller` in xce.build/ wipes xce_controller). --incremental instead
# reconfigures the EXISTING dir in place (`meson setup --reconfigure`),
# preserving whatever else was already built there.
#
# Deliberately NOT made the default: this project's capnp-generation
# custom_target (lib/controller.capnp.h/.c) has documented, unfixed
# missing-dependency-edge races (buglog.json, "retry once before
# debugging"). A full wipe papers over that gap -- worst case it's a loud,
# self-evident, retry-fixable failure on a clean build. Without the wipe,
# the SAME gap can instead cause silent staleness: a `.capnp` schema edit
# not triggering regeneration, so the build reports success while linking
# against stale generated code. Use --incremental only when you specifically
# want a sibling component alongside an already-built one in the same dir;
# rebuild without it (a real clean build) if anything looks off afterward.
INCREMENTAL=0
ARGS=()
for arg in "$@"; do
case "$arg" in
--incremental) INCREMENTAL=1 ;;
*) ARGS+=("$arg") ;;
esac
done
set -- "${ARGS[@]}"
COMPONENT="${1:-all}"
# Build PROFILE controls the meson buildtype + sanitizer (and the default build
@ -48,16 +78,25 @@ SRC_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$SRC_DIR"
usage() {
echo "Usage: $0 [component] [profile|build_dir] [build_dir]"
echo "Usage: $0 [component] [profile|build_dir] [build_dir] [--incremental]"
echo "Components: all (default), lib, controller, scheduler, worker, apiserver, xcecli, xceadmin"
echo "Profiles: asan (default), debug (non-ASAN -O0 -g3, for gdb/cores), release"
echo "--incremental: reconfigure the existing build dir in place instead of a full"
echo " rm -rf + fresh setup -- preserves other already-built components in the same"
echo " dir (bug-1565). Not the default: see the comment at the top of this script"
echo " for the staleness tradeoff. Rebuild without it if anything looks wrong."
exit 1
}
setup_build() {
echo "=== Clean build: $BUILD_DIR (profile=$PROFILE) ==="
rm -rf "$BUILD_DIR"
meson setup "$BUILD_DIR" "${MESON_OPTS[@]}"
if [ "$INCREMENTAL" = 1 ] && [ -f "$BUILD_DIR/build.ninja" ]; then
echo "=== Incremental build: $BUILD_DIR (profile=$PROFILE) — reconfiguring in place, other components' binaries preserved. If anything looks wrong, rebuild without --incremental. ==="
meson setup --reconfigure "$BUILD_DIR" "${MESON_OPTS[@]}"
else
echo "=== Clean build: $BUILD_DIR (profile=$PROFILE) ==="
rm -rf "$BUILD_DIR"
meson setup "$BUILD_DIR" "${MESON_OPTS[@]}"
fi
}
case "$COMPONENT" in
@ -139,6 +178,11 @@ case "$COMPONENT" in
setup_build
echo "=== Building + testing xceadmin (via meson) ==="
meson compile -C "$BUILD_DIR" xceadmin
WHEEL_FILE=$(ls "$BUILD_DIR"/xceadmin/dist/xceadmin-*.whl 2>/dev/null || true)
if [ -n "$WHEEL_FILE" ]; then
echo "=== xceadmin wheel: $WHEEL_FILE ==="
echo " Install it directly with: pip install \"$WHEEL_FILE\""
fi
;;
all)
setup_build