Skip to content

Commit

Permalink
Kconfig (#432)
Browse files Browse the repository at this point in the history
* 内核编译配置

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

* 将设置feature函数放入CargoHandler中
  • Loading branch information
Jomocool authored Nov 17, 2023
1 parent 11f78b7 commit e4600f7
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 2 deletions.
3 changes: 2 additions & 1 deletion build-scripts/kernel_build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
195 changes: 195 additions & 0 deletions build-scripts/kernel_build/src/kconfig/mod.rs
Original file line number Diff line number Diff line change
@@ -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()
}
}
2 changes: 2 additions & 0 deletions build-scripts/kernel_build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ extern crate cc;

mod bindgen;
mod cfiles;
mod kconfig;
mod utils;

/// 运行构建
Expand All @@ -12,4 +13,5 @@ pub fn run() {

crate::bindgen::generate_bindings();
crate::cfiles::CFilesBuilder::build();
crate::kconfig::KConfigBuilder::build();
}
15 changes: 15 additions & 0 deletions build-scripts/kernel_build/src/utils/cargo_handler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::{env, path::PathBuf};

use crate::kconfig::Feature;

lazy_static! {
static ref CARGO_HANDLER_DATA: CargoHandlerData = CargoHandlerData::new();
}
Expand Down Expand Up @@ -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());
}
}
}
}

/// 目标架构
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
kernel/ktest/index
kernel/cpu_arch/index
kernel/libs/index
kernel/configuration/index


.. toctree::
Expand Down
105 changes: 105 additions & 0 deletions docs/kernel/configuration/config.md
Original file line number Diff line number Diff line change
@@ -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
```
9 changes: 9 additions & 0 deletions docs/kernel/configuration/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
内核编译配置
====================================


.. toctree::
:maxdepth: 1
:caption: 目录

config
1 change: 1 addition & 0 deletions kernel/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
target/
src/kernel
Cargo.lock
D.config

# 将自动生成的C-Rust FFI加到gitignore
src/include/bindings/bindings.rs
Expand Down
2 changes: 1 addition & 1 deletion kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit e4600f7

Please sign in to comment.