C++ Logo

sg15

Advanced search

Packaging: Where should "library interface object files" live?

From: Jan Kokemüller <jan.kokemueller_at_[hidden]>
Date: Sat, 10 Feb 2024 10:04:09 +0100
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

Received on 2024-02-10 09:04:14