From e750c0531ae5c6f239703d990a73a32ac2c2f27f Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Mon, 2 Nov 2026 02:50:49 +0100 Subject: [PATCH 1/2] ci(freebsd): add a dispatch-only, informational FreeBSD build workflow Add .github/workflows/freebsd.yml, a standalone workflow triggered only by workflow_dispatch. It builds the UI-embedded binary inside FreeBSD 15.1 and 14.4 x86_64 VMs (vmactions/freebsd-vm, full-SHA pin to v1.5.9) with the canonical scripts/build.sh and runs the binary with --version. It declares read-only permissions, uploads and publishes nothing, is not part of ci-ok and is not called by release.yml or dry-run.yml, so a FreeBSD red never gates a pull request or a release. scripts/env.sh now detects FreeBSD and selects gmake there (BSD make cannot read the GNU make syntax of Makefile.cbm) and make everywhere else; the environment summary line reports the choice. scripts/build.sh runs $MAKE at all three build call sites. macOS, Linux and Windows still run make, so their builds are unchanged. Distilled from #1422 by PR9000: the release matrix, the x86_64-host choice, the aarch64 exclusion, the vmactions VM approach with a SHA pin, fail-fast: false and the gmake detection all come from that pull request, which built on the FreeBSD groundwork of #1093, #1423 and #1467. Co-authored-by: Pedro Ramos <131530838+pr9000@users.noreply.github.com> Signed-off-by: Martin Vogel --- .github/workflows/freebsd.yml | 66 +++++++++++++++++++++++++++++++++++ scripts/build.sh | 9 ++--- scripts/env.sh | 17 +++++++-- 3 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/freebsd.yml diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml new file mode 100644 index 0000000000..ad3de23dd4 --- /dev/null +++ b/.github/workflows/freebsd.yml @@ -0,0 +1,66 @@ +# FreeBSD build, INFORMATIONAL ONLY. Builds the UI-embedded binary (the one +# every platform ships) inside a FreeBSD VM with the canonical scripts/build.sh, +# then checks that the binary starts (--version). +# +# NON-GATING: workflow_dispatch only. This workflow is not part of the ci-ok +# aggregate and is not called by release.yml or dry-run.yml, so a FreeBSD red +# never blocks a pull request or a release. Nothing from it is uploaded or +# published, and it runs with read-only permissions. +name: FreeBSD build (informational) + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + build-freebsd: + name: build (freebsd-${{ matrix.release }}, ${{ matrix.arch }}, clang) + strategy: + fail-fast: false + matrix: + release: ['15.1', '14.4'] + arch: ['x86_64'] + # arch: ['x86_64', 'aarch64'] + # aarch64 is disabled for now: lightningcss (a native Rust dependency + # of the Vite/CSS build) publishes no prebuilt binary for freebsd-arm64, + # so `npm run build` fails with "Cannot find module + # '../lightningcss.freebsd-arm64.node'". That is a gap in the package's + # platform coverage, not something fixable on our side without + # vendoring a Rust build of it. Re-enable once lightningcss ships that + # target, or once the frontend build runs natively on a Linux host + # instead of inside the FreeBSD VM. + include: + - arch: x86_64 + sync: rsync + # - arch: aarch64 + # sync: scp + # Must be an x86_64 host (ubuntu-latest). QEMU guest emulation on the arm + # runners (ubuntu-*-arm) degrades so badly that runs hit 3+ hour timeouts. + runs-on: ubuntu-latest + timeout-minutes: 90 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Build and run inside a FreeBSD ${{ matrix.release }} (${{ matrix.arch }}) VM + # https://github.com/vmactions/freebsd-vm + uses: vmactions/freebsd-vm@c46abacb49f09938ca4e1702d15d836285d694cc # v1.5.9 + with: + release: ${{ matrix.release }} + arch: ${{ matrix.arch }} + # Sync options: rsync, sshfs, nfs, scp + sync: ${{ matrix.sync }} + # Nothing from the VM is used after the run, so skip the copy back. + copyback: false + mem: 6144 + cpu: 4 + prepare: | + pkg update -f + pkg install -y gmake sqlite3 pkgconf node22 npm-node22 bash + which python3 >/dev/null 2>&1 || ln -sf $(which python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 2>/dev/null | head -n 1) /usr/local/bin/python3 + run: | + scripts/build.sh --with-ui CC=clang CXX=clang++ + build/c/codebase-memory-mcp --version diff --git a/scripts/build.sh b/scripts/build.sh index ad646c5de7..a8035f9cd3 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -193,17 +193,18 @@ else cbm_remove_build_dir "$ROOT" "$BUILD_DIR" fi -# Step 2: Build (Makefile applies $ARCHFLAGS for the target arch on macOS) +# Step 2: Build (Makefile applies $ARCHFLAGS for the target arch on macOS; +# $MAKE comes from env.sh: gmake on FreeBSD, make elsewhere) if [[ "$PHASE" == vendored ]]; then - make -j"$NPROC" -f Makefile.cbm cbm-third-party \ + "$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 \ + "$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[@]}"}" \ + "$MAKE" -j"$NPROC" -f Makefile.cbm cbm "${RETRACE_ARGS[@]+"${RETRACE_ARGS[@]}"}" \ CFLAGS_EXTRA="$CFLAGS_EXTRA" "${EXTRA_MAKE_ARGS[@]+"${EXTRA_MAKE_ARGS[@]}"}" fi diff --git a/scripts/env.sh b/scripts/env.sh index e23affe4ca..13ece00b52 100755 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -6,8 +6,9 @@ # Exports: # ARCH — target architecture (arm64 / x86_64) # ARCHFLAGS — "-arch " on macOS (target slice for clang/ld), empty elsewhere +# MAKE — make program for Makefile.cbm (gmake on FreeBSD, make elsewhere) # NPROC — number of CPU cores -# OS — darwin / linux / windows +# OS — darwin / linux / windows / freebsd set -euo pipefail @@ -16,10 +17,22 @@ OS="$(uname -s | tr '[:upper:]' '[:lower:]')" case "$OS" in darwin) OS="darwin" ;; linux) OS="linux" ;; + freebsd*) OS="freebsd" ;; mingw*|msys*|cygwin*) OS="windows" ;; *) OS="unknown" ;; esac +# ── Select the make program ──────────────────────────────────── +# Makefile.cbm is written in GNU make syntax. FreeBSD ships BSD make as its +# default make, so builds there run gmake (pkg install gmake); every other +# platform runs make. Not exported: build.sh sources this file and runs +# $MAKE in the same shell. +if [[ "$OS" == "freebsd" ]]; then + MAKE="gmake" +else + MAKE="make" +fi + # ── Detect / override architecture ───────────────────────────── # Default: native HARDWARE architecture (not Rosetta-translated). # On macOS under Rosetta, uname -m returns x86_64 even on Apple Silicon. @@ -128,5 +141,5 @@ fi # ── Print environment summary ────────────────────────────────── print_env() { local context="$1" - echo "=== $context: os=$OS arch=$ARCH cores=$NPROC cc=${CC:-default} cxx=${CXX:-default} ===" + echo "=== $context: os=$OS arch=$ARCH cores=$NPROC cc=${CC:-default} cxx=${CXX:-default} make=$MAKE ===" } From f13c84735518ec5e468245a4b93cef1a013a91c7 Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Mon, 2 Nov 2026 18:11:59 +0100 Subject: [PATCH 2/2] ci(freebsd): build the headless binary in the FreeBSD VM The first proof run failed in both FreeBSD legs at `npm ci`: the UI dependency tree pulls in onnxruntime-node, which publishes builds for win32, darwin and linux only, so npm stops with EBADPLATFORM before the frontend is built. The VM boot, the pkg prepare step, the gmake detection and the source sync all worked. The job now builds the headless binary (scripts/build.sh without --with-ui) and drops node22/npm-node22 from the prepare step. That still proves the C core builds and starts on FreeBSD; the UI bundle is platform-independent JavaScript and is built on every other leg. The aarch64 comment now says what is actually unproven. Signed-off-by: Martin Vogel --- .github/workflows/freebsd.yml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index ad3de23dd4..88daf25451 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -1,6 +1,9 @@ -# FreeBSD build, INFORMATIONAL ONLY. Builds the UI-embedded binary (the one -# every platform ships) inside a FreeBSD VM with the canonical scripts/build.sh, -# then checks that the binary starts (--version). +# FreeBSD build, INFORMATIONAL ONLY. Builds the headless binary (the C core, +# no embedded UI) inside a FreeBSD VM with the canonical scripts/build.sh, +# then checks that the binary starts (--version). The UI build is not run here: +# its npm dependency tree pulls in onnxruntime-node, which publishes no FreeBSD +# build, so `npm ci` stops with EBADPLATFORM. The UI bundle itself is +# platform-independent JavaScript and is built on every other leg. # # NON-GATING: workflow_dispatch only. This workflow is not part of the ci-ok # aggregate and is not called by release.yml or dry-run.yml, so a FreeBSD red @@ -23,14 +26,10 @@ jobs: release: ['15.1', '14.4'] arch: ['x86_64'] # arch: ['x86_64', 'aarch64'] - # aarch64 is disabled for now: lightningcss (a native Rust dependency - # of the Vite/CSS build) publishes no prebuilt binary for freebsd-arm64, - # so `npm run build` fails with "Cannot find module - # '../lightningcss.freebsd-arm64.node'". That is a gap in the package's - # platform coverage, not something fixable on our side without - # vendoring a Rust build of it. Re-enable once lightningcss ships that - # target, or once the frontend build runs natively on a Linux host - # instead of inside the FreeBSD VM. + # aarch64 is disabled for now: it has not been proven with this + # workflow. Its earlier blocker was the frontend build (lightningcss + # publishes no freebsd-arm64 binary), which this headless job no + # longer runs. Re-enable after a green aarch64 proof run. include: - arch: x86_64 sync: rsync @@ -59,8 +58,8 @@ jobs: cpu: 4 prepare: | pkg update -f - pkg install -y gmake sqlite3 pkgconf node22 npm-node22 bash + pkg install -y gmake sqlite3 pkgconf bash which python3 >/dev/null 2>&1 || ln -sf $(which python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 2>/dev/null | head -n 1) /usr/local/bin/python3 run: | - scripts/build.sh --with-ui CC=clang CXX=clang++ + scripts/build.sh CC=clang CXX=clang++ build/c/codebase-memory-mcp --version