u-boot的编译分为两步:配置、编译。
(1)第一步:配置,执行make pangu_basic_defconfig进行配置,生成.config文件
(2)第二步:编译,执行make进行编译,生成u-boot.*。
u-boot从u-boot-2014.10版本引入Kbuild系统以后,Makefile的管理和组织跟以前版本有了很大的不同,这使得Makefile变得很复杂。
整个Makefile中,include很多其他不同用途的Makefile,各种目标和依赖也很多,因此要想完全搞清楚make的执行过程很困难,因此先根据u-boot编译过程慢慢分析,这里先分析u-boot的配置过程。
执行配置命令时,u-boot根目录下的Makefile中有唯一的规则匹配目标:495行
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
其中$(build)定义在scripts/Kbuild.include中:182行
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
因此上面的命令展开以后就是:
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.build obj=scripts/kconfig pangu_basic_defconfig
-f表示指定Makefile文件,因此make时实际运行的Makefile文件为scripts/Makefile.build。
依赖scripts_basic的定义位于u-boot顶层目录下的Makefile中:414行
# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
由上可知,scripts_basic并没有进一步的依赖,展开后的规则如下:
scripts_basic:
$(Q) make -f $(srctree)/scripts/Makefile.build obj=scripts/basic
$(Q) rm -f .tmp_quiet_recordmcount
-f表示指定Makefile文件,因此make时实际运行的Makefile文件为scripts/Makefile.build。
# SPDX-License-Identifier: GPL-2.0
# ==========================================================================
# Building
# ==========================================================================
# Modified for U-Boot
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif
根据传入的obj参数,设置src:
(1)对于scripts_basic目标,obj=scripts/basic,那么src=scripts/basic;(2)而对于%config目标,obj=scripts/kconfig,那么src=scripts/kconfig。
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
(1)当src=scripts/basic时,这里替换展开后相当于:
include ./scripts/basic/Makefile
那么对于scripts目标,它的最终结果就是编译scripts/basic/fixdep.c生成主机上的可执行文件fixdep。
(2)当src=scripts/kconfig时,这里替换展开后相当于:
include ./scripts/kconfig/Makefile
对于这里传入的目标pangu_basic_defconfig,它的匹配目标是:
%_defconfig: $(obj)/conf
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
展开为:
pangu_basic_defconfig: scripts/kconfig/conf
$(Q)scripts/kconfig/conf --defconfig=arch/../configs/pangu_basic_defconfig Kconfig
此处目标pangu_basic_defconfig依赖于scripts/kconfig/conf,接下来检查并生成依赖:
hostprogs-y := conf nconf mconf kxgettext qconf gconf
hostprogs-y指出conf被定义为主机上可执行的程序,其依赖于另外两个文件:
conf-objs := conf.o zconf.tab.o
通过编译conf.c和zconf.tab.c生成conf-objs,并链接为scripts/kconfig/conf。
生成依赖后就是执行目标的命令了:
$(Q)scripts/kconfig/conf --defconfig=arch/../configs/pangu_basic_defconfig Kconfig
conf工具从根目录下开始树状读取默认的Kconfig文件,分析其配置并保存在内存中。分析完默认的Kconfig文件后,再读取指定文件(即arch/../configs/pangu_basic_defconfig)更新得到最终的符号表,并输出到.config文件中。