Rust link 属性的内部工作原理与 C 中的 linking 相比如何?

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

link 属性使链接到共享库变得多么容易,这给我留下了深刻的印象。但是,我很好奇该属性的详细信息以及它与 C 中的链接相比如何。例如,给定以下 Rust 代码

#[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
}

它会更接近于类似于以下 C 代码的代码吗?

#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;
}

编译
clang -o test test.c -ldl # or your cc of choice

或者它会转化为使用 clang <other stuff> -lwayland-core 之类的东西吗?还是我完全错了,走错了方向?

以下是我通过 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.

编辑:

The Rust Programming Language has some more information under Advanced Linking

不知道这是真的,我只是根据编译器的输出得出这个答案。

我在 OS X 上,没有安装任何与 Wayland 相关的东西。如果我使用你的代码并用 cargo build --verbose 编译它,我会得到这个输出(稍微清理一下):

   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

其中的一些亮点:

"cc" [...] "-l" "wayland-client"

ld: library not found for -lwayland-client

根据该输出,我相信这是在正常编译时链接到动态库,而不是 运行 时加载动态库。


运行-动态库的时间加载曾经由 std::dynamic_lib, but one should now use a crate. I'm not sure what crate is best, but I did find libloading.

处理

作为一些社论,我建议创建 a mylibrary-sys crate that simply exposes the direct FFI bindings. In that crate, use the links key 以指定您要链接到本机库。这允许 Cargo 确保原生库只被链接一次。那么你不需要任何属性。