How cxpm is linked
cxpm installs software into sysroots and is itself meant to be dropped into one, so it cannot
lean on whatever C++ runtime the host happens to have. This page records what is linked
statically, what is not, and why.
The decision
| Binary | Linkage | Why |
|---|---|---|
cxpm |
libstdc++ and libgcc static, glibc dynamic | Runs on any machine with a compatible glibc, with no C++ runtime installed |
cxpm-descriptor-sandbox |
Fully dynamic, always | It dlopens plugins that were built against the shared libstdc++ |
Static C++ runtime, dynamic glibc
applications/cxpm/package.cpp passes -static-libstdc++ -static-libgcc as raw options. The
result depends on glibc only:
$ ldd applications/cxpm/.cxpm/build/cxpm/cxpm
linux-vdso.so.1
libm.so.6 => /usr/lib/libm.so.6
libc.so.6 => /usr/lib/libc.so.6
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2
It removes the dependency that actually breaks in practice, a libstdc++.so.6 older than the
compiler that built cxpm, and keeps glibc dynamic, which is what glibc itself is designed for.
Those two flags are the one place where cxpm’s own manifest is tied to GCC and Clang: there is no neutral option for them yet.
Changing it
The linkage is part of the manifest, so changing it is an edit to
applications/cxpm/package.cpp:
- Shared runtime, for a distribution whose policy forbids static copies of libstdc++: remove the two flags.
- Fully static: replace them with
-static. This is not the default because a statically linked glibc still loadslibnss_*modules withdlopento resolve host and user names, and those must match the glibc the binary was linked with;fetchand the package index client resolve host names. A fully static cxpm belongs with a libc designed for it, such as musl.
What makes a fully static build possible at all is that cxpm never calls dlopen: every
compiled package.cpp/toolchain.cpp is loaded by the sandbox helper.
The sandbox helper stays dynamic
cxpm-descriptor-sandbox is the process that loads a compiled manifest or toolchain plugin. Those
plugins are ordinary shared objects, compiled by the host C++ compiler against the shared
libstdc++. If the helper carried its own static copy of the runtime, the process would hold two
C++ runtimes at once (two allocators, two sets of std::string internals, two unwinders) and
passing a descriptor across the plugin boundary would be undefined behaviour. So the helper is
linked dynamically and uses the same libstdc++ the plugins do.
Checking it
ldd applications/cxpm/.cxpm/build/cxpm/cxpm # no libstdc++.so, no libgcc_s.so
ldd applications/cxpm-descriptor-sandbox/.cxpm/build/cxpm-descriptor-sandbox/cxpm-descriptor-sandbox
# libstdc++.so.6 present, on purpose
CI makes the first check on the installed binary.