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 确保原生库只被链接一次。那么你不需要任何属性。
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 optionalkind
key with three possible values:dylib
,static
, andframework.
编辑:
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 确保原生库只被链接一次。那么你不需要任何属性。