#!/bin/bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" SOURCE_DIR="${RUSTPROXY_SOURCE_DIR:?RUSTPROXY_SOURCE_DIR is required}" FREEBSD_RELEASE="${FREEBSD_RELEASE:-15.1-RELEASE}" DOCKER_IMAGE="${DOCKER_IMAGE:-rustproxy-freebsd15-builder:15.1-rust1.88}" DOCKER_CACHE_DIR="${DOCKER_CACHE_DIR:-/opt/opn-rustproxy/cache}" RUN_LINUX_TESTS="${RUN_LINUX_TESTS:-1}" APPLY_FREEBSD_PATCHES="${APPLY_FREEBSD_PATCHES:-1}" command -v docker >/dev/null 2>&1 || { echo "Docker is required" >&2; exit 1; } command -v rsync >/dev/null 2>&1 || { echo "rsync is required" >&2; exit 1; } [[ -f "$SOURCE_DIR/Cargo.toml" ]] || { echo "Invalid RustProxy source: $SOURCE_DIR" >&2; exit 1; } mkdir -p "$DOCKER_CACHE_DIR/cargo" "$DOCKER_CACHE_DIR/target" "$ROOT/dist/docker-build" "$ROOT/dist/.build-source" uid="$(id -u)" gid="$(id -g)" # Never modify the upstream checkout. FreeBSD/OPNsense-only patches are # applied to an isolated source copy which exists only for this build. BUILD_SOURCE_DIR="$SOURCE_DIR" PATCH_WORK_DIR="" cleanup_build_source() { if [[ -n "$PATCH_WORK_DIR" ]] && [[ -d "$PATCH_WORK_DIR" ]]; then rm -rf "$PATCH_WORK_DIR" fi } trap cleanup_build_source EXIT if [[ "$APPLY_FREEBSD_PATCHES" == "1" ]]; then PATCH_WORK_DIR="$(mktemp -d "$ROOT/dist/.build-source/rustproxy.XXXXXX")" rsync -a --delete \ --exclude='.git/' \ --exclude='target/' \ "$SOURCE_DIR/" "$PATCH_WORK_DIR/" "$ROOT/builder/freebsd/apply-patches.sh" "$PATCH_WORK_DIR" BUILD_SOURCE_DIR="$PATCH_WORK_DIR" else echo "FreeBSD/OPNsense source patches disabled (APPLY_FREEBSD_PATCHES=$APPLY_FREEBSD_PATCHES)." fi # Rebuild is cheap after the first run because the FreeBSD sysroot layer is cached. docker build \ --build-arg "FREEBSD_RELEASE=$FREEBSD_RELEASE" \ -t "$DOCKER_IMAGE" \ -f "$ROOT/builder/docker/Dockerfile" \ "$ROOT/builder/docker" run_args=( --rm --user "$uid:$gid" -e CARGO_HOME=/cargo -e CARGO_TARGET_DIR=/target -v "$BUILD_SOURCE_DIR:/src:ro" -v "$DOCKER_CACHE_DIR/cargo:/cargo" -v "$DOCKER_CACHE_DIR/target:/target" -v "$ROOT/dist/docker-build:/out" -w /src ) if [[ "$RUN_LINUX_TESTS" == "1" ]]; then echo "Running RustProxy tests in Linux builder container..." docker run "${run_args[@]}" "$DOCKER_IMAGE" \ cargo test --locked --release fi echo "Cross-compiling RustProxy for x86_64-unknown-freebsd..." docker run "${run_args[@]}" "$DOCKER_IMAGE" bash -c ' set -euo pipefail cargo build --locked --release --target x86_64-unknown-freebsd install -m 0555 /target/x86_64-unknown-freebsd/release/rust-proxy /out/rust-proxy desc="$(file -b /out/rust-proxy)" echo "$desc" header="$(llvm-readelf -h /out/rust-proxy)" printf "%s\n" "$header" | grep -E "Class:|Machine:|OS/ABI:" || true printf "%s\n" "$header" | grep -qi FreeBSD || { echo "Built ELF is not marked for FreeBSD" >&2; exit 1; } dynamic="$(llvm-readelf -d /out/rust-proxy || true)" printf "%s\n" "$dynamic" | grep NEEDED || true if printf "%s\n" "$dynamic" | grep -q "libc\.so\.6"; then echo "Linux libc detected in FreeBSD target binary" >&2 exit 1 fi ' RUSTPROXY_BINARY="$ROOT/dist/docker-build/rust-proxy" \ "$ROOT/builder/debian/package-freebsd.sh"