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

时间:2019-02-12 01:42:19

标签: rust rust-cargo

我试图创建一个嵌入友好的可执行文件(占用空间小,并且不依赖于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 {}
}

那是为了

  • 包括#![no_std]
  • 定义我们的条目(而不是main,因为我们没有可以调用它的运行时)
  • 并定义一个应急处理程序,因为不包括Rust std lib来为我们定义它。

我要编译的货运文件看起来像这样:

[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库中调用函数时,会发生问题。它是通过no_std行通过features=core构建的。对nm中的文件执行release/deps/libwasmi-*.rlib不会显示任何标准库符号。但是,使用此命令进行链接时:

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似乎试图至少在标准库支持中链接以进行紧急处理,但我不知道为什么。

我希望帮助您了解原因并了解如何预防。

如果我删除了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),但这无济于事。我尝试仅使用rustc来构建各种命令(不包括Cargo),但错误是相同的。我曾尝试将wasmi编译为静态库(ar)并将其链接,但是对于Rust来说,我花了很多时间尝试将其链接,但这并没有发生。

1 个答案:

答案 0 :(得分:-1)

我在rust论坛上寻求帮助后解决了这个问题。 enter link description here。具体来说,无法确定造成rust std lib链接到我的可执行文件的原因是...是板条箱问题,货物问题,rustc问题还是链接程序问题。我不知道问题出在哪里,但是基于所记录的类似错误,我认为正在以某种方式编译一个条板箱以带来意外的std lib。事实证明,即使错误消息相同,错误enter link description here也不相关。我没有遇到来自不同类型的依赖项(开发依赖项和构建依赖项)的意外传播的问题。我尝试了所有这些技术来查明什么是std lib:

  1. 我尝试使用货物树列出依赖项以列出所有板条箱 依赖项:

    wasmi v0.4.3(/ home / jlb6740 / github_dev / wasmi)
    ├──字节序v1.3.1(/ home / jlb6740 / github_dev / byteorder)
    ├──hashbrown v0.1.8(/ home / jlb6740 / github_dev / hashbrown)
    │├──字节序v1.3.1(/ home / jlb6740 / github_dev / byteorder)(
    │└──范围卫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)
        └──字节序v1.3.1(/ home / jlb6740 / github_dev / byteorder)(

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

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

  4. 我尝试查看deps /输出,并在所有 rlibs查看是否有任何库使用了std中的符号。一世 找不到这种情况。我以为礼拜就像 静态库以及它们使用的所有内容都将包含在其中 rlib,但显然不是。

  5. 我查看了货物锈蚀--C --print-link-args以检查链接器 标志,但是我找不到明显的告诉我这是 引入标准库。

这些东西都没有帮助我弄清楚引入std lib的原因。最终,在rust论坛上的建议是将货运检查用于完全不允许std lib的目标。此处列出了*的用户:enter link description here仅具有核心支持。我尝试过使用--target=thumbv7m-none-eabi运行,并看到:

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

原来是哈希棕,这是我的可执行文件的依赖项。它默认情况下构建了no_std,但是有一个以不同名称链接的extern std,并且由一个名为“ nightly”的功能来保护。在我努力建立no_std以外的任何东西时,警卫人员都被禁用了。在此之前,我一直没有尝试过提醒负责的板条箱。似乎应该有比获得货物树提供的更全面的条板箱依赖关系列表的更好方法,但是更改wasmi货物以确保设置了夜间功能可以解决我的问题。