@@ -72,23 +72,18 @@ ValidateReport validate(const Graph& g,
7272 // Each SourceUnit carries its OWN package name (set by the scanner) so this
7373 // works transparently for multi-package builds (path deps): each unit is
7474 // validated against its own manifest's package name, not the primary's.
75+ // 0.0.10+: module naming is the library author's choice. The build tool
76+ // no longer enforces that module names must be prefixed by the package
77+ // name. Only the forbidden-top-level-name check is retained to avoid
78+ // collisions with well-known module names (std, core, etc.).
7579 for (auto & u : g.units ) {
7680 if (!u.provides ) continue ;
7781 const auto & m = u.provides ->logicalName ;
7882 auto base = m.substr (0 , m.find (' :' )); // strip partition suffix
79- const auto & pkg_name = u.packageName ; // ← unit's own package
80- const bool is_public = is_public_package_name (pkg_name);
81-
82- if (is_public) {
83- if (base != pkg_name && !base.starts_with (pkg_name + " ." )) {
84- r.errors .push_back ({u.path ,
85- std::format (" public module '{}' must be prefixed by package name '{}'" ,
86- m, pkg_name)});
87- }
88- if (is_forbidden_top_module (base)) {
89- r.errors .push_back ({u.path ,
90- std::format (" module '{}' uses a forbidden top-level name (core/util/common/...)" , m)});
91- }
83+
84+ if (is_forbidden_top_module (base)) {
85+ r.errors .push_back ({u.path ,
86+ std::format (" module '{}' uses a forbidden top-level name (core/util/common/...)" , m)});
9287 }
9388 }
9489
@@ -124,12 +119,14 @@ ValidateReport validate(const Graph& g,
124119
125120 // 2.5 Lib-root convention (M5.x+).
126121 //
127- // For projects that ship a `kind = "lib"` target, expect a primary
128- // module-interface file at either `[lib].path` (explicit override) or
129- // `src/<package-tail>.cppm` (default convention). The file must
130- // declare `export module <full-package-name>;` (no partition suffix);
131- // partitions go in sibling files and are aggregated by re-exporting
132- // from the lib root, à la `lib.rs` in cargo.
122+ // For projects that ship a `kind = "lib"` target, check that the
123+ // lib-root file exists. The lib root is either `[lib].path` (explicit
124+ // override) or `src/<package-tail>.cppm` (default convention).
125+ //
126+ // 0.0.10+: the module name exported by the lib root is NOT required
127+ // to match [package].namespace + name. The library author decides
128+ // the module name; the build tool auto-detects it via the scanner.
129+ // Only structural correctness is enforced (file exists, no partition).
133130 //
134131 // Pure-binary projects (mcpp itself, scaffolded `mcpp new`) skip this
135132 // check — they have no lib-root concept.
@@ -147,13 +144,9 @@ ValidateReport validate(const Graph& g,
147144 const bool exists = std::filesystem::exists (lib_root_abs, ec);
148145 if (!exists) {
149146 if (was_explicit) {
150- // Explicit `[lib].path` pointing at a missing file is
151- // always an error.
152147 r.errors .push_back ({lib_root_rel, std::format (
153148 " [lib].path '{}' does not exist" , lib_root_rel.string ())});
154149 } else {
155- // Convention miss is a warning — gives existing projects
156- // a soft on-ramp before they rename / move files.
157150 r.warnings .push_back ({lib_root_rel, std::format (
158151 " lib target without conventional lib root '{}' "
159152 " (create the file or set [lib].path)" ,
@@ -162,13 +155,11 @@ ValidateReport validate(const Graph& g,
162155 }
163156 }
164157
165- // Even without on-disk verification we can still cross-check the
166- // graph: if a unit at the lib-root path is present, it must
167- // export `<package-name>` exactly ( no partition) .
158+ // If the lib-root file is in the graph, verify it exports a
159+ // primary module (not a partition). The actual module name is
160+ // the library author's choice — no name-matching enforced .
168161 const mcpp::modgraph::SourceUnit* lib_unit = nullptr ;
169162 for (auto & u : g.units ) {
170- // Match relative or absolute — projectRoot may be empty in
171- // tests, so we just compare path tails.
172163 auto u_rel = u.path .is_absolute () && !projectRoot.empty ()
173164 ? std::filesystem::relative (u.path , projectRoot)
174165 : u.path ;
@@ -180,27 +171,15 @@ ValidateReport validate(const Graph& g,
180171 if (lib_unit) {
181172 if (!lib_unit->provides ) {
182173 r.errors .push_back ({lib_unit->path , std::format (
183- " lib root '{}' must declare `export module {} ;`" ,
184- lib_root_rel.string (), manifest. package . name )});
174+ " lib root '{}' must declare `export module <name> ;`" ,
175+ lib_root_rel.string ())});
185176 } else {
186177 const auto & m = lib_unit->provides ->logicalName ;
187178 if (m.find (' :' ) != std::string::npos) {
188179 r.errors .push_back ({lib_unit->path , std::format (
189- " lib root '{}' exports a partition '{}' — must be the "
190- " primary module '{}' (no `:partition` suffix)" ,
191- lib_root_rel.string (), m, manifest.package .name )});
192- } else {
193- // 0.0.6+: compare against qualified name when namespace is set.
194- const std::string expected =
195- manifest.package .namespace_ .empty ()
196- ? manifest.package .name
197- : manifest.package .namespace_ + " ." + manifest.package .name ;
198- if (m != expected) {
199- r.errors .push_back ({lib_unit->path , std::format (
200- " lib root '{}' exports module '{}', expected '{}' "
201- " (must match [package].namespace + name)" ,
202- lib_root_rel.string (), m, expected)});
203- }
180+ " lib root '{}' exports a partition '{}' — "
181+ " must be a primary module (no `:partition` suffix)" ,
182+ lib_root_rel.string (), m)});
204183 }
205184 }
206185 }
0 commit comments