以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
概述
编译内核前需要进行两步配置,即先make x210ii_qt_defconfig,然后再make menuconfig。第一步如果成功,则会提示“configuration written to .config”。注意这里的“.config”文件。其实这两步的配置都是为了得到内容合适的.config文件,只不过第一步属于整体的配置,它完成大部分的配置项;第二步配置属于局部的配置,完成细节的调整。
而得到.config文件的目的,是让.config文件里面的配置值,指引各个目录下的Makefie文件的工作(比如是否编译某.c文件,是否以模块形式编入内核。比如某Makefile文件中有这句语句:obj-$(CONFIG_DM9000) += dm9000.o,则.config文件中的CONFIG_DM9000这个选项的值,将会决定dm9000.c是否编译(Y,N),或者是否以模块形式编入内核(M))。
关于.config文件的描述
.config文件是linux内核在编译过程中很重要的一个文件,它的作用类似与uboot中的include/configs/x210_sd.h,内核在编译过程中会读取.config文件中的配置项,并且用这些配置项去指导整个编译链接过程。
.config文件是一个隐藏文件,需要ls -a来查看。它的文件格式类似于脚本文件,其中的内容是类似于“CONFIG_ARM=y”的配置项,如下图所示。这些配置项类似于脚本文件中定义的变量,比如CONFIG_ARM=y可以理解为定义了一个变量CONFIG_ARM,变量的值为y(yes)。
两步配置法
从.config文件可以看出linux内核的可配置项非常多,这表明linux内核是高度可配置的。但是linux内核配置项的繁杂度超出了大脑能够处理的能力,所以linux内核不再像 uboot 那样直接手工配置,而是发明了一个图形化的配置工具menuconfig。其实只要人的大脑足够厉害,完全可以手工修改.config文件来完成内核的配置,只要.config文件中内容是正确的,就不会影响编译过程。
为了对.config文件中的两三千个配置项做逐一合适的配置,专门发明了两步结合的配置方式。
- 第一步make xxx_defconfig,完成大部分的配置项,
- 第二步make menuconfig,完成细节的调整。
第一步make xxx_defconfig,相当于“cp arch/arm/configs/xxx_defconfig .config”。arch/arm/configs目录下的xxx_defconfig文件是由他人手工配置好的.config文件。比如S5PV210这个SoC的开发板,它的最初配置是由三星的工程师完成的。
第二步make menuconfig,则是先读取第一步得到的.config,然后给出一个图形化界面,方便使用者寻找与修改配置项。
menuconfig工具和Kconfig、.config的关系
接上文。在make menuconfig时,弹出的配置界面上所显示的菜单和选择值,是怎么来的呢?这其实和两个文件有关,即Kconfig文件与.config文件。其中Kconfig文件提供配置界面上的菜单项目,.config文件提供或者接收配置界面上的菜单的选择值。
也就是说,menuconfig显示的菜单内容,由内核源码树各个目录下的Kconfig文件来提供。Kconfig文件中按照一定的格式包含了一些配置项,每一个配置项在make menuconfig中都会成为一个菜单项目。menuconfig中显示的菜单目录结构和源码目录中的Kconfig的目录结构是一样的。如果在某个Kconfig文件中删除某个配置项,再次make menuconfig时,此配置项不再存在。
在make menuconfig时,会读取.config文件,并且用.config文件中的选择结果(Y、N、M)来初始化menuconfig中各个菜单项的选择值。当退出make menuconfig时,menuconfig工具检查是否更改了某些配置项的值,如果没有则直接退出,如果有改动则提示是否保存。此时更改且选择保存,则会将配置重新写入.config文件中,下一次再次打开make menuconfig时会再次加载.config文件。
Kconfig文件详解
上面提到“menuconfig显示的菜单内容,由内核源码树各个目录下的Kconfig文件来提供”,那Kconfig文件是怎样的呢?我们在做驱动移植等工作时,有时需要自己在Kconfig文件中添加一个配置项,以便将某个设备驱动添加到内核的配置项目中,这时候就需要对Kconfig的配置项格式有所了解。
Kconfig文件在kernel中有很多,几乎每个目录下都有这个文件。我们截取其中一个Kconfig文件的片段来解释。该文件是\drivers\i2c\Kconfig文件。
1、Kconfig的格式
Kconfig文件是按照一定的格式来书写的,menuconfig工具可以识别这种格式,然后从中提取出有效信息组成menuconfig中的菜单项。
(1)#开头的行是注释行。
(2)“menuconfig”表示菜单(本身属于一个菜单中的项目,但是其又有子菜单项目),而“config”表示菜单中的一个配置项(本身并没有子菜单下的项目)。
(3)menuconfig或者config后面用空格隔开的大写字母,是这个配置项的名字。这个字符串前面添加CONFIG_后就构成了.config文件中的配置项名字。
(4)一个menuconfig后面跟着的所有config项就是这个menuconfig的子菜单,这就是Kconfig中表示的目录关系。
(5)内核源码目录树中每一个Kconfig都会source引入其所有子目录下的Kconfig,从而保证了所有的Kconfig项目都被包含进menuconfig中。如果在linux内核中添加一个文件夹,一定要在这个文件夹下创建一个Kconfig文件,然后在这个文件夹的上一层目录的Kconfig中source引入这个文件夹下的Kconfig文件。
2、tristate和bool的含义
tristate意思是三态,对应Y、N、M三种选择方式;bool对应Y和N。
3、depends的含义
(1)本配置项依赖于另一个配置项。如果那个依赖的配置项为Y或者M,则本配置项才有意义;如果依赖的哪个配置项本身被设置为N,则本配置项根本没有意义。
(2)depends可能会导致make menuconfig时找不到一些配置项。在menuconfig中如果找不到一个选项,但是这个选项在Kconfig中存在,则可能是它所依赖的配置项是不成立的。
(3)depends并不要求依赖的配置项一定是一个,可以是多个,而且还可以有逻辑运算。此时只要依赖项目运算式子的逻辑结果为真则依赖就成立。
4、help
帮助信息,阐明配置项的含义,以及配置方法。
5、Kconfig和.config文件和Makefile三者的关联
我们在make menuconfig时的选择值(Y、N、M)会决定.config文件中的CONFIG_XXX变量的选择值,从而影响编译链接过程。比如=y则会被编入,=m则会被单独连接成一个ko模块,=N则对应的代码不会被编译。
这是怎么实现的?这是通过Makefile实现的。比如某目录下的Makefile中有这个语句:obj-$(CONFIG_DM9000) += dm9000.o,它表示:
- 如果CONFIG_DM9000变量值为Y,则obj += dm9000.o,因此dm9000.c会被编译;
- 如果CONFIG_DM9000变量值为N,则dm9000.c不会被编译。
- 如果CONFIG_DM9000变量值为M,则会被连接成ko模块。