1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 内核架构师必备技能:编写自己的kconfig框架plus

内核架构师必备技能:编写自己的kconfig框架plus

时间:2021-07-19 20:00:33

相关推荐

内核架构师必备技能:编写自己的kconfig框架plus

/course/4032547?flowToken=1042705

目录

前言

一 Kconfig文件起步:bool实验

二 配置一个模块:tristate实验

三 配置一个菜单:menu实验

四 配置一个字符串:string实验

五 配置一个整数:int实验

六 添加一个带配置菜单:menuconfig实验

七 depends on实验

八 select实验

总结

前言

准备好了,这是一个实践文章,也可以说是实验指导手册。

阅读之前准备一个ubuntu虚拟机,准备一个内核源码,跟随我的脚步,动手一点一点测试,不要急慢慢来,保证自己确实看到了测试结果,如果遇到问题,欢迎评论区留言讨论。

众所周知,linux中有很多的kconfig文件,kconfig为Menuconfig提供菜单内容,执行makeMenuconfig后,这些被配置的内容以CONFIG_XXX=VALUE,的形式保存到.config文件中,这些value可以使y,m,或者是数字,也可能是字符串,例如向内核传递一个名字,或者传递一个外设的初始主频等。

本文通过几个例子介绍Kconfig的使用方法

一 Kconfig文件起步:bool实验

首先,在内核中的drivers目录下创建mydir目录

其次,在其中创建Kconfig文件。注意Kconfig中的K是大写的。

第三,为了在make menuconfig时,能够找到我们创建的Kconfig文件,还需要在mydir所在目录的Kconfig中引用mydir/Kconfig,就是修改文件drivers/Kconfig,在其中添加如下一行内容,

source "drivers/mydir/Kconfig"

我想测试方便,就添加在了第一行,添加后如下所示

创建目录mydir和其子文件Kconfig后,如下。

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3/drivers/mydir$ lsKconfig

在Kconfig中添加内容如下:

# SPDX-License-Identifier: GPL-2.0-onlyconfig LKMAO_HELLO_WORLDbool "hello"helpthis is hello world

然后再内核源码目录执行 make menuconfig,看到配置菜单,进入device drivers,如下所示,看到新的菜单hello,并且还有(NEW)字符串,光标停留在该配置项,按y,选中该模块,按n取消选中,按空格键对当前值取反。我们当前测试选y,代表将该模块集成到内核中。然后保存退出

选中配置项

保存.config文件退出以后,在.config文件中搜索HELLO,如下所示:

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config2159:CONFIG_LKMAO_HELLO_WORLD=y

搜索到变量CONFIG_LKMAO_HELLO_WORLD,并且值是y。这个变量名字就是由config LKMAO_HELLO_WORLD连接生成的。

如果hello选项选n,那么在.config中是否会出现呢?验证结果如下所示,它会在.config文件中添加

# CONFIG_LKMAO_HELLO_WORLD is not set

表示该变量对应的模块并不会被编译,更加不会被放到内核中。

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config2159:# CONFIG_LKMAO_HELLO_WORLD is not set

二 配置一个模块:tristate实验

上一节介绍的是bool类型,本家将它改成tristate类型,tristate三态类型,分别是集成到内核、不添加、编译成模块。修改前面的Kconfig中添加内容如下,修改后的Kconfig内容如下所示:

# SPDX-License-Identifier: GPL-2.0-onlyconfig LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAbool "lkmao asia"hellothis is hello asia

保存上述内容到Kconfig文件,然后make menuconfig,如下

看到了hello以后不带(NEW),后缀了,lkmao asia带有(NEW)后缀,下面将lkmao asia这个选项改为tristate,如下所示

# SPDX-License-Identifier: GPL-2.0-onlyconfig LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"hellothis is hello asia

保存,并make menuconfig,如下图所示,看到lkmao asia 选项前面已经编程尖括号<>了,

这是有y,n,m三种操作,相比bool的多出了m操作,我们按m效果如下

此时尖括号中出现M字符,这个在内核中表示该选项对应的文件会被编译为module即模块。save,然后退出,查看.config文件的变化。

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config2159:# CONFIG_LKMAO_HELLO_WORLD is not set2160:CONFIG_LKMAO_HELLO_ASIA=m

如下所示,增加了变量CONFIG_LKMAO_HELLO_ASIA,且它的值是m。

三 配置一个菜单:menu实验

在drivers的Kconfig文件中,我们看到如下一行,这一行用于创建菜单,接下来,我们创建自己的菜单。

menu "Device Drivers"

