Rust中的链接属性与C语言中的链接相比有何不同?

5

我对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;
}

编译时使用了 with。
clang -o test test.c -ldl # or your cc of choice

我需要翻译的内容:

或者它会被翻译成类似于使用 clang <other stuff> -lwayland-core 吗?还是我完全错误,走错了方向?

以下是我从阅读 The Rust Reference 中找到的唯一文档。

link - 表示本块中的声明需要正确链接到本地库。 link 支持一个可选的 kind 键,有三个可能的值:dylibstaticframework。

编辑:

The Rust Programming Language高级链接 下提供了更多信息。


1
如果您使用*nix类系统,请尝试在两个版本上运行ldd your-exe进行比较。C版本肯定不会报告对libwayland-client的依赖关系——那么Rust版本呢? - John Zwinck
好评!我使用了 RTLD_LAZY,它意味着“在执行动态库代码时解析未定义的符号”。这是从以下文档这里中获取的。由于这只是一个例子,所以我没有使用 pwl_display_connect。因此,如果您使用 RTLD_NOW,它可能会报告依赖项,但我可能是错的。 - Daniel Robertson
1
你错了,即使你使用 RTLD_NOW,C程序也不会静态依赖于 libwayland-client - John Zwinck
@Shepmaster 是正确的,当它失败时,它会显示使用了哪个命令以及输出-l<name>。谢谢! - Daniel Robertson
1个回答

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

以下是一些要点:

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

ld: library not found for -lwayland-client

从输出中可以看出,这是普通的编译时链接到动态库,而不是运行时加载动态库。


运行时加载动态库曾经由 std::dynamic_lib 处理,但现在应该使用一个 crate。我不确定哪个 crate 最好,但我找到了 libloading


作为一些编辑意见,我建议创建一个 mylibrary-sys crate,仅公开直接的 FFI 绑定。在该 crate 中,使用 the links key 指定您正在链接到本地库。这使 Cargo 可以确保本地库仅链接一次。然后您就不需要任何属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接