Kbuild

Kconfig

Kconfig解析

每个平台下都有一个Kconfig,Kconfig又通过source构建出一个Kconfig树,当make %config时,scripts/kconfig中的工具程序conf/mconf/qconf负责对Kconfig进行解析。

Kconfig文件说明:
scripts/kconfig/* kconfig解析程序
kconfig 各个内核源代码目录中配置文件
arch/$(ARCH)/deconfig arch缺省配置文件


Kconfig语法

参考内核目录下文档Documentation/kbuild/kconfig-language.txt
基本由以下这些构成:menu/endmenu,menuconfig,config,choice/endchoice,source,if/endif,comment

menu/endmenu
menu与endmenu必须同时出现。menu和endmenu中包含的内容就是子目录中的配置项。
比如,在init/Kconfig中24行(可能不同)显示为:

menu "General setup"
xxx
endmenu

这样,就会生成一个目录,特征就是右侧会出现一个箭头,如图1中第一行。当点击确认键时,会进入这个菜单项
这里写图片描述

menuconfig
menuconfig有点类似menu,但区别就在于menu后面多了一个config,这个menu是可以配置的,如上面一幅图中的第二行,前面比menu类型多了一个方框,通过空格可以修改这个配置项的选中状态。而且从格式上来看,也是有区别的。格式如init/Kconfig中1131行:

menuconfig MODULES
    bool "Enable loadable modulesupport"config
if MODULES
xxx
endif

也就是说,配置项是位于if和endif中。其中的部分就是MODULES子目录显示的内容。如果选中了MODULE,那么if和endif中的内容可以显示。如果没有定义,就只能进入一个空目录。

config
config是构成Kconfig的最基本单元,其中定义了配置项的详细信息。定义的格式参考arch/arm/Kconfig中的第8行:

 config ARM
        bool
        default y
        select xxxxxxxxxx
        help
          ???????????

可知,config需要定义名称,与menuconfig相同。这个名称不但用于裁剪内核中,还用于配置项之间的相互依赖关系中。
config的类型有5种,分别是bool(y/n),tristate(y/m/n),string(字符串),hex(十六进制),integer(整数)。其中,bool只能表示选中和不选,而tristate还可以配置成模块(m)。
其他语法如下:
1) depends on/requires:依赖关系
如果依赖的配置项没有选中,那么就当前项也无法选中。
2) select:反向依赖
如果当前项选中,那么也选中select后的选项。
3) range:范围,用于hex和integer
range A B表示当前值不小于A,不大于B
4) comment:注释

choice/endchoice

choice
        tristate "USB Gadget Drivers"
        default USB_ETH

config USB_ZERO
        tristate "Gadget Zero (DEVELOPMENT)"
        select USB_LIBCOMPOSITE
        select USB_F_SS_LB
        help
config USB_ETH
        tristate "Ethernet Gadget (with CDC Ethernet support)"
        help
xxx        
endchoice        

显示如下:
这里写图片描述
进入choice可以选择如下这些内容:
这里写图片描述
可见,choice有点类似于menu/endmenu,是在子窗口里选择,但是不同的是子窗口中只能选择一项。在prompt后会显示当前选择项的名称

source
source只是将另外一个Kconfig文件直接复制到当前位置而已。但它的作用也是明显的,可以将这个系统贯穿在一起。

从开始位置arch/arm/Kconfig,来将整个系统都作为配置型
当我们进入了linux源码的根目录时,输入make menuconfig。假设,此时根目录已经存在了.config,如果不存在,会自动生成。这时,在命令行显示如下:
make menuconfig
script/Kconfig/mconf arch/arm/Kconfig
显然,在执行make menuconfig时,会自动调用scripts/Kconfig/mconf arch/arm/Kconfig开始系统的配置,那么arch/arm/Kconfig就是配置的起点。这个文件会通过source指令来调用其他目录下的Kconfig文件,从而完成整体配置。这样,arch/arm/Kconfig就可以理解成main函数,而source指令就有点类似于include。可以按照上面的语法,来分析Kconfig文件。


Kbuild

kbuild即kernel build,用于编译linux内核文件,kbuild对makefile进行了功能上的扩充,使其在编译内核文件时更加高效简洁,大部分内核中的Makefile都是使用Kbuild组织结构的Kbuild Makefile。


Kbuild Makefile组成

Kbuild Makefile由五个部分组成:
kernel Makefile,顶层makefile,位于linux内核源代码的顶层目录,通过读取内核配置文件(.config)配置编译环境变量,并根据内核配置文件(.config)确定访问哪些子目录,用于编译Linux kernel目标文件vmlinux和模块module
arch/$(ARCH)/Makefile:系统对应平台的Makefile。kernel Makefile会根据此Makefile提取体系结构相关的信息
kbuild Makefiles:每个子目录都有kbuild Makefile,用来执行从其上层目录传递下来的命令,Kbuild Makefile从.config文件中提取信息,生成Kbuild编译内核需要的文件列表,它们负责生成built-in或模块化目标。(注意:kbuild Makefile是指使用kbuild结构的Makefile,内核中的大多数Makefile都是kbuild Makefile。)
Scripts/Makefile.*:所有kbuildMakefile的规则,它们包含了定义/规则等。
.config:内核配置文件(一般由make menuconfig生成)。


Kbuild Makefile分析

2.1 obj-y和obj-m
最简单的kbuild makefile可以仅包含:obj-$(CONFIG_FOO) += foo.o
其中$(CONFIG_FOO)可以等于y或者m,它的值由.config给出,如果$(CONFIG_FOO)既不是y也不是m,那么该文件不会被编译和链接。
当$(CONFIG_FOO)等于y时,上面语句等价于obj-y += foo.o,它告诉kbuild在当前目录下,有一个叫做foo.o的目标文件,它将从foo.c或则foo.S编译得到。
当$(CONFIG_FOO)等于m时,表示foo.o需要被编译成模块

2.1.1 obj-y生成built-in.o
Kbuild编译所有的$(obj-y)文件,并调用”$(LD) -r”把所有这些文件合并到built-in.o文件。这个built-in.o会被上一级目录的Makefile使用,最终链接到vmlinux中。
$(obj-y)中的文件是有顺序的。联接也是有顺序的,那是因为有些函数(module_init()/__initcall)将会在启动时按照他们出现的顺序进行调用

2.1.2 目标由多个源文件编译得到
如果某个目标由多个源文件编译得到,那么可以通过$( < module_name>-objs)或$(-y)把这些源文件告诉kbuild。Kbuild能够识别后缀-objs和-y,例如:

#drivers/isdn/i4l/Makefile
obj-$(CONFIG_ISDN) += isdn.o
isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o

Kbuild会编译所有$(isdn-objs)中的对象,并调用”$(LD) -r”把它们链接成isdn.o文件

2.1.3 目标由复合对象构成
Kbuild能够识别用于组成目标文件的后缀-objs和后缀-y。这就让Kbuild Makefile可以通过使用 CONFIG_ 符号来判断该对象是否是用来组合对象的。
-objs后面是目标文件,而-y针对复合对象。
下面是一个使用后缀-y的例子。后缀-y的好处是,可以使用CONFIG_XXX符号来决定是否加入某些源文件(.o从对应的.c或.S编译得到):

#fs/ext2/Makefile
obj-$(CONFIG_EXT2_FS)       += ext2.o
ext2-y                      := balloc.o bitmap.o
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o

在这个例子中,如果 $(CONFIG_EXT2_FS_XATTR) 是 ‘y’,xattr.o将是复合对象 ext2.o的一部分。
注意:当然,当你要将其编译进内核时,上面的语法同样适用。
所以,如果你的 CONFIG_EXT2_FS=y,那Kbuild会按你所期望的那样,生成 ext2.o文件,然后将其联接到 built-in.o中,最终连接进内核中。
如果CONFIG_ETX2_FS=m,由balloc.o和bitmap.o两个目标文件最终链接生成ext2.o,直至ext2.ko文件,保存在/lib/modules目录下方便加载。

2.1.4 以上3种的总结
obj-y生成built-in.o
obj-$(…)+=xxx.o 表示是否编译xxx.o目标文件

目标由多个源文件编译得到
xxx-objs+=xxx1.o xxx2.o xxx3.o 目标文件xxx.o依赖哪些文件

目标由复合对象构成
xxx-y+=xxx1.o 复合对象xxx.o目标依赖哪些文件
xxx-$(…)+=xxx2.o xxx3.o 复合对象xxx.o目标可能还依赖哪些文件

2.1.5 调用子目录Makefile
Makefile只负责编译当前目录中的对象。子目录中的对象,由子目录中的Makefile负责。如何让make调用子目录中的Makefile?答案是把子目录包含到obj-y或obj-m中。例如:

#fs/Makefile
obj-$(CONFIG_EXT2_FS) += ext2/

当CONFIG_EXT2_FS为y或m时,kbuild系统会在ext2目录中调用make命令(也即调用ext2目录中的Makefile)

2.2 lib-y和lib-m
在一个目录下,obj-y所列出的文件,将被编译成built-in.o文件,而lib-y或lib-m所列出的文件,将在当前目录下生成lib.a文件。
注意:一般lib-y或lib-m只用在lib/和arch/*/lib这两个目录中。

