How do I use a rlib/dylib?

Say I created a static library libfoo.a using crate-type = ["staticlib"]. How would I use this in another rust project (aka rustc bar.rs --extern foo=libfoo.a)?

(I tried setting crate-type = ["rlib"] and using it like specified here, but I get (libloading is a dependency of foo)
error[E0463]: can't find crate for `libloading` which `foo` depends on)

  1. If you build a classic static library, you'll have to use it via C API, i.e. it will declare some #[no_mangle] extern "C" functions, and user will refer to them via extern "C" block, too. The library itself might be linked either with -l command line argument or with #[link] attribute on the block.
  2. If you just want to use one library as dependency of another, it'd probably be better to just let cargo do it job, without the hassle with static libraries.
1 Like

My use case is as follows -

  1. Crate foo implements several structs, traits and functions. I wish to compile this down to a single file (like the .so file generated in C++). Note that this crate contains several dependencies managed by cargo.
  2. Crate bar then links to this file (rustc bar.rs -L libfoo.xyz).

The problem here is that libfoo.rlib/libfoo.so doesn't include the dependencies of crate foo, and thus I get: error[E0463]: can't find crate for `libloading` which `foo` depends on.

One way around this is rustc bar.rs -L /path/to/foo/target/release/deps -L libfoo.xyz which compiles bar successfully.
Is it possible to archive the required dependencies into a single file?

*.so would contain all the dependencies necessary. How are you using it from bar?

Minimal reproducible example:

// Cargo.toml
[package]
name = "testing"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["dylib"]

[dependencies]
rand = "0.8.5"
// src/lib.rs
pub fn print_rand() {
    let x: f64 = rand::random();
    println!("Hello, world: {}", x);
}

Running cargo build --release creates file target/release/libtesting.so.


// temp.rs
extern crate testing;

fn main() {
    testing::print_rand();
}

Running rustc temp.rs --extern testing=./target/release/libtesting.so gives:

error[E0463]: can't find crate for `rand` which `testing` depends on
 --> tmp.rs:1:1
  |
1 | extern crate testing;
  | ^^^^^^^^^^^^^^^^^^^^^ can't find crate

error: aborting due to previous error

For more information about this error, try `rustc --explain E0463`.

The staticlib and cdylib crate types are primarily intended as self-contained binaries that can be used via their C API. It's quite possible for one Rust crate to use another Rust crate through its C API (e.g. by writing extern bindings and using FFI-safe types), but unless you have exotic constraints (e.g. can only use pre-compiled libraries for IP/distribution reasons) this is probably not the path you want to go down.

Normally, you'll use cargo to build your application and add an entry to the [dependencies] section of your Cargo.toml file. The Dependencies chapter of The Cargo Book explains a bit about adding dependencies, but if you want to use something that hasn't been published to crates.io you can use a path dependency.

[package]
name = "temp"

[dependencies]
testing = { path "./path/to/testing" }

Cargo will then make sure your dependency is compiled to a rlib so it can be linked to your library. You can see the actual calls to rustc by running cargo build --verbose.

If you do have particular circumstances which mean you can't just add the crate to your Cargo.toml and must depend on a *.a or *.so file, you should be able to treat it like any other native library and follow various FFI guides on how to achieve the linking part (e.g. The Nomicon has a chapter on FFI).

3 Likes

That clears it. Thanks a lot Michael!

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.