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?
rustc invokes the system linker which looks for all libraries specified in #[link(...)] in library directories. There are usually several default library directories (like /lib and /usr/lib on Linux), and more can be specified via linker flags ( rustc accepts -L options which it then passes through to the linker).
Rust has supported producing statically linked binaries since RFC #1721 which proposed the target-feature=+crt-static flag to statically link the platform C library into the final binary.
To be extra clear about this, Rust does support dynamic linking; it's just limited to interfacing via the stable C ABI. The ABI-resilience conerns described in the article are ultimately punted to the users and/or the dev ecosystem, albeit some facilities (namely, bindgen/cbindgen) are also provided to ease the task.
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.
That, and the fact that the C ABI can't represent all of Rust's language constructs, is why static is the default. The ABI should only be an issue across different rustc versions. But it should be possible to compile a dynamic library and link it dynamically to another program using the exact same rustc.
Rust library crates expose generics and those can only be optimized at link time (static linking required) or at run time (JIT compiler required). Rust's LTO is already really good.
If/When Rust supports dynamic linking there will still be a tradeoff between dynamism and link-time optimization. Many (most?) Rust library crates expose generics and those can only be optimized at link time (static linking required) or at run time (JIT compiler required).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With