kbuild 指向到不同类型的 makefile:
- Makefile 位于源代码根目录的顶级 makefile 。
- .config 是内核配置文件 。
- arch/$(ARCH)/Makefile 是架构的 makefile,它用于补充顶级 makefile 。
- scripts/Makefile.* 描述所有的 kbuild makefile 的通用规则 。
- 最后,大约有 500 个 kbuild makefile 。
作为一个例子,让我们看看如何在 x86-64 上生成 vmlinux:

文章插图
vmlinux overview
(此插图基于 Richard Y. Steven 的 博客。有过更新,并在作者允许的情况下使用 。)
进入 vmlinux 的所有 .o 文件首先进入它们自己的 built-in.a,它通过变量KBUILD_VMLINUX_INIT、KBUILD_VMLINUX_MAIN、KBUILD_VMLINUX_LIBS 表示,然后被收集到 vmlinux 文件中 。
在下面这个简化的 makefile 代码的帮助下,了解如何在 Linux 内核中实现递归 make:
# In top Makefilevmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) +$(call if_changed,link-vmlinux)# Variable assignmentsvmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN) $(KBUILD_VMLINUX_LIBS)export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y2) $(drivers-y) $(net-y) $(virt-y)export KBUILD_VMLINUX_LIBS := $(libs-y1)export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.ldsinit-y := init/drivers-y := drivers/ sound/ firmware/net-y := net/libs-y := lib/core-y := usr/virt-y := virt/# Transform to corresponding built-in.ainit-y := $(patsubst %/, %/built-in.a, $(init-y))core-y := $(patsubst %/, %/built-in.a, $(core-y))drivers-y := $(patsubst %/, %/built-in.a, $(drivers-y))net-y := $(patsubst %/, %/built-in.a, $(net-y))libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))libs-y2 := $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y)))virt-y := $(patsubst %/, %/built-in.a, $(virt-y))# Setup the dependency. vmlinux-deps are all intermediate objects, vmlinux-dirs# are phony targets, so every time comes to this rule, the recipe of vmlinux-dirs# will be executed. Refer "4.6 Phony Targets" of `info make`$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;# Variable vmlinux-dirs is the directory part of each built-in.avmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m)$(core-y) $(core-m) $(drivers-y) $(drivers-m)$(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))# The entry of recursive make$(vmlinux-dirs): $(Q)$(MAKE) $(build)=$@ need-builtin=1递归 make 的 配方(recipe)被扩展开是这样的:
make -f scripts/Makefile.build obj=init need-builtin=1这意味着 make 将进入 scripts/Makefile.build 以继续构建每个 built-in.a 。在scripts/link-vmlinux.sh 的帮助下,vmlinux 文件最终位于源根目录下 。
vmlinux 与 bzImage 对比许多 Linux 内核开发人员可能不清楚 vmlinux 和 bzImage 之间的关系 。例如,这是他们在 x86-64 中的关系:

文章插图
源代码根目录下的 vmlinux 被剥离、压缩后,放入 piggy.S,然后与其他对等对象链接到 arch/x86/boot/compressed/vmlinux 。同时,在 arch/x86/boot 下生成一个名为 setup.bin 的文件 。可能有一个可选的第三个文件,它带有重定位信息,具体取决于 CONFIG_X86_NEED_RELOCS 的配置 。
由内核提供的称为 build 的宿主程序将这两个(或三个)部分构建到最终的 bzImage 文件中 。
依赖跟踪kbuild 跟踪三种依赖关系:
- 所有必备文件(*.c 和 *.h)
- 所有必备文件中使用的 CONFIG_ 选项
- 用于编译该目标的命令行依赖项
#ifdef CONFIG_SMP__boot_cpu_id = cpu;#endif当 CONFIG_SMP 改变时,这段代码应该重新编译 。编译源文件的命令行也很重要,因为不同的命令行可能会导致不同的目标文件 。
当 .c 文件通过 #include 指令使用头文件时,你需要编写如下规则:
main.o: defs.h recipe...管理大型项目时,需要大量的这些规则;把它们全部写下来会很乏味无聊 。幸运的是,大多数现代 C 编译器都可以通过查看源文件中的 #include 行来为你编写这些规则 。对于 GNU 编译器集合(GCC),只需添加一个命令行参数:-MD depfile
# In scripts/Makefile.libc_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)-include $(srctree)/include/linux/compiler_types.h$(__c_flags) $(modkern_cflags)$(basename_flags) $(modname_flags)
推荐阅读
- Linux多进程和多线程的一次gdb调试实例
- Linux安装Mysql解决中文乱码
- LINUX 11G RAC ASM磁盘组在线增加磁盘扩容
- Linux IO磁盘篇整理小记
- Linux中的xargs命令
- 如何用 Linux 命令行工具解析和格式化输出 JSON
- linux文件目录结构
- linux - fcitx-rime 设置简体中文
- 如何在 Linux 中查找服务的端口号
- Linux零拷贝技术,看完这篇文章就懂了
