You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Symbols from static libraries used by dependent crates are no longer included into cdylib #96192
# make a static library containing `symbol`
gcc lib.c -o lib.o -c
ar rc liblib.a lib.o
# compile an rlib that uses `symbol`
rustc dep.rs --crate-type rlib
# compile a cdylib that uses the rlib, and attempt to link the static library
rustc test.rs --crate-type cdylib -Lnative=. -lstatic=lib --extern dep=libdep.rlib
Previously, this worked and linked symbol into the resulting cdylib:
# nm libtest.so | grep -w symbol
00000000000066b5 t symbol
However, it now results in an unresolved symbol:
# nm libtest.so | grep -w symbol
U symbol
Which seems wrong, since we asked to link liblib.a into libtest.so. The issue also doesn't occur if the static library is used directly from the cdylib crate.
Bisection reveals that the regression occurred in #95501, which is a rollup; the most likely culprit appears to be #93901.
It becomes clearer what happens if you build test.rs as an executable.
rustc test.rs --crate-type bin -Lnative=. -lstatic=lib --extern dep=libdep.rlib
= note: /usr/bin/ld: /home/we/linkrepr/libdep.rlib(dep.dep.468be17b-cgu.0.rcgu.o): in function `dep::inner':
dep.468be17b-cgu.0:(.text._ZN3dep5inner17h014ce670d35af615E+0x3): undefined reference to `symbol'
The build will just fail, while with cdylibs remaining unresolved symbols are ok by default.
rustc sorts libraries (both rlibs and native libraries) in topological order, so dependency libraries come after libraries that depend on them.
In your build nothing says that dep.rs (libdep.rlib) depends on lib.c (liblib.a), so rustc puts liblib before libdep on the command line (besides the topological sorting the order may be considered random).
So liblib is simply dropped by the linker when it's encountered, because it doesn't provide any necessary symbols at that point.
What saved the build before #93901 is that rustc linked liblib as whole-archive in that particular case, so it wasn't dropped even if it wasn't needed.
After #93901 we try not to use whole-archive unless explicitly requested, so this case is broken.
The right fix here is to specify that dep.rs depends on lib.c, by using #[link(name = "lib")] or -l lib when compiling dep.rs.
Thanks for the detailed response! That makes sense, and the solution seems reasonable. I'm fine with saying that this is not a bug then.
For what it's worth this happened because we're using Bazel and rules_rust, wherein adding native dependencies to a Rust target causes them to be added only to the final crate's command line, not intermediate ones. So it's possible that other people will hit this too. But that's a rules_rust issue, not really a rustc one.
Activity
goffrie commentedon Apr 18, 2022
I had hoped that #95604 would fix this since it seems very related, but I downloaded the try build and it does not appear to.
petrochenkov commentedon Apr 19, 2022
It becomes clearer what happens if you build test.rs as an executable.
The build will just fail, while with cdylibs remaining unresolved symbols are ok by default.
rustcsorts libraries (both rlibs and native libraries) in topological order, so dependency libraries come after libraries that depend on them.In your build nothing says that dep.rs (libdep.rlib) depends on lib.c (liblib.a), so rustc puts liblib before libdep on the command line (besides the topological sorting the order may be considered random).
So liblib is simply dropped by the linker when it's encountered, because it doesn't provide any necessary symbols at that point.
What saved the build before #93901 is that rustc linked liblib as whole-archive in that particular case, so it wasn't dropped even if it wasn't needed.
After #93901 we try not to use whole-archive unless explicitly requested, so this case is broken.
The right fix here is to specify that dep.rs depends on lib.c, by using
#[link(name = "lib")]or-l libwhen compiling dep.rs.goffrie commentedon Apr 20, 2022
Thanks for the detailed response! That makes sense, and the solution seems reasonable. I'm fine with saying that this is not a bug then.
For what it's worth this happened because we're using Bazel and
rules_rust, wherein adding native dependencies to a Rust target causes them to be added only to the final crate's command line, not intermediate ones. So it's possible that other people will hit this too. But that's arules_rustissue, not really a rustc one.