ArceOS 开发指南
ArceOS 既是可以单独运行的模块化 Unikernel,也是 StarryOS 与 Axvisor 共享的基础能力层。本文档面向在 TGOSKits 工作区 内进行 ArceOS 相关开发的场景,覆盖开发环境、模块开发规范、应用与平台开发、测试策略、调试技巧和跨架构验证。
1. 开发环境
1.1 工具链
TGOSKits 工作区根目录的 rust-toolchain.toml 已锁定统一工具链:
| 配置项 | 值 |
|---|---|
| channel | nightly-2026-04-27 |
| profile | minimal |
| components | rust-src, llvm-tools, rustfmt, clippy |
| targets | x86_64-unknown-none, riscv64gc-unknown-none-elf, aarch64-unknown-none-softfloat, loongarch64-unknown-none-softfloat |
进入工作区后 rustup 会自动切换到该工具链,无需手动配置。
1.2 QEMU
ArceOS 开发和测试依赖 QEMU system emulator:
| 架构 | QEMU 包名 | 验证 命令 |
|---|---|---|
| aarch64 | qemu-system-aarch64 | qemu-system-aarch64 --version |
| riscv64 | qemu-system-riscv64 | qemu-system-riscv64 --version |
| x86_64 | qemu-system-x86_64 | qemu-system-x86_64 --version |
| loongarch64 | qemu-system-loongarch64 | qemu-system-loongarch64 --version |
推荐版本 ≥ 8.0。Debian/Ubuntu 安装示例:
sudo apt install qemu-system-arm qemu-system-misc qemu-system-x86
1.3 交叉编译工具链(可选)
大部分场景下 cargo + rust-src 即可完成 no_std 交叉编译,无需额外交叉工具链。仅当模块依赖 C 代码或需要链接外部 .a 时,才需安装对应的 gcc 交叉编译器。
2. 目录结构总览
os/arceos/
├── modules/ # 内核模块(17 个)
│ ├── axhal/ # 硬件抽象层
│ ├── axtask/ # 任务/线程管理 + 调度器
│ ├── axalloc/ # 内存分配器
│ ├── axdriver/ # 统一设备驱动框架
│ ├── axnet/ # 网络(legacy, smoltcp)
│ ├── axnet-ng/ # 网络(next-gen)
│ ├── axfs/ # 文件系统(legacy)
│ ├── axfs-ng/ # 文件系统(next-gen, ext4/fat)
│ ├── axlog/ # 多级日志
│ ├── axsync/ # 同步原语
│ ├── axmm/ # 页表/内存管理
│ ├── axdisplay/ # 图形显示
│ ├── axdma/ # DMA 支持
│ ├── axinput/ # 输入设备
│ ├── axipi/ # 核间中断
│ ├── axruntime/ # 运行时初始化,调用 main()
│ └── axconfig/ # 编译时配置生成
├── api/ # 对外 API 层
│ ├── axfeat/ # 顶层 feature 聚合(单一真相源)
│ ├── arceos_api/ # 公共 API 和类型
│ └── arceos_posix_api/ # POSIX 兼容 API
├── ulib/ # 用户侧库
│ ├── axstd/ # Rust std 风格接口
│ └── axlibc/ # C libc 接口
└── examples/ # 示例应用
├── helloworld/
├── httpserver/
├── httpclient/
├── shell/
└── ... # 含 C 示例(helloworld-c 等)
3. 模块开发
3.1 模块标准结构
以 axtask 为代表的典型模块结构:
modules/axtask/
├── Cargo.toml # features + 依赖
└── src/
├── lib.rs # 模块根,条件编译,re-exports
├── api.rs # 公共 API 函数
├── task.rs # Task 结构体
├── run_queue/ # 调度器 run queue 实现
└── wait_queue.rs
关键约定:
lib.rs:使用cfg_if!和#[cfg(feature = "...")]进行条件编译,通过pub use向外暴露公共 APIapi.rs:存放面向应用的公共函数,如spawn(),sleep(),yield_now()- init 函数:模块暴露
init_*()函数,由axruntime::rust_main()在启动时根据 feature 配置调用
典型的 init 调用链(axruntime 中):
// axruntime/src/lib.rs (简化)
pub unsafe fn rust_main() {
ax_log::init();
ax_hal::platform_init();
#[cfg(feature = "alloc")]
ax_alloc::init();
#[cfg(feature = "paging")]
ax_mm::init();
#[cfg(feature = "multitask")]
ax_task::init_scheduler();
#[cfg(feature = "fs-ng")]
ax_fs_ng::init_filesystems(/* ... */);
#[cfg(feature = "net-ng")]
ax_net_ng::init_network(/* ... */);
// ...
main();
}
3.2 开发一个新模块
假设要添加 axmymod 模块,步骤如下:
1) 创建目录和文件
os/arceos/modules/axmymod/
├── Cargo.toml
└── src/
├── lib.rs
└── api.rs
2) 编写 Cargo.toml
[package]
name = "ax-mymod"
version.workspace = true
edition.workspace = true
[dependencies]
ax-feat = { path = "../../api/axfeat" }
log = "0.4"
[features]
default = []
myfeature = []
3) 编写 lib.rs
#![no_std]
extern crate log;
mod api;
pub use api::*;
4) 编写 api.rs,暴露 init 函 数和公共 API
use log::info;
pub fn init() {
info!("axmymod initialized.");
}
pub fn do_something() -> i32 {
42
}
5) 在 axruntime 中接入 init 调用
在 os/arceos/modules/axruntime/src/lib.rs 的 rust_main() 中添加:
#[cfg(feature = "mymod")]
ax_mymod::init();
6) 在 axfeat 中注册 feature
在 os/arceos/api/axfeat/Cargo.toml 中添加:
[features]
mymod = ["dep:ax-mymod", "ax-runtime/mymod"]
[dependencies]
ax-mymod = { path = "../../modules/axmymod", optional = true }
7) 验证
cargo xtask arceos qemu --package ax-helloworld --arch aarch64 --features mymod
3.3 Feature 驱动编译
ArceOS 的核心设计是 feature 聚合:应用在 Cargo.toml 中声明需要的 feature,axfeat 将它们传播到对应模块。
axfeat 中的 feature 定义示例(简化):
[features]
# CPU
smp = ["alloc", "ax-hal/smp", "ax-runtime/smp", "ax-task?/smp"]
fp-simd = ["ax-hal/fp-simd"]
# 内存
alloc = ["ax-alloc", "ax-runtime/alloc"]
paging = ["alloc", "ax-hal/paging", "ax-runtime/paging"]
# 任务
multitask = ["alloc", "ax-task/multitask", "ax-sync/multitask", "ax-runtime/multitask"]
sched-fifo = ["ax-task/sched-fifo"]
sched-rr = ["ax-task/sched-rr", "irq"]
sched-cfs = ["ax-task/sched-cfs", "irq"]
# 上层协议栈
fs = ["alloc", "paging", "ax-driver/virtio-blk", "dep:ax-fs", "ax-runtime/fs"]
net = ["alloc", "paging", "ax-driver/virtio-net", "dep:ax-net", "ax-runtime/net"]
这意味着:
- 启用
smp会自动启用alloc并传播到ax-hal、ax-runtime、ax-task - 启用
net会自动拉起 alloc + paging + virtio-net 驱动 + ax-net 模块 - 应用只需关心自身需要的功能,不需要了解底层模块的依赖图
3.4 修改已有模块
修改已有模块时的推荐流程:
| 改动类型 | 验证命令 | 扩展验证 |
|---|---|---|
基础 crate(axerrno, kspin, page_table_multiarch) | cargo test -p <crate> | cargo xtask arceos qemu --package ax-helloworld --arch riscv64 |
HAL(axhal) | cargo xtask arceos qemu --package ax-helloworld --arch aarch64 | 多架构验证 |
调度器(axtask) | cargo xtask arceos qemu --package ax-helloworld --arch riscv64 | cargo xtask arceos test qemu --target riscv64gc-unknown-none-elf |
网络(axnet / axnet-ng) | cargo xtask arceos qemu --package ax-httpserver --arch aarch64 --net | 检查 TCP 连接和吞吐 |
文件系统(axfs / axfs-ng) | cargo xtask arceos qemu --package ax-shell --arch aarch64 --blk | 检查文件读写 |
驱动(axdriver) | cargo xtask arceos qemu --package ax-helloworld --arch aarch64 | 启用对应设备 --blk / --net |
4. 应用开发
4.1 新增 Rust 示例应用
1) 创建目录和文件
os/arceos/examples/myapp/
├── Cargo.toml
└── src/
└── main.rs
2) Cargo.toml
[package]
name = "myapp"
version = "0.1.0"
edition.workspace = true
[dependencies]
ax-std.workspace = true
3) src/main.rs
#![cfg_attr(any(feature = "ax-std", target_os = "none"), no_std)]
#![cfg_attr(any(feature = "ax-std", target_os = "none"), no_main)]
// 条件 编译宏:仅在目标平台编译 app 代码
#[cfg(any(not(target_os = "none"), feature = "ax-std"))]
macro_rules! app { ($($item:item)*) => { $($item)* }; }
#[cfg(not(any(not(target_os = "none"), feature = "ax-std")))]
macro_rules! app { ($($item:item)*) => {}; }
app! {
#[cfg(feature = "ax-std")]
use ax_std::println;
#[cfg_attr(feature = "ax-std", unsafe(no_mangle))]
fn main() {
println!("Hello from myapp!");
}
}
所有 Rust 示例都使用相同的
app!宏模式来处理条件编译。
4) 验证
cargo xtask arceos qemu --package myapp --arch aarch64