fix(scripts): link semver-checks baselines with rust-lld - #642
fix(scripts): link semver-checks baselines with rust-lld#642Kateřina Churanová (kate-shine) wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
There’s a concrete path-handling bug in directory creation (-Path vs -LiteralPath) and the non-Windows override behavior is documented inconsistently with the implementation/tests.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR addresses Windows MAX_PATH failures when running cargo semver-checks --baseline-rev during release/CI by scoping those invocations to a short scratch CARGO_TARGET_DIR (defaulting to %SystemDrive%\ox-semver) while keeping all other Cargo commands on the repo-local target/.
Changes:
- Add
Get-SemverChecksTargetDirandInvoke-SemverChecksClito centralize target-dir scoping + env restoration for semver-checks runs. - Update both the release flow (
Invoke-CrateSemverCheck) and CI semver report script to use the shared helper and capture exit codes reliably. - Add unit tests and documentation describing the Windows scratch-directory behavior and override knob.
File summaries
| File | Description |
|---|---|
| scripts/lib/releasing.ps1 | Adds target-dir resolution and a shared semver-checks CLI wrapper; routes release semver checks through it. |
| scripts/ci/semver-report.ps1 | Uses the shared semver-checks wrapper and consumes its captured output/exit code. |
| scripts/release-packages.ps1 | Documents the Windows MAX_PATH issue and the short scratch target-dir mitigation. |
| scripts/tests/Pester/unit/releasing/SemverChecksTargetDir.Tests.ps1 | Adds unit coverage for target-dir resolution behavior and overrides. |
| docs/releasing.md | Documents the Windows baseline-build scratch directory behavior and override. |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 3
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #642 +/- ##
========================================
Coverage 100.0% 100.0%
========================================
Files 532 543 +11
Lines 59937 60394 +457
========================================
+ Hits 59937 60394 +457 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… override scope Addresses review feedback on microsoft#642: - Create the scratch directory with [System.IO.Directory]::CreateDirectory instead of New-Item. New-Item only offers the wildcard-expanding -Path (it has no -LiteralPath), which disagreed with the surrounding Test-Path -LiteralPath check for a user-supplied OXIDIZER_SEMVER_TARGET_DIR containing `[`, `]` or `*`. CreateDirectory is literal, creates intermediate directories and is a no-op when the directory exists, so the separate existence check is gone too. - Correct the docs: OXIDIZER_SEMVER_TARGET_DIR is honored on every platform. Only the *default* is Windows-only. Both docs previously implied non-Windows ignored the override, contradicting the implementation and its tests. - Document that the override must be absolute, since a relative path would be resolved against different working directories by this process and by the cargo child process. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The implementation documents OXIDIZER_SEMVER_TARGET_DIR as “must be an absolute path” but does not validate/enforce that invariant, which can lead to unintended relative directory creation/use.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (1)
scripts/lib/releasing.ps1:643
- Get-SemverChecksTargetDir’s comments/docs state OXIDIZER_SEMVER_TARGET_DIR “must be an absolute path”, but the function currently returns the raw value with no validation. A relative value (or drive-relative like
C:foo) would be accepted and could create the semver-checks scratch directory in an unintended location, depending on the caller’s working directory.
if (-not [string]::IsNullOrWhiteSpace($env:OXIDIZER_SEMVER_TARGET_DIR)) {
return $env:OXIDIZER_SEMVER_TARGET_DIR
}
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
There was a problem hiding this comment.
🟡 Changes recommended
The new OXIDIZER_SEMVER_TARGET_DIR “absolute path” contract is documented but not enforced in code, and the legacy-scratch containment check can mis-detect nested target dirs due to path normalization/separator handling.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (3)
scripts/lib/releasing.ps1:700
- Clear-LegacySemverChecksScratch detects “TargetDir is repo target or nested under it” using a hard-coded
"$normalizedRepoTarget\"prefix. If TargetDir uses/separators (valid on Windows) or comes from a different path normalization, this check can fail and the function may delete the live scratch directory unexpectedly.
# When the override deliberately points back at the repository's own target
# directory, this *is* the live scratch directory — leave it alone.
$normalizedTarget = $TargetDir.TrimEnd('\', '/')
$normalizedRepoTarget = $repoTarget.TrimEnd('\', '/')
if ($normalizedTarget -eq $normalizedRepoTarget -or $normalizedTarget.StartsWith("$normalizedRepoTarget\", [StringComparison]::OrdinalIgnoreCase)) {
return
scripts/lib/releasing.ps1:643
- Get-SemverChecksTargetDir’s comment/docs say OXIDIZER_SEMVER_TARGET_DIR “must be an absolute path”, but the override is returned without validation. A relative (or drive-relative like
C:foo) value can resolve differently between this script and the cargo child process, and may reintroduce hard-to-diagnose failures.
if (-not [string]::IsNullOrWhiteSpace($env:OXIDIZER_SEMVER_TARGET_DIR)) {
return $env:OXIDIZER_SEMVER_TARGET_DIR
}
scripts/tests/Pester/unit/releasing/SemverChecksTargetDir.Tests.ps1:27
- The scripts/docs state OXIDIZER_SEMVER_TARGET_DIR must be an absolute path; add a unit test to lock in that contract (e.g. a relative override should throw) so future refactors don’t silently accept ambiguous relative paths.
It 'honors an explicit OXIDIZER_SEMVER_TARGET_DIR override on every platform' {
$env:OXIDIZER_SEMVER_TARGET_DIR = 'D:\short'
Get-SemverChecksTargetDir | Should -Be 'D:\short'
}
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
There was a problem hiding this comment.
🟡 Changes recommended
OXIDIZER_SEMVER_TARGET_DIR is documented as requiring an absolute path but is not validated (and a unit test currently uses a Windows path on non-Windows), which can lead to incorrect target-dir handling and legacy-scratch cleanup decisions.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (2)
scripts/lib/releasing.ps1:643
- Get-SemverChecksTargetDir documents that OXIDIZER_SEMVER_TARGET_DIR “must be an absolute path”, but the override is currently returned verbatim with no validation. A relative (or drive-relative like
C:foo) value can then be passed to CreateDirectory/CARGO_TARGET_DIR, which may resolve differently than intended and can also cause Clear-LegacySemverChecksScratch to mis-detect containment and delete the in-repo scratch unexpectedly.
if (-not [string]::IsNullOrWhiteSpace($env:OXIDIZER_SEMVER_TARGET_DIR)) {
return $env:OXIDIZER_SEMVER_TARGET_DIR
}
scripts/tests/Pester/unit/releasing/SemverChecksTargetDir.Tests.ps1:26
- This test uses a Windows-style override path ('D:\short') even when running on Linux/macOS. Since the docs state OXIDIZER_SEMVER_TARGET_DIR must be an absolute path, it’s clearer/safer for the test to use a platform-appropriate absolute path (e.g., based on GetTempPath()) so it doesn’t imply a Windows path is valid everywhere.
It 'honors an explicit OXIDIZER_SEMVER_TARGET_DIR override on every platform' {
$env:OXIDIZER_SEMVER_TARGET_DIR = 'D:\short'
Get-SemverChecksTargetDir | Should -Be 'D:\short'
}
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
|
GHCP: Addressed the three suppressed findings from the last reviews. They had no inline threads to reply to, so recording the responses here. 1. Hardcoded separator in 2. 3. Test used Full unit suite: 343 passed, 0 failed. Both |
There was a problem hiding this comment.
🟡 Changes recommended
semver-report does not pass its -RepoRoot parameter through to Invoke-SemverChecksCli, so the helper’s legacy scratch cleanup can target the wrong directory when the script is run from a different working directory.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (2)
scripts/ci/semver-report.ps1:218
- Invoke-SemverChecksCli’s RepoRoot parameter defaults to the current working directory, but semver-report supports running against an explicit -RepoRoot. If the script is invoked from a different directory (but with -RepoRoot set), the helper’s legacy scratch cleanup will target the wrong path and may leave
<RepoRoot>/target/semver-checksbehind, leading topackage <name> is ambiguousonce CARGO_TARGET_DIR is redirected.
Write-Host "cargo semver-checks: $cargoName (on-disk v$onDisk) vs v$baselineVersion @ $shortSha..."
$semverRun = Invoke-SemverChecksCli -PackageName $cargoName -BaselineSha $baselineSha
$out = $semverRun.Output
scripts/lib/releasing.ps1:655
- The thrown message for a non-absolute OXIDIZER_SEMVER_TARGET_DIR always suggests a Windows-style example path (D:\ox-semver). Since the override is explicitly supported on Linux/macOS too, the example is confusing there; use a platform-neutral example (or include both) so users on non-Windows know what format is expected.
if (-not [System.IO.Path]::IsPathFullyQualified($override)) {
throw "OXIDIZER_SEMVER_TARGET_DIR must be an absolute path, but is '$override'. Use a fully qualified path such as 'D:\ox-semver'."
}
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
|
GHCP: Both suppressed findings addressed in f5d8cd8. 1. 2. Windows-only example in the error message — agreed, straightforwardly wrong for a knob documented as working on every platform. The example is now chosen per platform ( Full unit suite: 343 passed, 0 failed. |
There was a problem hiding this comment.
🟡 Changes recommended
The legacy-scratch containment guard in Clear-LegacySemverChecksScratch is vulnerable to path normalization differences (e.g. ..\ / .) and can delete the live scratch directory when the override points back into the repo target via a non-canonical path.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (1)
scripts/lib/releasing.ps1:723
- Clear-LegacySemverChecksScratch uses raw string comparisons for the containment guard, so a fully-qualified TargetDir that points at the repo target via normalization (e.g.
C:\repo\target\..\targetorC:\repo\target\.) won’t match and will incorrectly delete the live<repo>/target/semver-checksscratch dir. Normalize both paths (e.g. via[System.IO.Path]::GetFullPath) before TrimEnd/StartsWith comparisons.
$normalizedTarget = if ($IsWindows) { $TargetDir.Replace('/', '\') } else { $TargetDir }
$normalizedRepoTarget = if ($IsWindows) { $repoTarget.Replace('/', '\') } else { $repoTarget }
$normalizedTarget = $normalizedTarget.TrimEnd($separator)
$normalizedRepoTarget = $normalizedRepoTarget.TrimEnd($separator)
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Ralf Biedert (ralfbiedert)
left a comment
There was a problem hiding this comment.
🤖 Clear-LegacySemverChecksScratch compares lexical paths without canonicalizing dot segments. For example, OXIDIZER_SEMVER_TARGET_DIR=C:\repo\target\..\semver-out is fully qualified but is classified as being inside target, even though it resolves to a sibling. Cleanup can then be skipped, leaving stale semver-check clones that cause duplicate/ambiguous-package failures, or the wrong cache can be rebuilt. Please normalize both paths with [IO.Path]::GetFullPath() before the platform-specific equality/child comparison, and add Pester coverage for . and .. segments.
|
GHCP: Fixed in 5cd6709. |
|
GHCP: Follow-up simplification in 8b02915: replaced the platform-specific canonical-prefix comparison with Path.GetRelativePath. The guard now protects only the repository target itself or a configured target inside the legacy scratch being deleted; another target nested under repo/target no longer incorrectly suppresses stale-scratch cleanup. Added coverage for both cases. |
8e392b7 to
00c7bf1
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (1)
scripts/lib/releasing.ps1:983
- Get-SemverChecksLinkerEnvName relies on $Matches[1] from a -match executed inside the Where-Object scriptblock. In PowerShell, $Matches is scoped to where -match runs, so $Matches[1] here can be $null or stale, producing an incorrect CARGO_TARGET_*_LINKER name and disabling the intended rust-lld override.
$PSNativeCommandUseErrorActionPreference = $false
$hostLine = & rustc -vV 2>$null | Where-Object { $_ -match '^host:\s*(\S+)' }
if ($LASTEXITCODE -ne 0 -or -not $hostLine) {
return $null
}
00c7bf1 to
9673096
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (1)
scripts/lib/releasing.ps1:983
Get-SemverChecksLinkerEnvNamerelies on$Matches[1]coming from the-matchinside theWhere-Objectpipeline.$Matchesis scope-local to that script block, so$Matches[1]here can be$null/stale and can throw (ToUpperInvariant()on null) or generate the wrong Cargo env-var name. Re-run the match in the function scope (or use[regex]::Match) before reading$Matches.
$triple = $Matches[1].ToUpperInvariant() -replace '[^A-Z0-9]', '_'
9673096 to
2147d0e
Compare
|
GHCP: Fixed in 2147d0e. The finding was half right, and worth acting on either way. Empirically Switched to Added two tests that pin the parse: one mocks |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (2)
scripts/lib/releasing.ps1:1142
- The Windows path-length hint says a MAX_PATH-bound tool was reached "despite the rust-lld override", but ConvertFrom-SemverChecksOutput can be called even when no linker override was applied (e.g., if Get-SemverChecksLinkerEnvName returned $null or the caller didn’t use Invoke-SemverChecksCli). Reword to avoid stating the override definitely happened.
$pathHint = if ($IsWindows) {
' If the output contains LNK1104 or a path-length error, a MAX_PATH-bound tool was reached despite the rust-lld override; shorten the repository path.'
} else {
''
}
throw "cargo semver-checks did not produce a parseable result for '$PackageName' (exit $ExitCode). This usually means the tool is missing or the crate/baseline failed to build.$pathHint Output:`n$Output"
scripts/lib/releasing.ps1:980
- Get-SemverChecksLinkerEnvName checks rustc success via $LASTEXITCODE, but $LASTEXITCODE is only updated for native executables. In unit tests (and any environment where rustc is a PowerShell function/shim), this can read a stale exit code and incorrectly return
$null. Prefer checking $ ? immediately after invoking rustc.
$PSNativeCommandUseErrorActionPreference = $false
$version = & rustc -vV 2>$null | Out-String
if ($LASTEXITCODE -ne 0) {
return $null
}
legacy version
cargo-semver-checks nests its baseline registry checkout under the workspace target directory, so on Windows the intermediate artifact paths grow past 260 characters and the MSVC link.exe fails with LNK1104. link.exe is not long-path aware, so neither LongPathsEnabled nor a long-path-aware manifest on the calling process helps. Point the baseline build at rust-lld instead; LLVM prepends the \\?\ prefix internally and links successfully at those depths. Invoke-SemverChecksCli scopes CARGO_TARGET_<HOST_TRIPLE>_LINKER around the cargo call and restores or removes it afterwards. That variable is the environment spelling of [target.<triple>] linker in .cargo/config.toml, applied only where the problem is rather than to every build in the repository. The bare linker name suffices because rustc puts its own linker directory on PATH when it invokes the linker, so there is no need to locate the sysroot. The override deliberately does not go through RUSTFLAGS, which would replace target.<triple>.rustflags from .cargo/config.toml and silently drop the repository's -C target-cpu setting. Non-Windows platforms are unchanged, as their default linkers already handle long paths. Also route scripts/ci/semver-report.ps1 through Invoke-SemverChecksCli so it picks up the same handling, which additionally fixes a stale $LASTEXITCODE read after an intervening command. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2147d0e to
77948be
Compare
|
GHCP: Addressed both points from the latest review in 77948be. 1. I did not switch to Two regression tests pin this. I verified they are genuine by temporarily reverting the fix: both fail on the old code and pass on the new. 2. Linker tests 10 passed / 1 skipped, |
| [Parameter(Mandatory = $true)][string]$RepoRoot | ||
| ) | ||
|
|
||
| $linkerVar = Get-SemverChecksLinkerEnvName |
There was a problem hiding this comment.
🤖: Get-SemverChecksLinkerEnvName runs before Push-Location $RepoRoot, but rustup resolves directory-specific toolchain overrides from the current working directory. If this release entry point is invoked from a directory whose override has a different host triple (for example GNU outside the repo and MSVC inside it), this computes the wrong CARGO_TARGET_<TRIPLE>_LINKER; Cargo then runs in RepoRoot, ignores that variable, and the baseline still uses its default linker — i.e. the fix silently doesn't apply.
Please perform the rustc probe / environment setup after entering RepoRoot (while retaining the restoration finally), so the probe and semver-checks see the same active toolchain.
| [CmdletBinding()] | ||
| param() | ||
|
|
||
| if (-not $IsWindows) { |
There was a problem hiding this comment.
🤖: Non-blocking — the gate here is $IsWindows, but the justification (and the comment three lines above) is MSVC-specific: link.exe is what is not long-path aware. On a *-pc-windows-gnu host this still fires and sets the linker to rust-lld.exe — and rustc's flavor inference maps stem rust-lld to (Cc::No, Lld::Yes), so on a gnu target that switches linking from the gcc driver to lld invoked directly: a materially different link path that this fix doesn't need and that nothing here has exercised.
The triple is already parsed a few lines down, so the narrower gate is nearly free: compute the triple first, then return $null unless it ends in -msvc. That also makes the function say exactly what the comment says.
| # leaves untouched when it fails and so can hold a stale value. | ||
| $hostMatch = [regex]::Match($version, '(?m)^host:\s*(\S+)') | ||
| if (-not $hostMatch.Success) { | ||
| return $null |
There was a problem hiding this comment.
🤖: Non-blocking — failing open here is the right policy (a rustc probe must not break releases), but the skip is completely silent: on Windows, if rustc -vV is missing, throws, or prints no host: line, the override this whole PR exists for is quietly not applied, the baseline build fails with the original LNK1104, and the only thing the user sees is ConvertFrom-SemverChecksOutput's new hint telling them to shorten the repository path — advice for a problem the tooling believes it already fixed, with no indication that the intended remedy never ran.
A single Write-Warning on this Windows-and-no-triple path ("could not determine the host triple from rustc -vV; leaving the toolchain default linker in place") makes the two failure modes distinguishable without changing the fail-open behaviour.
| $path = "Env:\$linkerVar" | ||
| $hadPrevious = Test-Path $path | ||
| $previous = if ($hadPrevious) { (Get-Item $path).Value } else { $null } | ||
| Set-Item -Path $path -Value 'rust-lld.exe' |
There was a problem hiding this comment.
🤖: Non-blocking — worth deciding explicitly: this overwrites a pre-existing CARGO_TARGET_<HOST>_LINKER unconditionally, so a developer who has deliberately configured their own linker for the host target (a wrapper, a different lld, a custom driver) has that choice silently discarded for the duration of the semver run — restored afterwards, but ignored while it matters. The stated premise is "MSVC link.exe can't do long paths"; if the user has already told cargo not to use link.exe, the premise doesn't hold and we're overriding for nothing.
$hadPrevious is already computed just above, so honouring an explicit setting is a two-line change (skip the Set-Item when $hadPrevious, ideally with a note on stdout). If stomping it is the intended answer, a one-line comment saying so would keep the next reader from re-asking.
| try { | ||
| # A required version bump produces an expected non-zero exit code. | ||
| $PSNativeCommandUseErrorActionPreference = $false | ||
| $output = & cargo semver-checks --package $PackageName --baseline-rev $BaselineSha --all-features --color never 2>&1 | Out-String |
There was a problem hiding this comment.
🤖: Non-blocking — could we add a Windows-only integration test around this real invocation? Every new test mocks cargo, so they prove the environment-variable lifecycle but not the load-bearing claim of the PR: that cargo-semver-checks forwards this per-target linker setting to its inner baseline build, and that rustc resolves the bare rust-lld.exe there. If either assumption is wrong, the whole change is a no-op and the suite stays green.
A focused test under scripts/tests/Pester/integration/ (or a dedicated Windows workflow step) could install the pinned cargo-semver-checks version, create a tiny versioned crate under a deliberately deep path, call Invoke-SemverChecksCli, and assert a parseable result with no LNK1104.
| return ConvertFrom-SemverChecksOutput -Output $result.Output -ExitCode $result.ExitCode -PackageName $PackageName | ||
| } | ||
|
|
||
| # Parses `cargo semver-checks` combined output into a change type. Pure (no I/O) |
There was a problem hiding this comment.
🤖: Non-blocking — this header still says the function is "Pure (no I/O) so it can be unit-tested against captured tool output", but after this change its output also depends on $IsWindows, so the thrown message is no longer a function of the arguments alone — which is exactly why the new case in PureFunctions.Tests.ps1 has to carry -Skip:(-not $IsWindows). Worth a word in the comment (e.g. noting the message carries a platform-conditional hint) so the stated contract matches the code.
Problem
On Windows,
scripts/release-packages.ps1andscripts/ci/semver-report.ps1fail during thecargo semver-checksbaseline build:cargo-semver-checksnests its baseline registry checkout under the workspace targetdirectory, so intermediate artifact paths grow well past 260 characters. The MSVC
link.exeis not long-path aware — it fails regardless of the
LongPathsEnabledregistry settingor a long-path-aware manifest on the calling process.
Fix
Link the baseline build with
rust-lld, which prepends the\\?\prefix internally andhandles those depths.
Measured on a dev machine with
CARGO_TARGET_DIRat 239 characters:link.exe(default)LNK1104: cannot open file ...\debug\deps\<crate>.exerust-lldHow the override is applied
Invoke-SemverChecksClisetsCARGO_TARGET_<HOST_TRIPLE>_LINKER(e.g.CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER) torust-lld.exefor the duration of the call,restoring or removing the variable in a
finally.That variable is just the environment spelling of
[target.<triple>] linker = "..."in.cargo/config.toml— the same knob, applied only where the problem is rather than to everybuild in the repo. CI runs in short paths and does not have this problem, so switching its
linker would be blast radius for no gain.
An environment variable is used rather than a CLI flag because it is the only channel that
reaches the build that actually overflows
MAX_PATH.cargo-semver-checks(0.47.0) exposesno flag to forward cargo configuration, and as an external subcommand it receives
--configitself rather than letting cargo interpret it — while the failing build is the onethe tool spawns internally.
Two things keep the implementation small:
rustcputs its own linker directory onPATHwhen itinvokes the linker, so
rust-lldresolves without locating the sysroot. No flavor flag isneeded either —
rustcinfers thelinkflavor from therust-lldstem.RUSTFLAGS, which replacestarget.<triple>.rustflagsfrom.cargo/config.tomland would silently drop therepository's
-C target-cpu=x86-64-v3. Verified with a verbose build that the linkeroverride and the repo's
target-cpuflag coexist.Non-Windows platforms are unchanged; their default linkers already handle long paths.
Known limitation
This fixes the link step only.
cl.exe/lib.exeinvoked bycc-based build scriptsremain MAX_PATH-bound. In practice the semver-checks baseline builds have not hit that, but
it is a narrower guarantee than relocating the whole target directory would give.
Also in this PR
scripts/ci/semver-report.ps1now routes itscargo semver-checksinvocation through theshared
Invoke-SemverChecksCliinstead of calling cargo directly. Besides picking up thelinker override, this fixes a latent bug where
$LASTEXITCODEwas read after an interveningcommand and could be stale.
Tests
scripts/tests/Pester/unit/releasing/SemverChecksLinker.Tests.ps1: env-var naming for thehost triple, that
rust-lldis actually in the environment while cargo runs, andsave/restore including the case where cargo throws.
PureFunctions.Tests.ps1: updated theLNK1104hint assertion.