llvm_mingw_sysroot.sh (8545B)
1 #!/usr/bin/env bash 2 # Download the pinned llvm-mingw UCRT package into the user cache and extract 3 # only target headers/libs for kit's Windows cross-compile tests. 4 5 set -eu 6 7 ROOT="$(cd "$(dirname "$0")/.." && pwd)" 8 RELEASE="${KIT_LLVM_MINGW_RELEASE:-20260602}" 9 BASE_URL="${KIT_LLVM_MINGW_BASE_URL:-https://github.com/mstorsjo/llvm-mingw/releases/download/$RELEASE}" 10 11 cache_root() { 12 if [ -n "${KIT_LLVM_MINGW_DOWNLOAD_DIR:-}" ]; then 13 printf '%s\n' "$KIT_LLVM_MINGW_DOWNLOAD_DIR" 14 return 0 15 fi 16 if [ -n "${XDG_CACHE_HOME:-}" ]; then 17 printf '%s\n' "$XDG_CACHE_HOME/kit/llvm-mingw/$RELEASE" 18 return 0 19 fi 20 if [ -n "${HOME:-}" ]; then 21 printf '%s\n' "$HOME/.cache/kit/llvm-mingw/$RELEASE" 22 return 0 23 fi 24 printf 'llvm-mingw-sysroot: set XDG_CACHE_HOME, HOME, or KIT_LLVM_MINGW_DOWNLOAD_DIR\n' >&2 25 exit 1 26 } 27 28 DL_ROOT="$(cache_root)" 29 OUT_ROOT="${KIT_LLVM_MINGW_ROOT:-${XDG_CACHE_HOME:-$HOME/.cache}/kit/sysroots/windows/$RELEASE/ucrt}" 30 31 usage() { 32 cat <<EOF 33 usage: scripts/llvm_mingw_sysroot.sh <command> [arch] 34 35 commands: 36 doctor print selected package and tool availability 37 fetch download and verify the host llvm-mingw UCRT package 38 prepare [arch|all] extract target include/ and lib/ dirs (default: all) 39 path <arch> print the extracted target sysroot path 40 env <arch> print a KIT_SYSROOT export for the target sysroot 41 42 arches: 43 x64 | x86_64 | amd64 | aarch64 | arm64 | aa64 | all 44 45 downloads: 46 $DL_ROOT 47 48 extracted sysroots: 49 $OUT_ROOT 50 EOF 51 } 52 53 die() { 54 printf 'llvm-mingw-sysroot: %s\n' "$*" >&2 55 exit 1 56 } 57 58 canon_arch() { 59 case "${1:-all}" in 60 x64|x86_64|amd64) echo x64 ;; 61 aarch64|arm64|aa64) echo aarch64 ;; 62 all|"") echo all ;; 63 *) die "unknown arch '${1:-}'" ;; 64 esac 65 } 66 67 target_triple() { 68 case "$(canon_arch "$1")" in 69 x64) echo x86_64-w64-mingw32 ;; 70 aarch64) echo aarch64-w64-mingw32 ;; 71 *) die "target_triple requires a concrete arch" ;; 72 esac 73 } 74 75 host_package() { 76 local os mach 77 os="$(uname -s 2>/dev/null || echo unknown)" 78 mach="$(uname -m 2>/dev/null || echo unknown)" 79 case "$os" in 80 Darwin) 81 echo "llvm-mingw-$RELEASE-ucrt-macos-universal.tar.xz|d3310f9b86b368900850af8bc95da20648f9fc6b0be3bb64dbf8fb18d7c0894f|tar" 82 ;; 83 Linux) 84 case "$mach" in 85 x86_64|amd64) 86 echo "llvm-mingw-$RELEASE-ucrt-ubuntu-22.04-x86_64.tar.xz|9d191203f9768ead60662d3ae53cdf28e0a28b1e6d44b7f329b9202cb2add337|tar" 87 ;; 88 aarch64|arm64) 89 echo "llvm-mingw-$RELEASE-ucrt-ubuntu-22.04-aarch64.tar.xz|e71b61c968f65f94ed3878ca22ab663d7854d91c053c1b8a824ac2f1c9a18503|tar" 90 ;; 91 *) 92 die "unsupported Linux host architecture: $mach" 93 ;; 94 esac 95 ;; 96 MINGW*|MSYS*|CYGWIN*) 97 case "$mach" in 98 x86_64|amd64) 99 echo "llvm-mingw-$RELEASE-ucrt-x86_64.zip|3de3eda9377bbaf35f8c9001f190380f63b8ee981fa55d3ae9d7cce7c6ad7c70|zip" 100 ;; 101 aarch64|arm64) 102 echo "llvm-mingw-$RELEASE-ucrt-aarch64.zip|cb5c20fbe1808e31ada5cbe4efd9daa2fee19c91dac6ec5ca1ac46a9c7247e37|zip" 103 ;; 104 *) 105 die "unsupported Windows host architecture: $mach" 106 ;; 107 esac 108 ;; 109 *) 110 die "unsupported host OS: $os" 111 ;; 112 esac 113 } 114 115 pkg_field() { 116 local n=$1 pkg=$2 117 printf '%s\n' "$pkg" | awk -F'|' -v n="$n" '{ print $n }' 118 } 119 120 sha256_file() { 121 if command -v shasum >/dev/null 2>&1; then 122 shasum -a 256 "$1" | awk '{ print $1 }' 123 return 0 124 fi 125 if command -v sha256sum >/dev/null 2>&1; then 126 sha256sum "$1" | awk '{ print $1 }' 127 return 0 128 fi 129 die "missing shasum or sha256sum" 130 } 131 132 verify_archive() { 133 local path=$1 expect=$2 got 134 got="$(sha256_file "$path")" 135 [ "$got" = "$expect" ] || 136 die "checksum mismatch for $(basename "$path"): got $got want $expect" 137 } 138 139 archive_path() { 140 local pkg name 141 pkg="$(host_package)" 142 name="$(pkg_field 1 "$pkg")" 143 printf '%s\n' "$DL_ROOT/$name" 144 } 145 146 fetch_package() { 147 local pkg name digest url path 148 pkg="$(host_package)" 149 name="$(pkg_field 1 "$pkg")" 150 digest="$(pkg_field 2 "$pkg")" 151 url="$BASE_URL/$name" 152 path="$DL_ROOT/$name" 153 mkdir -p "$DL_ROOT" 154 if [ -f "$path" ]; then 155 verify_archive "$path" "$digest" 156 printf 'archive already verified: %s\n' "$path" 157 return 0 158 fi 159 command -v curl >/dev/null 2>&1 || die "curl not found" 160 printf 'download: %s\n' "$url" 161 curl -fL --retry 3 --retry-delay 2 --continue-at - -o "$path.part" "$url" 162 mv "$path.part" "$path" 163 verify_archive "$path" "$digest" 164 printf 'verified: %s\n' "$path" 165 } 166 167 archive_top() { 168 local path=$1 kind=$2 169 case "$kind" in 170 tar) tar -tf "$path" | sed -n '1s#/.*##p' ;; 171 zip) unzip -Z1 "$path" | sed -n '1s#/.*##p' ;; 172 esac 173 } 174 175 extract_arch() { 176 local arch triple pkg kind path top tmp out rt bi 177 arch="$(canon_arch "$1")" 178 [ "$arch" != all ] || die "extract_arch requires a concrete arch" 179 triple="$(target_triple "$arch")" 180 pkg="$(host_package)" 181 kind="$(pkg_field 3 "$pkg")" 182 path="$(archive_path)" 183 fetch_package 184 top="$(archive_top "$path" "$kind")" 185 [ -n "$top" ] || die "could not determine archive top directory" 186 tmp="$OUT_ROOT/.extract-$triple" 187 out="$OUT_ROOT/$triple" 188 rm -rf "$tmp" "$out.tmp" 189 mkdir -p "$tmp" "$OUT_ROOT" 190 case "$kind" in 191 tar) 192 tar -xf "$path" -C "$tmp" \ 193 "$top/$triple/include" \ 194 "$top/$triple/lib" \ 195 "$top/generic-w64-mingw32/include" 196 ;; 197 zip) 198 command -v unzip >/dev/null 2>&1 || die "unzip not found" 199 unzip -q "$path" \ 200 "$top/$triple/include*" \ 201 "$top/$triple/lib/*" \ 202 "$top/generic-w64-mingw32/include/*" \ 203 -d "$tmp" 204 ;; 205 esac 206 [ -r "$tmp/$top/$triple/include/windows.h" ] || 207 die "archive did not contain readable $triple/include/windows.h" 208 [ -d "$tmp/$top/$triple/lib" ] || 209 die "archive did not contain $triple/lib" 210 if [ -d "$tmp/$top/generic-w64-mingw32" ]; then 211 rm -rf "$OUT_ROOT/generic-w64-mingw32.tmp" 212 mv "$tmp/$top/generic-w64-mingw32" "$OUT_ROOT/generic-w64-mingw32.tmp" 213 rm -rf "$OUT_ROOT/generic-w64-mingw32" 214 mv "$OUT_ROOT/generic-w64-mingw32.tmp" "$OUT_ROOT/generic-w64-mingw32" 215 fi 216 mv "$tmp/$top/$triple" "$out.tmp" 217 rm -rf "$out" 218 mv "$out.tmp" "$out" 219 # Stage the clang compiler-rt builtins (the compiler runtime) into the sysroot 220 # under lib/windows/ so a standard clang cross-link works against it — not only 221 # llvm-mingw's own clang, which finds them in its resource dir. kit links its 222 # own rt and ignores these. Version-agnostic (matches lib/clang/<N>/lib/windows). 223 rt="$(case "$arch" in x64) echo x86_64 ;; aarch64) echo aarch64 ;; esac)" 224 bi="$(tar -tf "$path" | grep -E "/lib/clang/[0-9.]+/lib/windows/libclang_rt\.builtins-$rt\.a$" | head -1 || true)" 225 if [ -n "$bi" ]; then 226 tar -xf "$path" -C "$tmp" "$bi" 227 mkdir -p "$out/lib/windows" 228 cp "$tmp/$bi" "$out/lib/windows/" 229 fi 230 rm -rf "$tmp" 231 { 232 printf 'release=%s\n' "$RELEASE" 233 printf 'asset=%s\n' "$(basename "$path")" 234 printf 'url=%s/%s\n' "$BASE_URL" "$(basename "$path")" 235 printf 'sha256=%s\n' "$(pkg_field 2 "$pkg")" 236 printf 'target=%s\n' "$triple" 237 } > "$out/PROVENANCE" 238 printf 'sysroot ready: %s\n' "$out" 239 } 240 241 prepare() { 242 local arch 243 arch="$(canon_arch "${1:-all}")" 244 if [ "$arch" = all ]; then 245 extract_arch x64 246 extract_arch aarch64 247 else 248 extract_arch "$arch" 249 fi 250 } 251 252 sysroot_path() { 253 local arch triple 254 arch="$(canon_arch "$1")" 255 [ "$arch" != all ] || die "path requires a concrete arch" 256 triple="$(target_triple "$arch")" 257 printf '%s\n' "$OUT_ROOT/$triple" 258 } 259 260 doctor() { 261 local pkg 262 pkg="$(host_package)" 263 printf 'host: %s/%s\n' "$(uname -s 2>/dev/null)" "$(uname -m 2>/dev/null)" 264 printf 'release: %s\n' "$RELEASE" 265 printf 'asset: %s\n' "$(pkg_field 1 "$pkg")" 266 printf 'download cache: %s\n' "$DL_ROOT" 267 printf 'extract root: %s\n' "$OUT_ROOT" 268 for tool in curl tar shasum sha256sum unzip; do 269 if command -v "$tool" >/dev/null 2>&1; then 270 printf ' OK %s (%s)\n' "$tool" "$(command -v "$tool")" 271 else 272 printf ' MISSING %s\n' "$tool" 273 fi 274 done 275 for arch in x64 aarch64; do 276 printf ' %-7s %s\n' "$arch" "$(sysroot_path "$arch")" 277 done 278 } 279 280 cmd="${1:-}" 281 case "$cmd" in 282 doctor) doctor ;; 283 fetch) fetch_package ;; 284 prepare) shift; prepare "${1:-all}" ;; 285 path) [ $# -eq 2 ] || { usage; exit 2; }; sysroot_path "$2" ;; 286 env) 287 [ $# -eq 2 ] || { usage; exit 2; } 288 printf 'export KIT_SYSROOT=%s\n' "$(sysroot_path "$2")" 289 ;; 290 -h|--help|help|"") usage ;; 291 *) usage; exit 2 ;; 292 esac