mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
Kconfig (#432)
* 内核编译配置 * 将kernel.config的解析代码搬入crate * 将设置feature函数放入CargoHandler中
This commit is contained in:
parent
11f78b73e7
commit
e4600f7f7d
@ -9,3 +9,4 @@ edition = "2021"
|
||||
bindgen = "0.61.0"
|
||||
lazy_static = "1.4.0"
|
||||
cc = { version = "1.0.83", features = ["parallel"] }
|
||||
toml = "0.8.6"
|
195
build-scripts/kernel_build/src/kconfig/mod.rs
Normal file
195
build-scripts/kernel_build/src/kconfig/mod.rs
Normal 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()
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 目标架构
|
||||
|
@ -30,6 +30,7 @@
|
||||
kernel/ktest/index
|
||||
kernel/cpu_arch/index
|
||||
kernel/libs/index
|
||||
kernel/configuration/index
|
||||
|
||||
|
||||
.. toctree::
|
||||
|
105
docs/kernel/configuration/config.md
Normal file
105
docs/kernel/configuration/config.md
Normal file
@ -0,0 +1,105 @@
|
||||
# 内核编译配置说明
|
||||
|
||||
## 原理
|
||||
|
||||
  在内核目录下,用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
docs/kernel/configuration/index.rst
Normal file
9
docs/kernel/configuration/index.rst
Normal file
@ -0,0 +1,9 @@
|
||||
内核编译配置
|
||||
====================================
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: 目录
|
||||
|
||||
config
|
1
kernel/.gitignore
vendored
1
kernel/.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
target/
|
||||
src/kernel
|
||||
Cargo.lock
|
||||
D.config
|
||||
|
||||
# 将自动生成的C-Rust FFI加到gitignore
|
||||
src/include/bindings/bindings.rs
|
||||
|
Loading…
x
Reference in New Issue
Block a user