以x86架构32位机为例,即i386
从经典的helloworld程序开始
理解程序的编辑、编译、连接、运行的四个阶段
内核也是使用gcc、ld等工具编译连接出来的,并没有什么神秘之处
只不过文件繁多,代码树庞大而已,超出了大多数人的理解范围
就好像一般人对支配几千或几万块钱还是没有问题的
但是若突然让其支配上亿元时,一般人都是没有概念的
使用的工具make、gcc、ld、objdump、readelf、nm、objcopy、gzip等
一些程序的具体参数可以使用man查看具体含义
简单的浏览一下Documentation/kbuild目录中的几个文件
这几个文件介绍了内核的构建系统、Makefile的组织层次和一些特殊的命令等
阅读make的手册,了解基本的目标规则
编译之前先敲下make help,了解内核提供的一些参数
通过V=1参数显示具体的编译命令
内核在编译之前利用Kbuild系统提供的config机制解析各目录的Kconfig文件以便对内核进行剪裁
以make menuconfig为例
由顶层的Makefile开始匹配目标文件%config
解决完一些依赖后会进入scripts/kconfig目录执行子make
匹配scripts/kconfig/Makefile中的menuconfig目标
其依赖为scripts/kconfig/mconf小程序
编译出小程序mconf后,便运行该程序解析各个Kconfig文件
提供一个配置接口
配置完成后mconf便会在顶层目录生成一个.config文件
在编译内核的时候使用该.config文件生成
auto.conf供Makefile决定编译哪些目录
autoconf.h供代码预处理
这也是config机制的2个主要作用
使用make的- n、-p选项查看编译命令、变量等
以make bzImage为例
使用内核Makefile提供的参数V=1屏蔽@以便查看编译使用的参数和命令等
顶层的Makefile定义一些常用的变量、目录信息等
会包含对应架构下的目录下的Makefile,如arch/x86/Makefile
这样便找到目标bzImage,其依赖为顶层Makefile里的目标vmlinux
看下vmlinux的依赖$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
1. vmlinux.lds为对应架构的连接脚本,由arch/x86/kernel/vmlinux.lds.S生成
2. $(vmlinux-init)和$(vmlinux-main) 即各个.o与built-in.o文件
3. 这些vmlinux所依赖的.o目标文件由这2条规则
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
通过命令make -f scripts/Makefile.build obj=XXX/XXX编译所有的目录和子目录
总目录的控制由顶层Makefile定义
各个子目录的控制由其所在总目录下的Makfile和scripts/Makefile.lib控制
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
编译具体代码时都是使用scripts/Makefile.build这个Makefile
各个目录的built-in.o由对应目录下的.o文件连接而成
4. 顶层Makefile的目标vmlinux由rule_vmlinux__ => cmd_vmlinux__中的命令连接而成
5 . 解决完依赖vmlinux后
便执行arch/x86/Makefile中的目标bzImage的命令
make -f scripts/Makefile.build obj=arch/x86/boot arch/x86/boot/bzImage
6. 匹配arch/x86/boot/Makefile中的
规则$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
依赖2个2进制文件setup.bin和vmlinux.bin
7. 使用连接脚本arch/x86/boot/setup.ld生成setup.elf
setup.elf中的.o目标也在arch/x86/boot/Makefile中定义
使用objcopy得到依赖setup.bin
8. 含有压缩映像的arch/x86/boot/compressed/vmlinux
由顶层Makefile得到的vmlinux经objcopy得到arch/x86/boot/compressed/vmlinux.bin
使用gzip压缩vmlinux.bin得到vmlinux.bin.gz
使用arch/x86/boot/compressed/mkpiggy小程序得到arch/x86/boot/compressed/piggy.S
由arch/x86/boot/compressed/piggy.S经gcc编译后得到piggy.o
使用连接脚本arch/x86/boot/compressed/vmlinux.lds连接head_32.o、解压代码、…、piggy.o等
得到arch/x86/boot/compressed/vmlinux
9. 目标vmlinux.bin则会依赖arch/x86/boot/compressed/vmlinux
即需要先得到含有压缩过的vmlinux映像的连接合成文件
然后使用objcopy得到arch/x86/boot/vmlinux.bin
10. 最后使用小程序arch/x86/boot/tools/build将setup.bin和vmlinux.bin合并为bzImage
详细的注释请参考git://github.com/kernel-digger/linux-2.6.git
错漏之处还望不吝指出