kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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:
Mmk/bootstrap.mk | 54++++++++++++++++++++++++++++++++++++++++++++++++++----
Mrt/include/stdint.h | 15++++++++++-----
Ascripts/freebsd_bootstrap.sh | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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