flyedge.service runs /opt/fly/current/fly-edge After= and Requires= flysim.service, with its metrics on loopback :9102 and a ConditionPathExists so a release without the binary leaves it inactive. It is in no target and 07-enable.sh does not enable it; the header has the switch and the way back. build-flysim.sh also builds fly-edge beside the flysim binary and package-release.sh ships it when present. 05-deploy.sh writes FLY_FEED_VIA (default direct) into fly.env, flysim.service names FLY_BUS_DIR=/run/fly/bus and tmpfiles creates it. Watchdog check 2 reads the feed counters from whoever serves the feed: flyedge when fly.env says bus. lint.sh holds all of that, and drives check 2's choice against a fixture.
121 lines
6.3 KiB
Bash
Executable file
121 lines
6.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# infra/build/build-flysim.sh [OUT_PATH]
|
|
#
|
|
# Run INSIDE the throwaway build container (the throwaway build container `fly-build`, Debian 13,
|
|
# 16 cores, onboot=0 — docs/design/infra.md section 2), never on the WSL
|
|
# box and never on the host directly. Building against a newer glibc than
|
|
# Debian 13 trixie's and running on trixie fails at load; the build box
|
|
# being the same template on the same host removes that class of problem
|
|
# entirely.
|
|
#
|
|
# The sharp edge this script exists to get right every time:
|
|
# RUSTFLAGS="-C target-cpu=haswell" correct — the host's E5-2660 v3 is Haswell
|
|
# RUSTFLAGS="-C target-cpu=native" WRONG off-host — a different build
|
|
# machine's native ISA (e.g. Zen3) can
|
|
# emit instructions Haswell does not
|
|
# have; illegal instruction at run time.
|
|
#
|
|
# Also rejects musl static linking (x86_64-unknown-linux-musl): musl's
|
|
# allocator is materially slower under the per-millisecond neuron sweep's
|
|
# allocation pattern, and real-time factor is the whole ballgame. Ships a
|
|
# dynamically linked glibc binary built on the matching template instead.
|
|
#
|
|
# FLY_CARGO_FEATURES — opt-in cargo features for the flysim bin, comma or
|
|
# space separated. DEFAULT EMPTY, which is the plain CPU-only release build
|
|
# every tagged release so far was made with. The only feature today is
|
|
# `cuda`, the bit-exact LIF tick on the GPU:
|
|
#
|
|
# FLY_CARGO_FEATURES=cuda infra/build/build-flysim.sh ./flysim
|
|
#
|
|
# Three things make that safe to compile into a release binary, all measured
|
|
# (infra/docs/lif-cuda-spike.md, infra/docs/cuda-on-dev.md):
|
|
#
|
|
# * it needs no CUDA toolkit to build — the PTX is committed and embedded
|
|
# with include_str!, and the driver JITs it at module load;
|
|
# * `cudarc` is built with `dynamic-loading`, so `libcuda` is dlopen'd on
|
|
# first use. `ldd` on the binary lists no CUDA library, and a run
|
|
# without FLY_LIF_CUDA=1 never opens the driver — the same binary is
|
|
# therefore deployable to a GPU-less container;
|
|
# * the GPU tick is bit-exact with the CPU one, so `--print-compatibility`
|
|
# is byte-identical to a CPU-only build of the same tree and a live
|
|
# checkpoint restores onto either.
|
|
#
|
|
# Compiling the feature in does NOT turn it on. The backend attaches only
|
|
# when `FLY_LIF_CUDA=1` reaches the process, which on a container means
|
|
# `FLY_LIF_CUDA=1` in the env file so 05-deploy.sh writes it into
|
|
# /etc/fly/fly.env (off by default there too).
|
|
set -euo pipefail
|
|
|
|
log() { echo "build-flysim: $*" >&2; }
|
|
die() { echo "build-flysim: FATAL: $*" >&2; exit 1; }
|
|
|
|
: "${CARGO_TARGET:=x86_64-unknown-linux-gnu}"
|
|
: "${FLY_CARGO_FEATURES:=}"
|
|
OUT_PATH="${1:-./flysim}"
|
|
|
|
command -v cargo >/dev/null 2>&1 || die "cargo not found — this must run inside fly-build (the build container), which has the Rust toolchain, not on the host or the WSL box"
|
|
|
|
if [ "$CARGO_TARGET" != "x86_64-unknown-linux-gnu" ]; then
|
|
die "refusing target '$CARGO_TARGET': must be x86_64-unknown-linux-gnu (glibc), never a *-musl target"
|
|
fi
|
|
|
|
crate_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../services/flysim" 2>/dev/null && pwd || true)"
|
|
if [ -z "$crate_dir" ]; then
|
|
die "services/flysim does not exist yet in this checkout (it is built by workstream W1, docs/stream-mvp-plan.md) — nothing to build"
|
|
fi
|
|
|
|
# Empty FLY_CARGO_FEATURES must produce the plain command, not `--features ''`
|
|
# (cargo accepts that, but it would put an empty-string feature in the build
|
|
# plan's fingerprint and make a default build look different from every
|
|
# release built before this knob existed). An array, so the flag and its
|
|
# value survive as two argv entries whatever the feature list contains.
|
|
features_args=()
|
|
if [ -n "$FLY_CARGO_FEATURES" ]; then
|
|
features_args=(--features "$FLY_CARGO_FEATURES")
|
|
log "opt-in cargo features: $FLY_CARGO_FEATURES (default is none — see the FLY_CARGO_FEATURES note in this script's header)"
|
|
fi
|
|
|
|
log "building in $crate_dir for target-cpu=haswell (the host is E5-2660 v3, Haswell, AVX2, no AVX-512)"
|
|
(
|
|
cd "$crate_dir"
|
|
RUSTFLAGS="-C target-cpu=haswell" cargo build --release --target "$CARGO_TARGET" --bin flysim "${features_args[@]}"
|
|
# fly-edge (FLY_FEED_VIA=bus, docs/design/flybus.md): the feed WebSocket
|
|
# served from flysim's feed bus. Small, and no cargo features of its own;
|
|
# built every time so a release can switch a container onto the bus
|
|
# without a rebuild. It lands next to OUT_PATH, where package-release.sh
|
|
# looks for it.
|
|
RUSTFLAGS="-C target-cpu=haswell" cargo build --release --target "$CARGO_TARGET" --bin fly-edge
|
|
)
|
|
|
|
built="${crate_dir}/target/${CARGO_TARGET}/release/flysim"
|
|
[ -x "$built" ] || die "expected binary not found after build: $built"
|
|
|
|
# Sanity: confirm it is dynamically linked glibc, not a static/musl binary.
|
|
if command -v file >/dev/null 2>&1; then
|
|
file "$built" | grep -q 'dynamically linked' || die "$built does not look dynamically linked — check for an accidental musl/static target"
|
|
fi
|
|
|
|
# Sanity: no CUDA library may appear in the link. The `cuda` feature is only
|
|
# deployable because `cudarc`'s `dynamic-loading` dlopen's libcuda on first
|
|
# use — a DT_NEEDED on libcuda.so.1 instead would make the binary refuse to
|
|
# start on any container without the userspace driver, including the release container
|
|
# before gate 2 of the v0.2 plan and the fly-build container itself. Checked
|
|
# unconditionally, because the way this breaks is someone turning
|
|
# `dynamic-loading` off in Cargo.toml, not someone setting the env var.
|
|
if command -v ldd >/dev/null 2>&1; then
|
|
if ldd "$built" 2>/dev/null | grep -qi 'libcuda\|libnvrtc\|libcudart'; then
|
|
die "$built links a CUDA library dynamically — cudarc must keep its 'dynamic-loading' feature so libcuda is dlopen'd, or this binary cannot start on a GPU-less container:
|
|
$(ldd "$built" | grep -i 'libcuda\|libnvrtc\|libcudart')"
|
|
fi
|
|
fi
|
|
|
|
cp "$built" "$OUT_PATH"
|
|
chmod 0755 "$OUT_PATH"
|
|
log "built $OUT_PATH ($(du -h "$OUT_PATH" | cut -f1))"
|
|
edge_built="${crate_dir}/target/${CARGO_TARGET}/release/fly-edge"
|
|
[ -x "$edge_built" ] || die "expected binary not found after build: $edge_built"
|
|
edge_out="$(dirname "$OUT_PATH")/fly-edge"
|
|
cp "$edge_built" "$edge_out"
|
|
chmod 0755 "$edge_out"
|
|
log "built $edge_out ($(du -h "$edge_out" | cut -f1))"
|
|
log "next: infra/build/package-release.sh VERSION $OUT_PATH <stage-dir> <bridge-dir> <out-dir>"
|