Constantine
Constantine

Reputation: 2032

Rust can't link bindings to C library

I followed the rust-bindgen tutorial to make bindings for the scrypt C library. I can't run my test because of linking error:

/home/user/project/rust-scrypt/src/lib.rs:32: undefined reference to `crypto_scrypt'
      collect2: error: ld returned 1 exit status

and my test:

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
// ...
// ...
#[test]
fn test_script() {
  let mut kdf_salt = to_bytes("fd4acb81182a2c8fa959d180967b374277f2ccf2f7f401cb08d042cc785464b4");
    let passwd = "1234567890";
    let mut buf = [0u8; 32];

    unsafe {
        crypto_scrypt(passwd.as_ptr(), passwd.len(), kdf_salt.as_mut_ptr(), kdf_salt.len(),
                      2, 8, 1, buf.as_mut_ptr(), 32);
    }

    println!(">> DEBUG: {:?}", buf);
    // "52a5dacfcf80e5111d2c7fbed177113a1b48a882b066a017f2c856086680fac7");
}

The bindings have been generated and exist in bindings.rs. I don't know why the linker throws an error.

Here is my builds.rs

extern crate bindgen;

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

fn main() {
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let bindings = bindgen::Builder::default()
        .no_unstable_rust()
        .header("wrapper.h")
        .generate()
        .expect("Unable to generate bindings");

    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

And my Cargo.toml

[package]
name = "rust-scrypt"
version = "0.0.1"
build = "build.rs"

[build-dependencies]
bindgen = "0.23"

Upvotes: 3

Views: 3507

Answers (1)

Shepmaster
Shepmaster

Reputation: 430711

Please re-familiarize yourself with the "Building some native code" case study. Specifically, you have informed Rust what the interface of the library is, but you haven't told the compiler where the code is. That's what the error you are getting says: "I can't find the implementation of crypto_scrypt"

You need to add the library to the linker path and instruct it to be linked against.

From the linked case study, your build script can inform the compiler where the library is and what to link against:

println!("cargo:rustc-link-search=native={}", path_to_library);
println!("cargo:rustc-link-lib=static=hello"); // the name of the library

Please, please, please read the section about *-sys packages which documents the best practices for this type of integration. Namely, your Cargo.toml is missing the links key, which is going to cause problems if anyone ever tries to link in this library multiple times.

--

Note that there are already crates that purport to provide scrypt.

Upvotes: 7

Related Questions