66//
77// See .agents/docs/2026-05-12-compile-commands-design.md.
88
9+ module ;
10+ #include < cstdlib>
11+
912export module mcpp.build.flags;
1013
1114import 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);
0 commit comments