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)
cdylib
instead (rust reference chp 12) – Clelandcargo clean
&&cargo build -vv
to see with what arguments isrustc
executed. – Butylene