uboot-menuconfig和Kconfig图像化配置

1 ncurses 库安装#

uboot 或 Linux 内核可以通过输入make menuconfig来打开图形化配置界面,menuconfig是一套图形化的配置工具,需要ncurses库支持。
sudo apt-get install build-essential
sudo apt-get install libncurses5-dev

2 menuconfig菜单使用说明和举例#

menuconfig 重点会用到两个文件:.config Kconfig.config 文件前面已经说了,这个文件保存着 uboot 的配置项,使用 menuconfig 配置完 uboot 以后会更新.config 文件。Kconfig文件是图形界面的描述文件,也就是描述界面应该有什么内容,很多目录下都会有Kconfig文件。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
image
通过键盘上的“↑”“↓”键来选择要配置的菜单,按下“Enter”键进入子菜单。菜单中高亮的字母就是此菜单的热键,在键盘上按下此高亮字母对应的键可以快速选中对应的菜单。选中子菜单以后按下“Y”键就会将相应的代码编译进 Uboot 中,菜单前面变为“< * >”。按下“N”键不编译相应的代码,按下“M”键就会将相应的代码编译为模块,菜单前面变为“< M >”。按两下“Esc”键退出,也就是返回到上一级,按下“?”键查看此菜单的帮助信息,按下“/”键打开搜索框,可以在搜索框输入要搜索的内容。
在配置界面下方会有五个按钮,这五个按钮的功能如下:

1
2
3
4
5
<Select>:选中按钮,和“Enter”键的功能相同,负责选中并进入某个菜单。
<Exit>:退出按钮,和按两下“Esc”键功能相同,退出当前菜单,返回到上一级。
<Help>:帮助按钮,查看选中菜单的帮助信息。
<Save>:保存按钮,保存修改后的配置文件。
<Load>:加载按钮,加载指定的配置文件。

就以如何使能dns命令为例,讲解一下如何通过图形化界面来配置 uboot。进入“Command line interface --->”这个配置项:
image
选择“Network commands --->”,进入网络相关命令配置项:
image
可以看出,uboot 中有很多和网络有关的命令,比如bootp、tftpboot、dhcp等等。选中 dns,然后按下键盘上的“Y”键,此时dns前面的“[ ]”变成了“[ * ]” :
image
细心的朋友应该会发现,在mx6ull_alientek_emmc.h里面我们配置使能了 dhcpping命令,但是在上图中的“[ ]”并不是“[ * ]”,也就是说不编译dhcpping命令,这不是冲突了吗?实际情况是 dhcp ping 命令是会编译的。之所以在上图中没有体现出来时因为我们是直接在mx6ull_alientek_emmc.h中定义的宏CONFIG_CMD_PINGCONFIG_CMD_DHCP,而 menuconfig 是通过读取.config 文件来判断使能了哪些功能,.config里面并没有宏CONFIG_CMD_PINGCONFIG_CMD_DHCP,因此menuconfig不会选中这两项。
总结下:配置选项来自2个地方,一个是mx6ull_alientek_emmc.h,一个是.config
选中 dns,然后按下“H”或者“?”键可以打开dns命令的帮助提示信息:
image
选择dns命令以后,按两下 ESC 键(按两下ESC键相当于返回上一层),退出当前配置项,进入到上一层配置项,输入Y保存修改后的配置到.config
image
再打开.config,会发现多了“CONFIG_CMD_DNS=y”这一行:
image
再次编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
烧录uboot进sd卡,开机从sd卡启动,进入uboot命令行后,输入help或者?就可以看到uboot支持了dns命令。
测试:先将板子连接能上外网的路由器,要先设置一下dns服务器的 IP 地址,也就是设置环境变量 dnsip 的值:
setenv dnsip 114.114.114.114
saveenv
设置好以后就可以使用 dns 命令查看百度官网的 IP 地址了:
dns www.baidu.com
image
可以看到dns解析命令功能正常。

3 menuconfig 图形化配置原理#

3.1 make menuconfig 过程#

defconfig一样,make menuconfig 也会匹配到顶层 Makefile。

Uboot顶层Makefile解析-1. defconfig过程分析 - fuzidage - 博客园 (cnblogs.com)

uboot-编译defconfig分析 | Hexo (fuzidage.github.io)

