* 内核编译配置

* 将kernel.config的解析代码搬入crate

* 将设置feature函数放入CargoHandler中
This commit is contained in:
Jomo 2023-11-17 21:23:01 +08:00 committed by GitHub
parent 11f78b73e7
commit e4600f7f7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 331 additions and 2 deletions

View File

@ -8,4 +8,5 @@ edition = "2021"
[dependencies]
bindgen = "0.61.0"
lazy_static = "1.4.0"
cc = { version = "1.0.83", features = ["parallel"] }
cc = { version = "1.0.83", features = ["parallel"] }
toml = "0.8.6"

View File

@ -0,0 +1,195 @@
use std::{fs, io::Write, path::PathBuf};
use toml::Value;
use crate::utils::cargo_handler::CargoHandler;
/// 内核编译配置的构建器
pub struct KConfigBuilder;
impl KConfigBuilder {
pub fn build() {
// 如果存在kernel.config才去解析
if fs::metadata("kernel.config").is_ok() {
// 获取kernel.config所包含的模块
let modules = ConfigParser::parse_kernel_config();
// 扫描各模块下以及其包含模块的d.config然后将所有d.config路径添加到r中
let mut r = Vec::new();
for m in modules.iter() {
if m.enable() {
Self::dfs(m, &mut r);
}
}
// 扫描所有d.config以获取features
let features = ConfigParser::parse_d_configs(&r);
// 添加feature
CargoHandler::emit_features(features.as_slice());
// 生成最终内核编译配置文件D.config
Self::make_compile_cfg(&features);
}
}
/// 生成最终编译配置文件D.config
fn make_compile_cfg(features: &Vec<Feature>) {
let mut cfg_content = String::new();
for f in features.iter() {
if f.enable() {
cfg_content.push_str(&format!("{} = y\n", f.name()));
} else {
cfg_content.push_str(&format!("{} = n\n", f.name()));
}
}
let mut file = fs::File::create("D.config").expect("Failed to create file: D.config");
file.write_all(cfg_content.as_bytes())
.expect("Failed to write D.config");
}
/// 递归找所有模块下的d.config文件路径
///
/// ## 参数
///
/// `module` - 当前模块
/// `r` - 保存所有d.config文件路径
/// ## 返回值
///
/// 无
fn dfs(module: &Module, r: &mut Vec<PathBuf>) {
println!("{}", module.name());
let path_str = module.path().as_path().to_str().unwrap().to_string();
let d_config_str = format!("{}/d.config", path_str);
let d_config_path = PathBuf::from(&d_config_str);
let dcfg_content =
fs::read_to_string(&d_config_path).expect(&format!("Failed to read {}", d_config_str));
let m_include = ConfigParser::include(&dcfg_content);
for m in m_include.iter() {
if m.enable() {
Self::dfs(m, r);
}
}
r.push(d_config_path);
}
}
/// 内核编译配置文件解析器
struct ConfigParser;
impl ConfigParser {
/// 扫描kernel.config获取所包含的模块
pub fn parse_kernel_config() -> Vec<Module> {
let cfg_content =
fs::read_to_string("kernel.config").expect("Failed to read kernel.config.");
let r = Self::include(&cfg_content);
return r;
}
/// 扫描所有d.config以获取所有feature
pub fn parse_d_configs(d_configs: &Vec<PathBuf>) -> Vec<Feature> {
let mut r = Vec::new();
for d_config in d_configs.iter() {
r.extend(Self::parse_d_config(d_config));
}
return r;
}
/// 扫描当前d.config文件获取feature
pub fn parse_d_config(d_config: &PathBuf) -> Vec<Feature> {
let path_str = d_config.as_path().to_str().unwrap().to_string();
let dcfg_content =
fs::read_to_string(d_config).expect(&format!("Failed to read {}", path_str));
let dcfg_table: Value =
toml::from_str(&dcfg_content).expect(&format!("Failed to parse {}", path_str));
let mut r = Vec::new();
if let Some(features) = dcfg_table.get("module").unwrap().get("features") {
for f in features.as_array().unwrap().iter() {
let name = f.get("name").unwrap().as_str().unwrap().to_string();
let enable = f.get("enable").unwrap().as_str().unwrap().to_string() == "y";
r.push(Feature::new(name, enable));
}
}
return r;
}
/// 获取所包含的模块
///
/// ## 参数
///
/// `cfg_content` -配置文件内容
///
/// ## 返回值
///
/// 包含的模块集合
pub fn include(cfg_content: &str) -> Vec<Module> {
let cfg_table: Value = toml::from_str(&cfg_content).expect("Failed to parse kernel.config");
let mut r = Vec::new();
if let Some(include) = cfg_table.get("module").unwrap().get("include") {
for module in include.as_array().unwrap().iter() {
let name = module.get("name").unwrap().as_str().unwrap().to_string();
let path = PathBuf::from(module.get("path").unwrap().as_str().unwrap());
let enable = module.get("enable").unwrap().as_str().unwrap() == "y";
r.push(Module::new(name, path, enable));
}
}
return r;
}
}
/// 模块
struct Module {
/// 模块名
name: String,
/// 模块文件路径
path: PathBuf,
/// 是否启用
enable: bool,
}
impl Module {
pub fn new(name: String, path: PathBuf, enable: bool) -> Module {
Module { name, path, enable }
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn path(&self) -> PathBuf {
self.path.clone()
}
pub fn enable(&self) -> bool {
self.enable.clone()
}
}
/// feature
pub struct Feature {
/// feature标签名
name: String,
/// 是否启用
enable: bool,
}
impl Feature {
pub fn new(name: String, enable: bool) -> Feature {
Feature { name, enable }
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn enable(&self) -> bool {
self.enable.clone()
}
}

View File

@ -4,6 +4,7 @@ extern crate cc;
mod bindgen;
mod cfiles;
mod kconfig;
mod utils;
/// 运行构建
@ -12,4 +13,5 @@ pub fn run() {
crate::bindgen::generate_bindings();
crate::cfiles::CFilesBuilder::build();
crate::kconfig::KConfigBuilder::build();
}

View File

@ -1,5 +1,7 @@
use std::{env, path::PathBuf};
use crate::kconfig::Feature;
lazy_static! {
static ref CARGO_HANDLER_DATA: CargoHandlerData = CargoHandlerData::new();
}
@ -43,6 +45,19 @@ impl CargoHandler {
println!("cargo:rerun-if-changed={}", f.to_str().unwrap());
}
}
/// 添加features
///
/// ## Parameters
///
/// - `features` - The features to be set
pub fn emit_features(features: &[Feature]) {
for f in features.iter() {
if f.enable() {
println!("cargo:rustc-cfg=feature=\"{}\"", f.name());
}
}
}
}
/// 目标架构

