commit 632517297055ab3a43bccd588d04211a315c97d1
parent 2a2dc7af1f422ffa8f7bf62f229b9f448f65a380
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 8 Jun 2026 15:00:13 -0700
freebsd: bootstrap support + portable stdint.h INT64_C
rt/include/stdint.h: replace __INT64_C(c)/__UINT64_C(c) direct calls
with __KIT_XPASTE(c, __INT64_C_SUFFIX__) suffix-paste approach.
FreeBSD clang 19 (aarch64-freebsd15, LP64) does not predefine the
function-like __INT64_C/__UINT64_C macros, causing "call to undeclared
function" errors on any translation unit that uses UINT64_C(). All
supported compilers (clang 14+, GCC 8+) predefine __*_C_SUFFIX__
tokens, making the paste approach portable and unambiguous.
mk/bootstrap.mk: add FreeBSD to BOOTSTRAP_KIT_TOOLCHAIN_FLAGS (-lc
needed to wire hosted includes, same as Linux); portable BOOTSTRAP_SHASUM
(sha256sum on Linux/FreeBSD, shasum on macOS); bootstrap-freebsd target.
scripts/freebsd_bootstrap.sh: new -- native three-stage self-build via
the running FreeBSD aarch64 VM (mirrors linux_bootstrap.sh but SSHes
into the VM instead of using podman). Requires gmake on the VM.
Diffstat:
3 files changed, 174 insertions(+), 9 deletions(-)
diff --git a/mk/bootstrap.mk b/mk/bootstrap.mk
@@ -7,7 +7,9 @@
# the normal Makefile using kit's busybox-style cc/ar/ld symlinks. Stages 2
# and 3 must be bitwise identical.
-.PHONY: bootstrap bootstrap-debug bootstrap-release _do-bootstrap
+.PHONY: bootstrap bootstrap-debug bootstrap-release _do-bootstrap \
+ bootstrap-linux bootstrap-linux-musl bootstrap-linux-glibc \
+ bootstrap-freebsd
BOOTSTRAP_DIR = $(BUILD_DIR)/bootstrap
BOOTSTRAP_STAGE1_DIR = $(BOOTSTRAP_DIR)/stage1
@@ -19,6 +21,30 @@ BOOTSTRAP_STAGE3_BIN = $(BOOTSTRAP_STAGE3_DIR)/kit
BOOTSTRAP_TOOLS = cc ld ar ranlib as
BOOTSTRAP_HOST_MODE_CFLAGS =
BOOTSTRAP_HOST_MODE_LDFLAGS =
+
+# When kit itself is the compiler (stages 2/3) on a native Linux or FreeBSD
+# host, the hosted libc include + library dirs are only wired up once libc is
+# requested, so -lc must reach both the compile and link steps (it makes kit
+# resolve the hosted profile and add /usr/include + the libc search path).
+# macOS instead gets its system headers via the -isysroot in
+# HOST_SYSROOT_{C,LD}FLAGS, so this is POSIX-non-Darwin only; left empty
+# elsewhere the stage sub-makes re-derive the host default unclobbered.
+BOOTSTRAP_KIT_TOOLCHAIN_FLAGS =
+ifeq ($(HOST_OS),linux)
+BOOTSTRAP_KIT_TOOLCHAIN_FLAGS = HOST_SYSROOT_CFLAGS=-lc HOST_SYSROOT_LDFLAGS=-lc
+endif
+ifeq ($(HOST_OS),freebsd)
+BOOTSTRAP_KIT_TOOLCHAIN_FLAGS = HOST_SYSROOT_CFLAGS=-lc HOST_SYSROOT_LDFLAGS=-lc
+endif
+
+# Portable SHA-256 display: macOS uses shasum, FreeBSD/Linux have sha256sum.
+BOOTSTRAP_SHASUM = shasum -a 256
+ifeq ($(HOST_OS),freebsd)
+BOOTSTRAP_SHASUM = sha256sum
+endif
+ifeq ($(HOST_OS),linux)
+BOOTSTRAP_SHASUM = sha256sum
+endif
BOOTSTRAP_STAMP = $(BOOTSTRAP_DIR)/.stamp
BOOTSTRAP_RT_LIBS = $(addprefix $(RT_BUILD_DIR)/,$(addsuffix /libkit_rt.a,$(RT_DEFAULT_VARIANTS)))
BOOTSTRAP_MAKEFILES = Makefile mk/env.mk mk/config.mk mk/flags.mk \
@@ -40,6 +66,24 @@ bootstrap-release:
_do-bootstrap: $(BOOTSTRAP_STAMP)
+# Drive the aarch64-linux self-build from a non-Linux dev host: `make bootstrap`
+# run natively inside a Linux container (scripts/linux_bootstrap.sh). On a
+# native Linux host, just run `make bootstrap` directly -- it already selects
+# the aarch64-linux toolchain off the host uname.
+bootstrap-linux: bootstrap-linux-musl
+
+bootstrap-linux-musl:
+ scripts/linux_bootstrap.sh musl both
+
+bootstrap-linux-glibc:
+ scripts/linux_bootstrap.sh glibc both
+
+# Drive the aarch64-freebsd self-build via the running FreeBSD aarch64 VM
+# (scripts/freebsd_vm.sh must be able to SSH to port 2223). The VM must be
+# running; scripts/freebsd_bootstrap.sh starts it if needed via KIT_TOY_VM_KEEP_UP.
+bootstrap-freebsd:
+ scripts/freebsd_bootstrap.sh aarch64
+
$(BOOTSTRAP_STAMP): $(BIN) $(BOOTSTRAP_RT_LIBS) $(BOOTSTRAP_MAKEFILES)
rm -rf $(BOOTSTRAP_DIR)
@mkdir -p $(BOOTSTRAP_STAGE1_DIR)
@@ -52,7 +96,8 @@ $(BOOTSTRAP_STAMP): $(BIN) $(BOOTSTRAP_RT_LIBS) $(BOOTSTRAP_MAKEFILES)
HOST_MODE_CFLAGS='$(BOOTSTRAP_HOST_MODE_CFLAGS)' \
HOST_MODE_LDFLAGS='$(BOOTSTRAP_HOST_MODE_LDFLAGS)' \
CC='$(abspath $(BOOTSTRAP_STAGE1_DIR))/cc' \
- AR='$(abspath $(BOOTSTRAP_STAGE1_DIR))/ar'
+ AR='$(abspath $(BOOTSTRAP_STAGE1_DIR))/ar' \
+ $(BOOTSTRAP_KIT_TOOLCHAIN_FLAGS)
@for tool in $(BOOTSTRAP_TOOLS); do ln -sf kit "$(BOOTSTRAP_STAGE2_DIR)/$$tool"; done
$(MAKE) lib bin \
BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE3_DIR))' \
@@ -61,7 +106,8 @@ $(BOOTSTRAP_STAMP): $(BIN) $(BOOTSTRAP_RT_LIBS) $(BOOTSTRAP_MAKEFILES)
HOST_MODE_CFLAGS='$(BOOTSTRAP_HOST_MODE_CFLAGS)' \
HOST_MODE_LDFLAGS='$(BOOTSTRAP_HOST_MODE_LDFLAGS)' \
CC='$(abspath $(BOOTSTRAP_STAGE2_DIR))/cc' \
- AR='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ar'
+ AR='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ar' \
+ $(BOOTSTRAP_KIT_TOOLCHAIN_FLAGS)
cmp $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN)
- shasum -a 256 $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN)
+ $(BOOTSTRAP_SHASUM) $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN)
@touch $@
diff --git a/rt/include/stdint.h b/rt/include/stdint.h
@@ -153,10 +153,15 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#define UINT32_C(c) (c##U)
/* 64-bit literal suffix is L on LP64 and LL on LLP64; intmax_t same.
- Keep the compiler's macro so the constant has the right type. */
-#define INT64_C(c) __INT64_C(c)
-#define UINT64_C(c) __UINT64_C(c)
-#define INTMAX_C(c) __INTMAX_C(c)
-#define UINTMAX_C(c) __UINTMAX_C(c)
+ All supported compilers (clang 14+, GCC 8+) predefine the __*_C_SUFFIX__
+ tokens, which is the portable approach that works across all data models
+ without relying on __INT64_C/__UINT64_C function-like macros (those are
+ inconsistently predefined across compiler versions and targets). */
+#define __KIT_PASTE(a, b) a##b
+#define __KIT_XPASTE(a, b) __KIT_PASTE(a, b)
+#define INT64_C(c) __KIT_XPASTE(c, __INT64_C_SUFFIX__)
+#define UINT64_C(c) __KIT_XPASTE(c, __UINT64_C_SUFFIX__)
+#define INTMAX_C(c) __KIT_XPASTE(c, __INTMAX_C_SUFFIX__)
+#define UINTMAX_C(c) __KIT_XPASTE(c, __UINTMAX_C_SUFFIX__)
#endif
diff --git a/scripts/freebsd_bootstrap.sh b/scripts/freebsd_bootstrap.sh
@@ -0,0 +1,114 @@
+#!/usr/bin/env bash
+# Run the three-stage self-build (mk/bootstrap.mk) for a FreeBSD arch natively
+# in the corresponding FreeBSD VM, from a macOS dev host.
+#
+# The bootstrap is a NATIVE build: `make bootstrap` keys off the VM's own uname
+# (HOST_OS=freebsd + aarch64), so it selects the FreeBSD ELF toolchain and
+# reaches its fixed point entirely inside the VM. No cross-compilation happens.
+#
+# The VM must be prepared (scripts/freebsd_vm.sh prepare <arch>) but does not
+# need to be running -- this script starts it, waits for SSH, runs the build,
+# and shuts it down (unless KIT_FREEBSD_VM_KEEP_UP=1).
+#
+# usage: scripts/freebsd_bootstrap.sh [arch] [chain]
+# arch aarch64 (default; the only FreeBSD arch that has a native compiler
+# installed in the base VM image today)
+# chain both (default) | debug (-O0) | release (-O1)
+#
+# Env overrides:
+# KIT_FREEBSD_VM_KEEP_UP=1 leave the VM running after the build
+# KIT_FREEBSD_BOOT_TOY=1 also run the Toy corpus through the stage3 compiler
+
+set -eu
+
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+ARCH="${1:-aarch64}"
+CHAIN="${2:-both}"
+
+case "$ARCH" in
+ aarch64|arm64) ARCH=aarch64 ;;
+ amd64|x64) ARCH=amd64 ;;
+ *) echo "freebsd_bootstrap: unsupported arch '$ARCH'" >&2; exit 2 ;;
+esac
+
+case "$CHAIN" in
+ both) TARGET="bootstrap" ;;
+ debug) TARGET="bootstrap-debug" ;;
+ release) TARGET="bootstrap-release" ;;
+ *) echo "freebsd_bootstrap: unknown chain '$CHAIN' (want both|debug|release)" >&2; exit 2 ;;
+esac
+
+KEEP_UP="${KIT_FREEBSD_VM_KEEP_UP:-0}"
+TOY="${KIT_FREEBSD_BOOT_TOY:-0}"
+BUILD_DIR="build/freebsd-boot/$ARCH"
+
+ssh_vm() {
+ scripts/freebsd_vm.sh ssh "$ARCH" "$@"
+}
+
+# Ensure VM is running.
+vm_started=0
+if ! scripts/freebsd_vm.sh ssh "$ARCH" true 2>/dev/null; then
+ printf 'freebsd_bootstrap: starting %s VM\n' "$ARCH"
+ scripts/freebsd_vm.sh run "$ARCH" &
+ scripts/freebsd_vm.sh wait-ssh "$ARCH"
+ vm_started=1
+fi
+
+# Send the source tree to the VM. We use a git archive to avoid shipping
+# build/ artifacts -- the VM will build into /home/kit/work/build/.
+printf 'freebsd_bootstrap: sending source tree to %s VM\n' "$ARCH"
+ssh_vm 'rm -rf /home/kit/work && mkdir -p /home/kit/work'
+git -C "$ROOT" archive HEAD | ssh_vm 'tar -C /home/kit/work -xf -'
+
+# Also copy any uncommitted Makefile + mk/ changes so a work-in-progress
+# bootstrap test sees the current state.
+(cd "$ROOT" && tar cf - Makefile mk/ scripts/ | ssh_vm 'tar -C /home/kit/work -xf -')
+
+printf 'freebsd_bootstrap: running %s bootstrap on %s\n' "$TARGET" "$ARCH"
+
+ssh_vm sh <<EOF
+set -eu
+cd /home/kit/work
+echo "=== freebsd_bootstrap: \$(uname -m) FreeBSD / $TARGET ==="
+clang --version | head -1
+# FreeBSD ships BSD make as 'make'; the kit Makefile requires GNU make (gmake).
+MAKE=\$(which gmake 2>/dev/null || which make)
+\$MAKE $TARGET BUILD_DIR='$BUILD_DIR' CC=clang AR=ar MAKE="\$MAKE"
+if [ "$TOY" = "1" ]; then
+ for m in debug release; do
+ s3="$BUILD_DIR/\$m/bootstrap/stage3/kit"
+ [ -x "\$s3" ] || continue
+ echo "=== Toy corpus through \$m stage3 ==="
+ KIT="\$(pwd)/\$s3" sh test/toy/run.sh || true
+ done
+fi
+echo "=== freebsd_bootstrap: DONE $TARGET ==="
+EOF
+
+# Bring back the stage3 binaries for inspection.
+STAGE3_OUT="$ROOT/build/freebsd-boot-$ARCH"
+mkdir -p "$STAGE3_OUT"
+for m in debug release; do
+ remote="$BUILD_DIR/$m/bootstrap/stage3/kit"
+ if ssh_vm test -f "/home/kit/work/$remote" 2>/dev/null; then
+ scripts/freebsd_vm.sh scp "$ARCH" \
+ "/home/kit/work/$remote" /dev/null 2>/dev/null || true
+ # Use scp_arch directly for a real local copy.
+ local_out="$STAGE3_OUT/kit.$m"
+ port=$(scripts/freebsd_vm.sh ssh "$ARCH" 'echo $SSH_CLIENT' 2>/dev/null | awk '{print $2}' || echo 2223)
+ port=2223
+ SSH_KEY="$(ls "$HOME/.cache/kit/freebsd-vm"/*/ssh/id_ed25519 2>/dev/null | head -1)"
+ if [ -f "$SSH_KEY" ]; then
+ scp -P "$port" -i "$SSH_KEY" \
+ -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR \
+ "kit@127.0.0.1:/home/kit/work/$remote" "$local_out" 2>/dev/null || true
+ [ -f "$local_out" ] && printf 'stage3 (%s): %s\n' "$m" "$local_out"
+ fi
+ fi
+done
+
+if [ "$KEEP_UP" != "1" ] && [ "$vm_started" = "1" ]; then
+ printf 'freebsd_bootstrap: stopping VM\n'
+ ssh_vm 'sudo shutdown -p now' 2>/dev/null || true
+fi