1。新增双语文档。
This commit is contained in:
208
document/Kconfig/Kconfig.md
Normal file
208
document/Kconfig/Kconfig.md
Normal file
@@ -0,0 +1,208 @@
|
||||
# 如何为项目引入Kconfig配置系统
|
||||
|
||||
[English](Kconfig_EN.md)
|
||||
|
||||
<!-- TOC -->
|
||||
* [如何为项目引入Kconfig配置系统](#如何为项目引入kconfig配置系统)
|
||||
* [验证 python 环境](#验证-python-环境)
|
||||
* [C语言头文件生成脚本](#c语言头文件生成脚本)
|
||||
* [应用](#应用)
|
||||
* [创建Kconfig](#创建kconfig)
|
||||
<!-- TOC -->
|
||||
|
||||
项目中经常会有通过宏配置或选择参数:
|
||||
|
||||
```c
|
||||
#ifdef CFG_ENABLE
|
||||
#define CFG_ARGS "test"
|
||||
void printf_args(void)
|
||||
{
|
||||
printf("args: %s\n", CFG_ARGS);
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
当项目规模较小,配置项和依赖关系相对简单时,我们可以通过手动修改源代码来实现配置功能。但是,随着项目规模的增长和配置复杂度的增加,这种方式也会出现一些问题。
|
||||
|
||||
随着代码体量和调用关系的增多,对配置者来说`很难完全熟悉`
|
||||
代码结构及各模块之间的依赖关系。同时,如果配置项设置较为`随意且缺乏约束`,也很可能导致`错误配置`。这对项目质量和维护都带来一定难度。
|
||||
|
||||
对于规模较大的项目来说,需要一套专业的配置管理系统来解决这些问题。Kconfig正是为了应对这种需求而产生的。它通过配置脚本定义各配置选项及其依赖关系,并提供`图形化界面`
|
||||
供配置者操作。同时还会检查配置`合理性`,帮助我们实现定制化构建的同时`防止错误配置`。
|
||||
|
||||
如果有接触过Linux或者RT-Thread等,相信对Kconfig系统都不陌生。Kconfig是Linux内核和许多其他系统广泛使用的一款配置管理工具。它可以让开发人员在编译时选择性地包含或排除某些功能模块。
|
||||
|
||||
Kconfig使用配置脚本定义各种配置选项及其依赖关系。通过图形或字符型用户界面,开发者可以查看并设置各种配置。然后Kconfig会生成 `.config`
|
||||
文件保存选择结果。在编译的时候,会根据 `.config` 文件里设置的符号自动包含或排除对应的源代码。
|
||||
|
||||

|
||||
|
||||
## 验证 python 环境
|
||||
|
||||
Kconfig依赖于 ` python` ,如果没有 ` python` 环境请自行安装。
|
||||
|
||||
在命令行中使用所示命令验证:
|
||||
|
||||
```cmd
|
||||
python --version
|
||||
```
|
||||
|
||||
显示(正确显示版本即可):
|
||||
|
||||
```cmd
|
||||
Python 3.11.4
|
||||
```
|
||||
|
||||
## C语言头文件生成脚本
|
||||
|
||||
Kconfiglib 生成的是 `.config` 文件,并非C语言文件,需要使用脚本生成,`将以下代码复制到文件中并命名为kconfig.py`。
|
||||
|
||||
```python
|
||||
import re
|
||||
import pip
|
||||
|
||||
|
||||
def log_print(level, text):
|
||||
# Log level colors
|
||||
LEVEL_COLORS = {
|
||||
'error': '\033[31m',
|
||||
'success': '\033[32m',
|
||||
'warning': '\033[33m',
|
||||
'info': '\033[34m',
|
||||
}
|
||||
RESET_COLOR = '\033[0m'
|
||||
# Log level name
|
||||
LEVEL_NAME = {
|
||||
'error': 'ERROR',
|
||||
'success': 'SUCCESS',
|
||||
'warning': 'WARNING',
|
||||
'info': 'INFO',
|
||||
}
|
||||
print(LEVEL_COLORS[level] + LEVEL_NAME[level] + ': ' + text + RESET_COLOR)
|
||||
|
||||
|
||||
def install_package(package):
|
||||
log_print('info', "%s package installing..." % package)
|
||||
pip.main(['install', package])
|
||||
|
||||
|
||||
try:
|
||||
from kconfiglib import Kconfig
|
||||
except ImportError:
|
||||
install_package('kconfiglib')
|
||||
from kconfiglib import Kconfig
|
||||
|
||||
try:
|
||||
import curses
|
||||
except ImportError:
|
||||
install_package('windows-curses')
|
||||
import curses
|
||||
|
||||
|
||||
def generate_config(kconfig_file, config_in, config_out, header_out):
|
||||
kconf = Kconfig(kconfig_file, warn=False, warn_to_stderr=False)
|
||||
|
||||
# Load config
|
||||
kconf.load_config(config_in)
|
||||
kconf.write_config(config_out)
|
||||
kconf.write_autoconf(header_out)
|
||||
|
||||
with open(header_out, 'r+') as header_file:
|
||||
content = header_file.read()
|
||||
header_file.truncate(0)
|
||||
header_file.seek(0)
|
||||
|
||||
# Remove CONFIG_ and MR_USING_XXX following number
|
||||
content = content.replace("#define CONFIG_", "#define ")
|
||||
content = re.sub(r'#define MR_USING_(\w+) (\d+)', r'#define MR_USING_\1', content)
|
||||
|
||||
# Add the micro
|
||||
header_file.write("#ifndef _MR_CONFIG_H_\n")
|
||||
header_file.write("#define _MR_CONFIG_H_\n\n")
|
||||
|
||||
header_file.write("#ifdef __cplusplus\n")
|
||||
header_file.write("extern \"C\" {\n")
|
||||
header_file.write("#endif /* __cplusplus */\n\n")
|
||||
|
||||
# Write back the original data
|
||||
header_file.write(content)
|
||||
|
||||
# Add the micro
|
||||
header_file.write("\n#ifdef __cplusplus\n")
|
||||
header_file.write("}\n")
|
||||
header_file.write("#endif /* __cplusplus */\n\n")
|
||||
header_file.write("#endif /* _MR_CONFIG_H_ */\n")
|
||||
|
||||
header_file.close()
|
||||
log_print('success', "menuconfig %s make success" % header_out)
|
||||
|
||||
|
||||
def main():
|
||||
kconfig_file = ''
|
||||
config_in = '.config'
|
||||
config_out = '.config'
|
||||
header_out = 'config.h'
|
||||
generate_config(kconfig_file, config_in, config_out, header_out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
修改`main`函数中`header_out `可修改生成的函数文件名。
|
||||
|
||||
此脚本去除了Kconfig默认添加的`CONFIG_`前缀,并为其加上了`_CONFIG_H_` 和`C`声明。
|
||||
|
||||
# 应用
|
||||
|
||||
## 创建Kconfig
|
||||
|
||||
新建一个名字为 `Kconfig` 的文件(注意没有后缀名),和上一步中中创建的 `kconfig.py` 的文件放在一起。
|
||||
|
||||
```Kconfig
|
||||
mainmenu "Demo"
|
||||
|
||||
menu "Args configure"
|
||||
config CFG_ARG1
|
||||
bool "Enable arg1"
|
||||
default n
|
||||
|
||||
config CFG_ARG2
|
||||
int "Arg2 number"
|
||||
default 8
|
||||
range 0 64
|
||||
|
||||
endmenu
|
||||
```
|
||||
|
||||
在当前目录下调用命令行,输入:
|
||||
|
||||
```cmd
|
||||
menuconfig
|
||||
```
|
||||
|
||||
就可以看到我们刚刚写的Demo界面
|
||||
|
||||

|
||||
|
||||
回车后就可以看到配置的2个参数:
|
||||
|
||||

|
||||
|
||||
设置的范围也在输入时生效了:
|
||||
|
||||

|
||||
|
||||
配置完成后按`Q`退出,`Y`保存配置。
|
||||
|
||||
在当前目录下调用命令行,输入:
|
||||
|
||||
```cmd
|
||||
python kconfig.py
|
||||
```
|
||||
|
||||
运行 `python` 脚本生成`.h`文件。
|
||||
|
||||
显示生成`config.h`成功。打开这个文件:
|
||||
|
||||

|
||||
219
document/Kconfig/Kconfig_EN.md
Normal file
219
document/Kconfig/Kconfig_EN.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# How to introduce the Kconfig configuration system into a project
|
||||
|
||||
[中文](Kconfig.md)
|
||||
|
||||
<!-- TOC -->
|
||||
* [How to introduce the Kconfig configuration system into a project](#how-to-introduce-the-kconfig-configuration-system-into-a-project)
|
||||
* [Verify Python Environment](#verify-python-environment)
|
||||
* [C Header File Generation Script](#c-header-file-generation-script)
|
||||
* [Application](#application)
|
||||
* [Create Kconfig](#create-kconfig)
|
||||
<!-- TOC -->
|
||||
|
||||
There are often macro configurations or parameter selections in projects:
|
||||
|
||||
```c
|
||||
#ifdef CFG_ENABLE
|
||||
#define CFG_ARGS "test"
|
||||
void printf_args(void)
|
||||
{
|
||||
printf("args: %s\n", CFG_ARGS);
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
When the project scale is relatively small and the dependency relationships are relatively simple, we can manually
|
||||
modify the source code to implement configuration functions. However, as the project scale increases and configuration
|
||||
complexity increases, this approach will also have some problems.
|
||||
|
||||
As the code volume and call relations increase, it becomes `difficult` for configurers to fully understand
|
||||
the `code structure` and dependencies between modules. At the same time, if the configuration items are set in
|
||||
a `casual` and `lack of constraints` manner, it is also very likely to lead to `incorrect configuration`. This brings
|
||||
certain difficulties to project quality and maintenance.
|
||||
|
||||
For large-scale projects, a professional configuration management system is needed to solve these problems. Kconfig is
|
||||
designed to address this need. It defines various configuration options and their dependencies through configuration
|
||||
scripts, and provides a `graphical interface` for configurers to operate. It also checks the `rationality` of
|
||||
configurations to help us achieve customized builds while `preventing incorrect configurations`.
|
||||
|
||||
If you have experience with the Linux or RT-Thread, Kconfig system should not be unfamiliar. Kconfig is a widely used
|
||||
configuration management tool in Linux kernel and many other systems. It allows
|
||||
developers to selectively include or exclude some functional modules during compilation.
|
||||
|
||||
Kconfig uses configuration scripts to define various configuration options and their dependencies. Through graphical or
|
||||
character-based user interfaces, developers can view and set various configurations. Then Kconfig will generate
|
||||
a `.config` file to save the selection results. During compilation, it will automatically include or exclude the
|
||||
corresponding source code according to the settings in the `.config` file.
|
||||
|
||||

|
||||
|
||||
## Verify Python Environment
|
||||
|
||||
Kconfig depends on `python`. If there is no `python` environment, please install it yourself.
|
||||
Use the following command in the command line to verify:
|
||||
|
||||
```cmd
|
||||
python --version
|
||||
```
|
||||
|
||||
Display (Correctly displaying the version is okay):
|
||||
|
||||
```cmd
|
||||
Python 3.11.4
|
||||
```
|
||||
|
||||
## C Header File Generation Script
|
||||
|
||||
Kconfiglib generates a `.config` file instead of a C language file. A script is needed to generate header
|
||||
files. `Copy the following code to a file and name it kconfig.py.`
|
||||
|
||||
```python
|
||||
import re
|
||||
import pip
|
||||
|
||||
|
||||
def log_print(level, text):
|
||||
# Log level colors
|
||||
LEVEL_COLORS = {
|
||||
'error': '\033[31m',
|
||||
'success': '\033[32m',
|
||||
'warning': '\033[33m',
|
||||
'info': '\033[34m',
|
||||
}
|
||||
RESET_COLOR = '\033[0m'
|
||||
# Log level name
|
||||
LEVEL_NAME = {
|
||||
'error': 'ERROR',
|
||||
'success': 'SUCCESS',
|
||||
'warning': 'WARNING',
|
||||
'info': 'INFO',
|
||||
}
|
||||
print(LEVEL_COLORS[level] + LEVEL_NAME[level] + ': ' + text + RESET_COLOR)
|
||||
|
||||
|
||||
def install_package(package):
|
||||
log_print('info', "%s package installing..." % package)
|
||||
pip.main(['install', package])
|
||||
|
||||
|
||||
try:
|
||||
from kconfiglib import Kconfig
|
||||
except ImportError:
|
||||
install_package('kconfiglib')
|
||||
from kconfiglib import Kconfig
|
||||
|
||||
try:
|
||||
import curses
|
||||
except ImportError:
|
||||
install_package('windows-curses')
|
||||
import curses
|
||||
|
||||
|
||||
def generate_config(kconfig_file, config_in, config_out, header_out):
|
||||
kconf = Kconfig(kconfig_file, warn=False, warn_to_stderr=False)
|
||||
|
||||
# Load config
|
||||
kconf.load_config(config_in)
|
||||
kconf.write_config(config_out)
|
||||
kconf.write_autoconf(header_out)
|
||||
|
||||
with open(header_out, 'r+') as header_file:
|
||||
content = header_file.read()
|
||||
header_file.truncate(0)
|
||||
header_file.seek(0)
|
||||
|
||||
# Remove CONFIG_ and MR_USING_XXX following number
|
||||
content = content.replace("#define CONFIG_", "#define ")
|
||||
content = re.sub(r'#define MR_USING_(\w+) (\d+)', r'#define MR_USING_\1', content)
|
||||
|
||||
# Add the micro
|
||||
header_file.write("#ifndef _MR_CONFIG_H_\n")
|
||||
header_file.write("#define _MR_CONFIG_H_\n\n")
|
||||
|
||||
header_file.write("#ifdef __cplusplus\n")
|
||||
header_file.write("extern \"C\" {\n")
|
||||
header_file.write("#endif /* __cplusplus */\n\n")
|
||||
|
||||
# Write back the original data
|
||||
header_file.write(content)
|
||||
|
||||
# Add the micro
|
||||
header_file.write("\n#ifdef __cplusplus\n")
|
||||
header_file.write("}\n")
|
||||
header_file.write("#endif /* __cplusplus */\n\n")
|
||||
header_file.write("#endif /* _MR_CONFIG_H_ */\n")
|
||||
|
||||
header_file.close()
|
||||
log_print('success', "menuconfig %s make success" % header_out)
|
||||
|
||||
|
||||
def main():
|
||||
kconfig_file = ''
|
||||
config_in = '.config'
|
||||
config_out = '.config'
|
||||
header_out = 'config.h'
|
||||
generate_config(kconfig_file, config_in, config_out, header_out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
Modify `header_out` in the `main` function to modify the generated function file name.
|
||||
|
||||
This script removes the `CONFIG_` prefix added by Kconfig by default and adds `_CONFIG_H_` and `C` declarations to it.
|
||||
|
||||
# Application
|
||||
|
||||
## Create Kconfig
|
||||
|
||||
Create a new file named `Kconfig` (without extension), and put it together with the `kconfig.py` file created in the
|
||||
previous step.
|
||||
|
||||
```Kconfig
|
||||
mainmenu "Demo"
|
||||
|
||||
menu "Args configure"
|
||||
config CFG_ARG1
|
||||
bool "Enable arg1"
|
||||
default n
|
||||
|
||||
config CFG_ARG2
|
||||
int "Arg2 number"
|
||||
default 8
|
||||
range 0 64
|
||||
|
||||
endmenu
|
||||
```
|
||||
|
||||
Call menuconfig in the command line:
|
||||
|
||||
```cmd
|
||||
menuconfig
|
||||
```
|
||||
|
||||
Configure and generate header file.
|
||||
|
||||

|
||||
|
||||
Press enter, you can see the two parameters configured:
|
||||
|
||||

|
||||
|
||||
The range of Settings also takes effect when entering:
|
||||
|
||||

|
||||
|
||||
After the configuration is complete, press `Q` to exit and `Y` to save the configuration.
|
||||
|
||||
In the current directory, call up the command line and type:
|
||||
|
||||
```cmd
|
||||
python kconfig.py
|
||||
```
|
||||
|
||||
Run the `python` script to generate the `.h` file.
|
||||
|
||||
The `config.h` is successfully generated. Open this file:
|
||||
|
||||

|
||||
Reference in New Issue
Block a user