windows-ucrt-hosted-smoke.sh (16914B)
1 #!/usr/bin/env bash 2 # test/coff/windows-ucrt-hosted-smoke.sh — Type-K (mode P) hosted Windows UCRT 3 # smoke, on the shared scripted-shell kit (test/lib/kit_sh_kit.sh). 4 # 5 # One program per UCRT surface (Sleep, windows.h coverage, runtime, UCRT stdio, 6 # imported-data, TLS, GUI WinMain) is built with `kit cc` for both 7 # x86_64-windows and aarch64-windows; the link-level checks inspect the PE 8 # import directory via `kit objdump -p` (run_ok + contains), and a negative 9 # check asserts no legacy CRT DLL is imported directly. The Wine runtime check 10 # is run conditionally and self-skips when podman/Wine are absent. 11 # 12 # Serial by design (mode P): all programs share one $work sandbox. 13 # 14 # Self-skip: prints SKIP and exits 0 when no llvm-mingw UCRT sysroot is found. 15 set -u 16 17 ROOT=${KIT_TEST_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)} 18 KIT=${KIT:-"$ROOT/build/kit"} 19 SDK=${KIT_SYSROOT:-} 20 21 KIT_KIT_DIR="$ROOT/test/lib" 22 . "$ROOT/test/lib/kit_sh_kit.sh" 23 kit_report_init 24 25 LABEL_SUITE=windows-ucrt-hosted-smoke 26 27 find_sdk() { 28 local arch=$1 29 local d 30 for d in \ 31 "${XDG_CACHE_HOME:-$HOME/.cache}"/kit/sysroots/windows/*/ucrt/"$arch"-w64-mingw32 \ 32 "$ROOT"/build/llvm-mingw/*/ucrt/"$arch"-w64-mingw32 \ 33 /tmp/llvm-mingw*/llvm-mingw-*-ucrt-*/"$arch"-w64-mingw32 \ 34 /tmp/llvm-mingw*/"$arch"-w64-mingw32 \ 35 /private/tmp/llvm-mingw*/llvm-mingw-*-ucrt-*/"$arch"-w64-mingw32 \ 36 /private/tmp/llvm-mingw*/"$arch"-w64-mingw32; do 37 if [ -d "$d/lib" ] && [ -r "$d/include/windows.h" ]; then 38 printf '%s\n' "$d" 39 return 0 40 fi 41 done 42 return 1 43 } 44 45 sdk_for_arch() { 46 local arch=$1 47 local base 48 if [ -n "$SDK" ]; then 49 if [ "$(basename "$SDK")" = "$arch-w64-mingw32" ]; then 50 printf '%s\n' "$SDK" 51 return 0 52 fi 53 base=$(dirname "$SDK") 54 if [ -d "$base/$arch-w64-mingw32/lib" ] && 55 [ -r "$base/$arch-w64-mingw32/include/windows.h" ]; then 56 printf '%s\n' "$base/$arch-w64-mingw32" 57 return 0 58 fi 59 fi 60 find_sdk "$arch" 61 } 62 63 # kit presence: was a hard FAIL+exit 1 in the original. Preserve that verdict. 64 if [ ! -x "$KIT" ]; then 65 kit_fail "$LABEL_SUITE/kit-present" "kit binary not found: $KIT" 66 kit_summary "$LABEL_SUITE" 67 kit_exit 68 fi 69 70 TMP=${TMPDIR:-/tmp} 71 work=$(mktemp -d "$TMP/kit-windows-ucrt-smoke.XXXXXX") 72 WORK_REAL=$(cd "$work" && pwd -P) 73 trap 'rm -rf "$work"' EXIT 74 75 CONSOLE_C=$work/windows-h.c 76 HEADER_C=$work/windows-h-coverage.c 77 RUNTIME_C=$work/runtime.c 78 STDIO_C=$work/stdio.c 79 IMPORTDATA_C=$work/import-data.c 80 GUI_C=$work/gui.c 81 TLS_C=$work/tls.c 82 83 cat >"$CONSOLE_C" <<'SRC' 84 #include <windows.h> 85 int main(void) { Sleep(1); return 0; } 86 SRC 87 88 cat >"$HEADER_C" <<'SRC' 89 #include <windows.h> 90 #include <fileapi.h> 91 #include <processthreadsapi.h> 92 #include <synchapi.h> 93 #include <errhandlingapi.h> 94 #include <winuser.h> 95 96 _Static_assert(sizeof(long) == 4, "windows long is LLP64"); 97 _Static_assert(sizeof(WCHAR) == 2, "WCHAR is UTF-16"); 98 _Static_assert(sizeof(void*) == 8, "PE32+ pointer size"); 99 100 static DWORD WINAPI thread_proc(LPVOID ctx) { 101 return (DWORD)(ULONG_PTR)ctx; 102 } 103 104 static BOOL CALLBACK enum_windows_proc(HWND hwnd, LPARAM lparam) { 105 RECT r; 106 POINT p; 107 WINDOWPLACEMENT wp; 108 ZeroMemory(&wp, sizeof(wp)); 109 wp.length = sizeof(wp); 110 GetClientRect(hwnd, &r); 111 p.x = r.left; 112 p.y = r.top; 113 ClientToScreen(hwnd, &p); 114 SetLastError((DWORD)lparam); 115 return TRUE; 116 } 117 118 int main(void) { 119 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); 120 DWORD wrote = 0; 121 const char msg[] = "windows coverage\n"; 122 WriteFile(out, msg, sizeof(msg) - 1, &wrote, NULL); 123 124 SECURITY_ATTRIBUTES sa; 125 ZeroMemory(&sa, sizeof(sa)); 126 sa.nLength = sizeof(sa); 127 sa.bInheritHandle = FALSE; 128 129 WCHAR tmp_path[MAX_PATH]; 130 WCHAR file_path[MAX_PATH]; 131 GetTempPathW(MAX_PATH, tmp_path); 132 GetTempFileNameW(tmp_path, L"cfr", 0, file_path); 133 HANDLE h = CreateFileW(file_path, GENERIC_READ | GENERIC_WRITE, 0, &sa, 134 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL); 135 if (h != INVALID_HANDLE_VALUE) { 136 LARGE_INTEGER pos; 137 pos.QuadPart = 0; 138 SetFilePointerEx(h, pos, NULL, FILE_BEGIN); 139 CloseHandle(h); 140 DeleteFileW(file_path); 141 } 142 143 CRITICAL_SECTION cs; 144 InitializeCriticalSection(&cs); 145 EnterCriticalSection(&cs); 146 LeaveCriticalSection(&cs); 147 DeleteCriticalSection(&cs); 148 149 DWORD tid = 0; 150 HANDLE th = CreateThread(NULL, 0, thread_proc, (LPVOID)(ULONG_PTR)3, 0, &tid); 151 if (th) { 152 WaitForSingleObject(th, INFINITE); 153 CloseHandle(th); 154 } 155 156 EnumWindows(enum_windows_proc, 0); 157 MessageBoxW(NULL, L"", L"", MB_OK | MB_SETFOREGROUND); 158 return 0; 159 } 160 SRC 161 162 cat >"$RUNTIME_C" <<'SRC' 163 #include <windows.h> 164 #include <stdlib.h> 165 #include <string.h> 166 167 static int cmp_ints(const void *a, const void *b) { 168 int ia = *(const int *)a; 169 int ib = *(const int *)b; 170 return (ia > ib) - (ia < ib); 171 } 172 173 static int has_env(char **envp, const char *prefix) { 174 size_t n = strlen(prefix); 175 if (!envp) return 0; 176 for (; *envp; ++envp) { 177 if (strncmp(*envp, prefix, n) == 0) return 1; 178 } 179 return 0; 180 } 181 182 int main(int argc, char **argv, char **envp) { 183 if (argc < 3) return 10; 184 if (strcmp(argv[1], "alpha") != 0 || strcmp(argv[2], "beta") != 0) return 11; 185 if (!has_env(envp, "KIT_WIN_PROBE=present")) return 12; 186 187 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); 188 HANDLE err = GetStdHandle(STD_ERROR_HANDLE); 189 DWORD wrote = 0; 190 WriteFile(out, "stdout-ok\n", 10, &wrote, 0); 191 WriteFile(err, "stderr-ok\n", 10, &wrote, 0); 192 193 HANDLE heap = GetProcessHeap(); 194 char *mem = (char *)HeapAlloc(heap, 0, 32); 195 if (!mem) return 13; 196 strcpy(mem, "heap-ok"); 197 if (strcmp(mem, "heap-ok") != 0) return 14; 198 HeapFree(heap, 0, mem); 199 200 int vals[4] = {4, 1, 3, 2}; 201 qsort(vals, 4, sizeof(vals[0]), cmp_ints); 202 if (vals[0] != 1 || vals[3] != 4) return 15; 203 204 SetLastError(1234); 205 if (GetLastError() != 1234) return 16; 206 207 char dir[MAX_PATH]; 208 char path[MAX_PATH]; 209 if (!GetTempPathA(MAX_PATH, dir)) return 17; 210 wsprintfA(path, "%skit-runtime-%lu.tmp", dir, 211 (unsigned long)GetCurrentProcessId()); 212 HANDLE f = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, 0, 0, 213 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, 0); 214 if (f == INVALID_HANDLE_VALUE) return 18; 215 if (!WriteFile(f, "file-ok", 7, &wrote, 0) || wrote != 7) return 19; 216 SetFilePointer(f, 0, 0, FILE_BEGIN); 217 char buf[8]; 218 DWORD got = 0; 219 memset(buf, 0, sizeof(buf)); 220 if (!ReadFile(f, buf, 7, &got, 0)) return 20; 221 CloseHandle(f); 222 DeleteFileA(path); 223 if (got != 7 || strcmp(buf, "file-ok") != 0) return 21; 224 return 0; 225 } 226 SRC 227 228 cat >"$STDIO_C" <<'SRC' 229 #define _INC_STDIO_S 230 #include <stdio.h> 231 232 int main(void) { 233 puts("puts-ok"); 234 fputs("fputs-ok\n", stdout); 235 printf("printf-ok\n"); 236 fflush(stdout); 237 return 0; 238 } 239 SRC 240 241 cat >"$IMPORTDATA_C" <<'SRC' 242 #include <windows.h> 243 244 extern char **__dcrt_initial_narrow_environment; 245 246 int main(void) { 247 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); 248 DWORD wrote = 0; 249 WriteFile(out, "importdata\n", 11, &wrote, 0); 250 if (&__dcrt_initial_narrow_environment == 0) return 10; 251 if (__dcrt_initial_narrow_environment == 0) return 11; 252 return 0; 253 } 254 SRC 255 256 cat >"$GUI_C" <<'SRC' 257 #include <windows.h> 258 int WINAPI WinMain(HINSTANCE hinst, HINSTANCE prev, LPSTR cmd, int show) { 259 (void)hinst; 260 (void)prev; 261 (void)cmd; 262 (void)show; 263 return 0; 264 } 265 SRC 266 267 cat >"$TLS_C" <<'SRC' 268 struct tlsdir { 269 unsigned long long start; 270 unsigned long long end; 271 unsigned long long index; 272 unsigned long long callbacks; 273 unsigned int zero_fill; 274 unsigned int characteristics; 275 }; 276 277 extern unsigned char __ImageBase; 278 extern const struct tlsdir _tls_used; 279 280 _Thread_local int tls_init = 7; 281 _Thread_local int tls_zero; 282 283 static unsigned int rd32(const unsigned char *p) { 284 return (unsigned int)p[0] | 285 ((unsigned int)p[1] << 8) | 286 ((unsigned int)p[2] << 16) | 287 ((unsigned int)p[3] << 24); 288 } 289 290 static int check_tls_directory(void) { 291 const unsigned char *image = &__ImageBase; 292 unsigned int pe = rd32(image + 0x3c); 293 const unsigned char *opt = image + pe + 4 + 20; 294 const unsigned char *dir = opt + 112 + 9 * 8; 295 unsigned int tls_rva = rd32(dir); 296 unsigned int tls_size = rd32(dir + 4); 297 if (tls_size != 40) return 34; 298 if ((const unsigned char *)&_tls_used != image + tls_rva) return 35; 299 if (_tls_used.start == 0 || _tls_used.end <= _tls_used.start) return 36; 300 if (_tls_used.index == 0) return 37; 301 if (_tls_used.zero_fill != 0 || _tls_used.characteristics != 0) return 38; 302 return 0; 303 } 304 305 static int bump(void) { 306 tls_zero += 3; 307 tls_init += tls_zero; 308 return tls_init; 309 } 310 311 int main(void) { 312 int dir = check_tls_directory(); 313 if (dir) return dir; 314 int a = bump(); 315 int b = bump(); 316 if (a != 10) return 31; 317 if (b != 16) return 32; 318 if (tls_zero != 6) return 33; 319 return 0; 320 } 321 SRC 322 323 # ---- assert helpers (mode-P verbs, $work-confined) ------------------------- 324 325 # no_legacy_crt_imports NAME DUMP : pass iff DUMP imports no msvcrt/ucrt DLL. 326 no_legacy_crt_imports() { 327 local name=$1 dump=$2 328 if grep -Eiq 'DLL Name: (msvcrt|ucrt)\.dll' "$dump"; then 329 grep -Ei 'DLL Name: (msvcrt|ucrt)\.dll' "$dump" > "$work/$name.diag" 330 not_ok "$name" "$work/$name.diag" 331 else 332 ok "$name" 333 fi 334 } 335 336 # not_contains NAME FILE NEEDLE : pass iff NEEDLE is absent from FILE. 337 not_contains() { 338 local name=$1 file=$2 needle=$3 339 if grep -Fq "$needle" "$file"; then 340 { printf 'unexpected text: %s\n' "$needle"; } > "$work/$name.diag" 341 not_ok "$name" "$work/$name.diag" 342 else 343 ok "$name" 344 fi 345 } 346 347 # matches NAME FILE EREGEX : pass iff FILE has a line matching EREGEX. 348 matches() { 349 local name=$1 file=$2 re=$3 350 if grep -Eq "$re" "$file"; then ok "$name" 351 else { printf 'no line matched: %s\n' "$re"; } > "$work/$name.diag"; not_ok "$name" "$work/$name.diag"; fi 352 } 353 354 # run_wine_if_available LABEL IMAGE POD_ARCH EXE [ARGS...] : conditional Wine 355 # run. Self-skips (kit_skip) when podman or the container image is absent; 356 # otherwise pass iff the program exits 0 under Wine. 357 run_wine_if_available() { 358 local label=$1 image=$2 pod_arch=$3 exe=$4 359 shift 4 360 case "$pod_arch" in 361 amd64) 362 if [ -n "${KIT_WINDOWS_VM_X64:-${KIT_WINDOWS_VM_AMD64:-}}" ]; then 363 if KIT_WIN_PROBE=present "$ROOT/scripts/windows_vm.sh" run x64 "$exe" "$@" \ 364 > "$work/$label-vm.out" 2> "$work/$label-vm.err"; then 365 ok "$label-vm" 366 else 367 not_ok "$label-vm" "$work/$label-vm.err" 368 fi 369 return 0 370 fi 371 ;; 372 arm64) 373 if [ -n "${KIT_WINDOWS_VM_AARCH64:-${KIT_WINDOWS_VM_ARM64:-}}" ]; then 374 if KIT_WIN_PROBE=present "$ROOT/scripts/windows_vm.sh" run aarch64 "$exe" "$@" \ 375 > "$work/$label-vm.out" 2> "$work/$label-vm.err"; then 376 ok "$label-vm" 377 else 378 not_ok "$label-vm" "$work/$label-vm.err" 379 fi 380 return 0 381 fi 382 ;; 383 esac 384 if ! command -v podman >/dev/null 2>&1; then 385 skip_test "$label-wine" "podman unavailable" 386 return 0 387 fi 388 if ! podman image exists "$image" >/dev/null 2>&1; then 389 skip_test "$label-wine" "$image unavailable" 390 return 0 391 fi 392 if podman run --rm --arch "$pod_arch" -v "$WORK_REAL:/probe:ro" "$image" \ 393 bash -lc " 394 export WINEDEBUG=-all WINEPREFIX=/tmp/wineprefix KIT_WIN_PROBE=present 395 timeout 120s /usr/lib/wine/wine64 /probe/$(basename "$exe") $* 396 rc=\$? 397 echo \"$label exit=\$rc\" 398 test \"\$rc\" -eq 0 399 " > "$work/$label-wine.out" 2> "$work/$label-wine.err"; then 400 ok "$label-wine" 401 else 402 not_ok "$label-wine" "$work/$label-wine.err" 403 fi 404 } 405 406 ran=0 407 for arch in x86_64 aarch64; do 408 case "$arch" in 409 x86_64) 410 target=x86_64-windows 411 label=x64 412 image=localhost/kit-wine-amd64 413 pod_arch=amd64 414 ;; 415 aarch64) 416 target=aarch64-windows 417 label=aarch64 418 image=localhost/kit-wine-arm64 419 pod_arch=arm64 420 ;; 421 esac 422 423 if ! ARCH_SDK=$(sdk_for_arch "$arch"); then 424 skip_test "$LABEL_SUITE/$label-sysroot" "no $arch llvm-mingw UCRT sysroot" 425 continue 426 fi 427 # Discovered-but-invalid sysroot was a hard FAIL+exit 1 originally. 428 if [ ! -r "$ARCH_SDK/include/windows.h" ] || 429 [ ! -r "$ARCH_SDK/lib/libucrt.a" ]; then 430 echo "invalid UCRT llvm-mingw sysroot: $ARCH_SDK" > "$work/$label-sysroot.diag" 431 not_ok "$LABEL_SUITE/$label-sysroot" "$work/$label-sysroot.diag" 432 kit_summary "$LABEL_SUITE" 433 kit_exit 434 fi 435 436 ran=1 437 CONSOLE_EXE=$work/windows-h-$arch.exe 438 CONSOLE_DUMP=$work/windows-h-$arch.dump 439 HEADER_EXE=$work/windows-h-coverage-$arch.exe 440 HEADER_DUMP=$work/windows-h-coverage-$arch.dump 441 RUNTIME_EXE=$work/runtime-$arch.exe 442 RUNTIME_DUMP=$work/runtime-$arch.dump 443 STDIO_EXE=$work/stdio-$arch.exe 444 STDIO_DUMP=$work/stdio-$arch.dump 445 IMPORTDATA_EXE=$work/import-data-$arch.exe 446 IMPORTDATA_DUMP=$work/import-data-$arch.dump 447 TLS_EXE=$work/tls-$arch.exe 448 TLS_DUMP=$work/tls-$arch.dump 449 GUI_EXE=$work/gui-$arch.exe 450 GUI_DUMP=$work/gui-$arch.dump 451 452 # build_dump NAME EXE DUMP -- CC_ARGS... : build EXE, then `objdump -p` it 453 # into DUMP. Returns 0 only if both the EXE and the DUMP were produced, so 454 # the per-program import asserts below run iff the link round-tripped. 455 build_dump() { 456 local bn=$1 exe=$2 dump=$3; shift 3 457 [ "$1" = "--" ] && shift 458 run_ok "$bn-build" "$KIT" cc -target "$target" --sysroot "$ARCH_SDK" "$@" -o "$exe" 459 [ -f "$exe" ] || return 1 460 run_ok "$bn-objdump" "$KIT" objdump -p "$exe" 461 [ -s "$work/$bn-objdump.out" ] || return 1 462 cp "$work/$bn-objdump.out" "$dump" 463 } 464 465 # ---- console Sleep ---- 466 if build_dump "$label-console" "$CONSOLE_EXE" "$CONSOLE_DUMP" -- -mconsole "$CONSOLE_C"; then 467 no_legacy_crt_imports "$label-console-no-legacy-crt" "$CONSOLE_DUMP" 468 not_contains "$label-console-no-weak-set-app-type" "$CONSOLE_DUMP" "Name: __set_app_type" 469 contains "$label-console-kernel32" "$CONSOLE_DUMP" "DLL Name: KERNEL32.dll" 470 contains "$label-console-sleep" "$CONSOLE_DUMP" "Name: Sleep" 471 contains "$label-console-crt-runtime-dll" "$CONSOLE_DUMP" "DLL Name: api-ms-win-crt-runtime-l1-1-0.dll" 472 contains "$label-console-set-app-type" "$CONSOLE_DUMP" "Name: _set_app_type" 473 run_wine_if_available "$label-console-Sleep" "$image" "$pod_arch" "$CONSOLE_EXE" 474 fi 475 476 # ---- windows.h coverage ---- 477 if build_dump "$label-header" "$HEADER_EXE" "$HEADER_DUMP" -- -mconsole "$HEADER_C"; then 478 no_legacy_crt_imports "$label-header-no-legacy-crt" "$HEADER_DUMP" 479 contains "$label-header-CreateFileW" "$HEADER_DUMP" "Name: CreateFileW" 480 contains "$label-header-CreateThread" "$HEADER_DUMP" "Name: CreateThread" 481 contains "$label-header-WaitForSingleObject" "$HEADER_DUMP" "Name: WaitForSingleObject" 482 contains "$label-header-MessageBoxW" "$HEADER_DUMP" "Name: MessageBoxW" 483 fi 484 485 # ---- runtime ---- 486 if build_dump "$label-runtime" "$RUNTIME_EXE" "$RUNTIME_DUMP" -- "$RUNTIME_C"; then 487 no_legacy_crt_imports "$label-runtime-no-legacy-crt" "$RUNTIME_DUMP" 488 contains "$label-runtime-HeapAlloc" "$RUNTIME_DUMP" "Name: HeapAlloc" 489 contains "$label-runtime-CreateFileA" "$RUNTIME_DUMP" "Name: CreateFileA" 490 contains "$label-runtime-qsort" "$RUNTIME_DUMP" "Name: qsort" 491 run_wine_if_available "$label-runtime" "$image" "$pod_arch" "$RUNTIME_EXE" alpha beta 492 fi 493 494 # ---- UCRT stdio ---- 495 if build_dump "$label-stdio" "$STDIO_EXE" "$STDIO_DUMP" -- "$STDIO_C"; then 496 no_legacy_crt_imports "$label-stdio-no-legacy-crt" "$STDIO_DUMP" 497 contains "$label-stdio-crt-stdio-dll" "$STDIO_DUMP" "DLL Name: api-ms-win-crt-stdio-l1-1-0.dll" 498 contains "$label-stdio-fflush" "$STDIO_DUMP" "Name: fflush" 499 run_wine_if_available "$label-UCRT-stdio" "$image" "$pod_arch" "$STDIO_EXE" 500 fi 501 502 # ---- imported-data ---- 503 if build_dump "$label-importdata" "$IMPORTDATA_EXE" "$IMPORTDATA_DUMP" -- "$IMPORTDATA_C"; then 504 no_legacy_crt_imports "$label-importdata-no-legacy-crt" "$IMPORTDATA_DUMP" 505 contains "$label-importdata-crt-private-dll" "$IMPORTDATA_DUMP" "DLL Name: api-ms-win-crt-private-l1-1-0.dll" 506 contains "$label-importdata-dcrt-env" "$IMPORTDATA_DUMP" "Name: __dcrt_initial_narrow_environment" 507 run_wine_if_available "$label-imported-data" "$image" "$pod_arch" "$IMPORTDATA_EXE" 508 fi 509 510 # ---- TLS ---- 511 if build_dump "$label-tls" "$TLS_EXE" "$TLS_DUMP" -- "$TLS_C"; then 512 no_legacy_crt_imports "$label-tls-no-legacy-crt" "$TLS_DUMP" 513 matches "$label-tls-directory" "$TLS_DUMP" \ 514 '^[[:space:]]*9[[:space:]]+TLS[[:space:]]+0x[0-9a-fA-F]+[[:space:]]+0x00000028' 515 fi 516 517 # ---- GUI WinMain ---- 518 if build_dump "$label-gui" "$GUI_EXE" "$GUI_DUMP" -- -mwindows "$GUI_C"; then 519 contains "$label-gui-subsystem" "$GUI_DUMP" "Subsystem: 2 (WINDOWS_GUI)" 520 no_legacy_crt_imports "$label-gui-no-legacy-crt" "$GUI_DUMP" 521 fi 522 523 run_wine_if_available "$label-TLS" "$image" "$pod_arch" "$TLS_EXE" 524 done 525 526 if [ "$ran" -eq 0 ]; then 527 skip_test "$LABEL_SUITE" "set KIT_SYSROOT or install llvm-mingw UCRT under /tmp/llvm-mingw*" 528 fi 529 530 kit_summary "$LABEL_SUITE" 531 kit_exit