hosted.sh (14960B)
1 #!/usr/bin/env bash 2 # scripts/hosted.sh — one front-end for provisioning sysroots and 3 # cross-compiling+linking against them, across kit's hosted support set. Wraps 4 # the per-OS provisioners (it does not replace them): 5 # FreeBSD -> scripts/freebsd_sysroot.sh (base.txz extract) 6 # Windows -> scripts/llvm_mingw_sysroot.sh (llvm-mingw UCRT) 7 # Android -> scripts/android_ndk_sysroot.sh (Android NDK sysroot) 8 # Linux -> test/libc/{glibc,musl}/extract.sh (podman container extract) 9 # macOS -> host SDK (native; no cross sysroot) 10 # 11 # Targets: <os>[-<libc>]-<arch> (canonical arch tokens: aa64/x64/rv64[/rv32]) 12 # linux-glibc-{aa64,x64,rv64} linux-musl-{aa64,x64,rv64} 13 # freebsd-{aa64,x64,rv64} windows-{aa64,x64} android-aa64 macos-aa64 14 # freestanding-{aa64,x64,rv64,rv32,arm32} (no OS — cross only, bare-metal exec) 15 # Long arch spellings (aarch64/amd64/x86_64/riscv64) are accepted as input 16 # aliases; canon_token normalizes them to the short forms above. 17 # 18 # Commands: 19 # doctor support set + what is provisioned here 20 # list [selector] print expanded canonical tokens, one per line 21 # expand <selector> [--mode=cross|selfhost] 22 # like list, but mode-filtered (selfhost drops 23 # freestanding) and KIT_VM-filtered 24 # modes <target> print which modes apply ("cross" / "cross selfhost") 25 # prepare <target>|all provision the sysroot for a target 26 # path <target> print the sysroot dir ("" for macOS/freestanding) 27 # triple <target> print the kit -target triple 28 # tag <target> print the test/lib/exec_target.sh exec tag 29 # cc <target> [kit-cc-args] compile+link: kit cc -target T --sysroot S [...] 30 # 31 # Selector grammar (list/expand): all | <os> | linux-<libc> | <full-token> | 32 # comma-list of any of those. <os> is linux/freebsd/windows/macos/freestanding. 33 # 34 # env: KIT (default build/kit), KIT_VM (default 1; 0 drops freebsd/windows from 35 # expand), plus the per-OS provisioners' own env. 36 37 set -u 38 39 ROOT="$(cd "$(dirname "$0")/.." && pwd)" 40 KIT="${KIT:-$ROOT/build/kit}" 41 42 SUPPORT_SET_FALLBACK=" 43 linux-glibc-aa64 linux-musl-aa64 freebsd-aa64 android-aa64 freestanding-aa64 44 linux-glibc-x64 linux-musl-x64 freebsd-x64 freestanding-x64 45 linux-glibc-rv64 linux-musl-rv64 freebsd-rv64 freestanding-rv64 46 freestanding-rv32 freestanding-arm32 47 windows-aa64 windows-x64 macos-aa64 macos-x64 48 " 49 50 # A built candidate is the authority for selectors/triples. Keep the literal 51 # fallback only for bootstrap/provisioning before `make bin`; once `kit 52 # targets` is available, list/expand/doctor consume its versioned TSV registry. 53 # iOS/Wasm profiles are intentionally filtered here because this script has no 54 # provision/run personality for them yet; they remain visible in `kit targets`. 55 TARGET_REGISTRY_TSV="" 56 if [ -x "$KIT" ]; then 57 TARGET_REGISTRY_TSV="$("$KIT" targets --format=tsv 2>/dev/null || true)" 58 fi 59 SUPPORT_SET="$SUPPORT_SET_FALLBACK" 60 if [ -n "$TARGET_REGISTRY_TSV" ]; then 61 registry_support_set="$(printf '%s\n' "$TARGET_REGISTRY_TSV" | awk -F '\t' ' 62 $1 ~ /^linux-(glibc|musl)-(aa64|x64|rv64)$/ || 63 $1 ~ /^freebsd-(aa64|x64|rv64)$/ || 64 $1 ~ /^windows-(aa64|x64)$/ || 65 $1 == "android-aa64" || 66 $1 ~ /^macos-(aa64|x64)$/ || 67 $1 ~ /^freestanding-(aa64|x64|rv64|rv32|arm32)$/ { print $1 } 68 ')" 69 [ -n "$registry_support_set" ] && SUPPORT_SET="$registry_support_set" 70 fi 71 72 die() { printf 'hosted: %s\n' "$*" >&2; exit 1; } 73 74 # ---- target parsing -------------------------------------------------------- 75 # Sets globals: T_OS, T_LIBC (linux only), T_ARCH (canonical per-OS token). 76 parse_target() { 77 local t="$1" os rest a 78 os="${t%%-*}"; rest="${t#*-}" 79 T_OS="$os"; T_LIBC=""; T_ARCH="" 80 case "$os" in 81 linux) 82 T_LIBC="${rest%%-*}"; a="${rest#*-}" 83 case "$T_LIBC" in glibc|musl) ;; *) die "bad linux libc in '$t' (want glibc|musl)";; esac 84 case "$a" in 85 aa64|aarch64|arm64) T_ARCH=aarch64 ;; 86 x64|x86_64|amd64) T_ARCH=x64 ;; 87 rv64|riscv64) T_ARCH=rv64 ;; 88 *) die "bad linux arch '$a' in '$t'" ;; 89 esac ;; 90 freebsd) 91 case "$rest" in 92 amd64|x64|x86_64) T_ARCH=amd64 ;; 93 aarch64|arm64|aa64) T_ARCH=aarch64 ;; 94 riscv64|rv64) T_ARCH=riscv64 ;; 95 *) die "bad freebsd arch '$rest' in '$t'" ;; 96 esac ;; 97 windows) 98 case "$rest" in 99 x64|x86_64|amd64) T_ARCH=x64 ;; 100 aarch64|arm64|aa64) T_ARCH=aarch64 ;; 101 *) die "bad windows arch '$rest' in '$t'" ;; 102 esac ;; 103 android) 104 case "$rest" in 105 aarch64|arm64|aa64) T_ARCH=aarch64 ;; 106 *) die "bad android arch '$rest' in '$t' (want aa64)" ;; 107 esac ;; 108 macos) 109 case "$rest" in 110 aarch64|arm64|aa64) T_ARCH=aarch64 ;; 111 x64|x86_64|amd64) T_ARCH=x64 ;; 112 *) die "bad macos arch '$rest' in '$t' (want aa64|x64)" ;; 113 esac ;; 114 freestanding) 115 case "$rest" in 116 aarch64|arm64|aa64) T_ARCH=aarch64 ;; 117 x64|x86_64|amd64) T_ARCH=x64 ;; 118 rv64|riscv64) T_ARCH=rv64 ;; 119 rv32|riscv32) T_ARCH=rv32 ;; 120 arm32|arm|armv7m|armv7em|cortex-m3|cortex-m4|cortex-m7) T_ARCH=arm32 ;; 121 *) die "bad freestanding arch '$rest' in '$t'" ;; 122 esac ;; 123 *) die "unknown os in target '$t'" ;; 124 esac 125 } 126 127 triple_of() { 128 local canonical registry_triple 129 parse_target "$1" 130 canonical="$(canon_token "$1")" 131 if [ -n "$TARGET_REGISTRY_TSV" ]; then 132 registry_triple="$(printf '%s\n' "$TARGET_REGISTRY_TSV" | awk -F '\t' \ 133 -v selector="$canonical" '$1 == selector { print $2; exit }')" 134 if [ -n "$registry_triple" ]; then 135 printf '%s\n' "$registry_triple" 136 return 137 fi 138 fi 139 case "$T_OS" in 140 linux) 141 local suf=gnu; [ "$T_LIBC" = musl ] && suf=musl 142 case "$T_ARCH" in 143 aarch64) echo "aarch64-linux-$suf" ;; 144 x64) echo "x86_64-linux-$suf" ;; 145 rv64) echo "riscv64-linux-$suf" ;; 146 esac ;; 147 freebsd) 148 case "$T_ARCH" in 149 amd64) echo x86_64-freebsd ;; 150 aarch64) echo aarch64-freebsd ;; 151 riscv64) echo riscv64-freebsd ;; 152 esac ;; 153 windows) 154 case "$T_ARCH" in 155 x64) echo x86_64-windows ;; 156 aarch64) echo aarch64-windows ;; 157 esac ;; 158 android) 159 case "$T_ARCH" in 160 aarch64) echo aarch64-linux-android21 ;; 161 esac ;; 162 macos) 163 case "$T_ARCH" in 164 aarch64) echo aarch64-apple-darwin ;; 165 x64) echo x86_64-apple-darwin ;; 166 esac ;; 167 freestanding) 168 case "$T_ARCH" in 169 aarch64) echo aarch64-none-elf ;; 170 x64) echo x86_64-none-elf ;; 171 rv64) echo riscv64-none-elf ;; 172 rv32) echo riscv32-none-elf ;; 173 arm32) echo arm-none-eabi ;; 174 esac ;; 175 esac 176 } 177 178 # exec_target tag (test/lib/exec_target.sh). Linux/macOS use aa64/x64/rv64; 179 # FreeBSD uses amd64/aarch64/riscv64; Windows uses x64/aarch64. 180 tag_of() { 181 parse_target "$1" 182 local ea 183 case "$T_ARCH" in aarch64) ea=aa64 ;; x64) ea=x64 ;; rv64) ea=rv64 ;; *) ea="$T_ARCH" ;; esac 184 case "$T_OS" in 185 linux) [ "$T_LIBC" = glibc ] && echo "$ea-linux-glibc" || echo "$ea-linux" ;; 186 macos) echo "$ea-macos" ;; 187 freebsd) echo "$T_ARCH-freebsd" ;; 188 windows) echo "$T_ARCH-windows" ;; 189 android) echo "$ea-android" ;; 190 freestanding) echo "$ea-freestanding" ;; 191 esac 192 } 193 194 # Canonical token (<os>[-<libc>]-<short-arch>) for any input/alias spelling. 195 canon_token() { 196 parse_target "$1" 197 local ea 198 case "$T_ARCH" in 199 aarch64) ea=aa64 ;; x64|amd64) ea=x64 ;; rv64|riscv64) ea=rv64 ;; 200 rv32) ea=rv32 ;; arm32) ea=arm32 ;; *) ea="$T_ARCH" ;; 201 esac 202 case "$T_OS" in 203 linux) printf 'linux-%s-%s' "$T_LIBC" "$ea" ;; 204 *) printf '%s-%s' "$T_OS" "$ea" ;; 205 esac 206 } 207 208 # Which modes apply to a target. Freestanding has no hosted environment, so a 209 # compiler cannot run on it: cross only. 210 modes_of() { 211 parse_target "$1" 212 case "$T_OS" in 213 freestanding) echo cross ;; 214 android) echo cross ;; 215 macos) 216 # Self-host runs the freshly built kit on the host. A non-host macOS arch 217 # (e.g. an x86_64 kit on Apple silicon) would run under Rosetta, but that 218 # path isn't validated yet — so only the host-arch macOS target self-hosts. 219 local ha; ha="$(uname -m 2>/dev/null)" 220 case "$T_ARCH:$ha" in 221 aarch64:arm64|aarch64:aarch64|x64:x86_64|x64:amd64) echo "cross selfhost" ;; 222 *) echo cross ;; 223 esac ;; 224 *) echo "cross selfhost" ;; 225 esac 226 } 227 228 _linux_sysroot_dir() { # libc arch 229 local libc="$1" arch="$2" suf="" 230 case "$arch" in x64) suf=-x64 ;; rv64) suf=-rv64 ;; esac 231 printf '%s/sysroots/linux-%s%s' "${XDG_CACHE_HOME:-$HOME/.cache}/kit" "$libc" "$suf" 232 } 233 234 path_of() { 235 parse_target "$1" 236 case "$T_OS" in 237 linux) _linux_sysroot_dir "$T_LIBC" "$T_ARCH" ;; 238 freebsd) "$ROOT/scripts/freebsd_sysroot.sh" path "$T_ARCH" 2>/dev/null ;; 239 windows) "$ROOT/scripts/llvm_mingw_sysroot.sh" path "$T_ARCH" 2>/dev/null ;; 240 android) "$ROOT/scripts/android_ndk_sysroot.sh" path "$T_ARCH" 2>/dev/null ;; 241 macos) echo "" ;; 242 freestanding) echo "" ;; 243 esac 244 } 245 246 # ---- prepare --------------------------------------------------------------- 247 prepare_one() { 248 parse_target "$1" 249 case "$T_OS" in 250 linux) 251 command -v podman >/dev/null 2>&1 || die "podman required for linux sysroots" 252 bash "$ROOT/test/libc/$T_LIBC/extract.sh" -a "$T_ARCH" ;; 253 freebsd) "$ROOT/scripts/freebsd_sysroot.sh" "$T_ARCH" ;; 254 windows) "$ROOT/scripts/llvm_mingw_sysroot.sh" prepare "$T_ARCH" ;; 255 android) "$ROOT/scripts/android_ndk_sysroot.sh" prepare "$T_ARCH" ;; 256 macos) printf 'macos: native host SDK, nothing to prepare\n' ;; 257 freestanding) 258 printf 'freestanding: no sysroot to provision; run-time prereq is qemu-system-%s\n' \ 259 "$(triple_of "$1" | sed 's/-none-elf//')" ;; 260 esac 261 } 262 263 # ---- cc -------------------------------------------------------------------- 264 # cc <target> [extra kit cc args...] — adds -target, --sysroot, and any 265 # OS-mandatory flags; everything else (sources, -o, -O, -static, ...) passes 266 # through. macOS compiles native (no -target/--sysroot). 267 cc_target() { 268 local target="$1"; shift 269 parse_target "$target" 270 [ -x "$KIT" ] || die "kit not found at $KIT (run 'make bin')" 271 local triple sysroot; triple="$(triple_of "$target")"; sysroot="$(path_of "$target")" 272 local args=() 273 if [ "$T_OS" = macos ]; then 274 # Kit discovers and applies the native Xcode/CLT SDK itself. A native-arch 275 # build omits -target so the host default applies; a cross to the other 276 # macOS arch (e.g. x86_64 on Apple silicon, run via Rosetta) needs only the 277 # explicit target. No SDK-discovery helper is part of this path. 278 local ha; ha="$(uname -m 2>/dev/null)" 279 case "$T_ARCH:$ha" in 280 x64:arm64|x64:aarch64|aarch64:x86_64|aarch64:amd64) args+=(-target "$triple") ;; 281 esac 282 else 283 args+=(-target "$triple") 284 [ -n "$sysroot" ] && args+=(--sysroot "$sysroot") 285 [ "$T_OS" = windows ] && args+=(-mconsole) # console exit-code semantics 286 fi 287 exec "$KIT" cc "${args[@]}" "$@" 288 } 289 290 # ---- doctor ---------------------------------------------------------------- 291 doctor() { 292 printf 'host: %s/%s\n' "$(uname -s 2>/dev/null)" "$(uname -m 2>/dev/null)" 293 printf 'kit: %s%s\n' "$KIT" "$([ -x "$KIT" ] && echo '' || echo ' (missing)')" 294 printf 'support set (sysroot provisioned?):\n' 295 local t sr ok 296 for t in $SUPPORT_SET; do 297 sr="$(path_of "$t")" 298 case "$t" in 299 macos-*) ok='native' ;; 300 freestanding-*) ok='bare (qemu-system)' ;; 301 *) if [ -n "$sr" ] && [ -d "$sr" ]; then ok='yes'; else ok='no'; fi ;; 302 esac 303 printf ' %-22s triple=%-22s tag=%-16s sysroot=%s\n' \ 304 "$t" "$(triple_of "$t")" "$(tag_of "$t")" "$ok" 305 done 306 } 307 308 # ---- selector expansion ---------------------------------------------------- 309 # _match_one SELECTOR-ITEM -> space-separated canonical tokens (no filters). 310 _match_one() { 311 local it="$1" t 312 case "$it" in 313 linux|freebsd|windows|android|macos|freestanding) 314 for t in $SUPPORT_SET; do case "$t" in "$it"-*) printf '%s ' "$t" ;; esac; done 315 return ;; 316 linux-musl|linux-glibc) 317 for t in $SUPPORT_SET; do case "$t" in "$it"-*) printf '%s ' "$t" ;; esac; done 318 return ;; 319 esac 320 local c x; c="$(canon_token "$it")" || die "bad target '$it'" 321 for x in $SUPPORT_SET; do 322 [ "$x" = "$c" ] && { printf '%s ' "$c"; return; } 323 done 324 die "unknown target '$it' (not in support set; see '$0 list')" 325 } 326 327 # _expand_raw SELECTOR -> deduped canonical tokens (commas -> spaces; no 328 # filters). Returns non-zero (so callers can `|| die`) on an unknown token — 329 # _match_one's die exits only its own subshell, so we check each item's status. 330 _expand_raw() { 331 local sel item m raw="" t out="" 332 sel="$(printf '%s' "${1:-all}" | tr , ' ')" 333 for item in $sel; do 334 if [ "$item" = all ]; then raw="$raw $SUPPORT_SET"; continue; fi 335 m="$(_match_one "$item")" || return 1 336 raw="$raw $m" 337 done 338 for t in $raw; do case " $out " in *" $t "*) ;; *) out="$out $t" ;; esac; done 339 printf '%s' "${out# }" 340 } 341 342 # cmd_expand SELECTOR [--mode=cross|selfhost] -> filtered tokens, one per line. 343 # selfhost mode drops freestanding; KIT_VM=0 drops freebsd/windows. 344 cmd_expand() { 345 local sel="" mode="" a t toks 346 for a in "$@"; do case "$a" in --mode=*) mode="${a#--mode=}" ;; *) sel="$a" ;; esac; done 347 toks="$(_expand_raw "$sel")" || exit 1 348 for t in $toks; do 349 case "$t" in freebsd-*|windows-*) [ "${KIT_VM:-1}" = 0 ] && continue ;; esac 350 # selfhost mode keeps only targets whose modes_of advertises selfhost. This 351 # drops freestanding (cross-only) and a non-host-arch macOS target, whose 352 # self-host runs the built kit under emulation and isn't validated yet. 353 if [ "$mode" = selfhost ]; then 354 case " $(modes_of "$t") " in *" selfhost "*) ;; *) continue ;; esac 355 fi 356 printf '%s\n' "$t" 357 done 358 } 359 360 cmd="${1:-}" 361 case "$cmd" in 362 doctor) doctor ;; 363 list) shift; toks="$(_expand_raw "${1:-all}")" || exit 1; for t in $toks; do printf '%s\n' "$t"; done ;; 364 expand) shift; [ $# -ge 1 ] || die "usage: $0 expand <selector> [--mode=cross|selfhost]"; cmd_expand "$@" ;; 365 modes) [ $# -eq 2 ] || die "usage: $0 modes <target>"; modes_of "$2" ;; 366 prepare) 367 [ $# -ge 2 ] || die "usage: $0 prepare <selector>|all" 368 shift 369 toks="$(_expand_raw "$1")" || exit 1 370 for t in $toks; do prepare_one "$t"; done ;; 371 path) [ $# -eq 2 ] || die "usage: $0 path <target>"; path_of "$2" ;; 372 triple) [ $# -eq 2 ] || die "usage: $0 triple <target>"; triple_of "$2" ;; 373 tag) [ $# -eq 2 ] || die "usage: $0 tag <target>"; tag_of "$2" ;; 374 cc) [ $# -ge 2 ] || die "usage: $0 cc <target> [kit-cc-args]"; shift; cc_target "$@" ;; 375 -h|--help|help|"") sed -n '2,40p' "$0" | sed 's/^# \{0,1\}//' ;; 376 *) die "unknown command '$cmd' (try: doctor list expand modes prepare path triple tag cc)" ;; 377 esac