InsightSoftwareConsortium / InsightSoftwareConsortium/ITK
Vendored libraries share a SONAME, so two ITK builds cross-bind on Linux
- Dominant language
- C++
- Stars
- 1.7k
- Forks
- 748
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 64
Description
On Linux, two independently built ITKs loaded into one process share their vendored libraries, because those libraries live outside `namespace itk` and both builds ship them with **identical SONAMEs**. The dynamic linker keeps one copy, so one ITK's `ITKCommon` binds into the other ITK's VNL.
This is pre-existing and independent of any namespace mechanism, but it is a blocker for the goal in #6786 ("several independently distributed ITK builds coexisting in one process"), so it needs tracking on its own.
Measurement
Two `BUILD_SHARED_LIBS=ON` ITK trees built from the same source, differing only in an inline ABI namespace applied to `namespace itk` (the #6786 mechanism). Both loaded into one process; `LD_DEBUG=bindings` trace inspected.
Ubuntu 24.04, GCC 13.3.0, glibc 2.39, x86_64.
Total cross-library bindings between the two trees: 138, over 80 distinct symbols. **None are `itk::` symbols** — the C++ surface is cleanly separated. The breakdown:
| Caller → definer | count | why |
|---|---|---|
| build B `libITKCommon` → build A `libitksys` | 37 | outside `namespace itk`, same SONAME |
| build B `libITKCommon` → build A `libitkvnl` | 18 | outside `namespace itk`, same SONAME |
| build B `libITKCommon` → build A `libitkdouble-conversion` | 2 | outside `namespace itk`, same SONAME |
| build B `libITKCommon` → build A `libITKCommon` | 3 | header-only third-party statics, see below |
Example bindings: `vnl_vector::set_size`, `vnl_vector::~vnl_vector`, and 37 KWSys entry points resolving from the wrong build.
Both trees emit `libitkvnl-6.0.so.1`, `libitksys-6.0.so.1`, etc. Under glibc's flat symbol namespace the first-loaded definition wins for every subsequent reference.
Why macOS does not show this
macOS uses a two-level namespace: each Mach-O records the defining library for every imported symbol, so build B's `ITKCommon` binds to its own VNL by construction regardless of names. The same two builds on macOS show only 3 cross-bindings, all header-only statics.
So this is genuinely Linux-specific in its *observable* form, though the underlying ambiguity (two libraries, same name, same symbols) exists on any platform that resolves by name alone.
The residual three, which a SONAME change would not fix
Present identically on both platforms:
```
Eigen::internal::manage_caching_sizes(Eigen::internal::Action, long*, long*, long*)::m_cacheSizes
std::_Sp_make_shared_tag::_S_ti()::__tag
```
These are **header-only** function-local statics instantiated into both `libITKCommon` objects. No library-naming scheme reaches them, because the symbol is `Eigen::internal::…` / `std::…` rather than anything ITK controls. Two ITKs would share one Eigen CPU-cache-size cache — harmless in this instance, since it caches immutable hardware properties, but the pattern is worth knowing about: any header-only third-party code vendored outside `itk::` stays shared.
## Possible directions
Not a recommendation, just the options as they appear:
1. **Suffix the vendored library names** when a distinguishing build option is set — the approach VTK takes for its third-party libraries. Fits naturally with `ITK_ABI_NAMESPACE_NAME` if that lands from #6786, but is independently meaningful.
2. **Version the SONAMEs** by something other than the ITK version, so two same-version builds differ.
3. **Link the vendored libraries statically** into the ITK modules that use them, so nothing is exported to collide over.
4. **Accept it and document the limit** — two ITKs share vendored code, and that is safe for stateless libraries but not for any with mutable global state.
Option 4 needs an audit to be defensible: KWSys and VNL are not obviously free of process-global state, and sharing them across two ITKs with different build configurations is a stronger assumption than sharing Eigen's cache-size table.
Contributor guide
Research direction
Start with the two BUILD_SHARED_LIBS=ON builds described in the measurement and reproduce their Linux bindings using LD_DEBUG=bindings. Compare vendored-library name suffixing, SONAME versioning, static linking, and documentation as possible directions, then audit KWSys and VNL for process-global state. Done requires a selected, defensible approach that prevents unsafe cross-binding or documents the verified limit.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cmake, cpp, linux
- Domain
- build-system, operating-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100