u-boot的编译分两步:
- 第一步:配置,执行make xxx_defconfig
进行各项配置,生成.config
文件 (u-boot-2018.05之make配置过程分析)
- 第二步:编译,执行make
进行编译,生成可执行的二进制文件u-boot.*
顶层目标依赖
a). _all
和all
对$(ALL-y)
的依赖
从顶层Makefile开始查找,首先找到的是_all
伪目标:
# That's our default target when none is given on the command line
PHONY := _all
_all:
紧接着会对_all
伪目标添加all
伪目标的依赖:
PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif
all
自身依赖于$(ALL-y)
all: $(ALL-y)
b). $(ALL-y)
对u-boot
目标文件的依赖
$(ALL-y)
定义了最终需要生成所有文件:
# Always append ALL so that arch config.mk's can add custom ones
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
ALL-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin
ifeq ($(CONFIG_SPL_FSL_PBL),y)
ALL-$(CONFIG_RAMBOOT_PBL) += u-boot-with-spl-pbl.bin
else
ifneq ($(CONFIG_SECURE_BOOT), y)
# For Secure Boot The Image needs to be signed and Header must also
# be included. So The image has to be built explicitly
ALL-$(CONFIG_RAMBOOT_PBL) += u-boot.pbl
endif
endif
ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin
ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.img
ALL-$(CONFIG_TPL) += tpl/u-boot-tpl.bin
ALL-$(CONFIG_OF_SEPARATE) += u-boot.dtb
ifeq ($(CONFIG_SPL_FRAMEWORK),y)
ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img
endif
ALL-$(CONFIG_OF_HOSTFILE) += u-boot.dtb
ifneq ($(CONFIG_SPL_TARGET),)
ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%)
endif
ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf
ALL-$(CONFIG_EFI_APP) += u-boot-app.efi
ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi
ifneq ($(BUILD_ROM),)
ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom
endif
# enable combined SPL/u-boot/dtb rules for tegra
ifeq ($(CONFIG_TEGRA)$(CONFIG_SPL),yy)
ALL-y += u-boot-tegra.bin u-boot-nodtb-tegra.bin
ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb-tegra.bin
endif
以上的$(ALL-y)
目标中看起来非常复杂,但除了第一行的通用目标外,其余目标都只在特殊条件下才生成,这里略去不提。只分析通用目标依赖:
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
i. 依赖u-boot.bin
依赖u-boot.bin
:
ifeq ($(CONFIG_OF_SEPARATE),y)
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
$(call if_changed,cat)
u-boot.bin: u-boot-dtb.bin FORCE
$(call if_changed,copy)
else
u-boot.bin: u-boot-nodtb.bin FORCE
$(call if_changed,copy)
endif
如果打开了device tree支持,则有依赖关系: u-boot.bin --> u-boot-dtb.bin --> u-boot-nodtb.bin + dts/dt.dtb
这里没有打开device tree支持,所以: u-boot.bin --> u-boot-nodtb.bin
进一步,对于u-boot-nodtb.bin
,其规则是:
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
ii. 依赖System.map
依赖System.map
:
System.map: u-boot
@$(call SYSTEM_MAP,$<) > $@
iii. 依赖u-boot.cfg
依赖u-boot.cfg
:
u-boot.cfg: include/config.h FORCE
$(call if_changed,cpp_cfg)
2. u-boot
文件目标依赖
a). 依赖u-boot
依赖u-boot
:
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
$(call if_changed,u-boot__)
ifeq ($(CONFIG_KALLSYMS),y)
$(call cmd,smap)
$(call cmd,u-boot__) common/system_map.o
endif
其中$(u-boot-init)
和$(u-boot-main)
分别被定义为:
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
i. 依赖$(head-y)
$(head-y)
在arch/arm/Makefile
被定义为:
head-y := arch/arm/cpu/$(CPU)/start.o
ii. 依赖$(libs-y)
在顶层Makefile中搜索一下$(libs-y)
,其被定义为各层驱动目录下build-in.o
的集合:
libs-y += lib/
...此处...
libs-y := $(sort $(libs-y))
u-boot-dirs := $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
u-boot-main := $(libs-y)
b). 依赖u-boot.lds
依赖u-boot.lds
:
u-boot.lds: $(LDSCRIPT) prepare FORCE
$(call if_changed_dep,cpp_lds)
其中$(LDSCRIPT)
的定义如下:
# If board code explicitly specified LDSCRIPT or CONFIG_SYS_LDSCRIPT, use
# that (or fail if absent). Otherwise, search for a linker script in a
# standard location.
ifndef LDSCRIPT
#LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds.debug
ifdef CONFIG_SYS_LDSCRIPT
# need to strip off double quotes
LDSCRIPT := $(srctree)/$(CONFIG_SYS_LDSCRIPT:"%"=%)
endif
endif
# If there is no specified link script, we look in a number of places for it
ifndef LDSCRIPT
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot.lds
endif
endif
如果没有定义LDSCRIPT
和CONFIG_SYS_LDSCRIPT
,则默认使用u-boot自带的lds文件。包括board/$(BOARDIDR)
和$(CPUDIR)
目录下定制的针对board或cpu的lds文件,如果没有定制的lds文件,则采用arch/$(ARCH)/cpu
目录下默认的u-boot.lds
3. prepare
系列目标依赖
a). prepare
系列依赖的规则
实际上prepare
是一系列prepare
伪目标和动作的组合,完成编译前的准备工作:
# Things we need to do before we recursively start building the kernel
# or the modules are listed in "prepare".
# A multi level approach is used. prepareN is processed before prepareN-1.
# archprepare is used in arch Makefiles and when processed asm symlink,
# version.h and scripts_basic is processed / created.
# Listed in dependency order
PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3
# prepare3 is used to check if we are building in a separate output directory,
# and if so do:
# 1) Check that make has not been executed in the kernel src $(srctree)
prepare3: include/config/uboot.release
ifneq ($(KBUILD_SRC),)
@$(kecho) ' Using $(srctree) as source for U-Boot'
$(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \
echo >&2 " $(srctree) is not clean, please run 'make mrproper'"; \
echo >&2 " in the '$(srctree)' directory.";\
/bin/false; \
fi;
endif
# prepare2 creates a makefile if using a separate output directory
prepare2: prepare3 outputmakefile
prepare1: prepare2 $(version_h) $(timestamp_h) \
include/config/auto.conf
ifeq ($(wildcard $(LDSCRIPT)),)
@echo >&2 " Could not find linker script."
@/bin/false
endif
archprepare: prepare1 scripts_basic
prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=.
# All the preparing..
prepare: prepare0
伪目标prepare
,prepare0
,archprepare
,prepare1
,prepare2
,prepare3
之间的依赖如下:
b). prepare
系列其他的依赖规则
在prepare1
的依赖列表中,除了include/config/auto.conf
外,还有$(version_h)
和$(timestamp_h)
,他们的依赖分别为:
$(version_h): include/config/uboot.release FORCE
$(call filechk,version.h)
$(timestamp_h): $(srctree)/Makefile FORCE
$(call filechk,timestamp.h)
这里的两个filechk
函数调用会动态生成version.h
和timestamp.h
。
对于最里层的prepare3
的依赖include/config/uboot.release
,还存在下一级依赖:
# Store (new) UBOOTRELEASE string in include/config/uboot.release
include/config/uboot.release: include/config/auto.conf FORCE
$(call filechk,uboot.release)
对于include/config/auto.conf
,Makefile中有一个匹配的规则:
# If .config is newer than include/config/auto.conf, someone tinkered
# with it and forgot to run make oldconfig.
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
@# If the following part fails, include/config/auto.conf should be
@# deleted so "make silentoldconfig" will be re-run on the next build.
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \
{ rm -f include/config/auto.conf; false; }
@# include/config.h has been updated after "make silentoldconfig".
@# We need to touch include/config/auto.conf so it gets newer
@# than include/config.h.
@# Otherwise, 'make silentoldconfig' would be invoked twice.
$(Q)touch include/config/auto.conf
所以include/config/auto.conf
依赖于$(KCONFIG_CONFIG)
和include/config/auto.conf.cmd
。
- $(KCONFIG_CONFIG)
实际上就是.config
文件;
- include/config/auto.conf.cmd
是由fixdep
在编译时生成的依赖文件。