Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions docs/05-mcpp-toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,17 @@ macos_deployment_target = "14.0" # macOS 产物的最低支持系统版本(仅
(`LC_BUILD_VERSION minos`),即二进制能运行的最老 macOS。优先级与各生态
惯例一致:环境变量 `MACOSX_DEPLOYMENT_TARGET`(单次调用的显式覆盖,
cargo/rustc、cc 等同样尊重该变量)> 本字段(项目默认,类似 SwiftPM 的
`platforms:`)> 工具链/SDK 默认。该值会进入 BMI 指纹——切换 target 会
自动重建模块缓存。

**声明 floor 即静态运行时**:显式设置了 deployment target(env 或本
字段)且 `static_stdlib = true`(默认)时,macOS 链接会静态链入 LLVM
自带的 libc++/libc++abi —— 系统 libc++ 会把实际可运行版本钉死在构建机
的 OS(老系统缺新符号,如 `std::print` 的支撑符号),静态化才能真正
兑现声明的 floor。注意 LLVM 官方静态库自身的下限是 **14.0**。未声明
floor 时保持动态系统 libc++(产物只保证在构建机同版本及以上运行)。
`platforms:`)> **内建默认 `14.0`**(rustc 风格——每个 target 都有基线,
14.0 即 LLVM 官方静态库自身的下限)。该值会进入 BMI 指纹——切换 target
会自动重建模块缓存。

**默认即静态运行时(portable by default)**:`static_stdlib = true`
(默认)时,macOS 链接会静态链入 LLVM 自带的 libc++/libc++abi ——
系统 libc++ 会把实际可运行版本钉死在构建机的 OS(老系统缺新符号,
如 `std::print` 的支撑符号),静态化才能真正兑现 floor。因此默认构建的
产物在任何 macOS ≥ 14 上开箱即用。设 `static_stdlib = false` 退回动态
系统 libc++(产物只保证在构建机同版本及以上运行)。更低 floor(11–13)
需自建 libc++ 归档(已验证可行,数据级切换,按需提供)。

C++ 标准不要通过 `build.cxxflags = ["-std=..."]` 配置。请使用:

Expand Down
27 changes: 13 additions & 14 deletions src/build/flags.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -369,23 +369,22 @@ CompileFlags compute_flags(const BuildPlan& plan) {
// lld ships with the exact toolchain doing the compile.
f.ldStdlibDefault = " -lc++";
f.ldStdlibTest = " -lc++";
// Static libc++ is tied to an EXPLICIT deployment floor: when the
// user (or the release pipeline) declares a minimum macOS via the
// env var or [build] macos_deployment_target, the static LLVM
// libc++ is what makes that floor real (the system libc++ caps it
// at the build host's OS). With no declared floor, keep the
// 0.0.49 behavior — dynamic system libc++, host-coupled.
//
// TODO(macos-static-default): flip static to the unconditional
// default (rust-style "portable by default") once two tracked
// issues are fixed — (1) mixed C/C++ static binaries SIGSEGV at
// runtime (e2e 36_llvm_toolchain: answer.c + std::cout main.cpp,
// exit 139; root cause not yet isolated), (2) the std-module
// staging/fingerprint boundary (see canonical_compile_flags).
// Static libc++ + the deployment floor are the DEFAULT (rust-style
// "portable by default"): the resolver always yields a floor on
// macOS (built-in 14.0 unless env/manifest override), and the
// static LLVM libc++ is what makes that floor real — the system
// libc++ caps binaries at the build host's OS (a fresh user's
// std::println hello on macOS 14 died at dyld against the system
// libc++ before this). Opt-out: [build] static_stdlib = false
// (host-coupled dynamic libc++, the pre-0.0.52 no-declaration
// behavior). The two blockers that deferred this default are
// resolved: (1) mixed C/C++ split-brain SIGSEGV — fixed by
// -load_hidden (PR #117 forensics), (2) std-module staging /
// fingerprint drift — fixed by the single resolver (PR #119).
// TODO(macos-floor-11): the official LLVM archives are built for
// macOS 14; supporting 11-13 needs a custom libc++ build shipped
// via xlings-res (data-only change — swap the archive source).
// Both tracked in xlings
// Tracked in xlings
// .agents/docs/2026-06-05-macos-min-version-support.md §5.
if (f.staticStdlib && !macosDeploymentTarget.empty()
&& !llvmRootForStdlib.empty()) {
Expand Down
10 changes: 4 additions & 6 deletions src/cli.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -594,13 +594,11 @@ std::string canonical_compile_flags(const mcpp::manifest::Manifest& m) {
// into the fingerprint so switching targets rebuilds the BMI cache
// instead of dying with a module config mismatch.
//
// TODO(macos-default-floor): a built-in default floor (rustc-style,
// see the 0.0.50 revert) cannot land until the std-module prebuild /
// staging pipeline consumes the SAME resolved value as this rule and
// flags.cppm — injecting a default here alone left the test build's
// The built-in default floor (rustc-style) lives in the single
// resolver (platform::macos::deployment_target), so this rule, the
// flags and the std-module prebuild always agree — the 0.0.50-era
// attempt to inject a default here alone left the test build's
// std.pcm unstaged (import std failed wholesale on macos CI).
// Centralize the resolution in one helper, then re-land.
// See xlings .agents/docs/2026-06-05-macos-min-version-support.md §5.
if constexpr (mcpp::platform::is_macos) {
auto dtv = mcpp::platform::macos::deployment_target(
m.buildConfig.macosDeploymentTarget);
Expand Down
24 changes: 18 additions & 6 deletions src/platform/macos.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,34 @@ bool has_xcode_clt();
// Returns the SDK path if found, or nullopt.
std::optional<std::filesystem::path> sdk_path();

// Built-in default deployment floor (rustc-style: every target has a
// baseline). 14.0 = the floor of the official LLVM static libc++
// archives; with the default-static stdlib this makes `mcpp run`
// binaries portable to any macOS ≥ 14 out of the box (no declaration
// needed — a fresh user's std::println hello on macOS 14 used to die
// at dyld against the system libc++). Lower floors need a custom
// libc++ build (tracked; data-only swap via xlings-res).
inline constexpr std::string_view default_deployment_target = "14.0";

// Resolve the effective macOS deployment target: the
// MACOSX_DEPLOYMENT_TARGET env var (explicit per-invocation override,
// the convention cargo/rustc/cc honor) wins over `manifestValue` (the
// [build] macos_deployment_target project default); empty means
// toolchain/SDK default. THE single source of truth — flags.cppm, the
// BMI fingerprint rule and the std-module prebuild must all consume
// this same resolution, or cached std.pcm modules drift from the TUs
// (config-mismatch / unstaged-module failures observed on macos CI).
// [build] macos_deployment_target project default), which wins over
// the built-in default floor — the result is never empty on macOS.
// THE single source of truth — flags.cppm, the BMI fingerprint rule
// and the std-module prebuild must all consume this same resolution,
// or cached std.pcm modules drift from the TUs (config-mismatch /
// unstaged-module failures observed on macos CI).
std::string deployment_target(std::string_view manifestValue);

// Return macOS-specific runtime library directories for LLVM toolchains.
std::string deployment_target(std::string_view manifestValue) {
#if defined(__APPLE__)
if (const char* dt = std::getenv("MACOSX_DEPLOYMENT_TARGET"); dt && *dt)
return dt;
return std::string(manifestValue);
if (!manifestValue.empty())
return std::string(manifestValue);
return std::string(default_deployment_target);
#else
(void)manifestValue;
return {};
Expand Down
Loading