2.3 编译选项变量
2.3.1 ccflags-y、asflags-y、ldflags-y
这三个变量只在当前Makefile中有效。补充:$(KBUILD_CFLAGS)是定义在根目录Makefile中的变量,它适用于整个内核树。

2.3.2 subdir-ccflags-y、subdir-asflags-y
这两个变量作用于当前Makefile及其所有子目录。

2.3.3 CFLAGS_$@、AFLAGS_$@
这两个变量只在当前Makefile中有效。$@可以用来指定文件名,让不同文件可以使用不同的编译选项。例如:

# drivers/scsi/Makefile
CFLAGS_aha152x.o =   -DAHA152X_STAT-DAUTOCONF
CFLAGS_gdth.o    =# -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \
                             -DGDTH_STATISTICS
CFLAGS_seagate.o =   -DARBITRATE -DPARITY-DSEAGATE_USE_ASM

2.3.4 EXTRA_CFLAGS
有时需要连接内核源代码外部的系统头文件,但Kbuild默认的系统头文件都在内核源代码内部,如何使用外部的头文件需要借助Kbuild系统的特殊规则
EXTRA_CFLAGS+=$(ext_include_path)

2.3.5 ccflags、CFLAGS、EXTRA_CFLAGS之间的区别是
ccflags是gcc编译器选项,而CFLAGS、EXTRA_CFLAGS是makefile内部的预定义变量

