CMake will build and install a static or shared library, which seems just unnecessary, as the modules will be built again by the consumer. I’ve tried building an INTERFACE library, instead, but target_sources refuses to add a CXX_MODULES fileset with INTERFACE scope.
Modules have module initializer symbols that need to be provided once to be reliable (the ODR applies here). Providing it in a library is the reliable way to do this.
The BMIs will be built again, but not object files.
Sorry if it’s a dumb question, but what is a “module initializer symbol”? I can’t find any reference to the term in clang/MSVC docs or in the standard.
The new rule is that all global initializers required by module A will be called before those of module B if B contains import A. This is implemented by making a symbol for export module M; that is called for any import M; statement.
The BMIs will be built again, but not object files.
Hm but we do not distribute object files.
For example if we have a header only library like argparse which has a cppm file, I currently have to create a static library and build to module (?) but the only thing I want is to distribute the cppm file and a target that consuming projects can link to.
Currently I have
Something needs to provide the import_argparse_initializer() symbol (mangled as the ABI requires) to call so that global statics are properly initialized. I floated the idea in ISO (without a paper) to have a [[no_module_init]] attribute on the export module to indicate that the module does not need it (note that this also makes declarations about imported modules’ requirements) and therefore a module would not need to worry about the ODR and its module initialization function.
As an idea, could CMake build the required object file in the consumer project? In a similar fashion as when building the BMI, and only when the module FILE_SET is marked in the provided project as an INTERFACE property?
If someone can explain why that doesn’t cause problems with the ODR (either because it doesn’t provoke it or somehow shows how it is OK to ignore in this situation) when used in multiple targets that end up linked together later…ṡure. Currently CMake rejects INTERFACE FILE_SET of type CXX_MODULES because of it.
Linking duplicated module is clearly not welcomed but I think cmake should leave it to linker to diagnose. The check in cmake side seems to be an overdesign to me.
Uhh…that sounds super platform-specific to me. “No one” will do that.
Once we start making BMIs per importer configuration rather than assuming everything is compatible, I think we can do a survey of the actual risk with lifting the gate here. I just can’t bring the horses back into the barn if I allow it today and it is a problem. Plus, plumbing through INTERFACE modules is more complicated and would have delayed things even more (we might not find out we have modules until generate time when generator expressions are resolved and then we’re at a severe loss of where to hang any diagnostics[1] or (re-)scheduling things that need to happen for module-aware targets).
[1] At best, it’d all get reported on target_link_libraries which adds the module-providing target to the list.
No, we did that in a lot of places (Although we’re using bazel right now). I do think it is not true to say “no one“.
Once we start making BMIs per importer configuration rather than assuming everything is compatible, I think we can do a survey of the actual risk with lifting the gate here.
This makes me confusing. I don’t feel it relates to BMI. It is basic traditional linking problems.
I understand a lot of people today are concerning about “safe“ things. (Although it looks like we don’t have a consistent idea for “safe“). And I feel a lot of tools people are trying to force people to write “safe“ codes. But they seems to be an overkill to me. (including cmake doesn’t allow implementation partition units to not produce BMI).
And for the specific problem doesn’t relate to “safe“ issues. They will get the duplicated symbol by linker naturally if they did thing wrong. No body will get hurted.
Let me know if I’m understanding this correctly:
The provider project installs a header-only library with an INTERFACE FILE_SET of type CXX_MODULES.
The consumer project finds it using find_package.
The consumer builds an executable linking to the provider lib, using a set of compiler flags (e.g. C++ standard level, enabled extensions) of F1. This builds the provider lib with F1. Everything OK.
The consumer builds a library linking to the provider lib, with flags F2. This would require building the provider lib with F2.
The consumer finally builds an executable linking to both the provider lib and the lib built in the previous point, with flags F3. You’d try to build the provider lib again with F3, link it together, and that would create problems.
Is this the problem that would happen here? Wouldn’t something similar happen with BMIs, too?
BMIs are orthogonal here, you can think of them like PCH files, nothing in them violates ODR for the same reasons headers with only inline symbols don’t violate ODR.
The _ZGIW<module> symbol will violate ODR if it has multiple providers.