Linking a `.so` shared library into a static binary

I've been trying to set up a rust program along with a *-sys crate to build a shared library libfoo.so (downloaded from elsewhere) into a static binary which does not depend on that library being in the LD_LIBRARY_PATH. I have a build.rs file that does roughly this:

fn main() {
    println!("cargo:rustc-link-search=/path/to/foo/lib");
    println!("cargo:rustc-link-lib=foo");
}

where /path/to/foo/lib/libfoo.so is present. The rest of the foo-sys crate uses extern blocks etc to import the symbols from the library. This crate is used by the test executable crate which just depends on foo-sys.

When set up as described, it builds successfully, but the resulting executable does not run unless I also use LD_LIBRARY_PATH=/path/to/foo/lib, and this is not good because the library will only be available at build time. I would like to statically link to the shared library.

I read some things that suggested that I should instead use

    println!("cargo:rustc-link-search=/path/to/foo/lib");
    println!("cargo:rustc-link-lib=static=foo");

but this fails at build time with could not find native static library `foo`, perhaps an -L flag is missing?. It's also a bit weird to put this in the foo-sys crate since the decision to statically link seems like something for the executable to decide. I also have a line

    println!("cargo:rustc-link-arg=-Wl,-rpath,/path/to/foo/lib");

which I'm not sure whether to use or not.

A shared library doesn't contain any of its dependencies and expects the loader to resolve them on startup. That means it's not possible to take a shared library and statically link it into your crate because you don't have all the information you need.

This answer on StackOverflow explains it better than I could:

I was actually basing this off of a C build script that does seem to do the right thing, but after looking at it more carefully I see now that it is linking some other libraries (.a files in the same directory) instead of the shared library, and linking with those works as intended.

1 Like

Note that rustc has the --print native-static-libs option to print all dynamic libraries necessary to link the produced staticlib (which includes those passed by cargo when using cargo:rustc-link-lib). You have to pass this argument when compiling the staticlib and then rustc will print a bunch of arguments you need to pass to the linker.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.