您的位置:首页 > 其它

内核映像的形成——编译配置

2010-12-29 22:28 120 查看

2.2 内核编译分析

关于Kbuild的预备知识先说到这里,有了上面的这些知识大家就可以上手了,其他的那些重要的知识主要涉及到一些细节,等我们遇到了再去查GNU Make手册和linux-2.6.34.1/Documentation/kbuild下的那些文档(注意,这是一种很重要的学习方法)。

在递归访问目录之前,顶层Makefile要完成设置环境变量以及递归访问的准备工作。顶层Makefile包含的公共部分,而 arch/$(ARCH)/Makefile 包含着针对某一特定CPU架构的配置信息。所以,要在arch/$(ARCH)/Makefile 中设置一部分变量,并定义一些目标。

Kbuild执行的几个步骤(大致):
1) 根据内核配置生成文件 .config
2) 将内核的版本号存储在 include/linux/version.h
3) 生成指向 include/asm-$(ARCH) 的符号链接
4) 更新所有编译所需的文件: 附加的文件由 arch/$(ARCH)/Makefile 指定。
5) 递归向下访问所有在下列变量中列出的目录: init-* core* drivers-* net-* libs-*,并编译生成目标文件。这些变量的值可以在 arch/$(ARCH)/Makefile 中扩充。
6) 联接所有的目标文件,在源代码树顶层目录中生成 vmlinux。最先联接是在 head-y中列出的文件,该变量由 arch/$(ARCH)/Makefile 赋值。
7) 最后完成具体架构的特殊要求,并压缩vmlinux生成最终的内核镜像。
-- 包含生成启动指令
-- 准备 initrd 镜像或类似文件

2.2.1 编译配置

那么针对内核,我们从哪里下手呢?我们是在内核源代码最高目录linux-2.6.34.1上运行的make menuconfig,那么就从KBuild的顶层——linux-2.6.34.1/Makefile文件下手。

在这个文件找“menuconfig:”这一行。可是找不到怎么办,难道我们的思路出了问题?大家在学习代码的时候,如果一条路走不通了,可千万别急,有百度呢。查一查,GNU make手册,Makefile跟我们的C语言一样,可以include呢。也就是说,可以把其他Makefile嵌入进来。所以,我们再在该文件下搜一搜所以的include关键字,有这么几行:

309 include $(srctree)/scripts/Kbuild.include
452 include $(srctree)/arch/$(SRCARCH)/Makefile
486 -include include/config/auto.conf
491 -include include/config/auto.conf.cmd
535 include $(srctree)/arch/$(SRCARCH)/Makefile

注意到srctree宏,我们可以猜到就是当前目录,SRCARCH是x86,再加上我们只关注Makefile文件,所以我们就只关注/usr/src/kernels/linux-2.6.34.1/arch/x86/Makefile。搜一下,还是没有。这下我怀疑真的是我的思路错了。别着急,继续百度。终于在一个论坛上查到了,linux-2.6.34.1/Makefile文件的459行有段这样的代码:
459 %config: scripts_basic outputmakefile FORCE
460 $(Q)mkdir -p include/linux include/config
461 $(Q)$(MAKE) $(build)=scripts/kconfig $@

“%”就是前面讲到的模式规则,这里就用到了。所有以config结尾的目标(如:menuconfig xconfig gconfig)都采用这个规则。另外,$(Q)在286行定义,它根据KBUILD_VERBOSE是否设置而定义,如果设置就是空的,没有设置就是“@”。$(Q)$(MAKE)这两个宏组合在一起,就是@make,我们知道,就是不把命令详细信息打印出来。所以make menuconfig最终会运行@make $(build)=scripts/kconfig menuconfig命令。根据前面的知识,$@就是指目标menuconfig。至于后面的$(build)变量是什么?待会儿再讲。

这个规则有三个依赖:scripts_basic、outputmakefile、FORCE。下面看一下这三个依赖:
我们从最简单的开始,首先分析一下这个FORCE依赖,它的规则定式义在1553行:
FORCE:

