【u-boot-2018.11】make编译过程目标依赖分析

一、u-boot编译

uboot的编译分为两步:配置、编译。

(1)第一步:配置,执行make pangu_basic_defconfig进行配置,生成.config文件

(2)第二步:编译,执行make进行编译,生成u-boot.*。

二、u-boot编译过程目标依赖分析

1. u-boot目标依赖关系图

【u-boot-2018.11】make编译过程目标依赖分析_第1张图片

根据以上目标依赖关系图,为了分析方便,将整个目标依赖图分为三部分:_all、u-boot、prepare。

2. 目标_all

从顶层的Makefile开始查找,首先找到的目标为_all,126行:

# That's our default target when none is given on the command line
PHONY := _all
_all:

紧接着会对_all伪目标添加all伪目标依赖,192行:

# If building an external module we do not care about the all: rule
# but instead _all depend on modules
PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif

all自身依赖于$(ALL-y)和cfg,913行:

all:		$(ALL-y) cfg
ifeq ($(CONFIG_DM_I2C_COMPAT)$(CONFIG_SANDBOX),y)
	@echo "===================== WARNING ======================"
	@echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
	@echo "(possibly in a subsequent patch in your series)"
	@echo "before sending patches to the mailing list."
	@echo "===================================================="
endif
	@# Check that this build does not use CONFIG options that we do not
	@# know about unless they are in Kconfig. All the existing CONFIG
	@# options are whitelisted, so new ones should not be added.
	$(call cmd,cfgcheck,u-boot.cfg)

2.1. 目标$(ALL-y)

$(ALL-y)定义了最终需要生成的所有文件,804行

# 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 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
ifeq ($(CONFIG_MX6)$(CONFIG_SECURE_BOOT), yy)
ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot-ivt.img
else
ifeq ($(CONFIG_MX7)$(CONFIG_SECURE_BOOT), yy)
ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot-ivt.img
else
ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.img
endif
endif
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)$(CONFIG_BUILD_ROM),)
ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom
endif

# Build a combined spl + u-boot image for sunxi
ifeq ($(CONFIG_ARCH_SUNXI)$(CONFIG_SPL),yy)
ALL-y += u-boot-sunxi-with-spl.bin
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

# Add optional build target if defined in board/cpu/soc headers
ifneq ($(CONFIG_BUILD_TARGET),)
ALL-y += $(CONFIG_BUILD_TARGET:"%"=%)
endif

ifneq ($(CONFIG_SYS_INIT_SP_BSS_OFFSET),)
ALL-y += init_sp_bss_offset_check
endif

ifeq ($(CONFIG_MPC85xx)$(CONFIG_OF_SEPARATE),yy)
ALL-y += u-boot-with-dtb.bin
endif

以上的$(ALL-y)目标中看起来很复杂,但是除了第一行的通用目标外,其余的目标都只有在特殊条件下才生成,这里略去不提,只分析通用目标依赖:

ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map binary_size_check

2.1.1.目标u-boot.bin

在$(ALL-y)的通用目标中,先分析u-boot.bin,935行

ifeq ($(CONFIG_MULTI_DTB_FIT),y)

fit-dtb.blob: dts/dt.dtb FORCE
	$(call if_changed,mkimage)

MKIMAGEFLAGS_fit-dtb.blob = -f auto -A $(ARCH) -T firmware -C none -O u-boot \
	-a 0 -e 0 -E \
	$(patsubst %,-b arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) -d /dev/null

u-boot-fit-dtb.bin: u-boot-nodtb.bin fit-dtb.blob
	$(call if_changed,cat)

u-boot.bin: u-boot-fit-dtb.bin FORCE
	$(call if_changed,copy)
else 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.bin  -->  u-boot-dtb.bin  -->  u-boot-nodtb.bin dts/dt.dtb

由以上可知,u-boot.bin的依赖有两个:u-boot-nodtb.bin和dts/dt.dtb。

(1)依赖u-boot-nodtb.bin,1039行

u-boot-nodtb.bin: u-boot FORCE
	$(call if_changed,objcopy)
	$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
	$(BOARD_SIZE_CHECK)

(2)依赖dts/dt.dtb,929行

dts/dt.dtb: u-boot
	$(Q)$(MAKE) $(build)=dts dtbs

目标u-boot-nodtb.bin和dts/dt.dtb的依赖是同一个u-boot。u-boot的分析在后面的一节。

2.1.2.目标u-boot.srec、u-boot.sym、System.map

(1)u-boot.srec,976行

u-boot.hex u-boot.srec: u-boot FORCE
	$(call if_changed,objcopy)

(2)u-boot.sym,1393行

u-boot.sym: u-boot FORCE
	$(call if_changed,sym)

(3)System.map,1579行

System.map:	u-boot
		@$(call SYSTEM_MAP,$<) > $@

以上三个目标的依赖都是u-boot。

2.1.3.目标binary_size_check

binary_size_check: u-boot-nodtb.bin FORCE
	@file_size=$(shell wc -c u-boot-nodtb.bin | awk '{print $$1}') ; \
	map_size=$(shell cat u-boot.map | \
		awk '/_image_copy_start/ {start = $$1} /_image_binary_end/ {end = $$1} END {if (start != "" && end != "") print "ibase=16; " toupper(end) " - " toupper(start)}' \
		| sed 's/0X//g' \
		| bc); \
	if [ "" != "$$map_size" ]; then \
		if test $$map_size -ne $$file_size; then \
			echo "u-boot.map shows a binary size of $$map_size" >&2 ; \
			echo "  but u-boot-nodtb.bin shows $$file_size" >&2 ; \
			exit 1; \
		fi \
	fi

