Skip to content

Commit 45daea9

Browse files
committed
test: run B3 — product flags via merged feat branch + v2 staged-archive injection
mcpp@HEAD now carries the flags.cppm staticStdlib implementation; xlings is built by it with NO injection (product-path verification). The bootstrap-built mcpp itself uses v2 injection: -L a dylib-free staged dir so the hardcoded -lc++ resolves to libc++.a (run B2 showed -nostdlib++ in user ldflags cannot remove the prepended -lc++).
2 parents 52182d4 + d8fdbe5 commit 45daea9

5 files changed

Lines changed: 80 additions & 4 deletions

File tree

mcpp.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mcpp"
3-
version = "0.0.49"
3+
version = "0.0.50"
44
description = "Modern C++ build & package management tool"
55
license = "Apache-2.0"
66
authors = ["mcpp-community"]

src/build/flags.cppm

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
//
77
// See .agents/docs/2026-05-12-compile-commands-design.md.
88

9+
module;
10+
#include <cstdlib>
11+
912
export module mcpp.build.flags;
1013

1114
import std;
@@ -120,6 +123,9 @@ CompileFlags compute_flags(const BuildPlan& plan) {
120123
std::string link_toolchain_flags;
121124
bool isClangWithCfg = false;
122125
std::filesystem::path cfgPath;
126+
// LLVM root of a clang-with-cfg toolchain — used by the macOS link
127+
// path below to locate libc++.a/libc++abi.a for staticStdlib.
128+
std::filesystem::path llvmRootForStdlib;
123129
if (mcpp::toolchain::is_clang(plan.toolchain)) {
124130
cfgPath = plan.toolchain.binaryPath.parent_path()
125131
/ (plan.toolchain.binaryPath.stem().string() + ".cfg");
@@ -131,6 +137,22 @@ CompileFlags compute_flags(const BuildPlan& plan) {
131137
auto llvmRoot = plan.toolchain.binaryPath.parent_path().parent_path();
132138
auto libcxxInclude = llvmRoot / "include" / "c++" / "v1";
133139
compile_toolchain_flags = " --no-default-config -nostdinc++";
140+
// macOS deployment target: make MACOSX_DEPLOYMENT_TARGET explicit
141+
// on the command line so (a) the ninja commands don't depend on
142+
// env propagation and (b) the value participates in the BMI
143+
// fingerprint via canonical flags — mixing targets in one sandbox
144+
// otherwise reuses a std.pcm built for a different
145+
// arm64-apple-macosxNN triple and dies with a config mismatch
146+
// (observed on macos CI). The link side is added to f.ld below
147+
// (the macOS link path doesn't consume link_toolchain_flags).
148+
if (mcpp::platform::is_macos) {
149+
if (const char* dt = std::getenv("MACOSX_DEPLOYMENT_TARGET");
150+
dt && *dt) {
151+
compile_toolchain_flags +=
152+
std::string(" -mmacosx-version-min=") + dt;
153+
}
154+
}
155+
llvmRootForStdlib = llvmRoot;
134156
// libc++ headers
135157
compile_toolchain_flags += " -isystem" + escape_path(libcxxInclude);
136158
if (!plan.toolchain.targetTriple.empty()) {
@@ -309,7 +331,38 @@ CompileFlags compute_flags(const BuildPlan& plan) {
309331
if constexpr (mcpp::platform::is_windows) {
310332
f.ld = user_ldflags + link_extra;
311333
} else if constexpr (mcpp::platform::needs_explicit_libcxx) {
312-
f.ld = std::format("{}{}{} -lc++{}{}", full_static, static_stdlib, b_flag, user_ldflags, link_extra);
334+
// macOS. Two min-version concerns (see xlings
335+
// .agents/docs/2026-06-05-macos-min-version-support.md):
336+
//
337+
// 1. stdlib linkage — `-lc++` resolves to the SYSTEM
338+
// /usr/lib/libc++.1.dylib, which caps the deployment floor at
339+
// the build host's OS: e.g. std::print's __is_posix_terminal
340+
// support symbol only exists in macOS 15's libc++, so a
341+
// minos-14 binary dies at launch on 14 (dyld missing-symbol
342+
// abort; verified on macos-14 CI). With staticStdlib (the
343+
// manifest default — previously silently ignored on the clang
344+
// route), link LLVM's own libc++.a/libc++abi.a instead:
345+
// runtime deps shrink to libSystem and the floor drops to
346+
// 11.0 (first arm64 macOS). Falls back to -lc++ when the
347+
// archives are absent.
348+
// 2. deployment target — mirror MACOSX_DEPLOYMENT_TARGET onto the
349+
// link command line so it doesn't depend on env propagation.
350+
std::string stdlib_link = " -lc++";
351+
if (f.staticStdlib && !llvmRootForStdlib.empty()) {
352+
auto libcxxA = llvmRootForStdlib / "lib" / "libc++.a";
353+
auto libcxxAbiA = llvmRootForStdlib / "lib" / "libc++abi.a";
354+
if (std::filesystem::exists(libcxxA)
355+
&& std::filesystem::exists(libcxxAbiA)) {
356+
stdlib_link = " -nostdlib++ " + escape_path(libcxxA)
357+
+ " " + escape_path(libcxxAbiA);
358+
}
359+
}
360+
std::string version_min;
361+
if (const char* dt = std::getenv("MACOSX_DEPLOYMENT_TARGET"); dt && *dt) {
362+
version_min = std::string(" -mmacosx-version-min=") + dt;
363+
}
364+
f.ld = std::format("{}{}{}{}{}{}{}", full_static, static_stdlib, b_flag,
365+
version_min, stdlib_link, user_ldflags, link_extra);
313366
} else {
314367
f.ld = std::format("{}{}{}{}{}{}{}{}", full_static, static_stdlib, link_toolchain_flags, b_flag,
315368
runtime_dirs, payload_ld, user_ldflags, link_extra);

src/cli.cppm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,17 @@ std::string canonical_compile_flags(const mcpp::manifest::Manifest& m) {
587587
std::string s;
588588
s += "-std="; s += m.package.standard;
589589
s += " -fmodules";
590+
// macOS deployment target changes the effective compile triple
591+
// (arm64-apple-macosxNN) — a std.pcm built for one target cannot be
592+
// loaded by a TU compiled for another. Fold it into the fingerprint
593+
// so switching MACOSX_DEPLOYMENT_TARGET rebuilds the BMI cache
594+
// instead of dying with a module config mismatch.
595+
if constexpr (mcpp::platform::is_macos) {
596+
if (const char* dt = std::getenv("MACOSX_DEPLOYMENT_TARGET"); dt && *dt) {
597+
s += " macos_deployment_target=";
598+
s += dt;
599+
}
600+
}
590601
if (!m.buildConfig.cStandard.empty()) {
591602
s += " c_standard=";
592603
s += m.buildConfig.cStandard;

src/main.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,17 @@ import std;
55
import mcpp.cli;
66

77
int main(int argc, char* argv[]) {
8-
return mcpp::cli::run(argc, argv);
8+
int rc = mcpp::cli::run(argc, argv);
9+
#ifdef __APPLE__
10+
// With statically linked libc++ (the macOS release linkage since
11+
// 0.0.50), static destruction can SIGABRT on exit — same issue xlings
12+
// guards against. A CLI tool needs no destructor-based cleanup; skip
13+
// static dtors entirely. _Exit bypasses atexit handlers too, so flush
14+
// the standard streams explicitly first.
15+
std::cout.flush();
16+
std::cerr.flush();
17+
std::_Exit(rc);
18+
#else
19+
return rc;
20+
#endif
921
}

src/toolchain/fingerprint.cppm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import mcpp.toolchain.detect;
1818

1919
export namespace mcpp::toolchain {
2020

21-
inline constexpr std::string_view MCPP_VERSION = "0.0.49";
21+
inline constexpr std::string_view MCPP_VERSION = "0.0.50";
2222

2323
struct FingerprintInputs {
2424
Toolchain toolchain;

0 commit comments

Comments
 (0)