View File

@ -30,6 +30,7 @@
kernel/ktest/index
kernel/cpu_arch/index
kernel/libs/index
kernel/configuration/index
.. toctree::

View File

@ -0,0 +1,105 @@
# 内核编译配置说明
## 原理
&emsp;&emsp;在内核目录下用kernel.config来设置内核编译配置信息以类似解析toml文件的方式去解析该文件然后接着去解析各模块下的d.config以获取feature的启用情况
## 示例
**kernel.config**
```toml
[[module.include]]
name = "init"
path = "src/init/"
enable = "y"
description = ""
[[module.include]]
name = "mm"
path = "src/mm/"
enable = "y"
description = ""
```
- **[[module.include]]:** 将模块加入到include列表中
- **name:** 模块名
- **path:** 模块路径存放着d.config
- **enable:**
- **y:** 启用解析模块下的d.config
- **n:** 不启用,不解析
- **description:** 模块的描述信息
**src/mm/d.config**
```toml
[module]
name = "mm"
description = ""
[[module.include]]
name = "allocator"
path = "src/mm/allocator/"
enable = "y"
description = ""
[[module.features]]
name = "mm_debug"
enable = "y"
description = ""
```
- **\[module\]:** 当前模块
- **name:** 当前模块名称
- **description:** 模块的描述信息
- **[[module.include]]:** 当前模块下所包含的模块与kernel.config下的相同
- **[[module.features]]:** 当前模块下的feature
- **name:** feature名
- **enable:** 是否开启
- **y:** 开启
- **n:** 不开启
- **description:** feature的描述信息
*以下是其它模块下的d.config*
**src/mm/allocator/d.config**
```toml
[module]
name = "allocator"
description = ""
[[module.features]]
name = "allocator_debug"
enable = "y"
description = ""
```
**src/init/d.config**
```toml
[module]
name = "init"
description = ""
[[module.features]]
name = "init_debug"
enable = "y"
description = ""
```
上面所有已开启模块的d.config中的feature会最终生成到内核目录下的D.config文件即D.config是最终内核编译的配置如下
**D.config**
```
init_debug = y
allocator_debug = y
mm_debug = y
```

View File

@ -0,0 +1,9 @@
内核编译配置
====================================
.. toctree::
:maxdepth: 1
:caption: 目录
config

1
kernel/.gitignore vendored
View File

@ -1,6 +1,7 @@
target/
src/kernel
Cargo.lock
D.config
# 将自动生成的C-Rust FFI加到gitignore
src/include/bindings/bindings.rs

View File

@ -64,4 +64,4 @@ debug = true # Controls whether the compiler passes `-g`
# The release profile, used for `cargo build --release`
[profile.release]
debug = false
debug = false