ci(windows): stub __imp_getenv for freestanding link; bump test timeo… #205
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Windows LLVM Build | |
| on: | |
| push: | |
| branches: [ master ] | |
| pull_request: | |
| branches: [ master ] | |
| # Automatically cancel any previous workflow on new push. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} | |
| cancel-in-progress: true | |
| jobs: | |
| build-and-test: | |
| name: ${{ matrix.flavour }} on Windows with LLVM | |
| runs-on: windows-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Standard pass: clang (GCC-style driver) + lld. Full UCRT, | |
| # no sanitizers (see Configure step for why). Verifies the | |
| # build works with default CRT linkage. This is the | |
| # historically-proven config for this workflow. | |
| - flavour: standard | |
| cc: clang | |
| cc_ld: lld | |
| setup_extra: '' | |
| verify_libc_diet: 'no' | |
| # Freestanding pass: clang-cl (MSVC driver) + lld-link. | |
| # Needed because the freestanding link args in meson.build | |
| # are MSVC syntax (/NODEFAULTLIB:..., /ENTRY:misra_start, | |
| # /SUBSYSTEM:CONSOLE) and only clang-cl forwards them to | |
| # the linker. MSVC syntax also requires lld in MSVC mode | |
| # (lld-link), not the generic lld dispatcher. Both | |
| # conditions come together at have_misra_start_win in | |
| # meson.build (clang-cl + x86_64). | |
| - flavour: freestanding | |
| cc: clang-cl | |
| cc_ld: lld-link | |
| setup_extra: '' | |
| verify_libc_diet: 'yes' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.x' | |
| - name: Install dependencies | |
| run: | | |
| pip install meson ninja | |
| shell: pwsh | |
| - name: Download and install LLVM/Clang | |
| run: | | |
| # Download Clang | |
| Invoke-WebRequest -Uri "https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.8/clang+llvm-18.1.8-x86_64-pc-windows-msvc.tar.xz" -OutFile "clang.tar.xz" | |
| # Extract the archive (using 7zip which is available on Windows runners) | |
| 7z x clang.tar.xz | |
| 7z x clang.tar | |
| # Move to a simpler path | |
| Move-Item "clang+llvm-18.1.8-x86_64-pc-windows-msvc" "C:\clang" | |
| # Add to PATH | |
| echo "C:\clang\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
| shell: pwsh | |
| - name: Verify Clang installation | |
| run: | | |
| clang --version | |
| clang++ --version | |
| lld --version | |
| llvm-ar --version | |
| shell: pwsh | |
| - name: Configure with Clang | |
| run: | | |
| # Set environment variables for Meson to use Clang with lld linker. | |
| # `CC_LD` is meson's first-class way to pick a non-default | |
| # linker (https://mesonbuild.com/howtox.html). Doing this via | |
| # env vars (not -Dc_link_args=...) avoids meson bug #14640 | |
| # where setting c_link_args suppresses b_sanitize injection. | |
| $env:CC = "${{ matrix.cc }}" | |
| $env:CXX = "${{ matrix.cc }}" | |
| $env:CC_LD = "${{ matrix.cc_ld }}" | |
| $env:CXX_LD = "${{ matrix.cc_ld }}" | |
| $env:AR = "llvm-ar" | |
| $env:RANLIB = "llvm-ranlib" | |
| # Sanitizers are intentionally NOT enabled on this workflow. | |
| # Two distinct things conspire against them: | |
| # | |
| # 1. AddressSanitizer + clang on Windows + meson is known to | |
| # misbehave at link time (the bundled VS2022 clang's asan | |
| # runtime ABIs don't match upstream). | |
| # | |
| # 2. UndefinedBehaviorSanitizer fails the link because the | |
| # `windows-latest` runner has VS2022 on PATH, so | |
| # lld-link's LIB-env-var search picks up Microsoft's | |
| # modified `clang_rt.ubsan_standalone-x86_64.lib` (with | |
| # __coe_win::ContinueOnError / __coe_win::RawWrite | |
| # references that only MS's proprietary "Continue On | |
| # Error" stubs provide) instead of our installed LLVM | |
| # 18.1.8's clang_rt. Pointing LIB at our LLVM's | |
| # lib\windows directory before VS's is possible but | |
| # fragile; not worth the complexity. | |
| # | |
| # Both matrix entries (standard + freestanding) therefore run | |
| # without sanitizers. ASan coverage on Windows lives in the | |
| # MSVC matrix entry. | |
| meson setup build --backend ninja ` | |
| -Dwarning_level=2 -Db_lundef=false ${{ matrix.setup_extra }} | |
| shell: pwsh | |
| - name: Build | |
| run: | | |
| meson compile -C build | |
| - name: Test | |
| run: | | |
| meson test -C build --print-errorlogs | |
| # Libc-diet assertion: Bin/ tools must import only OS-provided | |
| # platform DLLs. Anything UCRT/vcruntime (ucrtbase.dll, | |
| # vcruntime140.dll, msvcp140.dll, etc.) means the diet regressed. | |
| # Allowed: kernel32 + ws2_32 (Sockets) + dbghelp (Backtrace) + | |
| # advapi32 (some Win32 calls pull it). The meson auto-injected | |
| # user32/gdi32/etc. show up in the link line but typically don't | |
| # end up in IAT unless we actually call them. | |
| # | |
| # Uses llvm-readobj (already on PATH from the LLVM install step). | |
| # dumpbin would require VS dev-prompt to be sourced first. | |
| - name: Verify libc-diet (Bin/ tools import only platform DLLs) | |
| if: matrix.verify_libc_diet == 'yes' | |
| run: | | |
| $allowed = @( | |
| 'KERNEL32.dll', 'WS2_32.dll', 'DBGHELP.DLL', 'ADVAPI32.dll', | |
| 'USER32.dll', 'GDI32.dll', 'WINSPOOL.DRV', 'SHELL32.dll', | |
| 'ole32.dll', 'OLEAUT32.dll', 'COMDLG32.dll' | |
| ) | |
| $forbidden_pattern = '^(ucrtbase|ucrtbased|vcruntime\d+|vcruntime\d+d|msvcp\d+|msvcp\d+d|msvcr\d+|msvcr\d+d|api-ms-win-crt-)' | |
| $failed = 0 | |
| $bins = @('beam.exe', 'resolve.exe') | |
| foreach ($bn in $bins) { | |
| $path = "build\$bn" | |
| if (-not (Test-Path $path)) { | |
| Write-Host "::warning::$path not built, skipping libc-diet check" | |
| continue | |
| } | |
| # llvm-readobj --coff-imports prints one block per imported | |
| # DLL with a 'Name: <dll>' line at the top of each. | |
| $imports = & llvm-readobj --coff-imports $path 2>$null ` | |
| | Select-String -Pattern '^\s*Name:\s*(\S+)' ` | |
| | ForEach-Object { $_.Matches[0].Groups[1].Value } | |
| $bad = @() | |
| foreach ($imp in $imports) { | |
| if ($imp -match $forbidden_pattern) { | |
| $bad += "$imp (UCRT/vcruntime)" | |
| } else { | |
| $ok = $false | |
| foreach ($a in $allowed) { | |
| if ($imp -ieq $a) { $ok = $true; break } | |
| } | |
| if (-not $ok) { | |
| $bad += "$imp (not in platform allowlist)" | |
| } | |
| } | |
| } | |
| if ($bad.Count -gt 0) { | |
| Write-Host "::error::$bn imports forbidden DLLs (libc-diet broken):" | |
| foreach ($b in $bad) { Write-Host " $b" } | |
| $failed = 1 | |
| } else { | |
| Write-Host "OK: $bn imports $($imports -join ', ')" | |
| } | |
| } | |
| exit $failed | |
| shell: pwsh | |
| - name: Upload test logs | |
| # Always upload so we can audit which tests actually ran. Without | |
| # the artifact we have no way to tell a green run with N tests | |
| # from a green run with 0 tests. | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-logs-windows-llvm-${{ matrix.flavour }} | |
| path: build/meson-logs/testlog.txt |