kit

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

freebsd_sysroot.sh (5446B)


      1 #!/usr/bin/env bash
      2 # Build FreeBSD cross-compile sysroots from the official base.txz dist sets.
      3 #
      4 # Reproducible and VM-free: downloads (and caches) the base.txz for an arch,
      5 # verifies it against the release MANIFEST, then extracts the curated subset
      6 # kit -- and a clang/lld reference build -- needs. Both the downloaded tarball
      7 # and the extracted sysroot live under the XDG cache so `make clean` does not
      8 # wipe them.
      9 #
     10 # usage:
     11 #   scripts/freebsd_sysroot.sh <arch>|all     extract (cached unless FORCE=1)
     12 #   scripts/freebsd_sysroot.sh path <arch>    print the sysroot dir
     13 #
     14 # arches: amd64|x64 | aarch64|arm64 | riscv64|rv64
     15 #
     16 # env:
     17 #   KIT_FREEBSD_RELEASE         release tag (default: 15.0-RELEASE)
     18 #   KIT_FREEBSD_SYSROOT_CACHE   cache root (default: $XDG_CACHE_HOME/kit/freebsd-sysroot/<release>)
     19 #   KIT_FREEBSD_DIST_URL        mirror base (default: https://download.freebsd.org/releases)
     20 #   FORCE=1                     re-download / re-extract even if cached
     21 
     22 set -eu
     23 
     24 RELEASE="${KIT_FREEBSD_RELEASE:-15.0-RELEASE}"
     25 XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
     26 CACHE="${KIT_FREEBSD_SYSROOT_CACHE:-$XDG_CACHE_HOME/kit/freebsd-sysroot/$RELEASE}"
     27 MIRROR="${KIT_FREEBSD_DIST_URL:-https://download.freebsd.org/releases}"
     28 
     29 die() { printf 'freebsd-sysroot: %s\n' "$*" >&2; exit 1; }
     30 
     31 canon_arch() {
     32   case "${1:-}" in
     33     amd64|x64|x86_64) echo amd64 ;;
     34     aarch64|arm64|aa64) echo aarch64 ;;
     35     riscv64|rv64) echo riscv64 ;;
     36     *) die "unknown arch '${1:-}'" ;;
     37   esac
     38 }
     39 
     40 # FreeBSD dist layout is <machine>/<machine_arch>/<release>/base.txz.
     41 dist_path() {
     42   case "$(canon_arch "$1")" in
     43     amd64) echo amd64/amd64 ;;
     44     aarch64) echo arm64/aarch64 ;;
     45     riscv64) echo riscv/riscv64 ;;
     46   esac
     47 }
     48 
     49 sysroot_dir() { printf '%s/%s\n' "$CACHE" "$(canon_arch "$1")"; }
     50 
     51 # Curated members pulled out of base.txz. Headers + crt objects + the static
     52 # and shared libc, the FreeBSD-15 libsys split, and the compiler runtime
     53 # (libcompiler_rt / libgcc) whose helpers libc references -- e.g. rv64's
     54 # binary128 __multf3. The libgcc.a / libgcc_s.so symlinks and their targets
     55 # (libcompiler_rt.a, lib/libgcc_s.so.1) are listed together so they resolve.
     56 # Missing optional members (some arches lack a given crt variant) are
     57 # tolerated; a missing libc.a is fatal.
     58 SYSROOT_MEMBERS=(
     59   ./usr/include
     60   ./usr/lib/crt1.o ./usr/lib/crti.o ./usr/lib/crtn.o ./usr/lib/Scrt1.o
     61   ./usr/lib/crtbegin.o ./usr/lib/crtbeginT.o ./usr/lib/crtbeginS.o
     62   ./usr/lib/crtend.o ./usr/lib/crtendS.o
     63   ./usr/lib/libc.a ./usr/lib/libsys.a ./usr/lib/libm.a
     64   ./usr/lib/libssp_nonshared.a ./usr/lib/libc_nonshared.a
     65   ./usr/lib/libcompiler_rt.a ./usr/lib/libgcc.a ./usr/lib/libgcc_eh.a
     66   ./usr/lib/libgcc_s.so
     67   ./usr/lib/libpthread.a ./usr/lib/libthr.a
     68   ./lib/libc.so.7 ./lib/libsys.so.7 ./lib/libgcc_s.so.1
     69   ./lib/libpthread.so.3 ./lib/libthr.so.3
     70 )
     71 
     72 fetch_txz() {
     73   local arch="$1" dp url txz want got
     74   dp="$(dist_path "$arch")"
     75   url="$MIRROR/$dp/$RELEASE/base.txz"
     76   txz="$CACHE/dist/$arch-base.txz"
     77   mkdir -p "$CACHE/dist"
     78   if [ "${FORCE:-0}" = 1 ] || [ ! -f "$txz" ]; then
     79     printf 'download %s\n' "$url" >&2
     80     curl -fL --retry 3 -o "$txz.tmp" "$url" || die "download failed: $url"
     81     mv "$txz.tmp" "$txz"
     82   fi
     83   # Verify against the release MANIFEST (sha256 in column 2). Best effort: if
     84   # the MANIFEST is unreachable we proceed with the cached tarball.
     85   want="$(curl -fsL "$MIRROR/$dp/$RELEASE/MANIFEST" 2>/dev/null \
     86             | awk '$1=="base.txz"{print $2}')"
     87   if [ -n "$want" ]; then
     88     got="$(shasum -a 256 "$txz" | awk '{print $1}')"
     89     [ "$want" = "$got" ] || die "base.txz sha256 mismatch for $arch ($got != $want); rm $txz and retry"
     90     printf 'verified base.txz sha256 %s\n' "$got" >&2
     91   fi
     92   printf '%s\n' "$txz"
     93 }
     94 
     95 build_sysroot() {
     96   local arch dst txz
     97   arch="$(canon_arch "$1")"
     98   dst="$(sysroot_dir "$arch")"
     99   if [ "${FORCE:-0}" != 1 ] && [ -f "$dst/usr/lib/libc.a" ]; then
    100     printf 'sysroot cached: %s\n' "$dst"
    101     return 0
    102   fi
    103   txz="$(fetch_txz "$arch")"
    104   rm -rf "$dst"
    105   mkdir -p "$dst"
    106   printf 'extract sysroot %s -> %s\n' "$arch" "$dst"
    107   # bsdtar/GNU tar both extract named members (and whole dirs); a member absent
    108   # from the archive is a warning + nonzero exit, not a stop -- tolerate it and
    109   # gate on libc.a instead.
    110   tar -xf "$txz" -C "$dst" "${SYSROOT_MEMBERS[@]}" 2>/dev/null || true
    111   [ -f "$dst/usr/lib/libc.a" ] || die "extraction incomplete for $arch (no usr/lib/libc.a)"
    112   # FreeBSD uses libthr as the real thread library; libpthread is a symlink.
    113   # Recreate the symlinks so -lpthread/-lthr resolve correctly.
    114   if [ -f "$dst/lib/libthr.so.3" ]; then
    115     [ -e "$dst/usr/lib/libthr.so" ]    || ln -s ../../lib/libthr.so.3    "$dst/usr/lib/libthr.so"
    116     [ -e "$dst/usr/lib/libpthread.so" ] || ln -s ../../lib/libthr.so.3   "$dst/usr/lib/libpthread.so"
    117   fi
    118   if [ -f "$dst/lib/libpthread.so.3" ]; then
    119     [ -e "$dst/usr/lib/libpthread.so" ] || ln -s ../../lib/libpthread.so.3 "$dst/usr/lib/libpthread.so"
    120   fi
    121   if [ -f "$dst/usr/lib/libthr.a" ] && [ ! -e "$dst/usr/lib/libpthread.a" ]; then
    122     ln -s libthr.a "$dst/usr/lib/libpthread.a"
    123   fi
    124   printf 'sysroot ready: %s\n' "$dst"
    125 }
    126 
    127 cmd="${1:-}"
    128 case "$cmd" in
    129   ""|-h|--help|help)
    130     sed -n '2,24p' "$0" | sed 's/^# \{0,1\}//'
    131     ;;
    132   path)
    133     [ $# -eq 2 ] || die "usage: $0 path <arch>"
    134     sysroot_dir "$2"
    135     ;;
    136   all)
    137     for a in amd64 aarch64 riscv64; do build_sysroot "$a"; done
    138     ;;
    139   *)
    140     build_sysroot "$cmd"
    141     ;;
    142 esac