@@ -1712,6 +1712,19 @@ prepare_build(bool print_fingerprint,
17121712 // learned by experiment — writing the same value a second time in
17131713 // `[target.<triple>]` and observing that it works.
17141714 std::string pinReplacedDefault;
1715+ // THE HOST SPEC AS IT STOOD BEFORE A TARGET ROW'S CONVENTION REPLACED IT,
1716+ // whatever its origin. `build.mcpp` is compiled and run on this machine,
1717+ // so its compiler is a host fact; the row's pin is a target fact. Before
1718+ // this snapshot existed, `host_tc_for_build_program` read `tcSpec` after
1719+ // the row had overwritten it and resolved the row's payload "for the
1720+ // host" -- which works by accident for a payload whose compiler can also
1721+ // target the host (an NDK clang) and cannot work for one that cannot:
1722+ // `em++` produces WebAssembly under every invocation, and every project
1723+ // with a build program failed under `--target wasm32-emscripten` inside
1724+ // `emcc.py` (#622, measured by the dist-web member's first build). Empty
1725+ // when the row replaced nothing, in which case the row's pin remains the
1726+ // only spec there is and the previous behaviour is kept.
1727+ std::optional<std::string> hostSpecBeforeRowPin;
17151728 // THE PACKAGE WHOSE `requires` CHOSE THE COMPILER, AND WHAT IT ASKED FOR.
17161729 //
17171730 // Non-empty only when the graph's requirement actually changed the answer.
@@ -4114,10 +4127,19 @@ prepare_build(bool print_fingerprint,
41144127 "build.mcpp under a cross --target needs a resolvable host "
41154128 "toolchain — set one via [toolchain] or `mcpp toolchain default`"));
41164129 }
4117- auto spec = mcpp::toolchain::parse_toolchain_spec(*tcSpec);
4130+ // THE ROW'S CONVENTION IS NOT THE HOST'S COMPILER. When the target
4131+ // row's pin replaced a spec the user or the machine had chosen, the
4132+ // build program resolves the replaced one: it is what a native build
4133+ // on this machine would use, and it is what the user wrote. A pin
4134+ // that replaced nothing is resolved as before.
4135+ const std::string hostSpecText =
4136+ (tcOrigin == TcOrigin::TargetPin && hostSpecBeforeRowPin.has_value()
4137+ && !hostSpecBeforeRowPin->empty() && *hostSpecBeforeRowPin != "system")
4138+ ? *hostSpecBeforeRowPin : *tcSpec;
4139+ auto spec = mcpp::toolchain::parse_toolchain_spec(hostSpecText);
41184140 if (!spec || spec->version.empty()) {
41194141 return std::unexpected(std::format(
4120- "toolchain spec '{}' is invalid for the build.mcpp host resolve", *tcSpec ));
4142+ "toolchain spec '{}' is invalid for the build.mcpp host resolve", hostSpecText ));
41214143 }
41224144 // Deliberately NO target injection: the spec resolves for the host.
41234145 auto pkg = mcpp::toolchain::to_xim_package(*spec);
@@ -4128,7 +4150,7 @@ prepare_build(bool print_fingerprint,
41284150 auto payload = fetcher.resolve_xpkg_path(pkg.target(), /*autoInstall=*/true, &progress);
41294151 if (!payload) {
41304152 return std::unexpected(std::format(
4131- "host toolchain for build.mcpp ('{}'): {}", *tcSpec ,
4153+ "host toolchain for build.mcpp ('{}'): {}", hostSpecText ,
41324154 payload.error().message));
41334155 }
41344156 auto frontendR = mcpp::toolchain::payload_frontend(payload->root, pkg);
@@ -7240,6 +7262,12 @@ prepare_build(bool print_fingerprint,
72407262 if (tcOrigin == TcOrigin::GlobalDefault && tcSpec.has_value()
72417263 && *tcSpec != targetPinCandidate)
72427264 pinReplacedDefault = *tcSpec;
7265+ // Kept for the build program's host resolution; see the
7266+ // declaration. Taken from every origin, not only the global
7267+ // default, because a `[toolchain]` the manifest named is just as
7268+ // much the host's compiler as a remembered default is.
7269+ if (tcSpec.has_value() && *tcSpec != targetPinCandidate)
7270+ hostSpecBeforeRowPin = *tcSpec;
72437271 tcSpec = targetPinCandidate;
72447272 tcOrigin = TcOrigin::TargetPin;
72457273 }
0 commit comments