Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions .github/workflows/gc-native-roots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,22 @@
# prologue words, which is enough to say which walker is wrong
# without a second run.
#
# windows-latest REAL DEFECT, filed as #7985 (`perry.exe` cannot link
# against the official LLVM 22 release: /MT-vs-/MD CRT mismatch,
# bundled rpmalloc redefining malloc, and inkwell referencing
# target backends the release does not build). A SECOND,
# separate failure in the same arm — Git-bash `tar` reading
# `D:\a\_temp` as a remote host — was a workflow bug and is
# fixed here with `--force-local`.
# windows-latest FIXES LANDED; GREEN RUN PENDING. #8017 stopped linking the official archive's
# incompatible /MT + rpmalloc static objects, restricted
# inkwell to Perry's x86/AArch64 targets, and linked the
# archive's LLVM-C.dll instead. #7985's release follow-up
# keeps that DLL beside perry.exe in the Windows zip/npm
# package. A SECOND, separate failure in the same arm —
# Git-bash `tar` reading `D:\a\_temp` as a remote host — was
# fixed by #8028, which normalizes shell paths with `cygpath`
# and exports native Windows paths for Perry. `--force-local`
# was ineffective with the runner's bsdtar.
#
# So: after #7970 and #7997 three of the four arms should pass and only
# windows-latest should remain red, on #7985. This workflow is therefore still
# NOT a promotion candidate — promoting it while #7985 is open would block every
# PR. Promote only once all four arms are green, and per CLAUDE.md, run it green
# once BEFORE adding it to branch protection.
# So: all known defects now have fixes in the intended combined state, but the
# windows-latest arm remains unproven until a complete run measures it. Per
# CLAUDE.md this becomes a promotion candidate only AFTER one complete green
# run demonstrates all four arms; do not add it to branch protection based on
# a comment.
name: gc-native-roots
on:
# Must run where it can actually gate something. Branch-scoped triggers were
Expand Down
28 changes: 27 additions & 1 deletion .github/workflows/release-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -799,8 +799,34 @@ jobs:
if: runner.os == 'Windows'
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$binary = "target/${{ matrix.target }}/dist/perry.exe"
$llvmBin = Join-Path $env:LLVM_SYS_221_PREFIX 'bin'
$llvmReadObj = Join-Path $llvmBin 'llvm-readobj.exe'
$llvmRuntime = Join-Path $llvmBin 'LLVM-C.dll'

foreach ($required in @($binary, $llvmReadObj, $llvmRuntime)) {
if (-not (Test-Path -LiteralPath $required -PathType Leaf)) {
throw "Windows release prerequisite is missing: $required"
}
}

# #7985: the official LLVM archive's static libraries use /MT and
# bundle rpmalloc, so Perry links its LLVM C surface dynamically on
# Windows. Prove the release binary has the expected import before
# copying the matching DLL; otherwise this step could ship either a
# loader-broken executable or a stale, unused 70 MB runtime.
$imports = (& $llvmReadObj --coff-imports $binary | Out-String)
if ($LASTEXITCODE -ne 0) {
throw "llvm-readobj failed while inspecting $binary"
}
if ($imports -notmatch '(?m)^\s*Name:\s+LLVM-C\.dll\s*$') {
throw "$binary does not import LLVM-C.dll; refusing to package an unverified LLVM runtime"
}

New-Item -ItemType Directory -Force -Path staging
Copy-Item "target/${{ matrix.target }}/dist/perry.exe" staging/
Copy-Item $binary staging/
Copy-Item $llvmRuntime staging/
Copy-Item "xwin-install/bin/xwin.exe" staging/
# Include static libraries for linking (runtime, stdlib, UI)
$libs = @("perry_runtime.lib", "perry_stdlib.lib", "perry_ui_windows.lib")
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ jobs:
benchmarks/honest_bench/harness/run_http_bench.sh \
tests/test_benchmark_peer_fallback.sh