image
其中 build=-f ./scripts/Makefile.build obj, 展开后:
make -f ./scripts/Makefile.build obj=scripts/kconfig menuconfig
Makefile.build 会读取scripts/kconfig/Makefile中的内容,在scripts/kconfig/Makefile中可以找到如下代码:
image
其中obj= scripts/kconfigsilent是设置静默编译的,在这里可以忽略不计,Kconfig=Kconfig,因此扩展以后就是:
image
scripts/kconfig/mconf.c 这个文件会被编译,生成 mconf 这个可执行文件。mconf 会调用 uboot 根目录下的 Kconfig 文件开始构建图形配置界面。

3.1.1 Kconfig 语法简介#

3.1.1.1 mainmenu#

输入make menuconfig以后打开的默认界面就是mainmenu,在顶层 Kconfig 中有如下代码:
image
我们的uboot是UBOOTVERSION=2016.03,如下:
image

3.1.1.2 子Kconfig#

Kconfig 也可以调用其他子目录中的Kconfig文件,调用方法如下:
source "xxx/Kconfig"
顶层Kconfig中,调用了很多子Kconfig:
image

3.1.1.3 menu/endmenu 菜单#

menu 用于生成菜单,endmenu 就是菜单结束标志。在顶层Kconfig 中有如下代码:
image
体现在主菜单界面如下所示:
image
“General setup”菜单上面还有 “Architecture select (ARM architecture)”“ARM architecture”这两个子菜单,但是在顶层 Kconfig 中并没有看到这两个子菜单对应的menu/endmenu 代码块,那这两个子菜单是怎么来的呢?这两个子菜单就是arch/Kconfig文件生成的。包括主界面中的“Boot timing”、“Console recording”等等这些子菜单,都是分别由顶层Kconfig 所调用的 common/Kconfig、cmd/Kconfig 等这些子Kconfig文件来创建的。

3.1.1.4 config条目#

顶层Kconfig中的“General setup”子菜单内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
14 menu "General setup"
15
16 config LOCALVERSION
17 string "Local version - append to U-Boot release"
18 help
19 Append an extra string to the end of your U-Boot version.
20 This will show up on your boot log, for example.
21 The string you set here will be appended after the contents of
22 any files with a filename matching localversion* in your
23 object and source tree, in that order. Your total string can
24 be a maximum of 64 characters.
25
26 config LOCALVERSION_AUTO
27 bool "Automatically append version information to the version
string"
28 default y
29 help
......
45
46 config CC_OPTIMIZE_FOR_SIZE
47 bool "Optimize for size"
48 default y
49 help
......
54
55 config SYS_MALLOC_F
56 bool "Enable malloc() pool before relocation"
57 default y if DM
58 help
......
63
64 config SYS_MALLOC_F_LEN
65 hex "Size of malloc() pool before relocation"
66 depends on SYS_MALLOC_F
67 default 0x400
68 help
......
73
74 menuconfig EXPERT
75 bool "Configure standard U-Boot features (expert users)"
76 default y
77 help
......
82
83 if EXPERT
84 config SYS_MALLOC_CLEAR_ON_INIT
85 bool "Init with zeros the memory reserved for malloc (slow)"
86 default y
87 help
......
99 endif
100 endmenu # General setup

可以看到有大量的“config xxxx”的代码块,也就是config条目。“General setup”菜单的config条目具体配置项如下:
image
“config LOCALVERSION”对应着第一个配置项,“config LOCALVERSION_AUTO”对应着 第 二 个 配 置 项。

① 第 16 和 26 行,这两行都以 config 关键字开头,后面跟着 LOCALVERSION LOCALVERSION_AUTO,这两个就是配置项名字。假如我们使能了 LOCALVERSION_AUTO这个功能,那么就会下.config 文件中生成 CONFIG_LOCALVERSION_AUTO

config关键字下面的这几行是配置项属性,1724 行是 LOCALVERSION 的属性,2744 行是 LOCALVERSION_AUTO 的属性。

③ 属性里面描述了配置项的类型、输入提示、依赖关系、帮助信息和默认值等。第 17 行的string是变量类型,也就“CONFIG_ LOCALVERSION”的变量类型。可以为:bool、tristate、string、hex 和 int,一共 5 种。最常用的是 bool、tristate 和 string 这三种,bool 类型有两种值:y 和 n,当为 y 的时候表示使能这个配置项,当为 n 的时候就禁止这个配置项。tristate 类型有三种值:y、m 和 n,其中 y 和 n 的涵义与 bool 类型一样,m 表示将这个配置项编译为模块。string 为字符串类型,所以 LOCALVERSION 是个字符串变量,用来存储本地字符串,选中以后即可输入用户定义的本地版本号,如下图:
image

