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

https://ke.qq.com/course/4032547?flowToken=1042705

 

目录

前言

一 Kconfig文件起步:bool实验

二 配置一个模块:tristate实验

三 配置一个菜单:menu实验

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

五 配置一个整数:int实验

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

七 depends on实验

八 select实验

总结


前言

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

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

        众所周知,linux中有很多的kconfig文件,kconfig为Menuconfig提供菜单内容,执行make Menuconfig后,这些被配置的内容以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$ ls
Kconfig

在Kconfig中添加内容如下:

# SPDX-License-Identifier: GPL-2.0-only
config LKMAO_HELLO_WORLD
        bool "hello"
        help
        this 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 .config
2159: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 .config
2159:# CONFIG_LKMAO_HELLO_WORLD is not set

二 配置一个模块:tristate实验

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

# SPDX-License-Identifier: GPL-2.0-only
config LKMAO_HELLO_WORLD
        bool "hello"
        help
        this is hello world

config LKMAO_HELLO_ASIA
        bool "lkmao asia"
        hello
        this is hello asia


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

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

# SPDX-License-Identifier: GPL-2.0-only
config LKMAO_HELLO_WORLD
        bool "hello"
        help
        this is hello world

config LKMAO_HELLO_ASIA
        tristate "lkmao asia"
        hello
        this 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 .config
2159:# CONFIG_LKMAO_HELLO_WORLD is not set
2160: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-only
menu "hello menu"
config LKMAO_HELLO_WORLD
        bool "hello"
        help 
        this is hello world

config LKMAO_HELLO_ASIA
        tristate "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 menuconfig
drivers/Kconfig:244: 'menu' in different file than 'menu'
drivers/mydir/Kconfig:2: location of the 'menu'
<none>:34: syntax error
drivers/Kconfig:2: missing end statement for this entry
make[1]: *** [scripts/kconfig/Makefile:48: menuconfig] Error 1
make: *** [Makefile:629: menuconfig] Error 2
lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ 

修改Kconfig如下所示

# SPDX-License-Identifier: GPL-2.0-only
menu "hello menu"
config LKMAO_HELLO_WORLD
        bool "hello"
        help
        this is hello world

config LKMAO_HELLO_ASIA
        tristate "lkmao asia"
        help
        this is hello asia

endmenu

重新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=y
CONFIG_GCC_VERSION=110200
CONFIG_CLANG_VERSION=0
CONFIG_AS_IS_GNU=y
CONFIG_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.txt
init/Kconfig:2:config CC_VERSION_TEXT
init/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 the
init/Makefile:35:       "$(CONFIG_CC_VERSION_TEXT)" "$(LD)"

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

config CC_VERSION_TEXT
        string
        default "$(CC_VERSION_TEXT)"
        help
          This is used in unclear ways:

          - Re-run Kconfig when the compiler is updated
            The '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 updated
            include/linux/compiler-version.h contains this option in the comment
            line so fixdep adds include/config/CC_VERSION_TEXT into the
            auto-generated dependency. When the compiler is updated, syncconfig
            will 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:~$ make
CC_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-only
menu "hello menu"

config LKMAO_HELLO_NAME
        string "input your name"
        default "ha li bo te"
        help
        this is your name.

config LKMAO_HELLO_WORLD
        bool "hello"
        help
        this is hello world

config LKMAO_HELLO_ASIA
        tristate "lkmao asia"
        help
        this is hello asia

endmenu
~         

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

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

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

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -nR HELLO .config
2163:CONFIG_LKMAO_HELLO_NAME="ba wanglong"
2164:# CONFIG_LKMAO_HELLO_WORLD is not set
2165: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_VERSION
895:	default y if CC_IS_GCC && GCC_VERSION >= 120000 && GCC_VERSION < 130000 && GCC12_NO_ARRAY_BOUNDS

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

config GCC_VERSION
        int
        default $(cc-version) if CC_IS_GCC
        default 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_1
CC_IS_GCC = 
lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ 

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

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

# SPDX-License-Identifier: GPL-2.0-only
menu "hello menu"

config LKMAO_HELLO_VERSION
        int "hello version"
        default $(cc-version) if CC_IS_GCC
        default 9527

