@@ -29,6 +29,7 @@ import mcpp.lockfile;
2929import mcpp.publish.xpkg_emit;
3030import mcpp.pack;
3131import mcpp.config;
32+ import mcpp.xlings;
3233import mcpp.fetcher;
3334import mcpp.pm.resolver; // PR-R4: extracted from cli.cppm
3435import mcpp.pm.commands; // PR-R5: cmd_add / cmd_remove / cmd_update live here now
@@ -646,38 +647,46 @@ void patchelf_walk(const std::filesystem::path& dir,
646647 }
647648}
648649
649- // xim's gcc tarball is built with an absolute hardcoded path
650- // `/home/xlings/.xlings_data/subos/linux/lib/...` baked into the gcc specs
651- // (both as `--dynamic-linker` and `-rpath`). xim's gcc-specs-config.lua
652- // tries to override these but only matches `/lib64/ld-linux-x86-64.so.2`,
653- // not the baked-in `/home/xlings/...`, so the override silently no-ops.
650+ // xim bakes the installing user's XLINGS_HOME into gcc specs at install
651+ // time (as `--dynamic-linker` and `-rpath`). When mcpp uses its own
652+ // isolated sandbox (MCPP_HOME/registry/), the baked-in paths point to
653+ // xlings' home, not mcpp's sandbox glibc — binaries would fail to exec.
654654//
655- // TODO(xim-pkgindex-upstream): file an issue against xim-pkgindex's
656- // gcc-specs-config.lua to also match the `/home/xlings/...` baked-in
657- // path. Once fixed, this whole post-install fixup can be deleted.
658- //
659- // Result: gcc compiles user binaries with PT_INTERP pointing at
660- // `/home/xlings/.xlings_data/...` AND an rpath pointing at the same
661- // non-existent directory. `elfpatch.auto` (now functional thanks to the
662- // patchelf bootstrap) only fixes ELF binaries it scans; it doesn't touch
663- // the gcc specs text file.
664- //
665- // Mcpp does the post-install spec rewrite itself:
666- // - The dynamic-linker path becomes <glibc_lib64>/ld-linux-x86-64.so.2.
667- // - The rpath becomes <glibc_lib64>:<gcc_lib64> so user binaries can find
668- // both libc.so.6 (glibc) and libstdc++.so.6 + libgcc_s.so.1 (gcc).
669- // Idempotent.
655+ // Mcpp does a post-install spec rewrite:
656+ // - Dynamically detects the baked-in lib dir from the specs file
657+ // - Replaces the dynamic-linker path with <glibc_lib64>/ld-linux-x86-64.so.2
658+ // - Replaces the rpath with <glibc_lib64>:<gcc_lib64>
659+ // Idempotent — skips if already pointing at the correct glibc.
660+ // Extract the baked-in lib directory from a gcc specs file by finding
661+ // the dynamic-linker path that ends with `/ld-linux-x86-64.so.2`.
662+ // xim bakes the installing user's XLINGS_HOME into specs at install
663+ // time, so the path varies per machine — we cannot hardcode it.
664+ std::string detect_baked_lib_dir (const std::string& specsContent) {
665+ constexpr std::string_view kLoader = " /ld-linux-x86-64.so.2" ;
666+ auto pos = specsContent.find (kLoader );
667+ if (pos == std::string::npos) return " " ;
668+ // Walk backwards to find start of the absolute path
669+ auto start = pos;
670+ while (start > 0 && specsContent[start - 1 ] != ' '
671+ && specsContent[start - 1 ] != ' :'
672+ && specsContent[start - 1 ] != ' ;'
673+ && specsContent[start - 1 ] != ' \n ' ) {
674+ --start;
675+ }
676+ auto dir = specsContent.substr (start, pos - start);
677+ // Sanity: must be absolute
678+ if (dir.empty () || dir[0 ] != ' /' ) return " " ;
679+ // Skip if it already points to the target glibc (no fixup needed)
680+ return dir;
681+ }
682+
670683void fixup_gcc_specs (const std::filesystem::path& gccPkgRoot,
671684 const std::filesystem::path& glibcLibDir,
672685 const std::filesystem::path& gccLibDir)
673686{
674687 auto specsParent = gccPkgRoot / " lib" / " gcc" / " x86_64-linux-gnu" ;
675688 if (!std::filesystem::exists (specsParent)) return ;
676689
677- constexpr std::string_view kBakedDir =
678- " /home/xlings/.xlings_data/subos/linux/lib" ;
679- auto kBakedLoader = std::format (" {}/ld-linux-x86-64.so.2" , kBakedDir );
680-
681690 auto loaderReplacement = (glibcLibDir / " ld-linux-x86-64.so.2" ).string ();
682691 auto rpathReplacement = std::format (" {}:{}" ,
683692 glibcLibDir.string (),
@@ -701,12 +710,17 @@ void fixup_gcc_specs(const std::filesystem::path& gccPkgRoot,
701710 std::stringstream ss; ss << is.rdbuf ();
702711 std::string content = ss.str ();
703712
704- if (content.find (kBakedDir ) == std::string::npos) continue ;
713+ auto bakedDir = detect_baked_lib_dir (content);
714+ if (bakedDir.empty ()) continue ;
715+ // Already pointing at the right place — no fixup needed.
716+ if (bakedDir == glibcLibDir.string ()) continue ;
717+
718+ auto bakedLoader = bakedDir + " /ld-linux-x86-64.so.2" ;
705719
706720 // Order matters: replace the full loader file path first so the
707721 // shorter dir pattern doesn't eat its prefix.
708- replace_all (content, kBakedLoader , loaderReplacement);
709- replace_all (content, kBakedDir , rpathReplacement);
722+ replace_all (content, bakedLoader , loaderReplacement);
723+ replace_all (content, bakedDir , rpathReplacement);
710724
711725 std::ofstream os (specs);
712726 os << content;
@@ -2375,10 +2389,8 @@ int cmd_index_update(const mcpplibs::cmdline::ParsedArgs& /*parsed*/) {
23752389 auto cfg = mcpp::config::load_or_init (/* quiet=*/ false , make_bootstrap_progress_callback ());
23762390 if (!cfg) { mcpp::ui::error (cfg.error ().message ); return 4 ; }
23772391 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 ());
2392+ auto xlEnv = mcpp::config::make_xlings_env (*cfg);
2393+ std::string cmd = mcpp::xlings::build_command_prefix (xlEnv) + " update 2>&1" ;
23822394 std::array<char , 4096 > buf{};
23832395 std::FILE* fp = ::popen (cmd.c_str (), " r" );
23842396 if (!fp) { mcpp::ui::error (" failed to spawn index updater" ); return 1 ; }
@@ -2506,19 +2518,12 @@ int cmd_test(const mcpplibs::cmdline::ParsedArgs& /*parsed*/,
25062518 // visible to test binaries that shell out to them. The
25072519 // toolchain binary's path encodes the registry root — derive it.
25082520 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- }
2521+ if (auto xpkgs = mcpp::xlings::paths::xpkgs_from_compiler (ctx->tc .binaryPath )) {
2522+ // xpkgs is <registry>/data/xpkgs → registry = xpkgs/../..
2523+ auto registryDir = xpkgs->parent_path ().parent_path ();
2524+ auto sandboxBin = registryDir / " subos" / " default" / " bin" ;
2525+ if (std::filesystem::exists (sandboxBin))
2526+ pathPrefix = std::format (" PATH='{}':\" $PATH\" " , sandboxBin.string ());
25222527 }
25232528
25242529 std::string cmd = std::format (" {}'{}'" , pathPrefix, exe.string ());
@@ -2874,6 +2879,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
28742879 if (!cfg) { mcpp::ui::error (cfg.error ().message ); return 4 ; }
28752880
28762881 auto pkgsDir = cfg->xlingsHome () / " data" / " xpkgs" ;
2882+ auto xlEnv = mcpp::config::make_xlings_env (*cfg);
28772883
28782884 if (subname == " list" ) {
28792885 // `gcc 15.1.0-musl` and `musl-gcc@15.1.0` describe the same xpkg
@@ -3062,7 +3068,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
30623068 // `<root>/x86_64-linux-musl/{include,lib}` and doesn't link against
30633069 // xim:glibc, so this fixup is both unnecessary and harmful for it.
30643070 if (compiler == " gcc" && !isMusl) {
3065- auto glibcRoot = pkgsDir / " xim-x- glibc" ;
3071+ auto glibcRoot = mcpp::xlings::paths::xim_tool_root (xlEnv, " glibc" ) ;
30663072 std::filesystem::path glibcLibDir;
30673073 if (std::filesystem::exists (glibcRoot)) {
30683074 for (auto & v : std::filesystem::directory_iterator (glibcRoot)) {
@@ -3074,7 +3080,8 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
30743080 }
30753081 }
30763082 auto gccLibDir = payload->root / " lib64" ;
3077- auto patchelfBin = pkgsDir / " xim-x-patchelf" / " 0.18.0" / " bin" / " patchelf" ;
3083+ auto patchelfBin = mcpp::xlings::paths::xim_tool (xlEnv, " patchelf" ,
3084+ mcpp::xlings::pinned::kPatchelfVersion ) / " bin" / " patchelf" ;
30783085
30793086 if (!glibcLibDir.empty () && std::filesystem::exists (gccLibDir)
30803087 && std::filesystem::exists (patchelfBin))
@@ -3085,7 +3092,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
30853092
30863093 // (1) patchelf walk: rewrite PT_INTERP + RUNPATH for binutils
30873094 // and gcc xpkgs so they're self-contained in sandbox.
3088- auto binutilsRoot = pkgsDir / " xim-x- binutils" ;
3095+ auto binutilsRoot = mcpp::xlings::paths::xim_tool_root (xlEnv, " binutils" ) ;
30893096 if (std::filesystem::exists (binutilsRoot)) {
30903097 for (auto & v : std::filesystem::directory_iterator (binutilsRoot))
30913098 patchelf_walk (v.path (), loader, rpath, patchelfBin);
@@ -3150,7 +3157,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
31503157 compiler == " musl-gcc" ? " musl-gcc" : compiler, ximVersion)
31513158 : std::format (" {}@{}" , compiler, ximVersion);
31523159
3153- auto installDir = pkgsDir / std::format ( " xim-x-{} " , ximName) / ximVersion;
3160+ auto installDir = mcpp::xlings::paths::xim_tool (xlEnv , ximName, ximVersion) ;
31543161 if (!std::filesystem::exists (installDir)) {
31553162 mcpp::ui::error (std::format (
31563163 " {} is not installed. Run `mcpp toolchain install {} {}` first." ,
@@ -3177,7 +3184,7 @@ int cmd_toolchain(const mcpplibs::cmdline::ParsedArgs& parsed) {
31773184 }
31783185 std::string compiler = spec.substr (0 , at);
31793186 std::string version = spec.substr (at + 1 );
3180- auto installDir = pkgsDir / std::format ( " xim-x-{} " , compiler) / version;
3187+ auto installDir = mcpp::xlings::paths::xim_tool (xlEnv , compiler, version) ;
31813188 std::error_code ec;
31823189 if (!std::filesystem::exists (installDir, ec)) {
31833190 mcpp::ui::error (std::format (" {} is not installed" , spec));
0 commit comments