How to link a dynamic Rust library using only rustc and not cargo?
Asked Answered
T

1

6

My main.rs looks like

// #[link(name = "lib")]
extern "C" {
    fn hello();
}

fn main() {
    unsafe {
        hello();
    }
}

And lib.rs:

#[no_mangle]
pub fn hello() {
    println!("Hello, World!");
}

I have compiled lib.rs using rustc --crate-type=cdylib lib.rs -o lib.so

How do I link lib.so to rustc main.rs command ?

Tigges answered 5/4, 2019 at 14:24 Comment(2)
Apart from the reason that there is no reason that you should avoid cargo, you have to use cdylib instead (rust reference chp 12)Cleland
cargo clean && cargo build -vv to see with what arguments is rustc executed.Butylene
L
7

You need to match ABIs. When you use an extern "C" block, you need to declare your functions using the same ABI.

Name your dynamic library using the platform's conventions. Use .dylib on macOS, .lib on Windows, and .so on Linux. rustc will do this for you automatically if you don't provide a -o option.

Once you have built your dynamic library, you need to add it to the compiler's linker options. rustc --help has a list of the various compiler options. -L adds a directory to the search path and -l links to a specific library.

lib.rs

#[no_mangle]
pub extern "C" fn hello() {
    println!("Hello, World!");
}

main.rs

extern "C" {
    fn hello();
}

fn main() {
    unsafe {
        hello();
    }
}

Compiled and executed with:

$ rustc --crate-type=cdylib lib.rs
$ rustc main.rs -L . -l lib
$ ./main
Hello, World!

As I'm on macOS, I used otool to show that it's indeed dynamically linked:

$ otool -L main
main:
    liblib.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
    /usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)

See also:


For completeness, here's "normal" linking of crates:

lib.rs

pub fn hello() {
    println!("Hello, World!");
}

main.rs

fn main() {
    lib::hello();
}
$ rustc --crate-type=rlib lib.rs
$ rustc main.rs --extern lib=liblib.rlib
$ ./main
Hello, World!
$ otool -L main
main:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
    /usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
Lotson answered 5/4, 2019 at 15:40 Comment(3)
When I execute ./main after rustc main.rs -L . -l lib, I get the error error while loading shared libraries: liblib.so: cannot open shared object file, and lld main shows liblib.so => not found, is there a workaround rather then moving it to /lib/x86_64-linux-gnuTigges
@Tigges Linking Rust application with a dynamic library not in the runtime linker search path and How to set the environmental variable LD_LIBRARY_PATH in linuxLotson
to be clear I added #![feature(link_args)] #![link_args="-Wl,-rpath LOCATION_OF_LIB"] in main.rs and it workedTigges

© 2022 - 2024 — McMap. All rights reserved.