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

Dan*_*son 5 c linker dynamic-linking rust

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
}
Run Code Online (Sandbox Code Playgroud)

它会更接近以下 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;
}
Run Code Online (Sandbox Code Playgroud)

编译与

clang -o test test.c -ldl # or your cc of choice
Run Code Online (Sandbox Code Playgroud)

或者它会转化为诸如 using 之类的东西clang <other stuff> -lwayland-core吗?还是我完全错了,朝着错误的方向前进?

以下是我通过阅读The Rust Reference找到的唯一文档

link- 指示应链接到本机库,以便正确链接此块中的声明。link支持可选的kind有三个可能的值键:dylibstatic,和 framework.

编辑:

Rust 编程语言高级链接下有更多信息

She*_*ter 3

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

我使用的是 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
Run Code Online (Sandbox Code Playgroud)

其中的一些亮点:

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

ld: library not found for -lwayland-client

从该输出来看,我相信这是对动态库进行正常的编译时链接,而不是动态库的运行时加载。


动态库的运行时加载过去由 处理std::dynamic_lib,但现在应该使用 crate。我不确定哪个板条箱最好,但我确实找到了libloading


作为一些社论,我建议创建一个mylibrary-sys简单地公开直接 FFI 绑定的箱子。在该箱中,使用密钥links指定您要链接到本机库这使得 Cargo 能够确保本机库仅链接一次。那么你不需要任何属性。