6.8 KiB
Build & Deployment
Philosophy
A single Heremetic build system (Meson + Nix flakes) produces all artifacts — C daemons, Go binaries, AppImage. Only the asan profile (the default for /xce-build) includes both debug symbols and ASAN; debug builds symbols without ASAN, and release builds (including the nix xcecore production package) carry neither. Tests run as part of the build, not after. Deployment for HA testing uses a scripted local cluster with per-node data directories and cert management.
Build Commands
All builds use /xce-build (skill at .claude/skills/xce-build/):
/xce-build # all components + all tests
/xce-build lib # libxce + lib tests
/xce-build controller # lib + controller + controller tests + xce_test driver
/xce-build scheduler # lib + scheduler + scheduler tests
/xce-build worker # lib + worker (daemon only, no unit tests)
/xce-build apiserver # lib + apiserver + xcecli + Go unit tests
/xce-build xcecli # xcecli + Go tests
/xce-build xceadmin # xceadmin (meson-driven; builds src/xceadmin's venv/tests)
controller always builds xce_test alongside xce_controller — the driver /xce-test-ha needs, in every profile below. There is no separate build step for it.
Each invocation:
nix developinto the hermetic shellmeson setup <dir> --buildtype=<type> -Db_sanitize=<mode>(fresh clean build)meson compile -C <dir> [targets...]— per-component invocations pass an explicit target list scoped to just that component (e.g.controllercompiles onlyxce_controller controller_unit_test controller/xce_test); only/xce-build allcompiles with no target args, building everything- Run registered meson tests (skipped for non-
asanprofiles — see below)
Three profiles, three build dirs (/xce-build [component] [profile], second arg optional): asan (default, debug+ASAN, xce.build/, runs the meson test suite) for everyday development and CI-style verification; debug (-O0 -g3 no sanitizer, build.dbg/, build-only) for gdb/core-dump root-causing of heisenbugs that ASAN's allocator perturbs away; release (-O3 no sanitizer, build.release/, build-only) for soak/perf runs against production-shaped binaries. Each profile's own dir means the three never clobber each other — a debug rebuild doesn't invalidate an asan binary already in use.
ASAN Integration
ASAN is enabled in every build by default (-Db_sanitize=address). Controller tests set detect_leaks=0 (known pre-existing leaks flagged as technical debt). Test binaries print LeakSanitizer reports on stderr after exit.
Meson Structure
src/
├── meson.build # top-level: subdir() order, project()
├── lib/meson.build # libxce shared library + libxce_test
├── controller/meson.build # xce_controller daemon + controller_unit_test
├── worker/meson.build # xcecd daemon
├── scheduler/meson.build # scheduler daemon + test
├── autoscaler/meson.build # libscaler static lib + provider tools (no daemon binary)
├── frontend/apiserver/meson.build # Go apiserver via tools/go_build
├── frontend/xcecli/meson.build # Go xcecli via tools/go_build
└── xceadmin/meson.build # xceadmin config-build tool (used by /xce-deploy-ha)
Dependency flow: lib → {controller, worker, scheduler, apiserver}
Test registration:
# controller/meson.build
test('controller test', controller_unit_test,
suite: 'controller',
timeout: 300,
env: ['ASAN_OPTIONS=detect_leaks=0'])
XCE_TESTING flag: The controller_unit_test executable compiles with -DXCE_TESTING to enable test-only seams (hook variables, reset functions).
Nix Flake
Located at src/flake.nix. Provides:
nix develop # hermetic dev shell (meson, pkgconfig, capnp, packcc, Go 1.23.4, etc.)
nix build .#xcecore # C daemons + apiserver (release)
nix build .#xcecore_debug # default package: debug + ASAN
nix build .#xcecli # CLI only
AppImage: nix build .#xcecore/.#xcecore_debug do not produce an AppImage — they only install xce (a copy of tools/appimage/entry.sh, see src/meson.build) as a plain shell entry-point binary. The xce flake package (appImageEntryPackage in src/flake.nix) wraps that entry script with bundled daemons, haproxy, glow, and less; the actual .AppImage file is produced separately with nix bundle --bundler github:ralismark/nix-appimage --option sandbox false .#xce (see README.md, "3.5 build AppImage package").
Local HA Cluster Deployment
/xce-deploy-ha (skill at .claude/skills/xce-deploy-ha/):
/xce-deploy-ha localhost:9991 localhost:9992 localhost:9993
This creates under /tmp/xce-deploy/:
certs/ # TLS certs for all peers
controller/
ctrl-1/
conf/{current, cluster.bin.<tag>} # primary's config (tag = sha256sum prefix)
data/ # WAL + checkpoint storage
ctrl-2/
conf/ # receives config via OPCode_replConfigPush
data/
ctrl-3/ (same as ctrl-2)
logs/ # per-node log files
scripts/
start.sh ctrl-N # launch a single node
cleanup.sh # wipe data/standby-conf/logs, keep ctrl-1 config + certs
Startup (from deploy dir):
VERBOSE=-vvv scripts/start.sh ctrl-1 & # primary first
sleep 0.5
VERBOSE=-vvv scripts/start.sh ctrl-2 & # standby (0.5s stagger for election ordering)
sleep 0.5
VERBOSE=-vvv scripts/start.sh ctrl-3 &
Clean restart (keeps certs + ctrl-1 config, wipes all data):
kill -9 $(pgrep xce_controller) 2>/dev/null || true
bash scripts/cleanup.sh
# Then re-start all nodes
Go Frontend Build
Go builds use src/frontend/Makefile for development, Meson for production:
make build-server # → /tmp/apiserver
make build-cli # → /tmp/xce_static (CGO_ENABLED=0)
make test # unit tests (CGO_ENABLED=0)
make test-backend # CGO-backed backend tests (needs nix dev shell)
make test-integration # full regression suite (needs XCE_BIN + SRV_URL)
Go modules are independent — apiserver and xcecli have separate go.mod files, no go.work.
Production Artifacts
| Artifact | Build command | Output |
|---|---|---|
| Controller daemon | nix build .#xcecore |
xce_controller binary |
| Worker daemon | same | xcecd binary |
| Scheduler daemon | same | xce_scheduler binary |
| REST API server | same | xce_apiserver binary |
| CLI tool | nix build .#xcecli |
xcecli binary |
| AppImage | nix bundle --bundler github:ralismark/nix-appimage --option sandbox false .#xce |
.AppImage bundle (see README.md 3.5) |
| Debug build | nix build .#xcecore_debug |
full debug + ASAN binaries |