这个规则没有命令也没有依赖,只做一个.PHONY: $(PHONY)动作。这里要回顾一下GUN make的隐含规则。我们知道,make 的“隐含规则”功能会自动为我们自动去推导目标的依赖目标和生成命令。如果推导出来的目标(是什么,不知道,make的那么多隐含规则,谁也说不清楚)与伪目标(如%config)同名,也就是已经存在于系统中了,那么伪目标中的命令就不会被执行。而执行FORCE这个依赖的作用就是在执行此规则时,目标FORCE总会被认为是最新的。这样当它作为其它规则的依赖时,因为依赖总被认为被更新过的,所以那个%config目标中定义的命令总会被执行。其实我们也可以从force这个单词的中文意思中猜测(分析内核就需要这种连蒙带猜的精神)。

再来看看scripts_basic这个依赖的规则在384行定义:
PHONY += scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount

注意,PHONY这个变量是我们第一次见到,在内核源码中的Makefile随处可见,它的作用在最后一行定义:.PHONY: $(PHONY),表示PHONY变量中所有的目标都是伪目标,而不是具体的文件,所以,这里的scripts_basic就是个伪目标。

下面来讲build这个变量,它定义在我们刚才include的scripts/kbuild.include的114行:
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj

KBUILD_SRC是当前目录,后面会讲到,所以srctree参数也是当前目录,所以省去,上面的规则可写成如下形式:
scripts_basic:
@make –f scripts/Makefile.build obj=scripts/basic

这个规则的命令最终会进入scripts目录,执行Makefile.build文件(传说中的Kbuild脚本),并传递参数obj=scripts/basic。

最后再来看outputmakefile,参数构建规则在396行开始定义:
outputmakefile:
ifneq ($(KBUILD_SRC),)
$(Q)ln -fsn $(srctree) source
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile /
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

这个规则的命令运行一个shell脚本scripts/mkmakefile,并传递四个参数。这个脚本主要是在$(objtree)参数指定的目录中生成一个Makefile文件。由于这里KBUILD_SRC为空,所以这个脚本并不会被执行。

在他的依赖被处理完后,开始执行规则的命令。第一个命令创建了两个目录,第二个命令扩展后为:
@make –f scripts/Makefile.build obj=scripts/kconfig menuconfig

这个命令依然是执行scripts/Makefile.build这个makefile文件。并传递参数obj=scripts/kconfig和menuconfig。

scripts/Makefile.build脚本的具体代码我就不去分析了,但必须知道上面命令的原理,这是KBuild机制的重中之重。前办部分是@make –f scripts/Makefile.build,这整个部分就是KBuild的主题命令名称;obj=scripts/kconfig表示对应目录,KBuild只关心该目录中的Makefile文件;menuconfig是传进去的参数,意思是执行Makefile里面menuconfig的目标,我们看到在 scripts/kconfig/Makefile的20行定义:
8 ifdef KBUILD_KCONFIG
9 Kconfig := $(KBUILD_KCONFIG)
10 else
11 Kconfig := arch/$(SRCARCH)/Kconfig
12 endif
20 menuconfig: $(obj)/mconf
21 $< $(Kconfig)

从这个命令可以看出,最终会以arch/x86/Kconfig为参数运行scripts/kconfig/mconf这个脚本,出现配置界面。注意,mconf是个C程序,该程序并不属于内核,而是一个用户态程序。Linux 源代码中这一类程序还有很多。如在scripts/kconfig/目录下就有mconf,gconf,qconf 等等。它们用来执行内核的配置工作。

scripts/kconfig/mconf 这个程序采用了ncurses类库。这是一个在文本界面下进行画图操作类库。由于要适应不同平台,源代码中的mconf不是预编译

好的elf 可执行文件,而是在使用时才去编译生成。这使用户在运行make menuconfig时要依赖ncurses的开发包。所以,如果你机器上没有ncurses的rpm包,建议去下载并安装。

arch/x86/Kconfig,准确地说是各个Kconfig 文件记录了各个内核配置的选项。我们在make menuconfig 或者make xconfig 时显示的菜单项和帮助信息,都是从这个文件中读出来的。我们来看看这个文件的内容:
……
config NEED_PER_CPU_EMBED_FIRST_CHUNK
def_bool y
config NEED_PER_CPU_PAGE_FIRST_CHUNK
def_bool y
config H***E_CPUMASK_OF_CPU_MAP
def_bool I386_SMP
……

当年配置完menuconfig以后,就会在主目录下生成一个.config文件,我们再来看看这个文件的部分内容:
……
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_H***E_CPUMASK_OF_CPU_MAP=y
……

不错,生成一些CONFIG_XXX的东西。这些东西作为全局宏变量,由我们的Makefile引用。至于如何引用,且听下回分解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: