@@ -215,11 +215,14 @@ CompileFlags compute_flags(const BuildPlan& plan) {
215215 f.sysroot = link_toolchain_flags;
216216 }
217217
218- // Binutils -B flag — a GCC/libstdc++ payload concern (musl bundles its
219- // own as/ld; Clang and MSVC never take an external binutils).
220- bool isMuslTc = mcpp::toolchain::is_musl_target (plan.toolchain );
218+ // Binutils -B flag — a GCC/libstdc++ payload concern (musl and MinGW-w64
219+ // cross both bundle their own as/ld; Clang and MSVC never take an external
220+ // binutils). MinGW must not get the Linux binutils -B — its PE/SEH output
221+ // is only assemblable by its own x86_64-w64-mingw32-as.
222+ bool isMuslTc = mcpp::toolchain::is_musl_target (plan.toolchain );
223+ bool isMingwTc = mcpp::toolchain::is_mingw_target (plan.toolchain );
221224 std::filesystem::path binutilsBin;
222- if (!isMuslTc && caps.stdlib_id == " libstdc++" ) {
225+ if (!isMuslTc && !isMingwTc && caps.stdlib_id == " libstdc++" ) {
223226 auto ar = mcpp::toolchain::archive_tool (plan.toolchain );
224227 if (!ar.empty ())
225228 binutilsBin = ar.parent_path ();
@@ -361,6 +364,27 @@ CompileFlags compute_flags(const BuildPlan& plan) {
361364 if (prof.lto ) link_extra += " -flto" ;
362365 if (prof.strip ) link_extra += " -s" ;
363366
367+ // MinGW PE link — keyed on the TARGET (is_mingw_target), NOT the host: a
368+ // Linux-hosted cross build produces exactly the same PE link as a native
369+ // Windows MinGW build (host≠target). No rpath/loader/payload model. Static
370+ // + libstdc++exp (std::print's __open_terminal/__write_to_terminal live in
371+ // libstdc++exp.a, not plain libstdc++). Self-contained binutils → no -B.
372+ if (isMingwTc) {
373+ std::string mingw_static;
374+ std::string mingw_stdexp;
375+ if (caps.stdlib_id == " libstdc++" ) {
376+ // `-static` for the whole link — MinGW's standalone-exe convention
377+ // (the piecemeal -static-libstdc++ recipe still pulls
378+ // libwinpthread-1.dll). Opt out via [build] static_stdlib=false.
379+ if (f.staticStdlib || f.linkage == " static" )
380+ mingw_static = " -static" ;
381+ mingw_stdexp = " -lstdc++exp" ;
382+ }
383+ f.ld = std::format (" {}{}{}{}{}" , mingw_static, static_stdlib,
384+ user_ldflags, mingw_stdexp, link_extra);
385+ return f;
386+ }
387+
364388 if constexpr (mcpp::platform::is_windows) {
365389 if (isMsvcDialect) {
366390 // Native cl.exe: link.exe does the link (SeparateLinker). Search
@@ -374,30 +398,10 @@ CompileFlags compute_flags(const BuildPlan& plan) {
374398 f.ld = libpaths + user_ldflags;
375399 return f;
376400 }
377- // PE link: no rpath/loader/payload model. MSVC-ABI Clang needs
378- // nothing extra (MSVC STL/SDK via the driver); MinGW adds the static
379- // libstdc++/libgcc pair (static_stdlib above) and -B so its own
380- // binutils resolve, plus `-static` for full static when requested
381- // (MinGW supports it, unlike MSVC-ABI links).
382- std::string mingw_static;
383- std::string mingw_stdexp;
384- if (caps.stdlib_id == " libstdc++" ) {
385- // `-static` for the whole link — winlibs' own recommendation for
386- // standalone exes. The piecemeal recipe (-static-libstdc++ +
387- // -Wl,-Bstatic -lwinpthread) verifiably loses to the driver's
388- // implicit closing libs: CI import tables still showed
389- // libwinpthread-1.dll. System DLLs (KERNEL32/UCRT) still resolve
390- // via their import libs. Tied to staticStdlib so
391- // [build] static_stdlib=false opts back into DLL-coupled links.
392- if (f.staticStdlib || f.linkage == " static" )
393- mingw_static = " -static" ;
394- // std::print's terminal probe (__open_terminal /
395- // __write_to_terminal, bits/print.h) lives in libstdc++exp.a on
396- // Windows targets — plain -lstdc++ leaves them undefined.
397- mingw_stdexp = " -lstdc++exp" ;
398- }
399- f.ld = std::format (" {}{}{}{}{}{}" , mingw_static, static_stdlib, b_flag,
400- user_ldflags, mingw_stdexp, link_extra);
401+ // PE link, MSVC-ABI Clang (native MinGW is handled by the target-keyed
402+ // branch above and has already returned): no rpath/loader/payload —
403+ // MSVC STL/SDK come via the driver, nothing extra needed.
404+ f.ld = std::format (" {}{}{}" , static_stdlib, user_ldflags, link_extra);
401405 } else if constexpr (mcpp::platform::needs_explicit_libcxx) {
402406 // macOS. Two min-version concerns (see xlings
403407 // .agents/docs/2026-06-05-macos-min-version-support.md):
0 commit comments