33import std;
44import mcpp.config;
55import mcpp.manifest;
6+ import mcpp.platform;
67import mcpp.platform.runtime_binding;
78import mcpp.xlings.runtime_selection;
89
@@ -64,6 +65,27 @@ struct RuntimeHome {
6465 "workspace": {{}}
6566 }})" , runtimeName, envValue);
6667 }
68+
69+ void point_default_glibc_view_at (std::string_view version) const {
70+ auto payload = install_glibc_payload (version);
71+ auto view = cfg.xlingsHome () / " subos" / " default" / " lib" ;
72+ std::filesystem::create_directories (view);
73+ std::filesystem::create_symlink (
74+ payload / " libc.so.6" , view / " libc.so.6" );
75+ std::filesystem::create_symlink (
76+ payload / " ld-linux-x86-64.so.2" ,
77+ view / " ld-linux-x86-64.so.2" );
78+ }
79+
80+ std::filesystem::path install_glibc_payload (
81+ std::string_view version) const {
82+ auto payload = cfg.xlingsHome () / " data" / " xpkgs"
83+ / " xim-x-glibc" / version / " lib" ;
84+ std::filesystem::create_directories (payload);
85+ std::ofstream (payload / " libc.so.6" ) << " fixture libc" ;
86+ std::ofstream (payload / " ld-linux-x86-64.so.2" ) << " fixture loader" ;
87+ return payload;
88+ }
6789};
6890
6991TEST (RuntimeSelection, AbsenceMeansMcppDefault) {
@@ -134,7 +156,10 @@ TEST(RuntimeBinding, DefaultAlwaysUsesConfiguredMcppHomeDefault) {
134156 ASSERT_TRUE (binding.has_value ()) << binding.error ();
135157 EXPECT_EQ (binding->subosDir , expected);
136158 EXPECT_EQ (binding->runtimeId , " glibc@2.39" );
137- EXPECT_EQ (binding->libc , std::optional<std::string>(" glibc@2.39" ));
159+ if constexpr (mcpp::platform::is_linux)
160+ EXPECT_EQ (binding->libc , std::optional<std::string>(" glibc@2.39" ));
161+ else
162+ EXPECT_FALSE (binding->libc .has_value ());
138163 EXPECT_EQ (binding->provenance , " mcpp_default" );
139164 EXPECT_FALSE (binding->contractHash .empty ());
140165 ASSERT_EQ (binding->runtimeProviders .size (), 1u );
@@ -159,6 +184,59 @@ TEST(RuntimeBinding, ExplicitDefaultUsesGlobalDefaultButKeepsNamedIdentity) {
159184 EXPECT_EQ (binding->selection .mode , runtime::RuntimeSelection::Mode::NamedSubos);
160185}
161186
187+ TEST (RuntimeBinding, PhysicalSubosViewReconcilesAStaleDeclaredGlibcIdentity) {
188+ if constexpr (!mcpp::platform::is_linux)
189+ GTEST_SKIP () << " glibc SubOS views only exist on Linux" ;
190+
191+ RuntimeHome h;
192+ const auto subos = h.cfg .xlingsHome () / " subos" / " default" ;
193+ h.write (subos, " glibc@2.39" );
194+ h.point_default_glibc_view_at (" 2.44" );
195+
196+ mcpp::manifest::Manifest root;
197+ auto selection = runtime::select_runtime (root, std::nullopt , h.dir / " repo" );
198+ ASSERT_TRUE (selection);
199+ auto binding = mcpp::platform::runtime::resolve_runtime_binding (
200+ *selection, {}, h.cfg );
201+ ASSERT_TRUE (binding.has_value ()) << binding.error ();
202+
203+ EXPECT_EQ (binding->runtimeId , " glibc@2.44" );
204+ EXPECT_EQ (binding->libc , std::optional<std::string>(" glibc@2.44" ));
205+ ASSERT_EQ (binding->libraryDirs .size (), 1u );
206+ EXPECT_EQ (binding->libraryDirs .front (),
207+ h.cfg .xlingsHome () / " data" / " xpkgs"
208+ / " xim-x-glibc" / " 2.44" / " lib" );
209+ }
210+
211+ TEST (RuntimeBinding, BrokenSubosViewFallsBackOnlyToTheExactDeclaredPayload) {
212+ if constexpr (!mcpp::platform::is_linux)
213+ GTEST_SKIP () << " glibc SubOS views only exist on Linux" ;
214+
215+ RuntimeHome h;
216+ const auto subos = h.cfg .xlingsHome () / " subos" / " default" ;
217+ h.write (subos, " glibc@2.44" );
218+ auto payload = h.install_glibc_payload (" 2.44" );
219+ auto view = subos / " lib" ;
220+ std::filesystem::create_directories (view);
221+ std::filesystem::create_symlink (
222+ payload.parent_path () / " lib64" / " libc.so.6" ,
223+ view / " libc.so.6" );
224+
225+ mcpp::manifest::Manifest root;
226+ auto selection = runtime::select_runtime (root, std::nullopt , h.dir / " repo" );
227+ ASSERT_TRUE (selection);
228+ auto binding = mcpp::platform::runtime::resolve_runtime_binding (
229+ *selection, {}, h.cfg );
230+ ASSERT_TRUE (binding.has_value ()) << binding.error ();
231+
232+ EXPECT_EQ (binding->runtimeId , " glibc@2.44" );
233+ ASSERT_EQ (binding->libraryDirs .size (), 1u );
234+ EXPECT_EQ (binding->libraryDirs .front (), payload);
235+ EXPECT_EQ (binding->loader ,
236+ std::optional<std::filesystem::path>(
237+ payload / " ld-linux-x86-64.so.2" ));
238+ }
239+
162240TEST (RuntimeBinding, NamedSubosIsOwnedByTheRootAndMissingIsHardError) {
163241 RuntimeHome h;
164242 auto manifest = named (" el8" );
@@ -203,8 +281,12 @@ TEST(RuntimeBinding, NamedEnvironmentsHaveDistinctContractsAndRoundTrip) {
203281 auto decoded = mcpp::platform::runtime::deserialize_runtime_binding (encoded);
204282 ASSERT_TRUE (decoded.has_value ()) << decoded.error ();
205283 EXPECT_EQ (decoded->contractHash , el8->contractHash );
206- ASSERT_TRUE (decoded->hostLibc .has_value ());
207- EXPECT_EQ (*decoded->hostLibc , " 2.43" );
284+ if constexpr (mcpp::platform::is_linux) {
285+ ASSERT_TRUE (decoded->hostLibc .has_value ());
286+ EXPECT_EQ (*decoded->hostLibc , " 2.43" );
287+ } else {
288+ EXPECT_FALSE (decoded->hostLibc .has_value ());
289+ }
208290 EXPECT_EQ (decoded->subosDir , el8->subosDir );
209291 ASSERT_EQ (decoded->environment .size (), 1u );
210292 EXPECT_EQ (decoded->environment [0 ].var , " DRIVERS" );
0 commit comments