Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do the inner workings of the Rust link attribute compare to linking in C?

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 optional kind key with three possible values: dylib, static, and framework.

Edit:

The Rust Programming Language has some more information under Advanced Linking

like image 710
Daniel Robertson Avatar asked Oct 19 '22 19:10

Daniel Robertson


1 Answers

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.

like image 110
Shepmaster Avatar answered Oct 27 '22 00:10

Shepmaster