如何解决为什么即使使用 no_std 也会在 rust 标准库符号中链接 cargo/rustc?

How to troubleshoot why cargo/rustc links in rust standard library symbols even when no_std is used?

我正在尝试创建一个嵌入友好的可执行文件(占地面积小,不依赖于 Rust 标准库),它使用已经支持 no_std 构建的库 (wasmi)。 Rust 的新手,我只是将指令拼凑在一起,但它的要点似乎是 follow the steps.

对于可执行文件:

#![no_std]
#![no_main]

use core::panic::PanicInfo;

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[no_mangle]
pub extern "C" fn _start(_argc: isize, _argv: *const *const u8) -> ! {
    interpret(_argc, _argv);
    loop {}
}

也就是:

我要编译的 Cargo 文件如下所示:

[package]
 name = "driver"
 version = "0.1.0"
 edition = "2018"

[dependencies.wasmi]
 path = "../../github_dev/wasmi" 
 features = ["core"]
 default-features = false
 test=false
 bench=false

 [profile.release]
 panic = "abort"
 lto = true
 incremental=false
 debug=true
 opt-level = "z"
 test=false
 bench=false

并生成一个非常小的二进制文件,它排除了任何标准库符号(使用 nm 进行检查)并按预期运行。

当我实际尝试调用 wasmi 库中的函数时出现问题。它是通过 features=core 行用 no_std 构建的。对 release/deps/libwasmi-*.rlib 中的文件执行 nm 显示没有标准库符号。然而,当 linking 使用此命令时:

rustc --release --verbose -- -C link-arg=-nostartfiles

它导致:

   Compiling driver v0.1.0 (/home/my_home/wasmi_embed/driver)
     Running rustc --edition=2018 --crate-name driver src/main.rs --color always --crate-type bin --emit=dep-info,link -C opt-level=3 -C panic=abort -C lto -C link-arg=-nostartfiles -C metadata=957eda2e590447ba -C extra-filename=-957eda2e590447ba --out-dir /home/my_home/wasmi_embed/driver/target/release/deps -L dependency=/home/my_home/wasmi_embed/driver/target/release/deps --extern libc=/home/my_home/wasmi_embed/driver/target/release/deps/liblibc-f7fb773c7b059a14.rlib --extern wasmi=/home/my_home/wasmi_embed/driver/target/release/deps/libwasmi-534aef1926b4eb6c.rlib

并发生错误:

error[E0152]: duplicate lang item found: panic_impl.
  --> src/main.rs:31:1
   |
31 | / pub extern fn panic(_info: &PanicInfo) -> ! {
32 | |     loop {}
33 | | }
   | |_^
   |
   = note: first defined in crate `std`.

Rust 似乎试图 link 在标准库中至少支持恐慌处理,但我不知道为什么。

我想了解原因并了解如何预防。

如果我删除 panic_impl 属性,那么我的可执行文件会编译,但它包含许多我试图阻止的标准库符号。

我看到的示例符号是:

my_home@my_puter:~/wasmi_embed/driver/target/release$ nm --demangle -A -a -B -s --line-number test_2018 2>/dev/null | grep std
driver:00000000000264c0 t rust_begin_unwind  /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/panicking.rs:311
driver:00000000000264a0 t rust_oom   /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/alloc.rs:203
driver:000000000001f490 t rust_panic /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/panicking.rs:524
driver:0000000000025aa0 t _$LT$std..panicking..continue_panic_fmt..PanicPayload$LT$$u27$a$GT$$u20$as$u20$core..panic..BoxMeUp$GT$::get::he4f810e299a2e0b4    /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/panicking.rs:372
driver:00000000000259a0 t _$LT$std..panicking..continue_panic_fmt..PanicPayload$LT$$u27$a$GT$$u20$as$u20$core..panic..BoxMeUp$GT$::box_me_up::hd8430725259668a8     /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/panicking.rs:367
driver:0000000000021520 t _$LT$std..sys_common..process..DefaultEnvKey$u20$as$u20$core..borrow..Borrow$LT$std..ffi..os_str..OsStr$GT$$GT$::borrow::hbacd0cd7d7fbf1c1/rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/sys_common/process.rs:27
driver:0000000000021570 t _$LT$std..error..$LT$impl$u20$core..convert..From$LT$alloc..string..String$GT$$u20$for$u20$alloc..boxed..Box$LT$$LP$dyn$u20$std..error..Err
... plus more

