Skip to content

build.rs hardcodes MSVC-only /STACK: linker flag, breaks builds on the GNU/mingw Windows target #3215

Closed

Description

@Derviis

Summary

build.rs unconditionally emits cargo:rustc-link-arg=/STACK:8388608 inside #[cfg(windows)], assuming the linker is always MSVC's link.exe. On the x86_64-pc-windows-gnu target the linker is GNU ld (via x86_64-w64-mingw32-gcc), which doesn't understand /STACK: syntax, so the build fails at the link step. This breaks cargo install --git ... (and any local build) for anyone whose default/active Rust toolchain targets *-pc-windows-gnu — not just MSVC-less setups, since rustup's per-project or rustup default toolchain selection can point at the GNU target even on a machine that otherwise reports x86_64-pc-windows-msvc as its default host.

Environment

  • OS: Windows 11 Pro (10.0.26100)
  • Rust: rustc 1.93.0 (254b59607 2026-01-19), host x86_64-pc-windows-gnu
  • Active toolchain: 1.93.0-x86_64-pc-windows-gnu
  • rtk commit: 23d1e899ce89bef54dfa7f3b6f66374c24f311e7 (build.rs last touched in 12276c174378d5fdbd7deb37f921bd8a46806cd4, 2026-03-26)

Steps to reproduce

  1. On Windows, have an active/default Rust toolchain targeting x86_64-pc-windows-gnu (e.g. rustup default stable-x86_64-pc-windows-gnu).
  2. Run cargo install --git https://github.com/rtk-ai/rtk.

Expected

Build succeeds and installs rtk.exe.

Actual

Link step fails:

error: linking with `x86_64-w64-mingw32-gcc` failed: exit code: 1
  |
  = note: "x86_64-w64-mingw32-gcc" ... "/STACK:8388608"
  = note: ...\ld.exe: cannot find /STACK:8388608: No such file or directory
          collect2.exe: error: ld returned 1 exit status

error: failed to compile `rtk v0.42.4 (...)`, intermediate artifacts can be found at `...`

ld treats /STACK:8388608 as a positional filename argument (not recognizing the MSVC flag syntax), so it errors out looking for a file by that name.

Root cause

rtk/build.rs

Lines 6 to 13 in 23d1e89

#[cfg(windows)]
{
// Clap + the full command graph can exceed the default 1 MiB Windows
// main-thread stack during process startup. Reserve a larger stack for
// the CLI binary so `rtk.exe --version`, `--help`, and hook entry
// points start reliably without requiring ad-hoc RUSTFLAGS.
println!("cargo:rustc-link-arg=/STACK:8388608");
}

#[cfg(windows)]
{
    // Clap + the full command graph can exceed the default 1 MiB Windows
    // main-thread stack during process startup. Reserve a larger stack for
    // the CLI binary so `rtk.exe --version`, `--help`, and hook entry
    // points start reliably without requiring ad-hoc RUSTFLAGS.
    println!("cargo:rustc-link-arg=/STACK:8388608");
}

The /STACK: syntax is specific to MSVC's link.exe. GNU ld (used on the *-pc-windows-gnu target) expects --stack=<size> / -Wl,--stack,<size>.

Suggested fix

Branch on CARGO_CFG_TARGET_ENV (set by Cargo for build scripts; "msvc" or "gnu" on Windows targets) and emit the linker-appropriate flag:

#[cfg(windows)]
{
    // Clap + the full command graph can exceed the default 1 MiB Windows
    // main-thread stack during process startup. Reserve a larger stack for
    // the CLI binary so `rtk.exe --version`, `--help`, and hook entry
    // points start reliably without requiring ad-hoc RUSTFLAGS.
    // MSVC's link.exe and GNU/mingw's ld use different flag syntax for this.
    if std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc") {
        println!("cargo:rustc-link-arg=/STACK:8388608");
    } else {
        println!("cargo:rustc-link-arg=-Wl,--stack,8388608");
    }
}

I applied exactly this patch locally, built with cargo +stable-x86_64-pc-windows-gnu install --path ., and confirmed rtk.exe builds and runs correctly (rtk --version, rtk hook claude, rtk gain all work as expected) on the GNU target. Happy to open a PR with this change if useful.