- name: Validate Windows LLVM runtime npm staging
run: ./tests/test_stage_npm_windows_llvm.sh

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
Expand Down
5 changes: 5 additions & 0 deletions changelog.d/8018-windows-llvm-runtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- Fixed the Windows release and npm packages after the LLVM 22 dynamic-link
change: `LLVM-C.dll` is now shipped beside `perry.exe`, and both packaging
paths fail closed if the executable's required LLVM runtime is absent. This
prevents extracted or npm-installed Windows builds from exiting with loader
error `0xC0000135` on machines without a separate LLVM installation.
9 changes: 9 additions & 0 deletions scripts/stage-npm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,16 @@ for entry in "${PLATFORMS[@]}"; do
mkdir -p "$pkg_dir/bin" "$pkg_dir/lib"

if [ "$kind" = "win" ]; then
# #7985: perry.exe imports the official LLVM archive's LLVM-C.dll to avoid
# mixing its /MT + rpmalloc static objects with Rust's /MD runtime. The DLL
# must stay beside the executable: Windows searches that directory first,
# and npm installs do not inherit CI's C:\llvm\bin PATH entry.
if [ ! -f "$src_dir/LLVM-C.dll" ]; then
echo " error: $artifact is missing LLVM-C.dll required by perry.exe (#7985)" >&2
exit 1
fi
cp "$src_dir/perry.exe" "$pkg_dir/bin/perry.exe"
cp "$src_dir/LLVM-C.dll" "$pkg_dir/bin/LLVM-C.dll"
for lib in "${WIN_CORE_LIBS[@]}" "$ui_lib"; do
[ -f "$src_dir/$lib" ] && cp "$src_dir/$lib" "$pkg_dir/lib/"
done
Expand Down
50 changes: 50 additions & 0 deletions tests/test_stage_npm_windows_llvm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Regression for #7985: the Windows release and npm artifacts must keep the
# dynamically linked LLVM-C.dll beside perry.exe.

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT

FIXTURE_REPO="$WORK/repo"
ARTIFACTS="$WORK/artifacts"
WIN_ARTIFACT="$ARTIFACTS/perry-windows-x86_64"

mkdir -p \
"$FIXTURE_REPO/scripts" \
"$FIXTURE_REPO/npm/perry/bin" \
"$FIXTURE_REPO/npm/perry-win32-x64" \
"$WIN_ARTIFACT"

cp "$REPO_ROOT/scripts/stage-npm.sh" "$FIXTURE_REPO/scripts/stage-npm.sh"
cp "$REPO_ROOT/npm/perry/package.json.tmpl" "$FIXTURE_REPO/npm/perry/package.json.tmpl"
cp "$REPO_ROOT/npm/perry/bin/perry.js" "$FIXTURE_REPO/npm/perry/bin/perry.js"
cp "$REPO_ROOT/npm/perry-win32-x64/package.json.tmpl" \
"$FIXTURE_REPO/npm/perry-win32-x64/package.json.tmpl"

printf '[workspace.package]\nversion = "0.0.0-test"\n' > "$FIXTURE_REPO/Cargo.toml"
printf 'fixture executable\n' > "$WIN_ARTIFACT/perry.exe"
printf 'fixture LLVM runtime\n' > "$WIN_ARTIFACT/LLVM-C.dll"

SKIP_MISSING=1 PERRY_NPM_NO_COMPRESS=1 \
"$FIXTURE_REPO/scripts/stage-npm.sh" "$ARTIFACTS" > "$WORK/stage.out"

cmp "$WIN_ARTIFACT/perry.exe" \
"$FIXTURE_REPO/npm/perry-win32-x64/bin/perry.exe"
cmp "$WIN_ARTIFACT/LLVM-C.dll" \
"$FIXTURE_REPO/npm/perry-win32-x64/bin/LLVM-C.dll"

# The negative direction is load-bearing: a missing DLL must stop publishing,
# not silently produce an npm package whose perry.exe dies with 0xC0000135.
rm "$WIN_ARTIFACT/LLVM-C.dll"
if SKIP_MISSING=1 PERRY_NPM_NO_COMPRESS=1 \
"$FIXTURE_REPO/scripts/stage-npm.sh" "$ARTIFACTS" \
> "$WORK/missing.out" 2> "$WORK/missing.err"; then
echo "stage-npm accepted a Windows artifact without LLVM-C.dll" >&2
exit 1
fi
grep -F 'missing LLVM-C.dll required by perry.exe (#7985)' "$WORK/missing.err" >/dev/null

echo "Windows LLVM runtime npm staging: OK (copy + missing-DLL refusal)"
Loading