From ef4da217aa484133f83a539bf6792495f0e563fe Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Mon, 22 Jun 2026 03:30:30 +0800 Subject: [PATCH] fix(toolchain): list '*' reflects effective project-aware toolchain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `mcpp toolchain default` and `mcpp toolchain list`'s `*` marker read only the global config.toml [toolchain] default, but the build resolver (prepare.cppm) reads the project mcpp.toml [toolchain] FIRST — it shadows the global default. So in a project with a [toolchain] section, `list` could mark `*` on a different toolchain than `mcpp run` actually resolves (the reported gcc@16.1.0-vs-gcc@15.1.0-musl divergence). Compute the effective default the same way a build does (project mcpp.toml [toolchain] for the current platform, else global config), mark `*` on it, and print a note when it comes from the project so it never silently disagrees with the build. --target overrides are not folded in (they only apply with an explicit --target). --- src/toolchain/lifecycle.cppm | 38 +++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/toolchain/lifecycle.cppm b/src/toolchain/lifecycle.cppm index 375c60a..cf21e36 100644 --- a/src/toolchain/lifecycle.cppm +++ b/src/toolchain/lifecycle.cppm @@ -13,6 +13,7 @@ import mcpp.config; import mcpp.fetcher; import mcpp.fetcher.progress; import mcpp.manifest; +import mcpp.platform; import mcpp.toolchain.detect; import mcpp.toolchain.registry; import mcpp.toolchain.post_install; @@ -151,8 +152,34 @@ list_available_xpkg_versions(const mcpp::config::GlobalConfig& cfg, // preserves the shared setup (cfg load + xlings bootstrap progress) // `mcpp toolchain list` — installed + available toolchains. +// The toolchain that `mcpp build`/`run` actually resolves from the current +// directory. A project mcpp.toml `[toolchain]` shadows the global config +// default (see prepare.cppm resolution order), so `mcpp toolchain default` +// and `mcpp toolchain list`'s `*` — which read only the global config — can +// otherwise disagree with what a build in this directory really uses. +// (`--target` overrides are intentionally not folded in: they only take +// effect when an explicit `--target` is passed.) +struct EffectiveDefault { + std::string spec; + bool fromProject = false; +}; + +EffectiveDefault effective_default_toolchain(const mcpp::config::GlobalConfig& cfg) { + std::error_code ec; + auto mpath = std::filesystem::current_path(ec) / "mcpp.toml"; + if (!ec && std::filesystem::exists(mpath, ec)) { + if (auto m = mcpp::manifest::load(mpath)) { + if (auto t = m->toolchain.for_platform(mcpp::platform::name); + t && !t->empty()) + return { *t, true }; + } + } + return { cfg.defaultToolchain, false }; +} + export int toolchain_list(const mcpp::config::GlobalConfig& cfg) { auto pkgsDir = cfg.xlingsHome() / "data" / "xpkgs"; + auto effective = effective_default_toolchain(cfg); auto pathCtx = mcpp::fetcher::make_path_ctx(&cfg); struct Row { std::string compiler; @@ -178,7 +205,7 @@ export int toolchain_list(const mcpp::config::GlobalConfig& cfg) { r.version = vEntry.path().filename().string(); r.bin = bin; r.isDefault = mcpp::toolchain::matches_default_toolchain( - cfg.defaultToolchain, r.compiler, r.version); + effective.spec, r.compiler, r.version); installed.push_back(std::move(r)); } } @@ -196,6 +223,15 @@ export int toolchain_list(const mcpp::config::GlobalConfig& cfg) { mcpp::toolchain::display_label(r.compiler, r.version), mcpp::ui::shorten_path(r.bin, pathCtx)); } + // Explain the `*` when it reflects a project override rather than + // the global default, so it never silently disagrees with what a + // build in this directory resolves. + if (effective.fromProject) { + std::println(" (* = effective toolchain from project mcpp.toml " + "[toolchain]; global default is '{}')", + cfg.defaultToolchain.empty() ? "" + : cfg.defaultToolchain); + } } // ─── Available section ──────────────────────────────────────────