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


Reply via email to