Integration tests fail when running make test:all. I add RUSTFLAGS="-C link-arg=-Wl,--allow-multiple-definition" to make/test.mk to work around duplicate symbol errors from libkrun.a(refer #437), but this flag silently breaks the inventory crate's compile-time registration mechanism.
Root Cause
Why --allow-multiple-definition is needed
libkrun.a is built from Rust source via cargo rustc --crate-type staticlib (see src/deps/libkrun-sys/build.rs). It embeds its own copy of the Rust standard library, compiled with a different toolchain version. When the test binary links against both the current libstd and the one inside libkrun.a, the linker reports hundreds of duplicate symbols:
duplicate symbol: std::sys::args::unix::imp::ARGV_INIT_ARRAY
duplicate symbol: std::panicking::EMPTY_PANIC
...
Without --allow-multiple-definition, linking fails entirely.
Why --allow-multiple-definition breaks inventory
The inventory crate (v0.3) works by placing submit! entries into a custom ELF linker section. The linker merges all such sections across compilation units and exposes section bounds via __start_<section> / __stop_<section> symbols. inventory::iter! uses these symbols to traverse collected entries at runtime.
When --allow-multiple-definition is active, the linker silently picks one definition when it encounters duplicates. Since libkrun.a also contains Rust stdlib artifacts (which may carry section data that interferes with inventory's markers), the __start_section / __stop_section bounds end up pointing to an empty range. As a result, inventory::iter::<EngineFactoryRegistration>() returns an empty iterator.
Failure chain
make test:all
→ test:integration:rust
→ cargo test -p boxlite --features krun,gvproxy --test '*'
→ links libkrun.a (krun feature enabled)
→ --allow-multiple-definition suppresses duplicate symbol errors
→ inventory section markers resolve to empty range
→ inventory::iter returns nothing
→ "Engine Libkrun is not registered. Available engines: []"
→ shim process fails to start → all integration tests fail
Affected tests (11 total)
boxlite::detach::detached_box_recoverable_after_restart
boxlite::execution_shutdown::test_concurrent_exec_workdir
boxlite::jailer::jailer_creates_isolated_mount_namespace
boxlite::jailer::jailer_enabled_box_starts_and_executes
boxlite::pid_file::is_same_process_validates_boxlite_shim
boxlite::pid_file::pid_file_contains_correct_pid
boxlite::recovery::recovery_with_live_process
boxlite::zygote_integration::test_zygote_concurrent_mixed_durations
boxlite::zygote_integration::test_zygote_concurrent_stdin_pipes
boxlite::zygote_integration::test_zygote_high_concurrency_16
boxlite::zygote_integration::test_zygote_repeated_bursts
Relevant files
make/test.mk — where RUSTFLAGS is set
src/boxlite/src/vmm/registry.rs — inventory::collect! and inventory::iter! usage
src/boxlite/src/vmm/krun/factory.rs — inventory::submit! for Libkrun engine
src/boxlite/Cargo.toml:69 — inventory = "0.3" dependency
src/deps/libkrun-sys/build.rs — builds libkrun.a from Rust source
Possible solutions
| Approach |
Description |
Trade-off |
Replace inventory with direct match |
Dispatch on VmmKind via match arms with #[cfg(feature = "krun")] guards. Remove inventory dependency entirely. |
Simplest and most robust. No linker tricks needed. 3 files changed, 1 dependency removed. |
| Targeted duplicate symbol handling |
Use linker version scripts or --undefined-version to allow only std::* duplicates while preserving inventory section markers. |
More precise but fragile; hard to guarantee inventory symbols are unaffected. |
Patch inventory crate |
Mark section marker symbols with __attribute__((used)) to prevent the linker from discarding them. |
Requires forking inventory; may not fully resolve the conflict. |
Integration tests fail when running
make test:all. I addRUSTFLAGS="-C link-arg=-Wl,--allow-multiple-definition"tomake/test.mkto work around duplicate symbol errors fromlibkrun.a(refer #437), but this flag silently breaks theinventorycrate's compile-time registration mechanism.Root Cause
Why
--allow-multiple-definitionis neededlibkrun.ais built from Rust source viacargo rustc --crate-type staticlib(seesrc/deps/libkrun-sys/build.rs). It embeds its own copy of the Rust standard library, compiled with a different toolchain version. When the test binary links against both the currentlibstdand the one insidelibkrun.a, the linker reports hundreds of duplicate symbols:duplicate symbol: std::sys::args::unix::imp::ARGV_INIT_ARRAY
duplicate symbol: std::panicking::EMPTY_PANIC
...
Without
--allow-multiple-definition, linking fails entirely.Why
--allow-multiple-definitionbreaksinventoryThe
inventorycrate (v0.3) works by placingsubmit!entries into a custom ELF linker section. The linker merges all such sections across compilation units and exposes section bounds via__start_<section>/__stop_<section>symbols.inventory::iter!uses these symbols to traverse collected entries at runtime.When
--allow-multiple-definitionis active, the linker silently picks one definition when it encounters duplicates. Sincelibkrun.aalso contains Rust stdlib artifacts (which may carry section data that interferes with inventory's markers), the__start_section/__stop_sectionbounds end up pointing to an empty range. As a result,inventory::iter::<EngineFactoryRegistration>()returns an empty iterator.Failure chain
make test:all
→ test:integration:rust
→ cargo test -p boxlite --features krun,gvproxy --test '*'
→ links libkrun.a (krun feature enabled)
→ --allow-multiple-definition suppresses duplicate symbol errors
→ inventory section markers resolve to empty range
→ inventory::iter returns nothing
→ "Engine Libkrun is not registered. Available engines: []"
→ shim process fails to start → all integration tests fail
Affected tests (11 total)
boxlite::detach::detached_box_recoverable_after_restartboxlite::execution_shutdown::test_concurrent_exec_workdirboxlite::jailer::jailer_creates_isolated_mount_namespaceboxlite::jailer::jailer_enabled_box_starts_and_executesboxlite::pid_file::is_same_process_validates_boxlite_shimboxlite::pid_file::pid_file_contains_correct_pidboxlite::recovery::recovery_with_live_processboxlite::zygote_integration::test_zygote_concurrent_mixed_durationsboxlite::zygote_integration::test_zygote_concurrent_stdin_pipesboxlite::zygote_integration::test_zygote_high_concurrency_16boxlite::zygote_integration::test_zygote_repeated_burstsRelevant files
make/test.mk— whereRUSTFLAGSis setsrc/boxlite/src/vmm/registry.rs—inventory::collect!andinventory::iter!usagesrc/boxlite/src/vmm/krun/factory.rs—inventory::submit!for Libkrun enginesrc/boxlite/Cargo.toml:69—inventory = "0.3"dependencysrc/deps/libkrun-sys/build.rs— buildslibkrun.afrom Rust sourcePossible solutions
inventorywith directmatchVmmKindviamatcharms with#[cfg(feature = "krun")]guards. Removeinventorydependency entirely.--undefined-versionto allow onlystd::*duplicates while preserving inventory section markers.inventorycrate__attribute__((used))to prevent the linker from discarding them.