修改我们的Kconfig文件如下所示:,新添加了一行menu "hello menu"

# SPDX-License-Identifier: GPL-2.0-onlymenu "hello menu"config LKMAO_HELLO_WORLDbool "hello"help this is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"help this is hello asia

make menuconfig看看效果,报错如下:missing end statement for this entry 缺少结束字段,drivers/Kconfig,解决这个问题

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ make menuconfigdrivers/Kconfig:244: 'menu' in different file than 'menu'drivers/mydir/Kconfig:2: location of the 'menu'<none>:34: syntax errordrivers/Kconfig:2: missing end statement for this entrymake[1]: *** [scripts/kconfig/Makefile:48: menuconfig] Error 1make: *** [Makefile:629: menuconfig] Error 2lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$

修改Kconfig如下所示

# SPDX-License-Identifier: GPL-2.0-onlymenu "hello menu"config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asiaendmenu

重新make menuconfig

新增了hello menu菜单,按回车键进入该菜单,如下所示

看到其中,我们添加的的两个选项,验证效果很好。

四 配置一个字符串:string实验

配置字符串并不常用,为了让本文章看起来比较完整,添加一个测试的例子,其实我也不知道该怎么写?怎么办,百度吗,不用那么麻烦,我们在.config文件中找找有没有赋值为字符串的CONFIG_XXX变量,然后再搜索这个变量在哪里定义的,然后,再把定义的地方复制过来,其实语法看一眼,然后再实验一次,就知道是啥意思了。说干就干。使用more命令查看.config文件的前十行:好厉害,找到了,按q退出more命令,这里不是按Esc退出more命名的。

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ more -n 10 .config## Automatically generated file; DO NOT EDIT.# Linux/x86 5.19.3 Kernel Configuration#CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0"CONFIG_CC_IS_GCC=yCONFIG_GCC_VERSION=110200CONFIG_CLANG_VERSION=0CONFIG_AS_IS_GNU=yCONFIG_AS_VERSION=23800

CONFIG_CC_VERSION_TEXT就是我们要找的字符串变量,CONFIG_GCC_VERSION就是我们下一小结要测试的整形变量,当然,这个可能还是字符串,我们就把它当做整形变量测试一下。

开始搜索CC_VERSION_TEXT,等等为什么不是搜索CONFIG_CC_VERSION_TEXT呢,CONFIG_被吃掉了吗?CONFIG_前缀是make menuconfig以后自动添加的,所以,搜索的时候要去掉CONFIG_前缀,如下所示:花的时间有点长。还是分析一下吧,CONFIG_CC_VERSION_TEXT看名字和值,应该是编译器版本信息,我猜它可能在init的Kconfig文件中定义的,试试

