这里通过以下三个最经典的步骤来分析下,一个bzImage内核映像是如何配置编译,并最终安装使用的。当然在整个内核构建过程中,还支持许多的特性,相信这个经典过程明确之后,分析其他的情况就不会太难了,这里以x86体系来做分析。分析版本2.6.34.1
(1) make menuconfig
研究代码最好的方法就是手眼并用,看代码的同时多多动手调试,我们先贴出了它实际运行的过程:
[root@www linux-2.6.34.1]# make menuconfig
HOSTCC scripts/basic/fixdep
HOSTCC scripts/basic/docproc
HOSTCC scripts/basic/hash
HOSTCC scripts/kconfig/conf.o
HOSTCC scripts/kconfig/kxgettext.o
HOSTCC scripts/kconfig/lxdialog/checklist.o
HOSTCC scripts/kconfig/lxdialog/inputbox.o
HOSTCC scripts/kconfig/lxdialog/menubox.o
HOSTCC scripts/kconfig/lxdialog/textbox.o
HOSTCC scripts/kconfig/lxdialog/util.o
HOSTCC scripts/kconfig/lxdialog/yesno.o
HOSTCC scripts/kconfig/mconf.o
SHIPPED scripts/kconfig/zconf.tab.c
SHIPPED scripts/kconfig/lex.zconf.c
SHIPPED scripts/kconfig/zconf.hash.c
HOSTCC scripts/kconfig/zconf.tab.o
HOSTLD scripts/kconfig/mconf
scripts/kconfig/mconf arch/x86/Kconfig
当我们在内核顶层目录执行make menuconfig(假设你知道menuconfig的作用,这里就不多讲了)时,就指定了当前make的对象是menuconfig,那么我们到Makefile中去找到这个目标。注意的是,在众多kbuild系统分析的博客中,都会交代都诸多的细节,我写这个系列的目的主要是为了理出一条清晰的思路,而不去纠缠太多细枝末节的条件判断,当然在最后我会贴出一些比较好的,并且包含多细节的博客分享给大家。
由于我们的目标是menuconfig,在Makefile里面属于一种叫做config-targets的构建对象,在Makefile中会将“include $(srctree)/arch/$(SRCARCH)/Makefile”,即arch/x86/Makefile包含进来,include的动作是相当于把arch/x86/Makefile的内容直接复制到上述语句的所在的地方,成为了当前的Makefile的一部分,自然了,里面的变量也就不需要export出来了。
接下来有一块内容:
%config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
这里%config是Makefile里面的通配表示,匹配以config结尾的所以字符,自然我们的menuconfig也是它匹配的类型。它的依赖包括script_basic, outputmakefile,剩下的FORCE,它的作用一句话概括,只要依赖条件中含有FORCE,目标总会被构建。接下来它的构建指令需要重点关注的是第二个(第一条就是创建两个目录),关于变量$(@),这里有详细的介绍。
这句指令中涉及到的$(build)在script/kbuild.include中被定义,它真实的样子是:
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
所以通过这个build的定义,上面的那句话可以翻译为:make -f script/Makefile.build obj=script/kconfig menuconfig
实际的执行过程可以到script下的Makefile.build看到:
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
这三句话就把script/kconfig/目录下的Makefile包含了进来,在这个Makefile中,定义了menuconfig的构建过程:
menuconfig: $(obj)/mconf
$< $(Kconfig)
我们的讨论环境里,$(Kconfig)指向的是arch/x86/Kconfig文件,这个文件里有啥?很明了,$(obj)/mconf,即script/kconfig/目录下生成的mconf程序会读取arch/x86/Kconfig文件中的内容来生成我们熟悉的配置界面,配置结束之后,在顶层目录下会生成一个名为.config的隐藏文件,这是后续构建过程的重要依据和参考。
依赖条件script_basic和outputmakefile又有怎样的前世今生呢?这里粗略的分析一下。
outputmakefile在我们make时通过”O=“指定了make输出目录才会执行有意义的动作,这里不是我们讨论的情况,先跳过。
script_basic我们可以在主Makefile中找到它:
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
主要的动作翻译过来就是:make -f script/Makefile.build obj=script/kconfig,由于没有指定构建对象(即$(build)=script/basic后面为空),所以make的目标就是针对script/Makefile.build的默认目标,很显然它就是“__build”。
这里我跳到重点的片段:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
这里需要说明的一点就是,在当前的讨论情景下只有always是含有实际对象的,其它的都为空,这里用到的的always是script/basic/Makefile中定义的,在开始时看到执行过程,则是通过Makefile.host产生了一些构建必要的工具,同时将这些工具生成指令写到一个.cmd结尾的文件里,如.docproc.cmd,.fixdep.cmd,.hash.cmd等。
这篇文章详细的描述了menuconfig的构建过程,上面我所写的这些,貌似重复和多余,但是对我个人而言,关于menuconfig,脑海里保存这些信息就足够了,细节就像是手册中的帮助文档,需要的时候查阅就可以了。
(2) make
直接make,那么就会执行makefile中的默认对象,这里就是vmlinux。
这里我们要提一点,在主Makefile中,include $(srctree)/arch/$(SRCARCH)/Makefile,也就是说将当前架构文件夹下的Makefile包含进来了。在该makfile中bzImage最终还是要以vmlinux为依赖,所以vmlinux是重点。那么vmlinux需要哪些依赖呢?我们列出来看:
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o)
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m)))
vmlinux.o: $(modpost-init) $(vmlinux-main)
以上两个是他们各自的依赖,而下面的这几个则是赋值。
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
kallsyms.o := .tmp_kallsyms$(last_kallsyms).o #last_kallsyms是1,2,3等数值
注意这里vmlinux-dirs,后面出现了它的依赖:
$(vmlinux-dirs): prepare scripts
到这里说句题外话,有很多前辈的工作,极大的缩短了我这样刚刚开始研究内核的人的学习曲线,想写点东西,前辈都写的很清楚了,这里就不想重复了。
这里给出云松大牛疯狂内核中的关于内核映像构建相关链接,很前面也很详细。这里主要的内容算是自己的一种总结和理解。
整理一下思路:
1. 各个目录下.o文件的编译生成
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
该命令的执行启动了.o文件的编译,由于vmlinux-dirs实际上就是各个目录的替身,在makefile.build中我们看到:
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
这里的操作就是会依次包含进各个目录下的Makefile,来编译该目录下的对象,编译的实际过程则是:
$(obj)/%.o: $(src)/%.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
if_changed_rule和cc_o_c是什么?看
这里2. 目录下的.o文件生成built-in.o
下面的命令启动.o连接成built-in.o
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
这里$(obj-y)是啥?你随便点开一个目录下的Makefile,看看就知道了,其实就是各个.o的集合。
3. 生成vmlinux.o
4. vmlinux.lds的生成
.lds文件称为链接脚本,它的语法和作用,参考这里。它在最终链接生成vmlinux起着重要的作用。它的构建规则在Makefile.build中定义:
$(obj)/%.lds: $(src)/%.lds.S FORCE
$(call if_changed_dep,cpp_lds_S)
5. 链接生成vmlinux
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
$(call if_changed_rule,vmlinux__)
这里关于kallsyms.o,可以参考这里。当目前位置,各个目录下的.o都已构建完毕,通过$(call if_changed_rule,vmlinux__)
就可以在顶层目录下生成vmlinux了。
6. 生成bzImage
生成bzImage的工作集中在x86/boot目录和x86/compressed目录中,其中boot目录下的makefile会使用tools/build这个工具将当前目录中生成的setup.bin vmlinux.bin和启动设备号信息(即ROOT_DEV)“打包”成bzImage。
其中boot目录下的setup.ld会将目录下的所有的.o文件连接成setup.elf,然后使用objcopy处理得到setup.bin。
在compressed目录下的makefile会将misc.o,piggy.o,head_32.o或者head_64.o链接成vmlinux,这个vmlinux会在上层boot目录中被objcopy处理生成vmlinux.bin。这里有个奇怪的东西,就是piggy.o,这个东西实际上就是将顶层目录下生成的vmlinux进行了objcopy+gzip处理之后的最终结果。
相关推荐
Kbuild系统使用Kbuild Makefile来编译内核或模块。当Kernel Makefile被解析完成后,Kbuild会读取相关的Kbuild Makefile进行内核或模块的编译。Kbuild Makefile有特定的语法指定哪些编译进内核中、哪些编译为模块、及...
KBUILD用于编译内核,也可以把自己的程序编译进内核。 <br>这是我的课程报告,根据网络资源整理的,希望对大家有帮助。
Linux内核是一种单体内核,但是通过动态加载模块的方式,使它的开发非常灵活方便。那么,它是如何编译内核的呢?我们可以通过分析它的Makefile入手。以下是一个简单的hello内核模块的Makefile. ifneq ($(KERNEL...
linux下各平台的下的makefile文件与gnu makefile有一些不一样,这里作了详细分解,有好几个文件,把这个看会了,看linux下makefile不是问题
2 内核映像的形成 8 2.1 MakeFile预备知识 9 2.1.1 Makefile书写规则 9 2.1.2 Makefile变量 10 2.1.3 条件判断 14 2.1.4 函数 17 2.1.5 隐含规则 17 2.1.6 定义模式规则 19 2.1 KBuild体系 23 2.1.1 内核目标 24 ...
kbuild一般编译内核,当前这个工程用于控制编译应用程序,非常不错的例子
介绍kbuild 的入门文档,很不错,分享一下
读核感悟 kbuild系统 make bzImage的过程 26 读核感悟 kbuild系统 make menuconfig 31 读核感悟 文件系统 用C来实现面向对象 32 读核感悟 设计模式 用C来实现虚函数表和多态 32 读核感悟 设计模式 用C来实现继承和...
Kbuild系统实现分析,Kconfig和Makefile语法
本文主要侧重于kbuild的实现分析,希望能从一个building system设计者的角度来更好的了解kbuid的实现和背后的设计思想
介绍了kbuild系统原理,讲得比较通俗易懂,适合初学者。
linux设备驱动makefile:2.4内核模块Makefile模板 #Makefile for linux2.4 KVER=$(shell uname -r) KDIR=/lib/modules/$(KVER)/build OBJS=mymodule.o CFLAGS=-D__KERNEL__ -I$(KDIR) /include -DMODULE
1.Linux内核配置方式 2.Kconfig 3.Kbuild Makefile 4.一个使用linux Kbuild实现可配置编译的例子
理解Kbuild有助于理解Linux的编译流程,对于Linux的体系架构理解起到事半功倍的作用
多的资料(《嵌入式Linux应用开发完全手册》、Documentation/kbuild/makefiles.txt)已经向我们展示了一个初级Linux用户者应该懂得的知识--怎样添加需要编译的文件、添加编译的规则、多个源文件构成一个目标文件的...
读核感悟-kbuild系统-make bzImage的过程.....................................26 读核感悟-kbuild系统-make menuconfig........................................31 读核感悟-文件系统-用C来实现面向对象............
为了探索Linux内核是如何编译的,本文将深入研究Kconfig/kBuild内部进程,解释.config文件和vmlinux/bzImage文件是如何生成的,并介绍一个用于依赖性跟踪的智能技巧。 Kconfig 构建内核的第一步总是配置。Kconfig...
本文主要侧重于kbuild 的实现分析,希望能从一个building system 设计者的角度来 更好地了解kbuild的实现和背后的设计思想。
构建:必须使用Linux kbuild系统将驱动程序构建为内核模块。 来自 : 构建外部模块的命令是: $ make -C <path> M=$PWD由于命令中提供了“ M = ”选项,kbuild系统知道正在构建外部模块。 要针对正在运行的内核进行...
非常不错的 Kbuild 分析教程,涉及方面也很多,许多知识点都覆盖到了,作者下了功夫写的,呵呵