Activity

  1. pszymkowiak commented on Jul 26, 2026

    @pszymkowiak
    Collaborator

    wshm · Automated triage by AI

    🔍 Automated Triage

    🐛 Category bug
    🟠 Priority high
    🎯 Confidence 96%

    Summary

    build.rs unconditionally emits MSVC-only /STACK: linker flag on cfg(windows), breaking builds on x86_64-pc-windows-gnu; fix by branching on CARGO_CFG_TARGET_ENV (patch provided and verified by reporter).

    This looks like a simple fix that could be auto-resolved. Repo maintainers can use /wshm fix to attempt it.

    📁 Relevant files
    • build.rs

    Triaged automatically by wshm · This is an automated analysis, not a human review.

  2. esidorenko-sl commented on Aug 27, 2026

    @esidorenko-sl
    Contributor

    Still reproduces on develop (322db4d): cargo build under stable-x86_64-pc-windows-gnu dies at the link step with ld.exe: cannot find /STACK:8388608.

    Gating the block on cfg(all(windows, target_env = "msvc")) is enough for a working build, in case emitting the -Wl,--stack equivalent for ld needs more thought than the MSVC-only guard.

  3. bharvey42 commented on Sep 1, 2026

    @bharvey42

    This still reproduces on develop @ aa40853 — cargo build under stable-x86_64-pc-windows-gnu dies at the link step, so the target is unbuildable on mainline today. Confirming esidorenko-sl's report from 2026-08-27.

    There are now six open PRs fixing this one line, and I don't think any of them is being read, because from this issue only one of the six is even visible — #3778 is the only one that says Fixes #3215. I went through all six against the current tree; posting the comparison here so the decision is cheap for whoever picks.

    PR Opened Gates on Non-msvc default
    #2539 galaxy-luke Jun 22 #[cfg(windows)] + TARGET string contains("gnu")
    #2895 silvaduartesuop Jul 8 #[cfg(windows)] + CARGO_CFG_TARGET_ENV GNU
    #3239 kamusmg Jul 27 CARGO_CFG_TARGET_OS + _ENV GNU
    #3547 andreguzik Aug 12 CARGO_CFG_TARGET_OS + _ENV GNU
    #3613 rhishi99 Aug 20 CARGO_CFG_TARGET_OS + _ENV MSVC
    #3778 BLCCoreStudio Aug 30 #[cfg(windows)] + CARGO_CFG_TARGET_ENV GNU

    Two things separate them.

    1. Host gating vs target gating. #2539, #2895 and #3778 fix the flag spelling but leave the #[cfg(windows)] block in place. In a build script that attribute describes the machine compiling build.rs, not the target being built, so it is wrong in both directions: cross-compiling to Windows from Linux skips the flag entirely (the stack fix silently disappears), and cross-compiling from a Windows host to a non-Windows target enters the block and emits a PE-only linker option into an ELF link. The else branch makes that concrete — on a Windows host targeting x86_64-unknown-linux-gnu, #2895/#3778 emit -Wl,--stack,8388608, and #2539's contains("gnu") matches that target too. #3239, #3547 and #3613 read CARGO_CFG_TARGET_OS, which is target-accurate.

    2. Which way the non-msvc branch defaults. #3613 is the only one that inverts it:

    let arg = match std::env::var("CARGO_CFG_TARGET_ENV").as_deref() {
        Ok("gnu") => format!("-Wl,--stack,{STACK_BYTES}"),
        _         => format!("/STACK:{STACK_BYTES}"),   // <-- gnullvm lands here
    };

    Anything that isn't literally gnu gets MSVC syntax, so *-pc-windows-gnullvm (aarch64 Windows) hits exactly the bug this issue is about. The others default the other way — unknown env gets the GNU flag — which is the safer default, since msvc is the one that needs the special spelling. #3613 otherwise has the nicest structure of the six (an extracted, documented set_windows_stack_size()); flipping that match arm would make it fully correct.

    Recommendation: #3239 or #3547. They are behaviourally identical — target-gated, GNU default — and differ only in style: #3239 spells out the reasoning in a comment (including why #[cfg(windows)] is the wrong gate, which is the trap the other three fell into), #3547 is the more compact expression of the same logic. Either closes this.

    Disclosure so you can weigh it: I've been running #3239 in a local fork build since 2026-08-08 on x86_64-pc-windows-gnu, daily, no issues. I have no stake in which one lands — #3547 is equally correct and I'd be just as happy to see it merged. What I care about is that one of them does, because until then anyone on this target can't build rtk at all, which also means they can't build a baseline to validate any other Windows PR against. That's a quiet multiplier on the rest of the Windows backlog.

    One structural note. This issue is labelled good first issue, and the duplicates arrive almost on a schedule — Jun 22, Jul 8, Jul 27, Aug 12, Aug 20, Aug 30, roughly one a fortnight. #2895 and #3778 are the same code, differing only in the wording of one comment. Each new duplicate raises the cost of picking, which delays the merge, which leaves the label up. Dropping good first issue once a candidate is chosen would stop the inflow.

    Also worth knowing when you do pick: none of these six has had CI run — they show check-target: SKIPPED, so a maintainer needs to approve the workflow before there's any signal to review.

  4. KuSh commented on Oct 31, 2026

    @KuSh
    Collaborator

    Fixed by #3613, shipped in v1.1.0: build.rs now passes -Wl,--stack to the MinGW linker and keeps /STACK: for MSVC only, and CI builds and tests the x86_64-pc-windows-gnu target. If the GNU build still fails for you on v1.1.0 or later, please comment and we will reopen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions