kit

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

kit_cross.sh (7323B)


      1 #!/usr/bin/env bash
      2 # scripts/kit_cross.sh — build a runnable `kit` binary for a hosted support-set
      3 # target, using either clang (independent toolchain, clang + lld end to end) or
      4 # kit itself (dogfood) as the cross-compiler. The general form of the old
      5 # windows_cross.sh; see doc/plan/PORT.md.
      6 #
      7 #   kit_cross.sh <target> [--cc=clang|kit] [--verify]
      8 #
      9 # target   a hosted token: linux-{glibc,musl}-{aa64,x64,rv64} | freebsd-{aa64,
     10 #          x64,rv64} | windows-{aa64,x64} | macos-aa64. (freestanding is excluded
     11 #          — kit needs an OS to run on.)
     12 # --cc     toolchain backend (default: kit).
     13 # --verify after building, run the cross-built kit on the target via the exec
     14 #          seam (kit --version) to confirm it executes there.
     15 #
     16 # Output: build/kit-cross/<toolchain>/<target>/kit[.exe]
     17 #
     18 # env: KIT (default build/kit), KIT_CROSS_OPT (codegen opt, default -O0).
     19 
     20 set -eu
     21 
     22 ROOT="$(cd "$(dirname "$0")/.." && pwd)"
     23 cd "$ROOT"
     24 HOSTED="$ROOT/scripts/hosted.sh"
     25 KIT="${KIT:-$ROOT/build/kit}"
     26 
     27 die() { printf 'kit_cross: %s\n' "$*" >&2; exit 1; }
     28 
     29 TARGET=""; TC="kit"; VERIFY=0
     30 for a in "$@"; do
     31   case "$a" in
     32     --cc=*)   TC="${a#--cc=}" ;;
     33     --verify) VERIFY=1 ;;
     34     -*)       die "unknown flag '$a'" ;;
     35     *)        TARGET="$a" ;;
     36   esac
     37 done
     38 [ -n "$TARGET" ] || die "usage: kit_cross.sh <target> [--cc=clang|kit] [--verify]"
     39 case "$TC" in clang|kit) ;; *) die "bad --cc '$TC' (want clang|kit)" ;; esac
     40 
     41 # ---- resolve target --------------------------------------------------------
     42 os="${TARGET%%-*}"
     43 case "$os" in freestanding) die "$TARGET is freestanding — kit needs an OS to run on" ;; esac
     44 triple_kit="$("$HOSTED" triple "$TARGET")" || die "bad target '$TARGET'"
     45 sysroot="$("$HOSTED" path "$TARGET" 2>/dev/null || true)"
     46 # macos is the degenerate native case: hosted.sh returns no sysroot, so the
     47 # "sysroot" is the host SDK (both backends consume it: clang via -isysroot, kit
     48 # via --sysroot). kit's internal OS tag for macOS is `darwin`, not `macos`.
     49 hos="$os"
     50 if [ "$os" = macos ]; then
     51   hos=darwin
     52   [ -n "$sysroot" ] || sysroot="$(xcrun --show-sdk-path 2>/dev/null || true)"
     53 fi
     54 arch_tok="${TARGET##*-}"
     55 case "$arch_tok" in
     56   aa64|aarch64) harch=aarch64; carch=aarch64 ;;
     57   x64|x86_64|amd64) harch=x86_64; carch=x86_64 ;;
     58   rv64|riscv64) harch=rv64; carch=riscv64 ;;
     59   *) die "bad arch in '$TARGET'" ;;
     60 esac
     61 
     62 # clang target triple (differs from kit's for windows: mingw gnu).
     63 clang_triple() {
     64   case "$os" in
     65     linux)   echo "$triple_kit" ;;                                   # carch-linux-{gnu,musl}
     66     freebsd) echo "${carch}-unknown-freebsd${KIT_FREEBSD_CLANG_VER:-14}" ;;
     67     windows) echo "${carch}-w64-windows-gnu" ;;
     68     macos)   echo "" ;;                                              # native
     69   esac
     70 }
     71 
     72 BUILD_DIR="build/kit-cross/$TC/$TARGET"
     73 TCDIR="$ROOT/$BUILD_DIR/toolchain"
     74 mkdir -p "$TCDIR"
     75 
     76 # ---- toolchain wrappers ----------------------------------------------------
     77 if [ "$TC" = kit ]; then
     78   [ -x "$KIT" ] || die "kit not found at $KIT (run 'make bin')"
     79   cat > "$TCDIR/cc" <<EOF
     80 #!/bin/sh
     81 exec "$KIT" cc -target $triple_kit ${sysroot:+--sysroot "$sysroot"} "\$@"
     82 EOF
     83   chmod +x "$TCDIR/cc"
     84   for t in ar ranlib as ld; do ln -sf "$KIT" "$TCDIR/$t"; done
     85   CC_W="$TCDIR/cc"; AR_W="$TCDIR/ar"
     86 else
     87   command -v clang >/dev/null 2>&1 || die "clang not found"
     88   ct="$(clang_triple)"
     89   if [ "$os" = macos ]; then
     90     sdk="$(xcrun --show-sdk-path 2>/dev/null || true)"
     91     # -arch selects the slice (x86_64 cross-builds on an arm64 host run under
     92     # Rosetta); kit's `aarch64` tag is Apple's `arm64`. Without this the wrapper
     93     # silently builds the native slice while env.mk selects HOST_ARCH sources.
     94     case "$carch" in
     95       aarch64) maarch=arm64 ;;
     96       x86_64)  maarch=x86_64 ;;
     97       *)       die "bad macos arch '$carch'" ;;
     98     esac
     99     cat > "$TCDIR/cc" <<EOF
    100 #!/bin/sh
    101 exec clang -arch $maarch ${sdk:+-isysroot "$sdk"} "\$@"
    102 EOF
    103   else
    104     command -v ld.lld >/dev/null 2>&1 || command -v lld >/dev/null 2>&1 || die "lld not found (needed for clang cross-link)"
    105     [ -n "$sysroot" ] && [ -d "$sysroot" ] || die "sysroot missing for $TARGET — run 'make provision TARGET=$TARGET'"
    106     extra=""
    107     if [ "$os" = windows ]; then
    108       # llvm-mingw's runtime is compiler-rt + libunwind (not libgcc), so select
    109       # them explicitly and compose a resource dir = host clang's headers + the
    110       # sysroot's staged compiler-rt builtins (lib/windows). These are toolchain
    111       # runtime-selection flags, not source workarounds (the windows sources are
    112       # plain-clang-clean).
    113       [ -d "$sysroot/lib/windows" ] || \
    114         die "windows sysroot lacks compiler-rt builtins (lib/windows) — re-run 'make windows-ucrt-sysroots'"
    115       RD="$TCDIR/clang-rt"; mkdir -p "$RD/lib"
    116       ln -sfn "$(clang -print-resource-dir)/include" "$RD/include"
    117       ln -sfn "$sysroot/lib/windows" "$RD/lib/windows"
    118       extra="-rtlib=compiler-rt -unwindlib=libunwind -resource-dir $RD"
    119     fi
    120     cat > "$TCDIR/cc" <<EOF
    121 #!/bin/sh
    122 exec clang --target=$ct --sysroot "$sysroot" -fuse-ld=lld $extra -Wno-unused-command-line-argument "\$@"
    123 EOF
    124   fi
    125   chmod +x "$TCDIR/cc"
    126   CC_W="$TCDIR/cc"
    127   AR_W="$(command -v llvm-ar 2>/dev/null || command -v ar)"
    128 fi
    129 
    130 # ---- build -----------------------------------------------------------------
    131 # kit cc emits no -MMD deps, so wipe the object tree (keep the toolchain) for a
    132 # correct full rebuild; harmless for the clang backend too.
    133 find "$BUILD_DIR" -mindepth 1 -maxdepth 1 ! -name toolchain -exec rm -rf {} + 2>/dev/null || true
    134 JOBS="$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)"
    135 
    136 printf 'kit_cross: building kit for %s via %s (triple=%s)\n' "$TARGET" "$TC" \
    137   "$([ "$TC" = clang ] && clang_triple || echo "$triple_kit")"
    138 
    139 # RELEASE=1 enables -ffunction-sections/-fdata-sections; dead-section GC then
    140 # drops the dead sections target headers' unused static inlines pull in. -O0
    141 # codegen + asserts on (HOST_MODE_CPPFLAGS=) keeps the cross-build fast but
    142 # checked. The sysroot rides the cc wrapper, so env.mk's host -isysroot is
    143 # cleared. The GC flag is linker-specific: GNU/lld (and kit ld) take
    144 # --gc-sections; Apple ld (clang on darwin) takes -dead_strip.
    145 GC_LDFLAG="-Wl,--gc-sections"
    146 if [ "$TC" = clang ] && [ "$os" = macos ]; then GC_LDFLAG="-Wl,-dead_strip"; fi
    147 make bin -j"$JOBS" \
    148   BUILD_DIR="$BUILD_DIR" \
    149   HOST_OS="$hos" HOST_ARCH="$harch" \
    150   RELEASE=1 HOST_OPTFLAGS="${KIT_CROSS_OPT:--O0}" HOST_MODE_CPPFLAGS= \
    151   HOST_MODE_LDFLAGS="$GC_LDFLAG" \
    152   HOST_SYSROOT_CFLAGS= HOST_SYSROOT_LDFLAGS= \
    153   KIT_UPDATE_INDEX_URL="${KIT_UPDATE_INDEX_URL:-https://example.invalid/kit-development.index}" \
    154   KIT_RELEASE_PUBKEYS="${KIT_RELEASE_PUBKEYS:-test/dist/keys/nonrelease.pub}" \
    155   KIT_RELEASE_ALLOW_TEST_KEY="${KIT_RELEASE_ALLOW_TEST_KEY:-1}" \
    156   CC="$CC_W" AR="$AR_W"
    157 
    158 OUT="$BUILD_DIR/kit"
    159 if [ "$os" = windows ]; then
    160   # Both clang and kit auto-append .exe to a -o output that has no extension for
    161   # a windows target, so the linker writes kit.exe directly (no copy needed).
    162   OUT="$BUILD_DIR/kit.exe"
    163 fi
    164 printf 'kit_cross: built %s\n' "$OUT"
    165 file "$OUT" 2>/dev/null || true
    166 
    167 # ---- verify (optional): run the cross-built kit on the target --------------
    168 if [ "$VERIFY" = 1 ]; then
    169   printf 'kit_cross: verifying %s runs on %s\n' "$OUT" "$TARGET"
    170   bash "$ROOT/scripts/kit_cross_verify.sh" "$TARGET" "$OUT"
    171 fi