Skip to content

Commit 568bbc8

Browse files
committed
fix(build): decide full-static from the TARGET, not from the build host
`supports_full_static` is a host constant (`is_linux`) describing what THIS machine's own binaries can be. flags.cppm read it to decide whether the ARTIFACT gets `-static` — a different question with a different answer the moment host != target. On a Linux host the two coincide for every Linux target, which is why this survived: it is invisible until a non-Linux host cross-compiles to Linux. There, `-static` was silently dropped and `x86_64-linux-musl` — a target whose entire reason to exist is a portable, fully static ELF — produced something else. No error, no warning; the flag just was not there. The predicate now reads the parsed triple: - empty triple → host target, so the host capability IS the answer - PE targets → false; their `-static` comes from the C++ runtime distribution contract (dist::Format::Pe), and answering true here would make both mechanisms emit it - macOS → false; libSystem must stay dynamic - linux → true, glibc or musl, native or cross - unparseable → fall back to the host answer rather than guess Every path that works today is bit-for-bit unchanged: on a Linux host every branch returns exactly what the old constant returned. Only the previously broken host!=target case changes. Turns the previous commit's assertions green: [==========] 6 tests from 1 test suite ran. [ PASSED ] 6 tests. Refs .agents/docs/2026-08-03-windows-host-linux-cross-design.md §1.3 (B2)
1 parent 2a4a5ba commit 568bbc8

2 files changed

Lines changed: 32 additions & 5 deletions

File tree

src/build/flags.cppm

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import mcpp.toolchain.detect;
2121
import mcpp.toolchain.dialect;
2222
import mcpp.toolchain.hostflags;
2323
import mcpp.toolchain.linkmodel;
24+
import mcpp.toolchain.model;
2425
import mcpp.toolchain.provider;
2526
import mcpp.toolchain.registry;
2627

@@ -536,7 +537,15 @@ CompileFlags compute_flags(const BuildPlan& plan) {
536537
// Link flags
537538
f.staticStdlib = plan.manifest.buildConfig.staticStdlib;
538539
f.linkage = plan.manifest.buildConfig.linkage;
539-
std::string full_static = (mcpp::platform::supports_full_static && f.linkage == "static") ? " -static" : "";
540+
// Whether the ARTIFACT can be fully static is a property of the target,
541+
// not of this machine. Reading the host constant directly here dropped
542+
// `-static` from every Windows→Linux cross build, silently turning the
543+
// musl targets into something they are not. The host constant is still
544+
// the right answer for a host-target build, so it is threaded in as the
545+
// fallback rather than discarded.
546+
const bool full_static_ok = mcpp::toolchain::target_supports_full_static(
547+
plan.toolchain.targetTriple, mcpp::platform::supports_full_static);
548+
std::string full_static = (full_static_ok && f.linkage == "static") ? " -static" : "";
540549

541550
// ---- C++ runtime distribution contract (issue #336) -------------------
542551
//

src/toolchain/model.cppm

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,28 @@ bool is_mingw_target(const Toolchain& tc) {
143143
}
144144

145145
bool target_supports_full_static(std::string_view targetTriple, bool hostCapability) {
146-
// STUB — deliberately reproduces the pre-fix behaviour so the regression
147-
// test added alongside it goes red. Replaced in the next commit.
148-
(void)targetTriple;
149-
return hostCapability;
146+
// Empty triple means "build for this machine" — target IS host, so the
147+
// host answer is the correct one. This is the only case where the host
148+
// capability legitimately decides.
149+
if (targetTriple.empty()) return hostCapability;
150+
151+
auto t = triple::parse(targetTriple);
152+
// Outside the triple language we have nothing to reason from. Fall back
153+
// to the host answer rather than guessing from a substring — a wrong
154+
// `true` here would emit `-static` at a target that cannot honour it.
155+
if (!t) return hostCapability;
156+
157+
// PE targets get their `-static` from the C++ runtime distribution
158+
// contract (dist::Format::Pe in flags.cppm), never from here. Returning
159+
// false is what keeps the two mechanisms from both emitting the flag.
160+
if (t->is_pe()) return false;
161+
162+
// macOS cannot fully static-link: libSystem must stay dynamic.
163+
if (t->os == "macos") return false;
164+
165+
// Linux ELF — glibc or musl, native or cross. This is the line that was
166+
// previously gated on the HOST being Linux.
167+
return t->os == "linux";
150168
}
151169

152170
BmiTraits bmi_traits(const Toolchain& tc) {

0 commit comments

Comments
 (0)