不依賴 stdlib

2018-08-12 22:03 更新

不依賴 stdlib

默認情況下,std 會鏈接到每一個 Rust 的封裝對象。在一些場景下,這并不是很理想的,在需要的情境下使用 #![no_std] 屬性使得程序可以獨立于 stdlib

// a minimal library
#![crate_type="lib"]
#![feature(no_std)]
#![no_std]

很顯然,這種方式比僅僅使用庫有更長的聲明周期:一個是使用 #[no_std] 來開始程序的執(zhí)行,控制程序開始指針可以有兩種方式:使用 #[start] 屬性或覆蓋 C main 函數(shù)。

#[start] 標記的函數(shù)可以以C語言的方式來傳遞命令行參數(shù):

#![feature(lang_items, start, no_std, libc)]
#![no_std]

// Pull in the system libc library for what crt0.o likely requires
extern crate libc;

// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}

// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

為了覆蓋插入式編輯器的 main 函數(shù)。一種方法是使用 #![no_main] 來關(guān)閉,然后使用正確 ABI 和名字來創(chuàng)建合適的標示,這些也需要覆蓋編譯器的名字。

`#![feature(no_std)]
#![no_std]
#![no_main]
#![feature(lang_items, start)]

extern crate libc;

#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
0
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }`   

編譯器目前已經(jīng)制造了一些假定的符號,它們可以在可執(zhí)行文件來調(diào)用。通常,這些函數(shù)是由標準庫提供的,如果沒有它的話,用戶就必須定義自己的。

這三個函數(shù)中的第一個,stack_exhausted,被調(diào)用何時堆棧溢出。此函數(shù)關(guān)于如何被調(diào)用和它必須做什么存在一些約束和限制。但是,如果堆棧限制寄存器沒有被維護,然后一個線程經(jīng)常有個無限的堆棧且這個函數(shù)不會被觸發(fā)。

這三個函數(shù)中的第三個函數(shù),eh_personality,用于編譯器的錯誤機制。這通常會被映射到 GCC 的個人函數(shù)(參照 libstd 的實現(xiàn)來獲取更多的信息),不會觸發(fā)錯誤的對象就被認為是該函數(shù)沒有被調(diào)用。最后一個函數(shù),panic_fmt,也是用于編譯器的錯誤機制的。

使用 libcore

注意:核心庫的結(jié)構(gòu)是不穩(wěn)定的,這里特別建議盡量在能使用標準庫的情況下就使用標準庫。

在上述技術(shù)的基礎(chǔ)上,我們就可以運行一些簡單的 Rust 代碼。標準庫可以提供一些更理想的函數(shù),但是,必須在 Rust 代碼中主動去建立。在某些情況下,標準庫也不是很有效,那么,可以使用 libcore.

核心庫具有較少的依賴性,并且比標準庫還精簡。此外,核心庫為編寫慣用且高效的 Rust 代碼提供了很多必要的函數(shù)。

舉個例子,下面是關(guān)于 C 中的兩個向量進行點乘的程序,這里使用了慣用的 Rust 實踐。

`#![feature(lang_items, start, no_std, core, libc)]
#![no_std]

extern crate core;

use core::prelude::*;

use core::mem;

#[no_mangle]
pub extern fn dot_product(a: *const u32, a_len: u32,
                      b: *const u32, b_len: u32) -> u32 {
use core::raw::Slice;

// Convert the provided arrays into Rust slices.
// The core::raw module guarantees that the Slice
// structure has the same memory layout as a &[T]
// slice.
//
// This is an unsafe operation because the compiler
// cannot tell the pointers are valid.
let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
    mem::transmute((
        Slice { data: a, len: a_len as usize },
        Slice { data: b, len: b_len as usize },
    ))
};

// Iterate over the slices, collecting the result
let mut ret = 0;
for (i, j) in a_slice.iter().zip(b_slice.iter()) {
    ret += (*i) * (*j);
}
return ret;
}

#[lang = "panic_fmt"]
extern fn panic_fmt(args: &core::fmt::Arguments,
                file: &str,
                line: u32) -> ! {
loop {}
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}`

注意,這里有個與上例中不同的附加lang 項目,panic_fmt.它必須由 libcore 的使用者來ID來定義,因為,核心庫聲明了這個警告,但是并沒有定義它。這里的 panic_fmt lang 項目 就是警告的對象定義。它必須滿足應(yīng)用不會退出的條件。

正如上例中看到的那樣,核心庫就是用于在多種獨立于平臺的應(yīng)用場景下支持 Rust.未來的庫,如liballoc、會在libcore的基礎(chǔ)上添加更多的功能,使的可以應(yīng)用于其他特定的平臺,但不變的是仍然會比標準庫更精簡便攜。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號