Hi, I have a C native library linking issue for Rust. Let's say I have the following setup in a Linux system:
- A native C library (Lib A) which uses a custom build system
- A Rust wrapper (FFI) library (Lib B) to exports the functions of the above C library, a build.rs script is there to find the Lib A and link to Lib A statically
- A Rust library (Lib C) to use the Lib B and other libs for its work
- A binary (Bin D) which use Lib C to do its work
When I build the Bin D, I got the Undefined Reference error. The undefined references are just the functions in Lib A.
My question is, why the symbols that Bin D use are not linked to Lib B statically? I expect Lib B has all the required symbols and code, so all dependencies (Lib C and Bin D) can just use Lib B to work. What's the solution for this problem?
What does your build.rs
script for Lib B look like?
That's common expectation but that's not how static libraries work on POSIX platforms. If you use library B and it depends on library A then you have to specify -lB -lA
(in that order) in the command-line of the linker.
You may find approximately bazillion partial solutions on stackoverflow. Typical solution is to use pkgconfig or libtool but there are lots of other half-solutions.
But they are just the different ways to satisfy the basic requirement outlined above.
That issue is the reason C libraries often vendor in third-party code instead of using external libraries.
It looks like the following, but uses a special method to find path of Lib A.
println!("cargo:rustc-link-lib=static=A");
println!("cargo:rustc-link-search={Lib A path}");
Lib A is the only native library, Lib B and Lib C are rust libraries, so seems it's not "-lB -lA" problem.
Are you using an absolute or relative path for {Lib A path}
? I can't reproduce the issue if I use an absolute path.
I'm using absolute path for Lib A. The problem seems the Lib A is not linked to Lib B. I see there is a note for linking in Using C libraries in Rust: make a sys crate (kornel.ski), seems the static linking works in a very weird way.
The extern crate
is implied by Lib C using any symbols from Lib B, and from Bin D using any symbols from Lib C.
It's odd that it isn't linking, though. What's the full output that you get from cargo build -v
following a full cargo clean
, including the rustc
invocations?
Seems the problem is the system setup. When building Bin D, the path for Lib A is inaccessible somehow. I have to embed the Lib A into the Lib B, so it can always be found. The problem solved.
This raises another question. Is it possible to let a crate (Bin D) to use the compiled form (rlib, etc.) of its dependency (Lib B), so the crate (Bin D) won't need the original native library (Lib A) during linking?
I can't give you a conclusive answer, because I still have no clue what your setup looks like. But you might want to look into the --extern
flag, which allows you to add additional rlibs to the compilation that you can import with extern crate B;
. Note that if you're using static linking, then the object files from Lib A should be copied into the rlib in Lib B.