🐼
Rustのno_std環境でStringを使う
経緯
STM32マイコンでRustを勉強をしててUART出力できるようになった際に、no_std環境で可変文字列(String)を扱いたくなって調査したので備忘録
確認環境
バージョン | |
---|---|
rustc | rustc 1.62.0-nightly (8bf93e9b6 2022-04-09) |
方法
allocの実装が必要。
そのために以下手順を実施
No | 実施内容 |
---|---|
1 | Nightly Rustへの切り替え |
2 | #[global_allocator]アトリビュート指定オブジェクトの宣言 |
3 | #[alloc_error_handler]アトリビュート指定の関数実装 |
4 | Stringのuse宣言追加 |
Nightly Rustへの切り替え
必須ではないが手順2、手順3のために基本的に必要。ないとビルドエラーになる。
ターミナルで以下実施
rustup override set nightly
global_allocatorアトリビュート指定オブジェクトの宣言
アプリのどこかに#[lobal_allocator]
アトリビュートを指定したグローバル変数を宣言する必要がある。
この変数の型はGlobalAllocトレイトを実装している必要がある。
自前で実装してもよいが、ここでは公開されているalloc-cortex-mを使用。
alloc-cortex-m使用例
3手順に分けて記載
- Cargo.tomlのdependenciesに追加
Cargo.toml
[dependencies]
alloc-cortex-m = "0.4.2"
- アプリ内にグローバル変数宣言
use alloc_cortex_m::CortexMHeap;
#[global_allocator]
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
- アプリ開始時に初期化
#[entry]
fn main() -> ! {
{
use core::mem::MaybeUninit;
const HEAP_SIZE: usize = 1024*20; //20KBの領域
static mut HEAP: [MaybeUninit<u8>; HEAP_SIZE] =
[MaybeUninit::uninit(); HEAP_SIZE];
unsafe { ALLOCATOR.init(HEAP.as_ptr() as usize, HEAP_SIZE) }
}
alloc_error_handlerアトリビュート指定の関数実装
以下2つ必要
-
#![feature(alloc_error_handler)]
をルートモジュール先頭に追加
ルートモジュール先頭でないとビルドエラーになる
main.rs
#![no_std]
#![no_main]
#![feature(alloc_error_handler)]
- 関数実装
アプリ内に関数を実装する
use core::alloc::Layout;
#[alloc_error_handler]
fn oom(_: Layout) -> ! {
loop {}
}
Stringのuse宣言追加
アプリでString
を使用するためにuseが必要。
他にもto_string()
関数やformat()
マクロなどを使う際にも都度必要。
おそらく一纏めにするor記載省略する方法があるが、ここでは明示的に記載。
use alloc::string::String;
use alloc::string::ToString;
use alloc::format;
fn test() {
let base_string = String::from("aiueo:"); //Stringのuse必要
let mut count:u32 = 0;
loop {
let custom_string = format!("{}{}{}", //formatのuse必要
base_string, count.to_string(),"\n"); //ToStringのuse必要
//custom_stringを使ったUART送信処理
...
count=count+1;
}
}
備考
Nightly Rust
を使わない方法
手順2、手順3に対して以下実施によりStable Rust
でもalloc実装可能
- 手順2(
global_allocatorアトリビュート指定オブジェクトの宣言
)に対して
Nightly Rust
を要求しないアロケータを使用する (alloc-cortex-m
はNG)
または自前でGlobalAllocトレイトを実装する。
自前で実装する場合は参考1.を参照
- 手順3(
alloc_error_handlerアトリビュート指定の関数実装
)に対して
nightly-crimes
を使用してalloc_error_handler
関係を囲む。
Cargo.toml
[dependencies]
nightly-crimes = "1.0.2"
main.rs
#![no_std]
#![no_main]
use nightly_crimes::nightly_crimes;
nightly_crimes! {
#![feature(alloc_error_handler)]
use core::alloc::Layout;
#[alloc_error_handler]
fn oom(_: Layout) -> ! {
loop {}
}
}
参考
Discussion