2.4 $(src)、$(obj)、$(kecho)
$(src)指向当前Makefie所在目录的相对路径。$(obj)指向用来保存目标文件的相对目录。示例如下:

#drivers/scsi/Makefile
$(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr$(src)/script_asm.pl
$(CPP) -DCHIP=810 - < $< | ...$(src)/script_asm.pl

这里,$(src)等于drivers/scsi/,$(obj)同样也等于drivers/scsi/。
使用“make -s”命令时,只会输出警告和错误信息。$(kecho)能够将其后的内容输出到标准输出流(一般就是显示器),前提是没有使用“make -s”。示例如下:

#arch/blackfin/boot/Makefile
$(obj)/vmImage: $(obj)/vmlinux.gz
$(call if_changed,uimage)
@$(kecho) 'Kernel: $@ is ready'

2.5 $(CC)相关功能
2.5.1 as-option、ld-option、cc-option
当编译、链接文件时,xx-opiton可以用来检查当前使用的$(CC)是否支持给出的编译选项。如前者不支持,可使用后者。例如:

#arch/sh/Makefile
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)

如果当前的$(CC)不支持-Wa$(comma)-isa=$(isa-y),那么可以使用第二个编译选项(这里为空)。

2.5.2 cc-option-yn
cc-option-yn用来检查$(CC)是否支持给出的编译选项。如支持,返回y,否则返回n。例如:

#arch/ppc/Makefile
biarch := $(call cc-option-yn, -m32)
aflags-$(biarch) += -a32
cflags-$(biarch) += -m32

2.5.3 cc-option-align
gcc在3.0之后改变了指定函数、循环等对齐选项的类型。gcc <3.00时,cc-option-align =-malign;gcc >=3.00时,cc-option-align =-falign。使用$(cc-option-align)来选择正确的前缀。例如:

KBUILD_CFLAGS += $(cc-option-align)-functions=4

2.5.4 cc-version、cc-ifversion、cc-fullversion
cc-version返回$(CC)版本。如$(CC)为gcc 3.41,那么cc-version返回0341。例如:

#arch/i386/Makefile
cflags-y += $(shell \
if [ $(call cc-version) -ge 0300 ] ; then \
       echo "-mregparm=3"; fi ;)

cc-ifversion在版本符合条件的前提下返回最后一个参数。示例如下:

#fs/reiserfs/Makefile
ccflags-y := $(call cc-ifversion, -lt, 0402, -O1)

如果$(CC)版本低于4.2,那么ccflags-y将等于-O1。
cc-fullversion给出更详细的版本信息,例如:

#arch/powerpc/Makefile
$(Q)if test "$(call cc-fullversion)" = "040200" ; then \
    echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ;\
        false ; \
fi

2.5.5 cc-cross-prefix
cc- cross-prefix用于检查是否存在给定前缀的$(CC),如存在,返回第一个匹配的前缀,否则返回空。如有多个前缀需要匹配,各前缀之间使用单个空格隔开。例如:

#arch/m68k/Makefile
ifneq ($(SUBARCH),$(ARCH))
     ifeq ($(CROSS_COMPILE),)
          CROSS_COMPILE := $(call cc-cross-prefix,m68k-linux-gnu-)
     endif
endif

Kbuild 目标

模块的编译

编译模块的时候,你可以将模块放在代码树中,用Make modules的方式来编译你的模块,obj-$(CONFIG_EXT2) += ext2.o即可
你也可以将模块相关文件目录放在代码树以外的位置,用如下的命令来编译模块:
make -C < path to kernel src> M=$PWD modules
-C指定代码树的位置,M=$PWD或M=’PWD’告诉kbuild回到当前目录来执行build操作


参考文章

  1. Kbuild分析
  2. make menuconfig/.config/Kconfig解析
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

luckywang1103

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

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

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

打赏作者

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

抵扣说明:

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

余额充值