I am seriously impressed with how easy the link
attribute makes linking to shared libraries. However, I am curious about the the details of the attribute and how it compares to linking in C. For instance, given the following Rust code
#[allow(bad_style)]
struct wl_display;
fn main() {
#[link(name="wayland-client", kind="dylib")]
extern {
fn wl_display_connect(name: *const u8) -> *mut wl_display;
}
// do work
}
Would it translate closer to something like the following C code?
#include <stdio.h>
#include <dlfcn.h>
struct wl_display;
int main() {
struct wl_display* (*pwl_display_connect)(const char *name);
char* error;
void* handle = dlopen("/usr/lib/libwayland-client.so", RTLD_LAZY);
if(!handle) {
fprintf(stderr, "Error opening lib: %s\n", dlerror());
exit(1);
}
pwl_display_connect = dlsym(handle, "wl_display_connect");
// do work
if(!pwl_display_connect) {
fprintf(stderr, "Error loading function: %s\n", dlerror());
exit(1);
}
if(dlclose(handle) < 0) {
fprintf(stderr, "Error closing lib: %s\n", dlerror());
exit(1);
}
return 0;
}
compiled with with
clang -o test test.c -ldl # or your cc of choice
Or would it translate to something like using clang <other stuff> -lwayland-core
? Or am I entirely wrong and headed in the wrong direction?
The following is the only documentation I found from reading through the The Rust Reference
link
- indicate that a native library should be linked to for the declarations in this block to be linked correctly.link
supports an optionalkind
key with three possible values:dylib
,static
, andframework.
The Rust Programming Language has some more information under Advanced Linking
I don't know this to be true, I'm simply basing this answer based on the compiler's output.
I am on OS X and do not have anything Wayland-related installed. If I take your code and compile it with cargo build --verbose
, I get this output (cleaned up a bit):
Compiling wat v0.1.0 (file:///private/tmp/wat)
Running `rustc src/main.rs --crate-name wat --crate-type bin -g --out-dir /private/tmp/wat/target/debug --emit=dep-info,link -L dependency=/private/tmp/wat/target/debug -L dependency=/private/tmp/wat/target/debug/deps`
error: linking with `cc` failed: exit code: 1
note: "cc" "-m64" "-L" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib" "/private/tmp/wat/target/debug/wat.0.o" "-o" "/private/tmp/wat/target/debug/wat" "-Wl,-dead_strip" "-nodefaultlibs" "-L" "/private/tmp/wat/target/debug" "-L" "/private/tmp/wat/target/debug/deps" "-L" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib" "-l" "wayland-client" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/libstd-ca1c970e.rlib" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/libcollections-ca1c970e.rlib" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/librustc_unicode-ca1c970e.rlib" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/librand-ca1c970e.rlib" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/liballoc-ca1c970e.rlib" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/liballoc_jemalloc-ca1c970e.rlib" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/liblibc-ca1c970e.rlib" "/Users/shep/Projects/rust/x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/libcore-ca1c970e.rlib" "-l" "System" "-l" "pthread" "-l" "c" "-l" "m" "-l" "compiler-rt"
note: ld: library not found for -lwayland-client
A few highlights from that:
"cc" [...] "-l" "wayland-client"
ld: library not found for -lwayland-client
From that output, I believe that this is doing normal compile-time linking to a dynamic library, not run-time loading of a dynamic library.
Run-time loading of a dynamic library used to be handled by std::dynamic_lib
, but one should now use a crate. I'm not sure what crate is best, but I did find libloading.
As some editorial, I would suggest creating a mylibrary-sys
crate that simply exposes the direct FFI bindings. In that crate, use the links
key to specify that you are linking to a native library. This allows Cargo to ensure that the native library is only linked to once. Then you don't need any attributes.
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