$ echo $(grep -nR CC_VERSION_TEX init/*) > result.txt

或者,这两个都可以,

$ grep -nR CC_VERSION_TEX init/* > result.txt

然后看到result.txt

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ cat result.txtinit/Kconfig:2:config CC_VERSION_TEXTinit/Kconfig:4: default "$(CC_VERSION_TEXT)"init/Kconfig:10: CC_VERSION_TEXT so it is recorded in include/config/auto.conf.cmd.init/Kconfig:15: line so fixdep adds include/config/CC_VERSION_TEXT into theinit/Makefile:35: "$(CONFIG_CC_VERSION_TEXT)" "$(LD)"

在init/Kconfig文件中有五个地方使用到它了,我们接下来,我们会对他们全部设计测试例程。先分析一下如下所示的内容:

config CC_VERSION_TEXTstringdefault "$(CC_VERSION_TEXT)"helpThis is used in unclear ways:- Re-run Kconfig when the compiler is updatedThe 'default' property references the environment variable,CC_VERSION_TEXT so it is recorded in include/config/auto.conf.cmd.When the compiler is updated, Kconfig will be invoked.- Ensure full rebuild when the compiler is updatedinclude/linux/compiler-version.h contains this option in the commentline so fixdep adds include/config/CC_VERSION_TEXT into theauto-generated dependency. When the compiler is updated, syncconfigwill touch it and then every file will be rebuilt.

其中有一个string,我们看到的第三个数据类型,前两个是bool和tristate,它有一个默认值"$(CC_VERSION_TEXT)",这个我猜CC_VERSION_TEXT还是一个环境变量,为了验证这个猜想,创建一个Makefile,在其中添加如下内容:

all:@echo 'CC_VERSION_TEXT = '$(CC_VERSION_TEXT)

lkmao@lkmao-virtual-machine:~$ makeCC_VERSION_TEXT = lkmao@lkmao-virtual-machine:~$

打印值是空的,这个不重要,我还是关心语法吧。无论它是什么default 后面的值,都是CONFIG_CC_VERSION_TEXT的默认值,除非我们给了它另外一个值。

help

后面是帮助信息,这里需要注意的是,

1 help单独占一行。

2 后来的帮助信息不需要双引号

根据分析,依照init/Kconfig文件修改我们自己的Kconfig内容如下所示:我们的Kconfig又丰富了。

这里需要注意的是:string 后面如果不加字符串,则menuconfig中是不会有这个子菜单项的。

# SPDX-License-Identifier: GPL-2.0-onlymenu "hello menu"config LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asiaendmenu~

如下所示:多出一行input your name并且默认值是(ha li bo te)(哈利波特)

修改它的值为ba wang long (霸王龙)如下所示:

保存并退出,查看.config中新增的值:

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -nR HELLO .config2163:CONFIG_LKMAO_HELLO_NAME="ba wanglong"2164:# CONFIG_LKMAO_HELLO_WORLD is not set2165:CONFIG_LKMAO_HELLO_ASIA=m

看到新增加了CONFIG_LKMAO_HELLO_NAME变量,且值是"ba wanglong",霸王龙字符串赋值完毕。

五 配置一个整数:int实验

上一节看到CONFIG_GCC_VERSION=110200,猜测它可能是整数,为什么?因为,根据我们自己的测试结果:看到了吧,霸王龙两边是有双引号的,110200两边没有双引号,所以猜它不是字符串。

2163:CONFIG_LKMAO_HELLO_NAME="ba wanglong"

开始验证之前,找找CONFIG_GCC_VERSION是在哪里定义的,搜索GCC_VERSION,还在init目录下找:如下所示

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n GCC_VERSION init/Kconfig 22:config GCC_VERSION895:default y if CC_IS_GCC && GCC_VERSION >= 120000 && GCC_VERSION < 130000 && GCC12_NO_ARRAY_BOUNDS

定义在22行,看到895行了吗,这说明Kconfig文件中还可以使用if、&& 、>=、<,如果百度的话,估计很难看到这些内容的。所以啊,宝藏就在内核目录里。init/Kconfig中是这样定义的

config GCC_VERSIONintdefault $(cc-version) if CC_IS_GCCdefault 0

我猜它的意思是,如果CC_IS_GCC为真,那么GCC_VERSION的值就是$(cc-version),否则的话,值就是0,这个要怎么验证呢,在根目录中的Makefile中打印CC_IS_GCC的值,在修改根目录的Makefile,在尾部添加内容:

hello_1:@echo 'CC_IS_GCC = '${CC_IS_GCC}

然后make hello_1:

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ make hello_1CC_IS_GCC = lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$

验证失败。直接在我们自己的Kconfig中做验证吧。

依照init/Kconfig文件修改我们自己的Kconfig内容如下所示:越来越多了。说明我们的经验越来越丰富了,继续下去,很快就变成高手了。

# SPDX-License-Identifier: GPL-2.0-onlymenu "hello menu"config LKMAO_HELLO_VERSIONint "hello version"default $(cc-version) if CC_IS_GCCdefault 9527config LKMAO_HELLO_CHECKint "this is for test"default CC_IS_GCCconfig LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asiaendmenu

这个地方改了几次,得到上面代码,你如果在看我写的内容,并且也在测试,如果出问题,不要怕,多改一次,多验证,在出错中寻找经验,这样的经验,记忆最深刻。痛苦的回忆总是刻骨铭心的。新增两项,其中hello version的值是110200,CC_IS_GCC的值是n

查看.config的值

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config2163:CONFIG_LKMAO_HELLO_VERSION=1102002164:CONFIG_LKMAO_HELLO_CHECK=n2165:CONFIG_LKMAO_HELLO_NAME="ba wanglong"2166:# CONFIG_LKMAO_HELLO_WORLD is not set2167:CONFIG_LKMAO_HELLO_ASIA=m

重新make menuconfig,修改HELLO_VERSON的值为123456

验证结果:

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config2163:CONFIG_LKMAO_HELLO_VERSION=1234562164:CONFIG_LKMAO_HELLO_CHECK=n2165:CONFIG_LKMAO_HELLO_NAME="ba wanglong"2166:# CONFIG_LKMAO_HELLO_WORLD is not set2167:CONFIG_LKMAO_HELLO_ASIA=m

关于CONFIG_LKMAO_HELLO_CHECK=n,这个估计是个很学术的话题啊,还是分析一下吧,Makefile中的变量是弱类型的,int、string等只是高速mecnuconfig,菜单应该以何种方式显示,例如如果是bool类型,子菜单就显示为中括号[ ],如果是tristate就显示为尖括号< >,如果是字符串或者int类型就显示为小括号( )。验证一下弱类型这种猜测:给hello verson输入三角龙:然后选择ok。

报错如下所示:

输入一个n

还是报错

那为什么2164:CONFIG_LKMAO_HELLO_CHECK=n就可以呢?上面至少验证了,普通的字符串是不能直接复制给int类型的。

六 添加一个带配置菜单:menuconfig实验

先看两个菜单选项的对比图

如上所示,hello menu菜单前面什么都没有,EISA support 前面有中括号,我们就要做一个这样的菜单,修改我们的Kconfig内容如下所示:注意menu "hello menu"和endmenu两行已经被#注释掉了,留在这里是为了对比。我们新增了LKMAO_HELLO_MENU,默认值是y

# SPDX-License-Identifier: GPL-2.0-only#menu "hello menu"menuconfig LKMAO_HELLO_MENUbool "hello worldd menu"default yhelpthis is for kconfig learn & testconfig LKMAO_HELLO_VERSIONint "hello version"default $(cc-version) if CC_IS_GCCdefault 9527config LKMAO_HELLO_CHECKint "this is for test"default CC_IS_GCCconfig LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asia#endmenu

make menuconfig验证如下:

这并不是我们想要的效果。看看init/Kconfig中的用法

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep menuconfig init/Kconfig menuconfig CGROUPSmenuconfig CGROUP_SCHEDmenuconfig NAMESPACESmenuconfig EXPERTmenuconfig MODULES

里面有

menuconfig CGROUPSbool "Control Group support"select KERNFShelpThis option adds support for grouping sets of processes together, foruse with process control subsystems such as Cpusets, CFS, memorycontrols or device isolation.See- Documentation/scheduler/sched-design-CFS.rst (CFS)- Documentation/admin-guide/cgroup-v1/ (features for grouping, isolationand resource control)Say N if unsure.if CGROUPSendif # CGROUPS

原来如此,需要加if 和endif,在菜单定义在if 和endif之间,修改我们自己的Kconfig

# SPDX-License-Identifier: GPL-2.0-only#menu "hello menu"menuconfig LKMAO_HELLO_MENUbool "hello worldd menu"default nhelpthis is for kconfig learn & testif LKMAO_HELLO_MENUconfig LKMAO_HELLO_VERSIONint "hello version"default $(cc-version) if CC_IS_GCCdefault 9527config LKMAO_HELLO_CHECKint "this is for test"default CC_IS_GCCconfig LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asiaendif #LKMAO_HELLO_MENU#endmenu

make menuconfig验证效果,如下所示,子菜单出现了

进入其中,看到了它的子菜单如下所示:

实验完毕。

七 depends on实验

这个没啥好说了,就是让A选项依赖于B选项,只有当B选中的时候,A才会出现,否则A处于隐藏状态。修改Kconfig代码如下所示

# SPDX-License-Identifier: GPL-2.0-only#menu "hello menu"menuconfig LKMAO_HELLO_MENUbool "hello world menu"default nhelpthis is for kconfig learn & testif LKMAO_HELLO_MENUconfig LKMAO_HELLO_VERSIONint "hello version"default $(cc-version) if CC_IS_GCCdefault 9527config LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_BOSSbool "have a boss"helpthis is my boss.config LKMAO_HELLO_MISHUdepends on LKMAO_HELLO_MISHUtristate "have a mishu"default yhelpthis is boss's mishu,she work for boss.endif #LKMAO_HELLO_MENU#endmenu

have a mishu依赖于have a boss,只有have a boss被选中,have a mishu才会出现,make menuconfig如下所示

当前have a boss没有被选中,现在选中它。

选中了have a boss,have a mishu选项也出现了。

实验完毕。

八 select实验

就是选中一个选项的时候,也会将其他选项选中,修改Kconfig代码如下所示:

未选中Hava a boss的执行结果

选中Have a boss的执行结果

看buy a good car 前面是_*_,表示该选项是被另一个选项选中的。

当然,如果没有选中hava a boos,have a good car选线是作为普通的选项操作的。

实验完毕

总结

本来只是想把刚刚写的Kconfig文件记录一下,后来觉得这个东西还有很多没有吃透的知识,有必要挖掘一下,解决就真的挖出了不少的东西。

还是要多实践,所思考。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。