std
之下
本节记录了通常由 std
crate 提供的功能,而 #![no_std]
的开发者为了构建 #![no_std]
的二进制 crate 必须处理(即提供)这些功能。
使用 libc
为了构建一个 #[no_std]
可执行文件,我们需要 libc
作为依赖项。我们可以使用 Cargo.toml
文件来指定它。
[dependencies]
libc = { version = "0.2.146", default-features = false }
请注意,默认功能已被禁用。这是一个关键步骤 - **libc
的默认功能包括 std
crate,因此必须禁用。**
或者,我们可以使用不稳定的 rustc_private
私有功能以及 extern crate libc;
声明,如下面的示例所示。请注意,windows-msvc 目标不需要 libc,并且它们的 sysroot 中也没有 libc
crate。我们不需要下面的 extern crate libc;
,并且在 windows-msvc 目标上使用它会导致编译错误。
在没有 std
的情况下编写可执行文件
我们可能需要夜间版编译器来生成 #![no_std]
可执行文件,因为在许多平台上,我们必须提供 eh_personality
lang item,这是一个不稳定的功能。
控制入口点有两种方式:使用 #[start]
属性,或者用你自己的函数覆盖 C main
函数的默认 shim。此外,还需要定义一个 panic 处理函数。
标记为 #[start]
的函数以与 C 相同的格式(除了使用的确切整数类型)传递命令行参数。
#![feature(start, lang_items, core_intrinsics, rustc_private)] #![allow(internal_features)] #![no_std] // Necessary for `panic = "unwind"` builds on cfg(unix) platforms. #![feature(panic_unwind)] extern crate unwind; // Pull in the system libc library for what crt0.o likely requires. #[cfg(not(windows))] extern crate libc; use core::panic::PanicInfo; // Entry point for this program. #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } // These functions are used by the compiler, but not for an empty program like this. // They are normally provided by `std`. #[lang = "eh_personality"] fn rust_eh_personality() {} #[panic_handler] fn panic_handler(_info: &PanicInfo) -> ! { core::intrinsics::abort() }
为了覆盖编译器插入的 main
shim,我们必须使用 #![no_main]
禁用它,然后创建具有正确 ABI 和正确名称的相应符号,这也需要覆盖编译器的名称修饰。
#![feature(lang_items, core_intrinsics, rustc_private)] #![allow(internal_features)] #![no_std] #![no_main] // Necessary for `panic = "unwind"` builds on cfg(unix) platforms. #![feature(panic_unwind)] extern crate unwind; // Pull in the system libc library for what crt0.o likely requires. #[cfg(not(windows))] extern crate libc; use core::ffi::{c_char, c_int}; use core::panic::PanicInfo; // Entry point for this program. #[no_mangle] // ensure that this symbol is included in the output as `main` extern "C" fn main(_argc: c_int, _argv: *const *const c_char) -> c_int { 0 } // These functions are used by the compiler, but not for an empty program like this. // They are normally provided by `std`. #[lang = "eh_personality"] fn rust_eh_personality() {} #[panic_handler] fn panic_handler(_info: &PanicInfo) -> ! { core::intrinsics::abort() }
如果您正在处理的目标没有通过 rustup 提供的标准库二进制版本(这可能意味着您正在自己构建 core
crate),并且需要 compiler-rt intrinsics(即,您在构建可执行文件时可能会遇到链接器错误:undefined reference to `__aeabi_memcpy'
),您需要手动链接到 compiler_builtins
crate 以获取这些 intrinsics 并解决链接器错误。