33

I do not know how to link a C library to Rust. Here's what I have done:

My lib.rs file contains

#[link(name = "test")]
extern {

The library is built and has the name libtest.a.

I do not know where to put it. I have tried several places, but I still have errors of this type when doing cargo run

error: linking with `cc` failed: exit code: 1
//..
note: /usr/bin/ld: no se puede encontrar -ltest
note: /usr/bin/ld: no se puede encontrar -ltest
note: /usr/bin/ld:.......
//..

Translation of the above /usr/bin/ld: no se puede encontrar -ltest -> usr/bin/ld: cannot find -ltest

I do not know where to put libtest.a so that /usr/bin/ld can find it. Cargo does not tell me where the library should be in the project.

My Cargo.toml contains

[dependencies.test]
path = "./src/test"

[dependencies]
bitflags = "0.7"
libc = "0.2"

[build-dependencies]
make-cmd = "0.1"

After reading the FFI section of the documentation again, I thought that maybe the error messages from before were because I was looking for a shared library, so I made the following changes:

#[link(name = "test", kind = "static")]

After these changes, I still do not know how to indicate where the library is, but the message now tells me this:

error: could not find native static library `test`, perhaps an -L flag is missing?
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Angel Angel
  • 19,670
  • 29
  • 79
  • 105

3 Answers3

33

Where should I place a static library

Wherever you want. You have to tell the compiler where to find it.


First, let's create a static library

$ cat hello.c
int square(int value) {
  return value * value;
}
$ gcc -c -o hello.o hello.c
$ ar rcs libhello.a hello.o

Next, we use a build script to set the value of rustc-link-search to point to the directory where I put the library:

fn main() {
    println!("cargo:rustc-link-search=/Projects/stack-overflow/using-c-static/");
}

We can now use the functions from the library:

#[link(name = "hello")]
extern "C" {
    fn square(val: i32) -> i32;
}

fn main() {
    let r = unsafe { square(3) };
    println!("3 squared is {}", r);
}

That's the basic functionality. You could also use the build script to specify which library to link, instead of having it in your code (rustc-link-lib). I prefer this because then the two configurations are right next to each other.

You should also probably follow the *-sys naming convention and create a crate dedicated to exposing the underlying API. Importantly, this crate should specify the link manifest key to avoid duplicate symbols at linking time.

If your build script needs more information, cargo passes many parameters via environment variables.

If you are compiling C code as part of your crate, you should look into crates like cc or cmake, which make the act of building a piece of software much easier.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I found two solutions, now I am going to read your response thanks for your time – Angel Angel May 07 '17 at 05:02
  • I see that in your answer there are some links, which I visit to find the solution I publish, I learned a lot but maybe it took me a long time to find it, bad luck not to have seen your answer before. Out of curiosity from the **build.rs** you can create the libraries thing I did not know, simple example `gcc::Config::new().file("src/hello.c").include("src").compile("libhello.a");` thanks again. – Angel Angel May 07 '17 at 05:19
  • I was using `#[link(name = "test", kind = "static")]` But after reading your question i use`#[link(name = "test")]` And I see that it works too, I thought it was mandatory for static put`kind = "static"` – Angel Angel May 07 '17 at 05:27
9

I just found a solution (two) but I do not know if it's the best way:

1- way

build.rs file

extern crate gcc;

fn main() {

    println!("cargo:rustc-link-search=native=/home/path/to/rust/proyect/folder/contain/file.a");
    println!("cargo:rustc-link-lib=static=test");
}

Cargo.toml

//..
build = "build.rs"
//..

2- way

Cargo.toml

//..
rustc-link-search = ["./src/lib"]
rustc-link-lib = ["test"]
root = "/home/path/to/rust/proyect/"
//..

["./src/lib"] -> place to lib.a refence to root

Angel Angel
  • 19,670
  • 29
  • 79
  • 105
0

If you don't want to specify the path to the library, and you are on Linux, you can just place it in "usr/local/lib" and say its name in main.rs like this :

#[link(name = "theLibraryname", kind = "")]

Also, you can place any header files in the include folder.

Note: The library name is without the lib prefix and .a extension.

E_net4
  • 27,810
  • 13
  • 101
  • 139
taste01
  • 35
  • 1
  • 6