目标binary_size_check的依赖是u-boot-nodtb.bin,在分析u-boot.bin时,已经分析了u-boot.nodtb.bin,它的依赖也是u-boot。

2.2. 目标cfg

cfg依赖于u-boot.cfg,907行:

cfg: u-boot.cfg

而u-boot.cfg又依赖于include/config.h,537行

u-boot.cfg spl/u-boot.cfg tpl/u-boot.cfg: include/config.h FORCE
	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf $(@)

依赖include/config.h是一个头文件,该头文件是在配置编译过程中自动生成的。

3.目标u-boot的依赖分析

从分析2.1可知,$(ALL-y)的所有通用目标最后都依赖于u-boot,因此在这里对u-boot进行分析,1380行:

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的依赖有三个:$(u-boot-init)、$(u-boot-main)、u-boot.lds。其中$(u-boot-init)和$(u-boot-main)分别被定义为,743行:

u-boot-init := $(head-y)
u-boot-main := $(libs-y)

3.1.依赖$(head-y)

$(head-y)的定义位于arch/arm/Makefile中,92行:

head-y := arch/arm/cpu/$(CPU)/start.o

3.2.依赖$(libs-y)

$(libs-y)位于顶层的Makefile中,在该Makefile中搜索一下,可以发现$(libs-y)被定义为各层驱动目录下build-in.o的集合,681 ~ 741行:

libs-y += lib/
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
libs-$(CONFIG_OF_EMBED) += dts/
libs-y += fs/
libs-y += net/
libs-y += disk/
libs-y += drivers/
libs-y += drivers/dma/
libs-y += drivers/gpio/
libs-y += drivers/i2c/
libs-y += drivers/mtd/
libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/raw/
libs-y += drivers/mtd/onenand/
libs-$(CONFIG_CMD_UBI) += drivers/mtd/ubi/
libs-y += drivers/mtd/spi/
libs-y += drivers/net/
libs-y += drivers/net/phy/
libs-y += drivers/pci/
libs-y += drivers/power/ \
	drivers/power/domain/ \
	drivers/power/fuel_gauge/ \
	drivers/power/mfd/ \
	drivers/power/pmic/ \
	drivers/power/battery/ \
	drivers/power/regulator/
libs-y += drivers/spi/
libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
libs-$(CONFIG_SYS_FSL_MMDC) += drivers/ddr/fsl/
libs-$(CONFIG_ALTERA_SDRAM) += drivers/ddr/altera/
libs-y += drivers/serial/
libs-y += drivers/usb/dwc3/
libs-y += drivers/usb/common/
libs-y += drivers/usb/emul/
libs-y += drivers/usb/eth/
libs-y += drivers/usb/gadget/
libs-y += drivers/usb/gadget/udc/
libs-y += drivers/usb/host/
libs-y += drivers/usb/musb/
libs-y += drivers/usb/musb-new/
libs-y += drivers/usb/phy/
libs-y += drivers/usb/ulpi/
libs-y += cmd/
libs-y += common/
libs-y += env/
libs-$(CONFIG_API) += api/
libs-$(CONFIG_HAS_POST) += post/
libs-y += test/
libs-y += test/dm/
libs-$(CONFIG_UT_ENV) += test/env/
libs-$(CONFIG_UT_OVERLAY) += test/overlay/

libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)

libs-y := $(sort $(libs-y))

u-boot-dirs	:= $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples

u-boot-alldirs	:= $(sort $(u-boot-dirs) $(patsubst %/,%,$(filter %/, $(libs-))))

libs-y		:= $(patsubst %/, %/built-in.o, $(libs-y))

3.3.依赖u-boot.lds

依赖u-boot.lds的定义位于顶层Makefile中,1531行:

u-boot.lds: $(LDSCRIPT) prepare FORCE
	$(call if_changed_dep,cpp_lds)

它的依赖有两个:$(LDSCRIPT)和prepare。依赖prepare在后面的一节分析,这里分析只分析一下$(LDSCRIPT),它的定义如下,567行:

# 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/$(BOARDDIR)和$(CPUDIR)目录下定制的针对board或cpu的lds文件;如果没有定制的lds文件,则采用arch/$(ARCH)/cpu目录下默认的lds文件。

4.prepare系列目标依赖

实际上prepare是一系列prepare伪目标和动作的组合,完成编译前的准备工作,它的相关的定义如下,1426行:

# 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

ifeq ($(CONFIG_USE_DEFAULT_ENV_FILE),y)
prepare1: $(defaultenv_h)
endif

archprepare: prepare1 scripts_basic

prepare0: archprepare FORCE
	$(Q)$(MAKE) $(build)=.

# All the preparing..
prepare: prepare0

伪目标prepare、prepare0、archprepare、prepare1、prepare2、prepare3的依赖关系在第1节中查看。

(1)在prepare1的依赖列表中,除了include/config/auto.conf之外,还有$(version_h)和$(timestamp_h),它们的依赖关系如下,440行:

version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.h
defaultenv_h := include/generated/defaultenv_autogenerated.h

(2)对于位于最后的prepare3的依赖include/config/uboot.release,它还有下一级依赖,1421行:

# Store (new) UBOOTRELEASE string in include/config/uboot.release
include/config/uboot.release: include/config/auto.conf FORCE
	$(call filechk,uboot.release)

(3)对于include/config/auto.conf,Makefile中有一个匹配规则,525行:

# 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 syncconfig
	@# 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在编译时生成的依赖文件。

你可能感兴趣的:(u-boot)