Bizarre linker issue with `cargo test` vs. binary crate


TLDR: Weird linking error that only shows up with cargo test – not when using library as a dependency in a binary crate.

Longer: I have a *-sys crate that I’m using in a pure Rust crate to provide a safe FFI wrapper. The *-sys crate gets statically linked a lib_.a file. I have some simple tests written in the library crate that I’d like to run. Linking fails when running cargo test with this error:

... relocation R_X86_64_32S against '.data' can not be used when making a shared object; recompile with -fPIC
... error adding symbols: Bad value
collect2: error: ld returned 1 exit status

However, if I include the pure Rust wrapper crate as a dependency in a binary crate, everything builds OK. I can also run cargo test from the binary crate without any linker errors.

At @mbrubeck’s suggestion on IRC, I looked into the linker args (cargo rustc -- -Z print-link-args), and they appear to be functionally identical expect for the rlibs that are pulled in (and the original source file, of course).

Does anyone have any idea what I can do to get this linking correctly with cargo test? I’d eventually like to publish this to but I don’t want to do that if someone can’t clone it down and run the tests without embedding it in a binary crate.


Is the binary crate that is compiling using the code in the underlying archive? If not, i’ll all get stripped out by the linker and you probably wouldn’t run into relocation issues.


Oh, you’re right! I had thought that including an extern crate would be enough to do it, but now after using some code in the binary crate, I’m getting the same linker error.

So maybe this problem is less bizarre than I thought, but it’s still opaque to someone without much experience troubleshooting linking (esp. with static archives). Do you know what I can do to fix this? Do I need to modify the compilation of the C code (like with the -fPIC option ld suggests)? Is this a problem with my buildscript for the sys crate?


The error means that some object file (.o) being linked was not compiled with the right options (and therefore has an inappropriate type of relocation). In this case, the culprit is presumably the C object files inside your .a, so you need to add -fPIC to the C compiler options.


If the C library uses a configure script to set up its build, the --with-pic option is usually the thing you’ll want.


Thanks so much to both of you for the help and clarification. The project has cmake, so I ended up using the cmake crate with:

Config::new("libfoo").define("CMAKE_POSITION_INDEPENDENT_CODE", "TRUE").build();

Everything now appears to be working. Thanks again!