config LKMAO_HELLO_CHECK
        int "this is for test"
        default CC_IS_GCC


config LKMAO_HELLO_NAME
        string "input your name"
        default "ha li bo te"
        help
        this is your name.

config LKMAO_HELLO_WORLD
        bool "hello"
        help
        this is hello world

config LKMAO_HELLO_ASIA
        tristate "lkmao asia"
        help
        this is hello asia

endmenu

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

 查看.config的值

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config
2163:CONFIG_LKMAO_HELLO_VERSION=110200
2164:CONFIG_LKMAO_HELLO_CHECK=n
2165:CONFIG_LKMAO_HELLO_NAME="ba wanglong"
2166:# CONFIG_LKMAO_HELLO_WORLD is not set
2167:CONFIG_LKMAO_HELLO_ASIA=m

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

验证结果: 

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config
2163:CONFIG_LKMAO_HELLO_VERSION=123456
2164:CONFIG_LKMAO_HELLO_CHECK=n
2165:CONFIG_LKMAO_HELLO_NAME="ba wanglong"
2166:# CONFIG_LKMAO_HELLO_WORLD is not set
2167: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_MENU
        bool "hello worldd menu"
        default y
        help
        this is for kconfig learn & test

config LKMAO_HELLO_VERSION
        int "hello version"
        default $(cc-version) if CC_IS_GCC
        default 9527

config LKMAO_HELLO_CHECK
        int "this is for test"
        default CC_IS_GCC


config LKMAO_HELLO_NAME
        string "input your name"
        default "ha li bo te"
        help
        this is your name.

config LKMAO_HELLO_WORLD
        bool "hello"
        help
        this is hello world

config LKMAO_HELLO_ASIA
        tristate "lkmao asia"
        help
        this is hello asia

#endmenu

make menuconfig验证如下:

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

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep menuconfig init/Kconfig 
menuconfig CGROUPS
menuconfig CGROUP_SCHED
menuconfig NAMESPACES
menuconfig EXPERT
menuconfig MODULES

里面有

menuconfig CGROUPS
        bool "Control Group support"
        select KERNFS
        help
          This option adds support for grouping sets of processes together, for
          use with process control subsystems such as Cpusets, CFS, memory
          controls or device isolation.
          See
                - Documentation/scheduler/sched-design-CFS.rst  (CFS)
                - Documentation/admin-guide/cgroup-v1/ (features for grouping, isolation
                                          and resource control)

          Say N if unsure.
if CGROUPS
endif # CGROUPS

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

# SPDX-License-Identifier: GPL-2.0-only
#menu "hello menu"
menuconfig LKMAO_HELLO_MENU
        bool "hello worldd menu"
        default n
        help
        this is for kconfig learn & test

if LKMAO_HELLO_MENU
config LKMAO_HELLO_VERSION
        int "hello version"
        default $(cc-version) if CC_IS_GCC
        default 9527

config LKMAO_HELLO_CHECK
        int "this is for test"
        default CC_IS_GCC


config LKMAO_HELLO_NAME
        string "input your name"
        default "ha li bo te"
        help
        this is your name.

config LKMAO_HELLO_WORLD
        bool "hello"
        help
        this is hello world

config LKMAO_HELLO_ASIA
        tristate "lkmao asia"
        help
        this is hello asia
endif #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_MENU
        bool "hello world menu"
        default n
        help
        this is for kconfig learn & test

if LKMAO_HELLO_MENU
config LKMAO_HELLO_VERSION
        int "hello version"
        default $(cc-version) if CC_IS_GCC
        default 9527


config LKMAO_HELLO_NAME
        string "input your name"
        default "ha li bo te"
        help
        this is your name.

config LKMAO_HELLO_BOSS
        bool "have a boss"
        help
        this is my boss.

config LKMAO_HELLO_MISHU
        depends on LKMAO_HELLO_MISHU
        tristate "have a mishu"
        default y
        help
        this 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文件记录一下,后来觉得这个东西还有很多没有吃透的知识,有必要挖掘一下,解决就真的挖出了不少的东西。

    还是要多实践,所思考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千册

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值