为prj添加kconfig支持
KConfig是一个配置系统,它允许用户和开发者通过配置文件/配置界面选择需要的编译选项。目前大量的项目都有用到该配置系统(linux、u-boot、rt-thread、esp-idf/adf、zephyr等),可以说是一个项目的构建系统中的不可缺少的重要组成部分。
目录
1 搭建KConfig环境
2 头文件生成脚本-kconfig.py
3 编写Kconfig文件
4 修改Makefile文件
1 搭建KConfig环境
KConfig是一个配置描述文件,通常在其对应的配置界面来进行操作配置(当然手动修改也可以,但很麻烦,容易漏)。 要解析该文件还需要有相应的工具,如menuconfig、nconfig、xconfig等,但这里我们选择python的kconfiglib库。
安装kconfiglib时可以采用如下方式:
windows环境:
python -m pip install windows-curses
python -m pip install kconfiglib
linux环境:
sudo apt-get update
sudo apt install python-pip
pip install kconfiglib
安装完成后通过’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
[Space] toggles values if possible, and enters menus otherwise. [Enter] works
the other way around.
The mconf feature where pressing a key jumps to a menu entry with that
character in it in the current menu isn't supported. A jump-to feature for
jumping directly to any symbol (including invisible symbols), choice, menu or
comment (as in a Kconfig 'comment "Foo"') is available instead.
2 头文件生成脚本-kconfig.py
使用Kconfiglib生成的是.config文件,而c代码要使用,必须要提供.h头文件,主要是通过kconfiglib中提供的class Kconfig的write_autoconf方法来操作,但是也需要一个脚本来调用这个库。
这里做一个相对通用的实现,可以根据传入的Kconfig、.config(保存的配置)、autoconfig.h文件的路径来读取、修改配置;生成相关C语言的位置头文件(autoconfig.h)
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os, sys, argparse
from kconfiglib import Kconfig
from menuconfig import menuconfig
def mconf_set_env(args):
"""
Set Kconfig Env
"""
os.environ["MENUCONFIG_STYLE"] = "default selection=fg:white,bg:blue"
os.environ["KCONFIG_CONFIG"] = os.path.join(args.config_out)
os.environ["KCONFIG_CONFIG_HEADER"] = "# Generated by My Kconfig Demo"
os.environ["KCONFIG_AUTOHEADER"] = os.path.join(args.c_config_header_file_out)
os.environ["CONFIG_"] = ""
def mconfig(argv):
args = parse_args()
mconf_set_env(args)
kconf = Kconfig(args.kconfig_file)
menuconfig(kconf)
kconf.write_autoconf()
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--handwritten-input-configs",
action="store_true",
help="Assume the input configuration fragments are "
"handwritten fragments and do additional checks "
"on them, like no promptless symbols being "
"assigned")
parser.add_argument("kconfig_file",
help="witch Kconfig file use")
parser.add_argument("config_out",
help="Output configuration file")
parser.add_argument("c_config_header_file_out",
help="Output c config header file")
return parser.parse_args()
if __name__ == "__main__":
mconfig(sys.argv)
使用该脚本的命令格式为:
[python kconfig.py $path/kconfig_file $path/config_out $path/c_config_header_file_out]
python kconfig.py $path/Kconfig $path/.config $path/autoconfig.h
3 编写Kconfig文件
Kconfig是一个文件也是一种语言,其中的表达的是配置项的内容以及配置项之间的关系。而kconfiglib就是一个用于解析并向用户显示Kconfig文件的一个工具组件。
Kconfig的一些参考资料:
linux: Kconfig Language — The Linux Kernel documentation
zephyr: Configuration System (Kconfig) — Zephyr Project Documentation
博主fluidog的博文: Kconfig语法
简书上的文章: kconfig语法整理
以下是一个包含常规Kconfig使用的示例:
menu "Example Configuration Menu"
config EXAMPLE_BOOL
bool "Example boolean option"
default n
help
This is an example of a boolean option. It can be either 'y' (yes) or 'n' (no).
config EXAMPLE_TRISTATE
tristate "Example tristate option"
default m
help
This is an example of a tristate option. It can be 'y' (built-in), 'm' (module), or 'n' (disabled).
config EXAMPLE_INT
int "Example integer option"
default 10
help
This is an example of an integer option. You can enter any integer value.
config EXAMPLE_STRING
string "Example string option"
default "Hello, world!"
help
This is an example of a string option. You can enter any string value.
config EXAMPLE_HEX
hex "Example hexadecimal option"
default 0x10
help
This is an example of a hexadecimal option. You can enter any hexadecimal value.
config EXAMPLE_CHOICE
choice "Example choice option"
default EXAMPLE_CHOICE_OPTION_1
help
This is an example of a choice option. You can choose one of the following options.
config EXAMPLE_CHOICE_OPTION_1
bool "Choice Option 1"
config EXAMPLE_CHOICE_OPTION_2
bool "Choice Option 2"
endchoice
endmenu
在这个示例中,定义了一个名为 “Example Configuration Menu” 的菜单,其中包含多种类型的配置项,包括布尔值、三态值、整数、字符串、十六进制和选择项。每个配置项都有一个默认值和一个帮助文本,帮助文本用于解释该配置项的用途。
4 修改Makefile文件
在完成了上述不走后,还需要在Makefile中将kconfig.py脚本进行调用,常规的会在Makefile中添加一个menuconfig的目标(或者通过.sh脚本文件来直接调用)。
.PHONY = all clean menuconfig
ROOT = $(PWD)
all: main.o autoconfig.h
gcc main.o -o main
main.o: main.c
gcc main.c -c -o main.o
clean:
rm main.o main
menuconfig:
python kconfig.py $(ROOT)/Kconfig $(ROOT)/.config $(ROOT)/autoconfig.h