Skip to content

Commit 666818f

Browse files
committed
refactor: extract xlings abstraction layer (mcpp.xlings module)
Consolidate all xlings (external package manager) interactions into a single leaf module `mcpp.xlings`. This eliminates: - Duplicate NDJSON pipe implementations in config.cppm and package_fetcher.cppm (existed due to cyclic import workaround) - Triplicated xpkgs directory climb logic in flags.cppm, ninja_backend.cppm, and stdmod.cppm - Scattered hardcoded version strings and magic paths The new module provides: - Env struct + pinned version constants - Pure path helpers (xpkgs_base, xim_tool, find_sibling_binary, etc.) - Unified NDJSON event parser and subprocess call - Bootstrap lifecycle (ensure_init, ensure_patchelf, ensure_ninja) - Shell command builders and run_capture utility Net result: +750 lines (new module), -618 lines (removed duplication) = net -528 lines across 7 refactored files.
1 parent a5fbcc0 commit 666818f

8 files changed

Lines changed: 840 additions & 618 deletions

File tree

src/build/flags.cppm

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export module mcpp.build.flags;
1010

1111
import std;
1212
import mcpp.build.plan;
13+
import mcpp.xlings;
1314

1415
export namespace mcpp::build {
1516

@@ -101,27 +102,9 @@ CompileFlags compute_flags(const BuildPlan& plan) {
101102
bool isMuslTc = plan.toolchain.targetTriple.find("-musl") != std::string::npos;
102103
std::filesystem::path binutilsBin;
103104
if (!isMuslTc) {
104-
auto bp = plan.toolchain.binaryPath;
105-
std::filesystem::path xpkgsDir;
106-
for (auto p = bp.parent_path(); p.has_parent_path() && p != p.root_path();
107-
p = p.parent_path()) {
108-
if (p.filename() == "xpkgs") {
109-
xpkgsDir = p;
110-
break;
111-
}
112-
}
113-
if (!xpkgsDir.empty()) {
114-
auto root = xpkgsDir / "xim-x-binutils";
115-
std::error_code ec;
116-
if (std::filesystem::exists(root, ec)) {
117-
for (auto& v : std::filesystem::directory_iterator(root, ec)) {
118-
auto candidate = v.path() / "bin";
119-
if (std::filesystem::exists(candidate / "ar", ec)) {
120-
binutilsBin = candidate;
121-
break;
122-
}
123-
}
124-
}
105+
if (auto ar = mcpp::xlings::paths::find_sibling_binary(
106+
plan.toolchain.binaryPath, "binutils", "bin/ar")) {
107+
binutilsBin = ar->parent_path(); // bin/ar → bin/
125108
}
126109
}
127110
std::string b_flag;

src/build/ninja_backend.cppm

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import mcpp.build.plan;
2323
import mcpp.build.flags;
2424
import mcpp.build.compile_commands;
2525
import mcpp.dyndep;
26+
import mcpp.xlings;
2627

2728
export namespace mcpp::build {
2829

@@ -456,30 +457,9 @@ std::expected<BuildResult, BuildError> NinjaBackend::build(const BuildPlan& plan
456457
// -B<binutils-bin> flag we emit into cxxflags/ldflags (see
457458
// emit_ninja_string). No PATH injection needed here.
458459
std::filesystem::path ninjaBin;
459-
{
460-
auto bp = plan.toolchain.binaryPath;
461-
std::filesystem::path xpkgsDir;
462-
for (auto p = bp.parent_path(); p.has_parent_path() && p != p.root_path();
463-
p = p.parent_path()) {
464-
if (p.filename() == "xpkgs") {
465-
xpkgsDir = p;
466-
break;
467-
}
468-
}
469-
if (!xpkgsDir.empty()) {
470-
// xim's ninja xpkg puts the binary at <v>/ninja (no bin/ subdir).
471-
auto root = xpkgsDir / "xim-x-ninja";
472-
std::error_code ec;
473-
if (std::filesystem::exists(root, ec)) {
474-
for (auto& v : std::filesystem::directory_iterator(root, ec)) {
475-
auto candidate = v.path() / "ninja";
476-
if (std::filesystem::exists(candidate, ec)) {
477-
ninjaBin = candidate;
478-
break;
479-
}
480-
}
481-
}
482-
}
460+
if (auto nb = mcpp::xlings::paths::find_sibling_binary(
461+
plan.toolchain.binaryPath, "ninja", "ninja")) {
462+
ninjaBin = *nb;
483463
}
484464

485465
std::string ninjaProgram =

src/cli.cppm

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import mcpp.lockfile;
2929
import mcpp.publish.xpkg_emit;
3030
import mcpp.pack;
3131
import mcpp.config;
32+
import mcpp.xlings;
3233
import mcpp.fetcher;
3334
import mcpp.pm.resolver; // PR-R4: extracted from cli.cppm
3435
import mcpp.pm.commands; // PR-R5: cmd_add / cmd_remove / cmd_update live here now
@@ -675,7 +676,7 @@ void fixup_gcc_specs(const std::filesystem::path& gccPkgRoot,
675676
if (!std::filesystem::exists(specsParent)) return;
676677

677678
constexpr std::string_view kBakedDir =
678-
"/home/xlings/.xlings_data/subos/linux/lib";
679+
mcpp::xlings::pinned::kXlingsBuildHostLib;
679680
auto kBakedLoader = std::format("{}/ld-linux-x86-64.so.2", kBakedDir);
680681

681682
auto loaderReplacement = (glibcLibDir / "ld-linux-x86-64.so.2").string();
@@ -2375,10 +2376,8 @@ int cmd_index_update(const mcpplibs::cmdline::ParsedArgs& /*parsed*/) {
23752376
auto cfg = mcpp::config::load_or_init(/*quiet=*/false, make_bootstrap_progress_callback());
23762377
if (!cfg) { mcpp::ui::error(cfg.error().message); return 4; }
23772378
mcpp::ui::status("Updating", "all index repos");
2378-
std::string cmd = std::format(
2379-
"env -u XLINGS_PROJECT_DIR XLINGS_HOME='{}' '{}' update 2>&1",
2380-
cfg->xlingsHome().string(),
2381-
cfg->xlingsBinary.string());
2379+
auto xlEnv = mcpp::config::make_xlings_env(*cfg);
2380+
std::string cmd = mcpp::xlings::build_command_prefix(xlEnv) + " update 2>&1";
23822381
std::array<char, 4096> buf{};
23832382
std::FILE* fp = ::popen(cmd.c_str(), "r");
23842383
if (!fp) { mcpp::ui::error("failed to spawn index updater"); return 1; }
@@ -2506,19 +2505,12 @@ int cmd_test(const mcpplibs::cmdline::ParsedArgs& /*parsed*/,
25062505
// visible to test binaries that shell out to them. The
25072506
// toolchain binary's path encodes the registry root — derive it.
25082507
std::string pathPrefix;
2509-
{
2510-
auto tcBin = ctx->tc.binaryPath;
2511-
// tc binary at <registry>/data/xpkgs/xim-x-*/ver/bin/g++
2512-
// Climb to <registry> = .../(xpkgs)/../..
2513-
for (auto p = tcBin; !p.empty() && p != p.root_path(); p = p.parent_path()) {
2514-
if (p.filename() == "xpkgs") {
2515-
auto registryDir = p.parent_path().parent_path();
2516-
auto sandboxBin = registryDir / "subos" / "default" / "bin";
2517-
if (std::filesystem::exists(sandboxBin))
2518-
pathPrefix = std::format("PATH='{}':\"$PATH\" ", sandboxBin.string());
2519-
break;
2520-
}
2521-
}
2508+
if (auto xpkgs = mcpp::xlings::paths::xpkgs_from_compiler(ctx->tc.binaryPath)) {
2509+
// xpkgs is <registry>/data/xpkgs → registry = xpkgs/../..
2510+
auto registryDir = xpkgs->parent_path().parent_path();
2511+
auto sandboxBin = registryDir / "subos" / "default" / "bin";
2512+
if (std::filesystem::exists(sandboxBin))
2513+
pathPrefix = std::format("PATH='{}':\"$PATH\" ", sandboxBin.string());
25222514
}
25232515

25242516
std::string cmd = std::format("{}'{}'", pathPrefix, exe.string());
@@ -2874,6 +2866,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
28742866
if (!cfg) { mcpp::ui::error(cfg.error().message); return 4; }
28752867

28762868
auto pkgsDir = cfg->xlingsHome() / "data" / "xpkgs";
2869+
auto xlEnv = mcpp::config::make_xlings_env(*cfg);
28772870

28782871
if (subname == "list") {
28792872
// `gcc 15.1.0-musl` and `musl-gcc@15.1.0` describe the same xpkg
@@ -3062,7 +3055,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
30623055
// `<root>/x86_64-linux-musl/{include,lib}` and doesn't link against
30633056
// xim:glibc, so this fixup is both unnecessary and harmful for it.
30643057
if (compiler == "gcc" && !isMusl) {
3065-
auto glibcRoot = pkgsDir / "xim-x-glibc";
3058+
auto glibcRoot = mcpp::xlings::paths::xim_tool_root(xlEnv, "glibc");
30663059
std::filesystem::path glibcLibDir;
30673060
if (std::filesystem::exists(glibcRoot)) {
30683061
for (auto& v : std::filesystem::directory_iterator(glibcRoot)) {
@@ -3074,7 +3067,8 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
30743067
}
30753068
}
30763069
auto gccLibDir = payload->root / "lib64";
3077-
auto patchelfBin = pkgsDir / "xim-x-patchelf" / "0.18.0" / "bin" / "patchelf";
3070+
auto patchelfBin = mcpp::xlings::paths::xim_tool(xlEnv, "patchelf",
3071+
mcpp::xlings::pinned::kPatchelfVersion) / "bin" / "patchelf";
30783072

30793073
if (!glibcLibDir.empty() && std::filesystem::exists(gccLibDir)
30803074
&& std::filesystem::exists(patchelfBin))
@@ -3085,7 +3079,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
30853079

30863080
// (1) patchelf walk: rewrite PT_INTERP + RUNPATH for binutils
30873081
// and gcc xpkgs so they're self-contained in sandbox.
3088-
auto binutilsRoot = pkgsDir / "xim-x-binutils";
3082+
auto binutilsRoot = mcpp::xlings::paths::xim_tool_root(xlEnv, "binutils");
30893083
if (std::filesystem::exists(binutilsRoot)) {
30903084
for (auto& v : std::filesystem::directory_iterator(binutilsRoot))
30913085
patchelf_walk(v.path(), loader, rpath, patchelfBin);
@@ -3150,7 +3144,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
31503144
compiler == "musl-gcc" ? "musl-gcc" : compiler, ximVersion)
31513145
: std::format("{}@{}", compiler, ximVersion);
31523146

3153-
auto installDir = pkgsDir / std::format("xim-x-{}", ximName) / ximVersion;
3147+
auto installDir = mcpp::xlings::paths::xim_tool(xlEnv, ximName, ximVersion);
31543148
if (!std::filesystem::exists(installDir)) {
31553149
mcpp::ui::error(std::format(
31563150
"{} is not installed. Run `mcpp toolchain install {} {}` first.",
@@ -3177,7 +3171,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
31773171
}
31783172
std::string compiler = spec.substr(0, at);
31793173
std::string version = spec.substr(at + 1);
3180-
auto installDir = pkgsDir / std::format("xim-x-{}", compiler) / version;
3174+
auto installDir = mcpp::xlings::paths::xim_tool(xlEnv, compiler, version);
31813175
std::error_code ec;
31823176
if (!std::filesystem::exists(installDir, ec)) {
31833177
mcpp::ui::error(std::format("{} is not installed", spec));

0 commit comments

Comments
 (0)