On Mon, 13 Jul 2026 08:31:18 -0700, Pierrick Bouvier wrote:
The problem is that if that the guest program, or the host library (host
libhello) may depend on libstdc++. If they do and if they depend on a
(newer) symbol not present in lorelei libstdc++, we break ABI. Same goes
for libgcc.
By not doing this, you'll be forced to provide a lorelei devkit
everytime a new libstdc++ is published, or a distribution updates its gcc.
The only solution is to embed libstd++ and libgcc statically, or rely on
host libraries. If you choose the second option, you know have the
opposite problem. So I think the only way to solve it is really static
linking, even if it will slightly increase binaries size.
The devkit already ships libstdc++ and libgcc anyway: its own
clang/LoreTLC link them dynamically, and we bundle them so the toolchain
even starts. So bundling libstdc++ for the thunk flow adds no new
dependency, it just reuses one the devkit must carry. Static-linking the
thunks wouldn't make the devkit any smaller or more self-contained
either, since clang still needs the dynamic libstdc++; we'd only be
adding static copies on top of it.
On the ABI risk itself: libstdc++ keeps a backward-compatible ABI, and
the copy we bundle is recent, so a thunked host library only breaks if
it was built against a strictly newer libstdc++ and references a new
symbol. Even then it needs no new devkit, because the resolution order
is the integrator's to choose. On a host newer than our bundle, putting
the system libstdc++ ahead of the devkit's on LD_LIBRARY_PATH lets the
host library bind the newest one, while clang and the Lorelei runtime
keep working against it by backward compatibility. So a gcc update on
the host doesn't force us to reship.
There's also an active reason not to static-link. Both the Lorelei
runtime and the generated thunk libraries depend on libstdc++. If we
statically link libstdc++ into a thunk while the host library it
dispatches to links the system libstdc++ dynamically, the process ends
up with two libstdc++ copies on the host side, right across the boundary
where C++ objects and exceptions pass between the thunk and the real
library. That can break:
- Exceptions: one thrown in the host library may not be caught in the
thunk. The two copies have different std::type_info for the same type,
so the match fails and it hits std::terminate.
- dynamic_cast / typeid across the boundary: they assume a single
type_info per type, so they can start returning null or misidentifying
types.
- Duplicated global state: two sets of the iostream objects, the
locale/facets, and the exception emergency buffer.
Based on the above reasons, I prefer to do that than statically link and
grow the big artifact. Does that hold for you?
Thanks,
Ziyang Zhang