本帖最后由 susutata 于 2024-11-10 20:20 编辑
#申请原创# @21小跑堂
利用 Kconfig 实现APM32项目的可视化配置
## 01 前言 最早接触到 `Kconfig` 文件是在使用 `ESP32` 的时候,`ESP-IDF` 的配置文件就是使用 `Kconfig` 文件来进行配置的。后来发现在 `linux` 、`RT-Thread` 和 `Zephyr` 等项目中也有使用到 `Kconfig` 来进行项目配置。可以看出 `Kconfig` 在嵌入式领域大型项目中有着广泛的应用。
从实际项目开发的角度来看,会经常需去使能或者关闭某些功能、修改一些参数,这些参数可能会影响到代码的编译、运行、功能等。如果这些参数是直接写在代码中的,那么每次修改参数都需要修改代码,然后重新编译,这样的效率是非常低的。而使用 `Kconfig` 文件来进行配置,可以在不修改代码的情况下,通过配置文件来修改参数,然后重新编译即可。
这里举两个使用场景来说明如果没有用 `Kconfig` 文件来进行配置,一般会怎么做。
### 预编译场景 在命令行中通过 `-D` 宏定义来控制代码的编译,例如: gcc -DCONFIG_FEATURE_A -DCONFIG_PARAM_B=100
#define CONFIG_FEATURE_A
#define CONFIG_PARAM_B 100
### 代码条件编译场景 在代码中通过 `#ifdef` 来控制代码的编译,例如:#define CONFIG_FEATURE_A
#ifdef CONFIG_FEATURE_A
// do something
#endif
上面的两种方式在小型项目中还是可以接受的,但是在大型项目中,当参数很多时,这样的方式就会变得非常不方便,且不直观。而 `Kconfig` 就是为了解决这个问题而生的工具。
## 02 Kconfig 环境搭建 推荐使用 `python` 来安装 [Kconfiglib](https://pypi.org/project/kconfiglib) ,同时还要用到 `menuconfig` 来进行可视化配置。要注意的是,在 `windows` 下使用 `menuconfig` 还需要安装 `curses` 库。
python -m pip install windows-curses
python -m pip install kconfiglib
安装完成后,可以使用以下命令来检查 `Kconfig` 和 `menuconfig` 的安装情况:
PS E:\workspaces\Project\github\embedded\omni-sdk> pip show Kconfiglib
Name: kconfiglib
Version: 14.1.0
Summary: A flexible Python Kconfig implementation
Home-page: https://github.com/ulfalizer/Kconfiglib
Author: Ulf "Ulfalizer" Magnusson
Author-email: ulfalizer@gmail.com
License: ISC
Location: c:\users\lin\appdata\local\programs\python\python39\lib\site-packages
Requires:
Required-by:
PS E:\workspaces\Project\github\embedded\omni-sdk> menuconfig -h
usage: menuconfig [-h] [KCONFIG]
Overview
========
A curses-based Python 2/3 menuconfig implementation. The interface should feel
familiar to people used to mconf ('make menuconfig').
Supports the same keys as mconf, and also supports a set of keybindings
inspired by Vi:
J/K : Down/Up
L : Enter menu/Toggle item
H : Leave menu
Ctrl-D/U: Page Down/Page Up
G/End : Jump to end of list
g/Home : Jump to beginning of list
环境搭建完成后,就可以利用 `Kconfig` 来生成 `.config` 配置文件,但是这个文件的内容还需要转换为宏定义才能被 C 语言项目用来进行配置。
`.config` 文件格式:
#
# Components
#
# CONFIG_COMPONENT_CONSOLE is not set
# CONFIG_COMPONENT_CHERRYUSB is not set
# end of Components
# CONFIG_OMNI_DRIVER is not set
#
# Libraries
#
# CONFIG_U8G2 is not set
# CONFIG_SEGGER_RTT is not set
# CONFIG_SHELL_LETTER is not set
CONFIG_RTOS_NONE=y
# CONFIG_RTOS_CMSIS_RTX is not set
# CONFIG_RTOS_CMSIS_FREERTOS is not set
# CONFIG_RTOS_THREADX is not set
CONFIG_USB_NONE=y
# CONFIG_USB_CHERRYUSB is not set
# CONFIG_USB_STM32 is not set
# end of Libraries
可以编写一个 `Python` 脚本调用 `class Kconfig` 中的 `write_autoconf()` 方法来生成 `autoconf.h` 文件。推荐直接使用 `zephyr` 项目中的 `kconfig.py` 脚本。
- `kconfig_file`:顶层 `Kconfig` 文件的路径
- `config_out`:生成 `.config` 文件的路径
- `header_out`:生成 `xxx.h` C 语言头文件的路径
- `kconfig_list_out`:日志输出文件的路径
- `config_in`:配置片段文件
## 03 Kconfig 基本应用 这里不展开介绍 `Kconfig` 的语法,感兴趣的读者可以查看 `linux` 的 [Kconfig-language](https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt) 文档。
下面以搭建 `APM32` 项目为例,展示如何使用 `CMake` + `ARM GCC` + `Kconfig` 来进行项目配置。在开始之前,需要先安装 `CMake` 和 `ARM GCC` 工具链。之前的文章中已经介绍过如何安装这两个工具,这里就不再赘述。
下载 [apm32-kconfig-example](https://github.com/LuckkMaker/apm32-kconfig-example) 后打开目录可以找到顶层的 `Kconfig` 文件。
`Kconfig` :
配置项目名称、版本、`LED` 闪烁、闪烁间隔等配置。
mainmenu "APM32 Project Configuration"
config PROJECT_NAME
string
prompt "Project Name"
default "apm32-project"
help
"The name of the project. This will be used to name the output files."
config PROJECT_VERSION
string
prompt "Project Version"
default "0.0.1"
help
"The version of the project."
choice
prompt "LED Toggle"
default LED1_TOGGLE
config LED1_TOGGLE
bool "LED1"
help
"Enable LED toggle functionality."
config LED2_TOGGLE
bool "LED2"
help
"Enable LED toggle functionality."
endchoice
config LED_TOGGLE_INTERVAL
int
prompt "LED Toggle Interval"
default 500
help
"The interval at which LED will toggle."
`main.c` :
引用 `autoconf.h` 文件,根据配置文件中的配置来控制代码 `LED` 的闪烁及闪烁间隔。
#include "main.h"
#include "autoconf.h"
int main(void)
{
/* Device configuration */
DAL_DeviceConfig();
/* Infinite loop */
while (1)
{
#if defined(CONFIG_LED1_TOGGLE)
DAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);
#else
DAL_GPIO_TogglePin(GPIOE, GPIO_PIN_6);
#endif /* CONFIG_LED1_TOGGLE */
DAL_Delay(CONFIG_LED_TOGGLE_INTERVAL);
}
}
在终端输入 `menuconfig` 命令,可以看到如下界面:
如果不更改配置可以输入 `Q` 退出并保存配置,`Kconfig` 文件目录下会生成 `.config` 文件,内容如下:
CONFIG_PROJECT_NAME="apm32-project"
CONFIG_PROJECT_VERSION="0.0.1"
CONFIG_LED1_TOGGLE=y
# CONFIG_LED2_TOGGLE is not set
CONFIG_LED_TOGGLE_INTERVAL=500
有了该文件后,就可以使用 `Python` 脚本来生成 `autoconf.h` 文件,命令如下:
python tools/python/kconfig.py Kconfig .config autoconf.h kconfigLog.txt .config
生成的 `autoconf.h` 文件内容如下:
#define CONFIG_PROJECT_NAME "apm32-project"
#define CONFIG_PROJECT_VERSION "0.0.1"
#define CONFIG_LED1_TOGGLE 1
#define CONFIG_LED_TOGGLE_INTERVAL 500
这样就可以在代码中使用这些宏定义来控制代码的编译。
## 04 Kconfig 进阶应用 当项目越来越大时,可能会有多个`App` 例程共用一个模块但配置需求又不一样的情况。还是例如上面的例子,如果有两个 `App` 例程,一个需要 `LED1` 闪烁,另一个需要 `LED2` 闪烁,这时就需要用到 `prj.conf` 文件来进行配置。
-app1
-prj.conf
-main.c
-app2
-prj.conf
-main.c
-Kconfig
`app1/prj.conf` :
CONFIG_LED2_TOGGLE=y
CONFIG_LED_TOGGLE_INTERVAL=500
`app2/prj.conf` :
CONFIG_LED1_TOGGLE=y
CONFIG_LED_TOGGLE_INTERVAL=1000
在 `apm32-kconfig-example` 项目中使用下面的命令来根据 `prj.conf` 文件生成 `autoconf.h` 文件:
python tools/python/kconfig.py --handwritten-input-configs Kconfig .config autoconf.h kconfigLog.txt .config application/prj.conf
`prj.conf` :
CONFIG_LED2_TOGGLE=y
CONFIG_LED_TOGGLE_INTERVAL=500
`autoconf.h` :
#define CONFIG_PROJECT_NAME "apm32-project"
#define CONFIG_PROJECT_VERSION "0.0.1"
#define CONFIG_LED2_TOGGLE 1
#define CONFIG_LED_TOGGLE_INTERVAL 500
这样就可以根据不同的 `App` 例程来生成不同的 `autoconf.h` 文件,从而实现不同的配置。
本文使用的例子可以在 [apm32-kconfig-example](https://github.com/LuckkMaker/apm32-kconfig-example) 获取。
想要更多构建应用例子可以在 [omni-sdk](https://github.com/LuckkMaker/omni-sdk) 找到。
|