上述符号在dep目录下的任何rlib文件中都找不到,包括libwasmi,在不调用libwasmi代码时在驱动程序可执行文件中也找不到。

我已经阅读了 a similar issue(因此我在 Cargo.toml 中阅读了 test=falsebench=false),但这并没有帮助。我尝试使用不同的命令(不包括 Cargo)仅使用 rustc 进行构建,但错误是相同的。我曾尝试将 wasmi 编译为静态库 (ar) 并将其 link 放入其中,但作为 Rust 的新手,我花了很多时间尝试将其 link 放入其中,但事实并非如此正在发生。

我在 Rust 论坛寻求帮助后解决了这个问题。 enter link description here. Specifically, was not able to determine what was responsible for rust std lib being linked into my executable ... was it an issue with a crate or an issue with cargo or an issue with rustc or an issue with the linker. I did not know where the problem was born, but based on similar bugs filed I figured that somehow a crate was being compiled to bring in std lib unexpected. Turns out bug enter link description here 不相关,即使错误消息相同。我没有遇到来自不同类型依赖项(开发依赖项和构建依赖项)的意外传播的问题。我尝试了所有这些技术来查明是什么引入了标准库:

  1. 我尝试使用 cargo tree 来列出依赖项以列出所有 crate 依赖项:

    wasmi v0.4.3 (/home/jlb6740/github_dev/wasmi)
    ├── byteorder v1.3.1 (/home/jlb6740/github_dev/byteorder)
    ├── hashbrown v0.1.8 (/home/jlb6740/github_dev/hashbrown)
    │ ├── byteorder v1.3.1 (/home/jlb6740/github_dev/byteorder) ()
    │ └── scopeguard v0.3.3 (/home/jlb6740/github_dev/scopeguard)
    ├── libm v0.1.2
    ├── memory_units v0.3.0
    └── parity-wasm v0.31.0 (/home/jlb6740/github_dev/parity-wasm)
    └── byteorder v1.3.1 (/home/jlb6740/github_dev/byteorder) (
    )

  2. 我试过使用 cargo rustc --verbose … 但此时 verbose 确实 不表示任何东西正在使用默认功能,其中可能包括 使用 std

  3. 我尝试使用货物元数据……这生成了一长串 难以解析的依赖项,但我确实看到了一些实例 其中 scopeguard 和 byteorder 具有需要 std 的默认功能 支持。我下载了所有这些板条箱并进行了硬编码 属性,以便箱子只能在 no_std 支持下构建。

  4. 我试着查看 deps/ 输出并对所有 rlibs 查看是否有任何库使用了在 std 中找到的符号。我 找不到是这样的。我以为 rlibs 就像 静态库,他们使用的任何东西都将包含在 rlib 但显然不是。

  5. 我查看了 cargo rustc -- -C --print-link-args 以查看 linker 标志,但我找不到任何明显的东西告诉我它是 引入标准库。

None 这些东西帮助我查明是什么引入了标准库。最终,rust 论坛上的建议是对根本不允许 std lib 的目标使用 cargo check。此处列出 * 的那些:enter link description here 只有核心支持。我试过了,运行 --target=thumbv7m-none-eabi 并看到:

错误[E0463]: 找不到 alloc
的箱子 –> /home/jlb6740/github_dev/hashbrown/src/lib.rs:44:1
|
44 | extern crate std as alloc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^找不到箱子

原来它是 hashbrown,它是我的可执行文件依赖项的依赖项。它默认构建 no_std 但有一个 extern std linked 在不同的名称下,并由一个名为“nightly”的功能保护。在我除了 no_std 之外不建造任何东西的努力中,守卫被禁用了。在此之前,我尝试过的任何事情都没有提醒我负责的板条箱。似乎应该有比 cargo tree 提供的更好的方法来获得更全面的 crate 依赖项列表,但是更改 wasmi cargo 以确保设置了 nightly 功能解决了我的问题。