crustlinkerlinker-errorsffi

Why the linker cannot find my local C shared library for use with FFI in Rust?


I am trying to wrap a quite large C library in Rust. I used bindgen to generate the bindings. Rust seems content with those. However, despite my different attempts and my many reads of the build-script docs, I keep on getting linking issues.

The library I'm using has a set of csh script which end up building two .a files: cspice.a and csupport.a. They are both stored in the cspice_linux_gcc_64bit/lib of my project (cf. the tree at bottom). I currently test the proper binding by calling constants and functions from my tests, cf. lib.rs (on my Github).

Here is my error:

Running `rustc --crate-name spice src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=94c06ffe4bfd7d5f -C extra-filename=-94c06ffe4bfd7d5f --out-dir /home/chris/Workspace/rust/SPICE/target/debug/deps -L dependency=/home/chris/Workspace/rust/SPICE/target/debug/deps -L native=cspice_linux_gcc_64bit/lib -l static=cspice`

error: could not find native static library `cspice`, perhaps an -L flag is missing?

error: Could not compile `spice`.

Caused by:
  process didn't exit successfully: `rustc --crate-name spice src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=94c06ffe4bfd7d5f -C extra-filename=-94c06ffe4bfd7d5f --out-dir /home/chris/Workspace/rust/SPICE/target/debug/deps -L dependency=/home/chris/Workspace/rust/SPICE/target/debug/deps -L native=cspice_linux_gcc_64bit/lib -l static=cspice` (exit code: 101)
Build failed, waiting for other jobs to finish...
error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/chris/Workspace/rust/SPICE/target/debug/deps/spice-e22b64d176595306.0.o" "-o" "/home/chris/Workspace/rust/SPICE/target/debug/deps/spice-e22b64d176595306" "-Wl,--gc-sections" "-pie" "-nodefaultlibs" "-L" "/home/chris/Workspace/rust/SPICE/target/debug/deps" "-L" "cspice_linux_gcc_64bit/lib" "-L" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,--whole-archive" "-l" "cspice" "-Wl,--no-whole-archive" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libtest-163c20e386ec0612.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgetopts-bd312ea730ea22d0.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libterm-4959b4e709084e0a.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-35ad9950c7e5074b.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-fb44afc024bbc636.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-14b8f3202acdad6a.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librand-20a50a22d4c2b1e9.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcollections-b479831207997444.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-10b591f1a68dd370.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc_jemalloc-28913dc5a1e63cd7.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-6ecacccb5bdc4911.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_unicode-f4f0ae88f5ad8ad4.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-bfaa82017ca17cb2.rlib" "/home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-863b57a66ba6c3e1.rlib" "-Wl,-Bdynamic" "-l" "dl" "-l" "rt" "-l" "pthread" "-l" "gcc_s" "-l" "pthread" "-l" "c" "-l" "m" "-l" "rt" "-l" "pthread" "-l" "util"
  = note: /usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: cannot find -lcspice
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error(s)

error: Could not compile `spice`.

Caused by:
  process didn't exit successfully: `rustc --crate-name spice src/lib.rs --emit=dep-info,link -C debuginfo=2 --test -C metadata=e22b64d176595306 -C extra-filename=-e22b64d176595306 --out-dir /home/chris/Workspace/rust/SPICE/target/debug/deps -L dependency=/home/chris/Workspace/rust/SPICE/target/debug/deps -L native=cspice_linux_gcc_64bit/lib -l static=cspice` (exit code: 101)

I highly suspect that something is wrong with my build.rs or, less likely, my Cargo.toml.

# Cargo.toml
[package]
# ...
links = "cspice"
build = "build.rs"

[build-dependencies]
bindgen = "0.26.3"

# ...
// build.rs
extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    // Tell cargo to tell rustc to link the system bzip2
    // shared library.
    println!("cargo:rustc-link-search=native=cspice_linux_gcc_64bit/lib");
    println!("cargo:rustc-link-lib=static=cspice");
    //println!("cargo:rustc-flags=-L cspice_linux_gcc_64bit/lib");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("spice_wrapper.h")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");


    let out_path = PathBuf::from(out_dir.clone());
    // Write the bindings to the $OUT_DIR/bindings.rs file.
    bindings
        .write_to_file(out_path.join("spice_bindings.rs"))
        .expect("Couldn't write bindings!");
}

Solution

  • building two .a files: cspice.a and csupport.a

    On Linux, static libraries are generally called libfoo.a, but your library doesn't have the lib prefix.

    Renaming the file to libcspice.a should allow it to compile. I'm not sure if you'd want to modify your build script or the libraries build script to perform the renaming. It's even possible that the library itself has a compilation switch to use a platform-standard naming scheme.