string 后面的“Local version - append to U-Boot release”就是这个配置项在图形界面上的显示出来的标题。
④ 第 18 行,help 表示帮助信息,告诉我们配置项的含义,当我们按下“h”或“?”弹出来的帮助界面就是 help 的内容。
⑤ 第 27 行,说明“CONFIG_LOCALVERSION_AUTO”是个bool 类型,可以通过按下 Y 或N 键来使能或者禁止 CONFIG_LOCALVERSION_AUTO
⑥ 第 28 行,“default y”表示 CONFIG_LOCALVERSION_AUTO 的默认值就是 y,所以这一行默认会被选中。

3.1.1.5 depends on 和 select#

打开 arch/Kconfig 文件,在里面有这如下代码:
image
第 9 行,“depends on”说明“SYS_GENERIC_BOARD”项依赖于“HAVE_GENERIC_BOARD”,也就是说“HAVE_GENERIC_BOARD”被选中以后“SYS_GENERIC_BOARD”才能被选中。
第 17~20 行,“select”表示方向依赖,当选中“ARC”以后,“HAVE_PRIVATE_LIBGCC”、“HAVE_GENERIC_BOARD”、“SYS_GENERIC_BOARD”和“SUPPORT_OF_CONTROL”这四个也会被选中。

3.1.1.6 choice/endchoice#

arch/Kconfig文件中有如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
11 choice
12 prompt "Architecture select"
13 default SANDBOX
14
15 config ARC
16 bool "ARC architecture"
......
21
22 config ARM
23 bool "ARM architecture"
......
29
30 config AVR32
31 bool "AVR32 architecture"
......
35
36 config BLACKFIN
37 bool "Blackfin architecture"
......
40
41 config M68K
42 bool "M68000 architecture"
......
117
118 endchoice

choice/endchoice 代码段定义了一组可选择项,将多个类似的配置项组合在一起,供用户单选或者多选。该示例就是选择处理器架构,可以从ARC、ARM、AVR32等这些架构中选择,这里是单选。在 uboot 图形配置界面上选择“Architecture select”,进入以后如下图:
image
第 12 行的prompt给出这个choice/endchoice 段的提示信息为“Architecture select”

3.1.1.7 menuconfig#

menuconfig 和 menu 很类似,但是 menuconfig 是个带选项的菜单,如顶层Kconfig中的“General setup”中的列表中有一项menuconfig EXPERT
image
结果如下:
image
可以看到,前面有“[ ]”说明这个菜单是可选的,当选中这个菜单以后就可以进入到子选项中:
image
如果不选择“Configure standard U-Boot features (expert users)”,那么所描述的菜单就不会显示出来,进去以后是空白的。

3.1.1.8 comment#

comment用于注释, 也就是在图形化界面中显示一行注释。例如drivers/mtd/nand/Kconfig中:

1
2
3
4
5
6
74 config NAND_ARASAN
75 bool "Configure Arasan Nand"
76 help
......
80
81 comment "Generic NAND options"

第 81 行使用comment标注了一行注释,注释内容为:“Generic NAND options”,这行注释在配置项 NAND_ARASAN 的下面。
在配置项“Configure Arasan Nand”下面有一行注释,注释内容为“*** Generic NAND options ***”
image

4 menuconfig菜单实战练习#

接下来自定义一个菜单进行练习,自定义菜单要求如下:
①、在主界面中添加一个名为“My test menu”,此菜单内部有一个配置项。
②、配置项为“MY_TESTCONFIG”,此配置项处于菜单“My test menu”中。
③、配置项的为变量类型为 bool,默认值为 y
④、配置项菜单名字为“This is my test config”
⑤、配置项的帮助内容为“This is a empty config, just for tset!”
在顶层 Kconfig,在最后面加入如下代码:

1
2
3
4
5
6
7
8
9
1 menu "My test menu"
2
3 config MY_TESTCONFIG
4 bool "This is my test config"
5 default y
6 help
7 This is a empty config, just for test!
8
9 endmenu # my test menu

再次执行make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
image
可以看出,主菜单最后面出现了一个名为“My test menu”的子菜单,这个就是上面添加进来的子菜单。进入此子菜单:
image
可以看出,配置项也添加成功,按H查看帮助信息:
image
保存退出,打开.config文件:
image
配置项MY_TESTCONFIG默认也是被选中的,因此在.config 文件中肯定会有“CONFIG_MY_TESTCONFIG=y”这一行。