+1 to Daniel's perspective.

The counterargument/use cases mentioned in the linked bug ( https://github.com/llvm/llvm-project/issues/80639 ) are concerns around ABI stability across different flags/options.

My gut reaction is that (having consumers build the modular objects) is not how we should encourage people to write/distribute modules - and if ABI stability is an issue, like libc++ does for non-modular code, they can force/ensure that certain features that are ABI unstable, do not appear in the modular object through marking those features always_inline or whatever other techniques they're using today.

Though, for argument's sake - how bad would it be if projects got to choose which way they wanted to distribute the modular objects (prebuilt & available in the library versus consumer built) - while still insisting that there are no interface-only modular libraries (you have to make a .a/.so anyway, even if it's empty, to mark where your module description json is). Seems harder to convince people of th elatter, and there's a risk the ecosystem evolves to support interface-only modular libraries, which then makes discovery more complicated/less consistent... 

On Tue, Feb 13, 2024 at 9:29 AM Daniel Ruoso via SG15 <sg15@lists.isocpp.org> wrote:
So far, my expectation has been that the library will ship with the objects produced from the interface files, and that when importing a module from a pre-built library, the build system should produce only the BMI.

Are there any use cases that drive the other approach?

Daniel

On Tue, Feb 13, 2024, 11:11 Jan Kokemüller via SG15 <sg15@lists.isocpp.org> wrote:
Hi,

let's say I'm packaging a modularized C++ library "foo" that consists of a
module implementation unit "foo.cpp" and an importable module unit "foo.cppm".
Where should the "library interface object files" live? In the "libfoo.{a,so}"
I ship, or can I punt this task to the consumer, who will compile the
importable module unit "foo.cppm" anyway (to get the BMI's)?

With "library interface object files" I mean the object files that are
generated by compiling the importable module unit "foo.cppm". I'm using the
terminology from Daniela Engert's talk here:
<https://youtu.be/nP8QcvPpGeM?t=333>

At least with Clang, the "library interface object files" will at least contain
the symbol for the "module initializer function" as laid out by the proposed
updates to the Itanium ABI:
<https://github.com/itanium-cxx-abi/cxx-abi/pull/144/files#diff-b803017e5afd1b6dfe35e5e0e719d895559129c35b93f056074a72928269ae23R5022-R5048>

So far I had assumed from following discussions and from my own experiments
with CMake >= 3.28 and reading Conan's plan
(<https://blog.conan.io/2023/10/17/modules-the-packaging-story.html>) that the
"library interface object files" (that contain e.g. the symbols for the module
initializer functions) will live in the library artifact "libfoo.{a,so}". That
way, as a consumer of that library, I can describe that library in my CMake
build system by creating an "imported" CMake target, without having to build
anything else except for the BMI's of the importable module units.

Furthermore, I had also assumed that the P2577R2 style metadata file that
describes the modules of a library is placed next to a library artifact that
contains the "library interface object files" (including the module initializer
symbols). That is also the reason I thought there always _exists_ a library
artifact for the metadata file to be placed next to, as the library artifact
will always at least contain the module initializer symbol.

In contrast, an alternative style of packaging a modularized library is
possible, where the library artifact does _not_ contain the "library interface
object files", instead requiring the consumer to build them in addition to the
BMI's. In CMake terms, users then could _not_ create an "imported" library
target, instead having to add a "proper" library target to their build that
"owns" the "library interface object files".

In my mind, this alternative style creates a number of headaches for the build
and packaging ecosystems as they have to cope with those additional libraries
required for holding the "library interface object files". It would certainly
be simpler for consumers if those symbols where "owned" by the library artifact
itself.

I stumbled across this issue as I was trying to consume the experimental libc++
"std" module. libc++ chose the second approach, i.e. the module initializer
symbols are not packaged up in any library artifact provided by libc++. In the
resulting discussion on the libc++ bug tracker
(<https://github.com/llvm/llvm-project/issues/80639>) people have encouraged me
to approach SG15.

What do you think about this issue? I'm curious about use cases for the
alternative packaging approach. Certainly there would need to be another key
like "library-contains-interface-object-files" in the metadata file so that
users know what kind of packaging approach was used. But I hope there can be
convergence on one approach so that kind of complexity could be avoided.

-Jan
_______________________________________________
SG15 mailing list
SG15@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/sg15
_______________________________________________
SG15 mailing list
SG15@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/sg15