@@ -99,6 +99,22 @@ namespace mcpp::build {
9999// should not fail outright, only tell the user what it ignored.
100100inline void warn_unknown_xpkg_keys (const mcpp::manifest::Manifest& dm,
101101 std::string_view depLabel) {
102+ // ⚠️ A LAYER NAME THIS ENGINE DOES NOT KNOW IS A VERSION GAP, NOT A TYPO,
103+ // WHEN IT ARRIVES FROM A DEPENDENCY.
104+ //
105+ // The reserved `mcpp:` prefix is a closed set so a misspelling cannot
106+ // silently disable a behaviour. Refusing a DEPENDENCY's manifest for it made
107+ // the set closed in a second sense nobody intended: a published package
108+ // could never declare a layer named after the reader was released.
109+ // Ignoring the layer and saying so is what this engine already does for
110+ // every other unknown key, and it is the only response that lets the
111+ // vocabulary grow.
112+ for (auto const & cap : dm.unknownCapabilities ) {
113+ mcpp::ui::warning (std::format (
114+ " dependency '{}': `{}` names a target-side layer this mcpp does not "
115+ " know — ignored. A newer mcpp may resolve it; this build proceeds "
116+ " without that layer." , depLabel, cap));
117+ }
102118 for (auto const & key : dm.xpkgUnknownKeys ) {
103119 auto suggestion = mcpp::manifest::closest_known_xpkg_key (key);
104120 if (suggestion.empty ())
@@ -923,6 +939,21 @@ prepare_build(bool print_fingerprint,
923939 : mcpp::manifest::load (*root / " mcpp.toml" );
924940 if (!m) return std::unexpected (m.error ().format ());
925941
942+ // ⚠️ AND ONLY FOR THE ROOT. A layer name this engine does not know is a
943+ // typo in the manifest the author is looking at, and a version gap in a
944+ // dependency's. The reserved `mcpp:` prefix exists so the first is an error
945+ // rather than a silently disabled behaviour; refusing the second as well
946+ // meant the layer vocabulary could never be extended by a published package
947+ // (`warn_unknown_xpkg_keys` carries that half).
948+ if (!m->unknownCapabilities .empty ()) {
949+ auto const & cap = m->unknownCapabilities .front ();
950+ auto why = mcpp::targetside::parse_capability (cap);
951+ return std::unexpected (std::format (
952+ " {}: {}" , (*root / " mcpp.toml" ).string (),
953+ why ? std::format (" `{}` names no capability mcpp knows." , cap)
954+ : why.error ()));
955+ }
956+
926957 // A DISTRIBUTION package is not a source tree, and building "in" one is a
927958 // failure that looks like a success: `interface/` holds declarations whose
928959 // definitions are in the prebuilt archive, so the build compiles the
@@ -5563,6 +5594,20 @@ prepare_build(bool print_fingerprint,
55635594 : std::format (" {}@{}" , pkg.manifest .package .name ,
55645595 pkg.manifest .package .version );
55655596
5597+ // ⚠️ EVERY PACKAGE KIND, NOT ONLY THE ONES WITH AN XPKG
5598+ // DESCRIPTOR. `warn_unknown_xpkg_keys` reaches a dependency
5599+ // resolved through the index; a path or git dependency carries a
5600+ // manifest of its own and reached no warning at all, so a layer
5601+ // this engine does not know went by in silence. This loop sees
5602+ // every package in the graph.
5603+ for (auto const & cap : pkg.manifest .unknownCapabilities ) {
5604+ if (&pkg == &packages.front ()) continue ; // root: already refused
5605+ mcpp::ui::warning (std::format (
5606+ " package '{}': `{}` names a target-side layer this mcpp does "
5607+ " not know — ignored. A newer mcpp may resolve it; this build "
5608+ " proceeds without that layer." , pkgId, cap));
5609+ }
5610+
55665611 for (auto const & entry : pkg.manifest .provides ) {
55675612 std::optional<tsd::CapDecl> decl;
55685613 if (auto parsed = tsd::parse_capability (entry); parsed && *parsed)
@@ -5610,10 +5655,10 @@ prepare_build(bool print_fingerprint,
56105655 // one is: a typo would otherwise disable a check silently.
56115656 for (auto const & entry : pkg.manifest .requires_ ) {
56125657 auto parsed = tsd::parse_capability (entry);
5613- if (!parsed)
5614- return std::unexpected ( std::format (
5615- " package '{}': {} " , pkgId, parsed. error ()));
5616- if (!*parsed) continue ; // not in mcpp's namespace
5658+ // An unknown layer name is reported where the manifest was
5659+ // read — as an error for the root and a warning for a
5660+ // dependency — so it is skipped rather than refused twice.
5661+ if (!parsed || ! *parsed) continue ;
56175662 requirements.push_back ({ pkgId, (*parsed)->layer ,
56185663 (*parsed)->interfaceName });
56195664 }
0 commit comments