Files
codebase-memory-mcp/scripts/build.sh
T

211 lines
7.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# build.sh — Clean build of production binary (standard or with UI).
#
# Usage:
# scripts/build.sh # Standard binary
# scripts/build.sh --with-ui # Binary with the UI embedded
# scripts/build.sh --help # Full usage
# scripts/build.sh --version v0.8.0 # With version stamp
# scripts/build.sh --arch x86_64 # Force x86_64 build
# scripts/build.sh CC=gcc-14 CXX=g++-14 # Override compiler
#
# This script is the SINGLE source of truth for building release binaries.
# Used identically in local development and CI workflows.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
usage() {
cat <<'EOF'
Usage: scripts/build.sh [--with-ui] [--version V] [--arch ARCH] [VAR=VAL ...]
The canonical production-build entry: identical in local CI, PR CI, dry run
and release. Always a CLEAN build of BUILD_DIR (build/c by default) — the
content-verified compiler cache (ccache via scripts/env.sh) makes repeat
builds fast without ever reusing a stale object: every object is re-derived
from current sources; a cache hit is byte-identical to a cold compile by
construction (CCACHE_COMPILERCHECK=content).
Options:
--with-ui Build the web UI as a content-addressed sidecar (needs node).
--version V Stamp the version string (release venue passes the tag).
--arch ARCH Force target arch (arm64 | x86_64), e.g. under Rosetta.
--vendored-only Build only the third-party objects (make cbm-third-party)
into a clean BUILD_DIR, no binary.
--reuse-vendored Do NOT clean BUILD_DIR: build the binary on top of a
--vendored-only run with the same arguments, compiling
first-party code only. The pair exists for CodeQL's light
PR scan (codeql.yml): the first runs before tracing starts.
--retrace-from F With --reuse-vendored: F lists vendored paths (one per
line) whose objects must be rebuilt anyway (make -W), so a
vendored file the PR changes is compiled under tracing too.
-h, --help This text.
Make passthrough (VAR=VAL, forwarded verbatim):
CC= CXX= Compiler override (venues pass their matrix compiler).
BUILD_DIR= Build in an isolated directory — REQUIRED when a clean
product build must not wipe build/c's test-runner (e.g.
build/smoke for the local ladder smoke).
STATIC=1 Fully static portable build (Alpine/musl leg).
EXTRA_CFLAGS= EXTRA_LDFLAGS= Sanitizer soak builds (see _soak.yml).
Environment:
CBM_NO_CCACHE=1 Disable the compiler cache (build correctness is identical;
only speed changes).
Callers: _build.yml (all release artifacts) · pr.yml pr-smoke · every
docker-compose build/smoke service · win.sh build (Windows VM ladder).
EOF
}
for arg in "$@"; do
case "$arg" in
-h|--help) usage; exit 0 ;;
esac
done
# Pre-parse --arch flag before sourcing env.sh
for arg in "$@"; do
case "$arg" in
--arch=*) export CBM_ARCH="${arg#--arch=}" ;;
esac
done
prev_arg=""
for arg in "$@"; do
if [[ "${prev_arg:-}" == "--arch" ]]; then
export CBM_ARCH="$arg"
fi
prev_arg="$arg"
done
# shellcheck source=env.sh
source "$ROOT/scripts/env.sh"
# shellcheck source=path-safety.sh
source "$ROOT/scripts/path-safety.sh"
# Parse remaining arguments. BUILD_DIR is tracked for the clean step below so
# containerized legs can build in their own directory instead of deleting and
# clobbering the host's native build/c artifacts.
WITH_UI=false
PHASE=all
RETRACE_FROM=""
VERSION=""
BUILD_DIR="build/c"
EXTRA_MAKE_ARGS=()
prev_arg=""
for arg in "$@"; do
# Skip --arch and its value (already handled)
if [[ "${prev_arg:-}" == "--arch" ]]; then
prev_arg="$arg"
continue
fi
case "$arg" in
--with-ui)
WITH_UI=true
;;
--vendored-only)
PHASE=vendored
;;
--reuse-vendored)
PHASE=reuse
;;
--version|--retrace-from)
prev_arg="$arg"
continue
;;
--arch|--arch=*)
;; # already handled
-*)
# STRICT: an unknown flag never falls through into make where it
# would fail cryptically (or worse, be absorbed).
echo "build.sh: unknown option '$arg'. Please consult --help." >&2
exit 2
;;
BUILD_DIR=*)
BUILD_DIR="${arg#BUILD_DIR=}"
EXTRA_MAKE_ARGS+=("$arg")
;;
CC=*|CXX=*)
export "${arg}"
EXTRA_MAKE_ARGS+=("$arg")
;;
*=*)
EXTRA_MAKE_ARGS+=("$arg") # VAR=VAL make passthrough
;;
*)
# Bare words are only ever the value of --version; anything else is
# a usage error, not a silent make argument.
if [[ "${prev_arg:-}" == "--version" ]]; then
VERSION="$arg"
elif [[ "${prev_arg:-}" == "--retrace-from" ]]; then
RETRACE_FROM="$arg"
else
echo "build.sh: unexpected argument '$arg'. Please consult --help." >&2
exit 2
fi
;;
esac
prev_arg="$arg"
done
# Version flag
CFLAGS_EXTRA=""
if [[ -n "$VERSION" ]]; then
CLEAN_VERSION="${VERSION#v}"
CFLAGS_EXTRA="-DCBM_VERSION=\"\\\"$CLEAN_VERSION\\\"\""
fi
print_env "build.sh"
echo " ui=$WITH_UI version=${VERSION:-dev}"
# Verify compiler supports target arch
verify_compiler "$CC"
if [[ "$PHASE" != all ]] && $WITH_UI; then
echo "build.sh: --vendored-only / --reuse-vendored do not combine with --with-ui. Please consult --help." >&2
exit 2
fi
# --retrace-from: each listed path becomes `make -W <path>` (treated as changed
# now -- the retrace helper supplies direct compilation entrypoints, so nested
# includes do not depend on Makefile wildcard coverage; no timestamp race).
RETRACE_ARGS=()
if [[ -n "$RETRACE_FROM" ]]; then
if [[ "$PHASE" != reuse || ! -f "$RETRACE_FROM" ]]; then
echo "build.sh: --retrace-from needs --reuse-vendored and an existing list file. Please consult --help." >&2
exit 2
fi
while IFS= read -r retrace_path || [[ -n "$retrace_path" ]]; do
[[ -n "$retrace_path" ]] && RETRACE_ARGS+=(-W "$retrace_path")
done < "$RETRACE_FROM"
fi
# Step 1: Clean C build artifacts only (not node_modules — npm ci handles that).
# --reuse-vendored keeps the third-party objects of the --vendored-only run.
if [[ "$PHASE" == reuse ]]; then
if [[ ! -d "$BUILD_DIR" ]]; then
echo "build.sh: --reuse-vendored needs a --vendored-only run in $BUILD_DIR first." >&2
exit 2
fi
else
cbm_remove_build_dir "$ROOT" "$BUILD_DIR"
fi
# Step 2: Build (Makefile applies $ARCHFLAGS for the target arch on macOS)
if [[ "$PHASE" == vendored ]]; then
make -j"$NPROC" -f Makefile.cbm cbm-third-party \
CFLAGS_EXTRA="$CFLAGS_EXTRA" "${EXTRA_MAKE_ARGS[@]+"${EXTRA_MAKE_ARGS[@]}"}"
echo "=== Third-party objects built in ${BUILD_DIR} (no binary) ==="
exit 0
elif $WITH_UI; then
make -j"$NPROC" -f Makefile.cbm cbm-with-ui \
CFLAGS_EXTRA="$CFLAGS_EXTRA" "${EXTRA_MAKE_ARGS[@]+"${EXTRA_MAKE_ARGS[@]}"}"
else
make -j"$NPROC" -f Makefile.cbm cbm "${RETRACE_ARGS[@]+"${RETRACE_ARGS[@]}"}" \
CFLAGS_EXTRA="$CFLAGS_EXTRA" "${EXTRA_MAKE_ARGS[@]+"${EXTRA_MAKE_ARGS[@]}"}"
fi
echo "=== Build complete: ${BUILD_DIR}/codebase-memory-mcp ==="