[英]How can I link libraries to my C code and use that in a Rust binary?
I am trying to include a C file in my Rust project.我正在尝试在我的 Rust 项目中包含一个 C 文件。 The C file uses system dependencies.
C 文件使用系统依赖项。 Below is a minimal example that does not compile when I run
cargo build
.下面是一个在我运行
cargo build
时不会编译的最小示例。
If I take the failing command that Cargo is running and I append "-l" "nl-genl-3" "-l" "nl-3"
the command does succeed.如果我执行 Cargo 正在运行的失败命令并附加
"-l" "nl-genl-3" "-l" "nl-3"
该命令会成功。 Is it putting the the linker flags in the wrong place, because those flags definitely are in the command?难道把链接标志在错误的地方,因为这些标志肯定是在命令?
src/main.rs src/main.rs
#[link(name = "nl-genl-3")]
#[link(name = "nl-3")]
extern "C" {
fn nl_test(help_me_pls: usize) -> usize;
}
fn main() {
unsafe {
println!("nl.c function result: {:?}", nl_test(6));
}
}
src/nl.c src/nl.c
#include <linux/nl80211.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
int nl_test(int help_me_pls) {
struct nl_sock* socket = nl_socket_alloc();
nl_socket_free(socket);
return help_me_pls;
}
build.rs构建.rs
extern crate cc;
fn main() {
cc::Build::new()
.include("/usr/include/libnl3")
.file("src/nl.c")
.compile("libnl.a");
}
Cargo.toml Cargo.toml
[package]
name = "derp"
version = "0.1.0"
[build-dependencies]
cc = "1.0"
I get the following output when I run cargo build
当我运行
cargo build
时,我得到以下输出
Compiling cc v1.0.18
Compiling derp v0.1.0 (file:///root/derp)
error: linking with `cc` failed: exit code: 1
|
= note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-L" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.1vmrdj4gsxr690x4.rcgu.o" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.1y16o1qfye96o7m0.rcgu.o" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.3rngp6bm2u2q5z0y.rcgu.o" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.4oc10dk278mpk1vy.rcgu.o" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.4xq48u46a1pwiqn7.rcgu.o" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.51s1w397y42gpez1.rcgu.o" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.8xzrsc1ux72v29j.rcgu.o" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.oa3rad818d8sgn4.rcgu.o" "-o" "/root/derp/target/debug/deps/derp-5a7445c256565e2d" "/root/derp/target/debug/deps/derp-5a7445c256565e2d.crate.allocator.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "-L" "/root/derp/target/debug/deps" "-L" "/root/derp/target/debug/build/derp-c3cdcf1fbd0c70b2/out" "-L" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib" "-l" "nl-genl-3" "-l" "nl-3" "-Wl,-Bstatic" "-Wl,--whole-archive" "-l" "nl" "-Wl,--no-whole-archive" "-Wl,--start-group" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/libstd-774f1a5992f88ec5.rlib" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/libpanic_unwind-a65ab1ab71045d14.rlib" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/liballoc_jemalloc-5cced33d7a39db8e.rlib" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/libunwind-76fba694360269fc.rlib" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/liballoc_system-b3f660c2be971c37.rlib" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/liblibc-64d840c62d40ace0.rlib" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/liballoc-b3d8b67c899d207d.rlib" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/libcore-d9124265921c5963.rlib" "-Wl,--end-group" "/root/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/lib/rustlib/armv7-unknown-linux-gnueabihf/lib/libcompiler_builtins-1aad7d9a81def783.rlib" "-Wl,-Bdynamic" "-l" "dl" "-l" "rt" "-l" "pthread" "-l" "pthread" "-l" "gcc_s" "-l" "c" "-l" "m" "-l" "rt" "-l" "pthread" "-l" "util" "-l" "util"
= note: /root/derp/target/debug/build/derp-c3cdcf1fbd0c70b2/out/libnl.a(nl.o): In function `nl_test':
/root/derp/src/nl.c:6: undefined reference to `nl_socket_alloc'
/root/derp/src/nl.c:7: undefined reference to `nl_socket_free'
collect2: error: ld returned 1 exit status
From the Cargo documentation for build scripts :来自构建脚本的Cargo 文档:
rustc-link-lib=[KIND=]NAME
indicates that the specified value is a library name and should be passed to the compiler as a-l
flag.rustc-link-lib=[KIND=]NAME
表示指定的值是一个库名,应该作为-l
标志传递给编译器。 The optionalKIND
can be one ofstatic
,dylib
(the default), orframework
, seerustc --help
for more details.可选的
KIND
可以是static
、dylib
(默认)或framework
,有关更多详细信息,请参阅rustc --help
。
Add this to your build script:将此添加到您的构建脚本中:
println!("cargo:rustc-link-lib=nl-genl-3");
println!("cargo:rustc-link-lib=nl-3");
And remove the link
attributes from your Rust code.并从 Rust 代码中删除
link
属性。
The problem is that your linker flags are stating that the Rust code needs to link to the C libraries, but that's not fully true.问题是您的链接器标志表明 Rust 代码需要链接到 C 库,但这并不完全正确。 Your C code needs to link to the libraries, and your Rust code needs to link to the compiled C code.
您的C 代码需要链接到库,而您的 Rust 代码需要链接到已编译的 C 代码。 If you look at the arguments, you'll see this (abridged) output
如果你看一下参数,你会看到这个(删减的)输出
deps/derp-5a7445c256565e2d.1vmrdj4gsxr690x4.rcgu.o
(your Rust code) deps/derp-5a7445c256565e2d.1vmrdj4gsxr690x4.rcgu.o
(你的 Rust 代码)-l nl-genl-3
(system library) -l nl-genl-3
(系统库)-l nl-3
(system library) -l nl-3
(系统库)-l nl
(your C shim) -l nl
(你的 C 垫片) Argument order to linkers is important.链接器的参数顺序很重要。 If something isn't needed when the object is processed by the linker, it won't be used .
如果链接器处理对象时不需要某些东西,则不会使用它。
Here, the Rust code adds a dependency on code from the nl
library, so the linker is on the lookout for those symbols.在这里,Rust 代码添加了对来自
nl
库的代码的依赖,因此链接器正在寻找这些符号。 When nl-3
and nl-genl-3
are processed, we don't need any of the symbols from them, so they are mostly ignored.在处理
nl-3
和nl-genl-3
,我们不需要它们中的任何符号,因此它们大多被忽略。 When nl
is processed, we resolve the dependency from the Rust code, but nl
needs the symbols from nl-genl-3
and nl-3
, which will not be processed again.当
nl
被处理时,我们从 Rust 代码中解析依赖,但是nl
需要来自nl-genl-3
和nl-3
的符号,它们不会被再次处理。
It's not obvious, but the compile
method from cc
automatically prints out a cargo:rustc-link-lib
line to tie its build result into your Rust code.这并不明显,但是来自
cc
的compile
方法会自动打印出一个cargo:rustc-link-lib
行,将其构建结果绑定到您的 Rust 代码中。
See also:也可以看看:
Here it is how I solved it Rust + .so lib .这就是我解决它的方法Rust + .so lib 。 Hope It would help
希望它会有所帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.