UBOOT版本:uboot2018.03,开发板myimx8mmek240。
本文接续上篇文章,采用自下而上的方法,先从最原始的依赖开始,一步一步,执行命令生成目标。这里先把上节所有依赖关系再次列在这里:
--------------------------------------------|
| arch/arm/cpu \ $(u-boot-dirs)|
arch/arm/cpu/built-in.o \ | arch/arm/cpu/armv8 \ 的值 |
arch/arm/cpu/armv8/built-in.o \ | arch/arm/lib \ |
arch/arm/lib/built-in.o \ | arch/arm/mach-imx \ |
arch/arm/mach-imx/built-in.o \ | board/myzr/common \ |
board/myzr/common/built-in.o \ | board/myzr/myimx8mm \ |
board/myzr/myimx8mm/built-in.o \ | cmd \ |
cmd/built-in.o \ | common \ |
common/built-in.o \ | disk \ |
disk/built-in.o \ | drivers \ |
drivers/built-in.o \ | drivers/dma \ |
drivers/dma/built-in.o \ | drivers/gpio \ |
drivers/gpio/built-in.o \ | drivers/i2c \ |
include/config/auto.conf scripts_basic drivers/i2c/built-in.o \ | drivers/mtd \ |
\ / drivers/mtd/built-in.o \ | drivers/mtd/onenand \ |
\ / drivers/mtd/onenand/built-in.o \ | drivers/mtd/spi \ |
\ / drivers/mtd/spi/built-in.o \ | drivers/net \ |
scripts prepare drivers/net/built-in.o \ | drivers/net/phy \ |
----- ----- drivers/net/phy/built-in.o \ | . |
\ / . | . |
\ / . | . |
\ / . | env \ |
\ / env/built-in.o \ | fs \ |
$(u-boot-dirs) fs/built-in.o \ | lib \ |
------------------------- lib/built-in.o \ | net \ |
| \ net/built-in.o \ | test \ |
| \ test/built-in.o \ | test/dm |
| 依赖 \ test/dm/built-in.o ---------------------------------------------
| \ || include/config/uboot.release
| \ || arch/arm/cpu/armv8/u-boot.lds |
| \ || || outputmakefile prepare3
$(u-boot-init)==$(head-y) $(u-boot-main)== u-boot.lds FORCE \ /
arch/arm/cpu/armv8/start.o $(libs-y) / / \ /
\ | / / \ /
\ | / / \ /
\ | / / \ / include/generated/version_autogenerated.h include/generated/timestamp_autogenerated.h
\ | / / \ / | /
\ | / / \ / | /
---------------------------------------------- prepare2 $(version_h) $(timestamp_h) include/config/auto.conf(auto.conf里去掉了.config中的注释项目以及空格行,其它的都一样)
| \ \ / /
| \ \ / /
u-boot \ \ / /
--------------------------------------------------------------------------------------- \ \ / /
/ / \ \ \ -------------------------------------------
/ / \ \ \ prepare1 scripts_basic
/ | \ \ \ ------- -------------
| | | | | \ /
| dts/dt.dtb | | | \ /
| -------------------------- | | | -----------------------------------------
| / / | | | | archprepare
u-boot-nodtb.bin / / | | | | ----------
--------------- / / | | | | |
| \ \ / / | | | | |
| \ \/ / | | | | prepare0
| \ /\ / | | | | --------
| \ / \ / | | | | |
| \/ \-------\ / | | | | |
| /\ \ / | | | | tools prepare
| / \ \ / | | | | ----- -----
| / \ \/ | | | | \ /
u-boot-dtb.bin \ /\ | | | | \ /
-------------- \ / \-----------\ | | | | \ /
| \ / \ | | | | \ /
| \ / \| | | | spl/u-boot-spl
| \ / \ | | | --------------
| \ / |\--------------| | | | |
| \/ | | | | | |
u-boot.bin u-boot.img/u-boot-dtb.img u-boot.dtb binary_size_check u-boot.srec u-boot.sym System.map spl/u-boot-spl.bin
---------- -------------------------- --------- ----------------- ----------- --------- -------- -----------------
/ | | | | | | | |
/ | | | | | | | |
/ | | | | | | | |
u-boot.elf | | | | | | | |
--------- | | | | | | | |
\ | | | | | | | |
\ | | | | | | | |
\ \ \ | / / / / / include/config.h
\ \ \ | / / / / / |
\ \ \ | / / / / / |
\ \ \ | / / / / / |
\ \ \ | / / / / / |
\ \ \ | / / / / / u-boot.cfg
\ \ \ | / / / / / |
\ \ \ | / / / / / |
---------------------------------------------------------------------------------------------------------- |
$(ALL-y) cfg
\ /
\ /
\ /
-----------------------------------------------------------------------------------------------------
all
|
_all
参见:UBOOT编译--- include/config/auto.conf、 include/config/auto.conf.cmd、 include/generated/autoconf.h (二)。auto.conf 和 .config 的差别是:auto.conf 里去掉了 .config 中的注释项目以及空格行,其它的都一样。
参见:UBOOT编译--- make xxx_deconfig过程详解(一) - 4.1 依赖 scripts_basic。
<<<<<<<<<顶层Makefile>>>>>>>>>
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# targets and others. In general all targets except *config targets.
# Additional helpers built in scripts/
# Carefully list dependencies so we do not try to build scripts twice
# in parallel
PHONY += scripts
scripts: scripts_basic include/config/auto.conf
$(Q)$(MAKE) $(build)=$(@) //规则
规则展开后为:make -f $(srctree)/scripts/Makefile.build obj=scripts。未指定目标,采用Makefile.build中的默认目标__build。且在Makefile.build中会引用scripts目录下的Makefile。
# <<<<<<<<<scripts/Makefile.build>>>>>>>>>
PHONY := __build
__build:
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) // scripts/
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) // scripts/Makefile
include $(kbuild-file) (1)//include scripts/Makefile
......
include scripts/Makefile.lib //要关注这个引用位置 在include $(kbuild-file)之后.下面第6项会用来解析subdir-ym
......
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a (2)lib-target :=
endif
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)//去空格函数—strip
builtin-target := $(obj)/built-in.o (3) builtin-target :=
endif
modorder-target := $(obj)/modules.order
# We keep a list of all modules in $(MODVERDIR)
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
# Descending
# ---------------------------------------------------------------------------
PHONY += $(subdir-ym)
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
1. 引用scripts/Makefile
# <<<<<<<<<scripts/Makefile>>>>>>>>>
hostprogs-$(CONFIG_BUILD_BIN2C) += bin2c //CONFIG_BUILD_BIN2C未定义
always := $(hostprogs-y) //特别注意always定义的这个位置
//由于 Makefile中
//(1)使用“=”进行赋值,变量的值是整个makefile中最后被指定的值;
//(2)使用":="进行赋值,即根据当前位置进行赋值
// 因此这里的always只与hostprogs-$(CONFIG_BUILD_BIN2C)的定义有关,与后面的hostprogs-y无关
# The following hostprogs-y programs are only build on demand
hostprogs-y += docproc
# These targets are used internally to avoid "is up to date" messages
PHONY += build_docproc
build_docproc: $(obj)/docproc
@:
# Let clean descend into subdirs
subdir- += basic kconfig
subdir-$(CONFIG_DTC) += dtc //有定义
特别注意always定义的这个位置,由于CONFIG_BUILD_BIN2C未定义,always为空(注意always后面的hostprogs-y不生效)。此外CONFIG_DTC定义为y,因此subdir-y+= dtc。
2. lib-target的定义
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a (2)lib-target :=
endif
$(lib-y) $(lib-m) $(lib-)在scripts/Makefile中均未定义,因此lib-target := 。
3. builtin-target的定义
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)//去空格函数—strip
builtin-target := $(obj)/built-in.o (3) builtin-target :=
endif
$(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)在scripts/Makefile中均未定义,因此builtin-target:= 。
4. extra-y的定义
extra-y 在scripts/Makefile中未定义,因此extra-y:= 。
5. always的定义
在scripts/Makefile中always为空,因此always:= 。
6. subdir-ym的定义
# <<<<<<<<<scripts/Makefile.lib >>>>>>>>>
# Subdirectories we need to descend into
subdir-ym := $(sort $(subdir-y) $(subdir-m)) // dtc
......
subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) //scripts/dtc
subdir-ym定义在在scripts/Makefile.lib中,展开为scripts/dtc 。要想构建默认目标__build,要先构建依赖$ (subdir-ym)(即scripts/dtc)。$(subdir-ym)的规则也定义在Makefile.build中(递归调用),就是执行make -f ./scripts/Makefile.build obj=scripts/dtc。
make -f ./scripts/Makefile.build obj=scripts/dtc由于未指定目标,采用Makefile.build中的默认目标__build
# <<<<<<<<<scripts/Makefile.build>>>>>>>>>
PHONY := __build
__build:
# 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) //include scripts/dtc/Makefile (1)
......
include scripts/Makefile.lib //要关注这个引用位置 在include $(kbuild-file)之后 (2)
......
# Do not include host rules unless needed
ifneq ($(hostprogs-y)$(hostprogs-m),)
include scripts/Makefile.host //要关注这个引用 (3)
endif
......
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a (4)lib-target :=
endif
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)//去空格函数—strip
builtin-target := $(obj)/built-in.o (5) builtin-target :=
endif
modorder-target := $(obj)/modules.order
......
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
1. 引用scripts/dtc目录下的Makefile
# <<<<<<<<<scripts/dtc/Makefile>>>>>>>>>
hostprogs-y := dtc
always := $(hostprogs-y) //always := dtc
dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
srcpos.o checks.o util.o
dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
# Source files need to get at the userspace version of libfdt_env.h to compile
HOSTCFLAGS_DTC := -I$(src) -I$(src)/libfdt
HOSTCFLAGS_checks.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_data.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_flattree.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC)
# dependencies on generated files need to be listed explicitly
$(obj)/dtc-lexer.lex.o: $(obj)/dtc-parser.tab.h
# generated files need to be cleaned explicitly
clean-files := dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h
# Added for U-Boot
subdir-$(CONFIG_PYLIBFDT) += pylibfdt //未定义CONFIG_PYLIBFDT
2. 引用scripts/Makefile.lib
# <<<<<<<<<scripts/Makefile.lib>>>>>>>>>
always := $(addprefix $(obj)/,$(always)) //always := scripts/dtc/dtc
3. 引用scripts/Makefile.host
# <<<<<<<<<scripts/Makefile.host>>>>>>>>>
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) //(1) = dtc
# C executables linked based on several .o files
host-cmulti := $(foreach m,$(__hostprogs),\
$(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) //(2) dtc
# Object (.o) files compiled from .c files
host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))//(3) dtc-objs
......
__hostprogs := $(addprefix $(obj)/,$(__hostprogs)) //(4) scripts/dtc/dtc-objs
host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) //(5) scripts/dtc/dtc
host-cobjs := $(addprefix $(obj)/,$(host-cobjs)) //(6) cripts/dtc/**.o
......
# Link an executable based on list of .o files, all plain c
# host-cmulti -> executable
quiet_cmd_host-cmulti = HOSTLD $@
cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
$(addprefix $(obj)/,$($(@F)-objs)) \
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) //(7) scripts/dtc/dtc的编译 == $(always)
$(host-cmulti): FORCE
$(call if_changed,host-cmulti)
$(call multi_depend, $(host-cmulti), , -objs)
# Create .o file from a single .c file
# host-cobjs -> .o
quiet_cmd_host-cobjs = HOSTCC $@
cmd_host-cobjs = $(HOSTCC) $(hostc_flags) -c -o $@ $< //(6) 所有.o的编译
$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE
$(call if_changed_dep,host-cobjs)
4. lib-target的定义
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a (2)lib-target :=
endif
$(lib-y) $(lib-m) $(lib-)在scripts/Makefile中均未定义,因此lib-target := 。
5. builtin-target的定义
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)//去空格函数—strip
builtin-target := $(obj)/built-in.o (3) builtin-target :=
endif
$(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)在scripts/Makefile中均未定义,因此builtin-target:= 。
6. extra-y的定义
extra-y 在scripts/Makefile中未定义,因此extra-y:= 。
7. always的定义
在scripts/dtc/Makefil中定义为dtc,在scripts/Makefile.lib中添加目录前缀,最终为scripts/dtc/dtc。
8. subdir-ym的定义
subdir-ym为空。
综上,对于make -f ./scripts/Makefile.build obj=scripts/dtc:
- KBUILD_BUILTIN为y,$(builtin-target) $(lib-target) $(extra-y)为空;
- $(subdir-ym)为空;
- $(always)为scripts/dtc/dtc;
- 展开为:
- __build: $(always)
- @:
要想构建默认目标__build,要先构建依赖$ (always)(即scripts/dtc/dtc)。构建$ (always)等价于构建$(host-cmulti)。
编译打印命令如下:
make -f ./scripts/Makefile.build obj=scripts
HOSTCC scripts/dtc/dtc.o
HOSTCC scripts/dtc/flattree.o
HOSTCC scripts/dtc/fstree.o
HOSTCC scripts/dtc/data.o
HOSTCC scripts/dtc/livetree.o
HOSTCC scripts/dtc/treesource.o
HOSTCC scripts/dtc/srcpos.o
HOSTCC scripts/dtc/checks.o
HOSTCC scripts/dtc/util.o
SHIPPED scripts/dtc/dtc-lexer.lex.c
SHIPPED scripts/dtc/dtc-parser.tab.h
HOSTCC scripts/dtc/dtc-lexer.lex.o
SHIPPED scripts/dtc/dtc-parser.tab.c
HOSTCC scripts/dtc/dtc-parser.tab.o
HOSTLD scripts/dtc/dtc
真实执行的完整命令如下:
make -f ./scripts/Makefile.build obj=scripts
make -f ./scripts/Makefile.build obj=scripts/dtc
cc -Wp,-MD,scripts/dtc/.dtc.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/dtc.o scripts/dtc/dtc.c
cc -Wp,-MD,scripts/dtc/.flattree.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/flattree.o scripts/dtc/flattree.c
cc -Wp,-MD,scripts/dtc/.fstree.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/fstree.o scripts/dtc/fstree.c
cc -Wp,-MD,scripts/dtc/.data.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/data.o scripts/dtc/data.c
cc -Wp,-MD,scripts/dtc/.livetree.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/livetree.o scripts/dtc/livetree.c
cc -Wp,-MD,scripts/dtc/.treesource.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/treesource.o scripts/dtc/treesource.c
cc -Wp,-MD,scripts/dtc/.srcpos.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/srcpos.o scripts/dtc/srcpos.c
cc -Wp,-MD,scripts/dtc/.checks.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/checks.o scripts/dtc/checks.c
cc -Wp,-MD,scripts/dtc/.util.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/util.o scripts/dtc/util.c
cat scripts/dtc/dtc-lexer.lex.c_shipped > scripts/dtc/dtc-lexer.lex.c
cat scripts/dtc/dtc-parser.tab.h_shipped > scripts/dtc/dtc-parser.tab.h
cc -Wp,-MD,scripts/dtc/.dtc-lexer.lex.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/dtc-lexer.lex.o scripts/dtc/dtc-lexer.lex.c
cat scripts/dtc/dtc-parser.tab.c_shipped > scripts/dtc/dtc-parser.tab.c
cc -Wp,-MD,scripts/dtc/.dtc-parser.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/dtc -Iscripts/dtc/libfdt -c -o scripts/dtc/dtc-parser.tab.o scripts/dtc/dtc-parser.tab.c
cc -o scripts/dtc/dtc scripts/dtc/dtc.o scripts/dtc/flattree.o scripts/dtc/fstree.o scripts/dtc/data.o scripts/dtc/livetree.o scripts/dtc/treesource.o scripts/dtc/srcpos.o scripts/dtc/checks.o scripts/dtc/util.o scripts/dtc/dtc-lexer.lex.o scripts/dtc/dtc-parser.tab.o
综上,对于make -f $(srctree)/scripts/Makefile.build obj=scripts,默认目标__build:
- KBUILD_BUILTIN为y,$(builtin-target) $(lib-target) $(extra-y)为空 ;
- $(subdir-ym)为scripts/dtc;
- $(always)为空;
- 展开为:
- __build: scripts/dtc
- @:
# 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;prepare0又依赖 archprepare、FORCE;archprepare又依赖prepare1和scripts_basic;prepare1又依赖于
repare2、$ (version_h) 、$ (timestamp_h) 、 include/config/auto.conf;prepare2又依赖prepare3和outputmakefile;prepare3又依赖include/config/uboot.release,如果KBUILD_SRC为空,没有规则。涉及的具体目标链接:
除了prepare0有具体规则外,其它都是伪目标。
规则为:
make -f ./scripts/Makefile.build obj=.
在Makefile.build会引用当前目录下的Kbuild(注意这个引用的不是Makefile):
# <<<<<<<<<scripts/Makefile.build>>>>>>>>>
# 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)// ././Kbuild
include $(kbuild-file) (1)//include ././Kbuild
......
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a (2)lib-target :=
endif
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)//去空格函数—strip
builtin-target := $(obj)/built-in.o (3) builtin-target :=
endif
modorder-target := $(obj)/modules.order
# We keep a list of all modules in $(MODVERDIR)
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
1. 引用顶层目录Kbuild
# <<<<<<<<<Kbuild>>>>>>>>>
# 1) Generate generic-asm-offsets.h
generic-offsets-file := include/generated/generic-asm-offsets.h
always := $(generic-offsets-file) //include/generated/generic-asm-offsets.h
targets := lib/asm-offsets.s
# We use internal kbuild rules to avoid the "is up to date" message from make
lib/asm-offsets.s: lib/asm-offsets.c FORCE
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cc_s_c)
$(obj)/$(generic-offsets-file): lib/asm-offsets.s FORCE
$(call filechk,offsets,__GENERIC_ASM_OFFSETS_H__)
#####
# 2) Generate asm-offsets.h
#
ifneq ($(wildcard $(srctree)/arch/$(ARCH)/lib/asm-offsets.c),)//成立
offsets-file := include/generated/asm-offsets.h
endif
always += $(offsets-file) //include/generated/asm-offsets.h
targets += arch/$(ARCH)/lib/asm-offsets.s
CFLAGS_asm-offsets.o := -DDO_DEPS_ONLY
# We use internal kbuild rules to avoid the "is up to date" message from make
arch/$(ARCH)/lib/asm-offsets.s: arch/$(ARCH)/lib/asm-offsets.c FORCE
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cc_s_c)
$(obj)/$(offsets-file): arch/$(ARCH)/lib/asm-offsets.s FORCE
$(call filechk,offsets,__ASM_OFFSETS_H__)
2. lib-target的定义
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a (2)lib-target :=
endif
$(lib-y) $(lib-m) $(lib-)在顶层目录Kbuild中均未定义,因此lib-target := 。
3. builtin-target的定义
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)//去空格函数—strip
builtin-target := $(obj)/built-in.o (3) builtin-target :=
endif
$(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)在顶层目录Kbuild中均未定义,因此builtin-target:= 。
4. always的定义
在kbuild中定义为include/generated/asm-offsets.h和include/generated/asm-offsets.h 。
综上,对于默认目标__build:
- KBUILD_BUILTIN为y,$(builtin-target) $(lib-target) $(extra-y)为空 ;
- $(subdir-ym)为空(注意并不是所有的编译目标都是空);
- $(always)为nclude/generated/asm-offsets.h、include/generated/asm-offsets.h;
- 展开为:
- __build: include/generated/asm-offsets.h include/generated/asm-offsets.h
- @:
include/generated/asm-offsets.h 、include/generated/asm-offsets.h 的规则定义在顶层目录Kbuild中,如本小节(1)。
# <<<<<<<<<scripts/Kbuild.include:>>>>>>>>>
###
# filechk is used to check if the content of a generated file is updated.
# Sample usage:
# define filechk_sample
# echo $KERNELRELEASE
# endef
# version.h : Makefile
# $(call filechk,sample)
# The rule defined shall write to stdout the content of the new file.
# The existing file will be compared with the new one.
# - If no file exist it is created
# - If the content differ the new file is used
# - If they are equal no change, and no timestamp update
# - stdin is piped in from the first prerequisite ($<) so one has
# to specify a valid file as first prerequisite (often the kbuild file)
define filechk
$(Q)set -e; \
$(kecho) ' CHK $@'; \ //打印' CHK include/generated/generic-asm-offsets.h'
mkdir -p $(dir $@); \ //创建 include/generated/目录
$(filechk_$(1)) < $< > $@.tmp; \ //调用filechk_offsets < lib/asm-offsets.s > include/generated/generic-asm-offsets.h.tmp
if [ -r $@ ] && cmp -s $@ $@.tmp; then \ //如果存在目标,则比较更新,否则把$@.tmp更名为$@
rm -f $@.tmp; \
else \
$(kecho) ' UPD $@'; \
mv -f $@.tmp $@; \
fi
endef
# <<<<<<<<<Kbuild>>>>>>>>>
#
# Kbuild for top-level directory of U-Boot
# This file takes care of the following:
# 1) Generate generic-asm-offsets.h
# 2) Generate asm-offsets.h
# Default sed regexp - multiline due to syntax constraints
define sed-y
"s:[[:space:]]*\.ascii[[:space:]]*\"\(.*\)\":\1:; \
/^->/{s:->#\(.*\):/* \1 */:; \
s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:->::; p;}"
endef
# Use filechk to avoid rebuilds when a header changes, but the resulting file
# does not
define filechk_offsets
(set -e; \
echo "#ifndef $2"; \ //输出 #ifndef __GENERIC_ASM_OFFSETS_H__
echo "#define $2"; \ //输出 #define __GENERIC_ASM_OFFSETS_H__
echo "/*"; \ //输出 /*
echo " * DO NOT MODIFY."; \ //输出 * DO NOT MODIFY.
echo " *"; \ //输出 *
echo " * This file was generated by Kbuild"; \ //输出 * This file was generated by Kbuild
echo " */"; \ //输出 */
echo ""; \ //输出 空行
sed -ne $(sed-y); \ //使用正则表达式解析汇编中符合指定格式的行,并输出
echo ""; \ //输出 空行
echo "#endif" ) //输出 #endif
endef
# 1) Generate generic-asm-offsets.h
generic-offsets-file := include/generated/generic-asm-offsets.h
always := $(generic-offsets-file) //include/generated/generic-asm-offsets.h
targets := lib/asm-offsets.s
# We use internal kbuild rules to avoid the "is up to date" message from make
lib/asm-offsets.s: lib/asm-offsets.c FORCE (1)
$(Q)mkdir -p $(dir $@) //创建lib目录
$(call if_changed_dep,cc_s_c) //把lib/asm-offsets.c编译成lib/asm-offsets.s
$(obj)/$(generic-offsets-file): lib/asm-offsets.s FORCE (2)
$(call filechk,offsets,__GENERIC_ASM_OFFSETS_H__) //生成include/generated/generic-asm-offsets.h
1. 创建lib目录,把lib/asm-offsets.c编译成lib/asm-offsets.s;
2. 调用filechk生成include/generated/generic-asm-offsets.h:
(1)打印' CHK include/generated/generic-asm-offsets.h'
(2)创建 include/generated/目录
(3)调用filechk_offsets < lib/asm-offsets.s > include/generated/generic-asm-offsets.h.tmp
( 3.1) 输出 "#ifndef GENERIC_ASM_OFFSETS_H"
( 3.2) 输出 "#define GENERIC_ASM_OFFSETS_H"
( 3.3)输出 "/_"
( 3.4)输出 "_ DO NOT MODIFY."
( 3.5)输出 "_"
( 3.6)输出 "_ This file was generated by Kbuild"
( 3.7)输出 "*/"
( 3.8)输出 空行
( 3.9)使用正则表达式解析汇编lib/asm-offsets.s中符合指定格式的行(如下),并输出
( 3.10)输出 空行
( 3.12)输出 #endif
(4)如果已经存在目标文件include/generated/generic-asm-offsets.h,且比include/generated/generic-asm-offsets.h.tmp更新,则删除后者,保留前者;否则把include/generated/generic-asm-offsets.h.tmp更名为include/generated/generic-asm-offsets.h。
最终生成的include/generated/generic-asm-offsets.h文件如下:
# <<<<<<<<<Kbuild>>>>>>>>>
# 2) Generate asm-offsets.h
#
ifneq ($(wildcard $(srctree)/arch/$(ARCH)/lib/asm-offsets.c),)//成立
offsets-file := include/generated/asm-offsets.h
endif
always += $(offsets-file) //include/generated/asm-offsets.h
targets += arch/$(ARCH)/lib/asm-offsets.s
CFLAGS_asm-offsets.o := -DDO_DEPS_ONLY
# We use internal kbuild rules to avoid the "is up to date" message from make
arch/$(ARCH)/lib/asm-offsets.s: arch/$(ARCH)/lib/asm-offsets.c FORCE (1)
$(Q)mkdir -p $(dir $@) //创建lib目录
$(call if_changed_dep,cc_s_c) //把arch/arm/asm-offsets.c编译成arch/arm/asm-offsets.s
$(obj)/$(offsets-file): arch/$(ARCH)/lib/asm-offsets.s FORCE (2)
$(call filechk,offsets,__ASM_OFFSETS_H__)//include/generated/asm-offsets.h
1. 创建arch\arm\lib目录,把arch\arm\lib/asm-offsets.c编译成arch\arm\lib/asm-offsets.s;
2. 调用filechk生成include/generated/asm-offsets.h:
编译过程同上。
最终生成的include/generated/asm-offsets.h文件如下:
关于$(u-boot-dirs)的定义在上一篇文中已经讲过,所包含全部需要编译的目录,这里以仅以arch/arm/cpu/armv8 为例,其它雷同。
# <<<<<<<<<顶层Makefile>>>>>>>>>
u-boot-dirs := $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples //目标
......
# Handle descending into subdirectories listed in $(vmlinux-dirs)
# Preset locale variables to speed up the build process. Limit locale
# tweaks to this spot to avoid wrong language settings when running
# make menuconfig etc.
# Error messages still appears in the original language
PHONY += $(u-boot-dirs)
$(u-boot-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@ //规则
$ (Q) $ (MAKE) $ (build)=$@这个命令,引入各个目录下的Kbuild或Makefile,依据Makefile.build中定义的规则构建目标。
● 如果定义了hostprogs-y,则引入Makefile.host,构建目标
● 如果定义了obj-y,依据Makefile.build中的规则构建各个.o文件,并最终链接成build-in.o文件
$(u-boot-dirs)的定义在上文中已经讲过:
arch/arm/cpu \
arch/arm/cpu/armv8 \
arch/arm/lib \
arch/arm/mach-imx \
board/myzr/common \
board/myzr/myimx8mm \
cmd \
common \
disk \
drivers \
drivers/dma \
drivers/gpio \
drivers/i2c \
drivers/mtd \
drivers/mtd/onenand \
drivers/mtd/spi \
drivers/net \
drivers/net/phy \
.
.
.
env \
fs \
lib \
net \
test \
test/dm
下面以构建arch/arm/cpu/armv8为例:
arch/arm/cpu/armv8 : prepare scripts
$(Q)$(MAKE) $(build)=$@
其中 $ (build)定义在scripts/Kbuild.include 中,如下:
# <<<<<<<<<scripts/Kbuild.include>>>>>>>>>
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
展开为:
make -f scripts/basic/Makefile.build obj=arch/arm/cpu/armv8
在Makefile.build中,会引用要编译目录的Makefile(arch/arm/cpu/armv8/Makefile),这点在前文中多次讲到过:
# <<<<<<<<<scripts/Makefile.build>>>>>>>>>
# 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) //arch/arm/cpu/armv8/Makefile
include $(kbuild-file) (1)//include arch/arm/cpu/armv8/Makefile
......
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a (2)lib-target :=
endif
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)//去空格函数—strip
builtin-target := $(obj)/built-in.o (3) builtin-target := arch/arm/cpu/armv8/built-in.o
endif
modorder-target := $(obj)/modules.order
# We keep a list of all modules in $(MODVERDIR)
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
1. 引用arch/arm/cpu/armv8/目录下的Makefile
# <<<<<<<<<arch/arm/cpu/armv8/Makefile>>>>>>>>>
extra-y := start.o
obj-y += cpu.o
ifndef CONFIG_$(SPL_TPL_)TIMER
obj-y += generic_timer.o
endif
obj-y += cache_v8.o
obj-y += exceptions.o
obj-y += cache.o
obj-y += tlb.o
obj-y += transition.o
obj-y += fwcall.o
obj-y += cpu-dt.o
obj-$(CONFIG_ARM_SMCCC) += smccc-call.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
endif
obj-$(CONFIG_$(SPL_)ARMV8_SEC_FIRMWARE_SUPPORT) += sec_firmware.o sec_firmware_asm.o
obj-$(CONFIG_FSL_LAYERSCAPE) += fsl-layerscape/
obj-$(CONFIG_S32V234) += s32v234/
obj-$(CONFIG_ARCH_ZYNQMP) += zynqmp/
obj-$(CONFIG_TARGET_HIKEY) += hisilicon/
obj-$(CONFIG_ARMV8_PSCI) += psci.o
obj-$(CONFIG_ARCH_SUNXI) += lowlevel_init.o
obj-$(CONFIG_XEN) += xen/
2. lib-target的定义
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a (2)lib-target :=
endif
$(lib-y) $(lib-m) $(lib-)在arch/arm/cpu/armv8/Makefile中均未定义,因此lib-target := 。
3. builtin-target的定义
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)//去空格函数—strip
builtin-target := $(obj)/built-in.o (3) builtin-target := arch/arm/cpu/armv8/built-in.o
endif
综上,对于默认目标__build:
- KBUILD_BUILTIN为y,在arch/arm/cpu/armv8/Makefile中定义了obj-y,其它为空(注意,如果subdir-m不为空会继续遍历这些子目录)。所以builtin-target=arch/arm/cpu/armv8/built-in.o ,lib-targe=,extra-y=arch/arm/cpu/armv8/start.o ;
- $(subdir-ym)为空(注意并不是所有的编译目标都是空);
- $(always)为空;
- 展开为:
- __build: arch/arm/cpu/armv8/built-in.o arch/arm/cpu/armv8/start.o
- @:
$ (builtin-target)(*/build-in.o)依赖$(obj-y),也就是在arch/arm/cpu/armv8/Makefile中定义的那些.o文件。因此要先构建%.o,再构建%/built-in.o:
# <<<<<<<<<scripts/Makefile.build>>>>>>>>>
cmd_link_o_target = $(if $(strip $(obj-y)),\
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
$(cmd_secanalysis),\
rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
.o文件使用如下规则构建(因为-f指定 scripts/Makefile.build,优先在该文件中寻找规则):
# <<<<<<<<<scripts/Makefile.build>>>>>>>>>
# C (.c) files
# The C file is compiled and updated dependency information is generated.
# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
ifndef CONFIG_MODVERSIONS //校验符号用,这里我编译时未定义
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< //重点关注 %.c --> %.o的具体编译命令
else
# When module versioning is enabled the following steps are executed:
# o compile a .tmp_<file>.o from <file>.c
# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
# not export symbols, we just rename .tmp_<file>.o to <file>.o and
# are done.
# o otherwise, we calculate symbol versions using the good old
# genksyms on the preprocessed source and postprocess them in a way
# that they are usable as a linker script
# o generate <file>.o from .tmp_<file>.o using the linker to
# replace the unresolved symbols __crc_exported_symbol with
# the actual value of the checksum generated by genksyms
cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
cmd_modversions = \
if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
$(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
> $(@D)/.tmp_$(@F:.o=.ver); \
\
$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
-T $(@D)/.tmp_$(@F:.o=.ver); \
rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
else \
mv -f $(@D)/.tmp_$(@F) $@; \
fi;
endif
......
define rule_cc_o_c
$(call echo-cmd,checksrc) $(cmd_checksrc) \
$(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
$(cmd_modversions) \
$(call echo-cmd,record_mcount) \
$(cmd_record_mcount) \
scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
$(dot-target).tmp; \
rm -f $(depfile); \
mv -f $(dot-target).tmp $(dot-target).cmd
endef
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
quiet_cmd_as_o_S = AS $(quiet_modtag) $@
cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< //重点关注 %.S --> %.o的具体编译命令
$(obj)/%.o: $(src)/%.S FORCE
$(call if_changed_dep,as_o_S)
其中CONFIG_MODVERSIONS 宏的作用,请参考: Linux内核编译 CONFIG_MODVERSIONS 作用。
执行cmd_cc_o_c定义的命令将.c编译成.o,执行cmd_as_o_S定义的命令将.S编译成.o。
编译打印命令如下:
CC arch/arm/cpu/armv8/cpu.o
CC arch/arm/cpu/armv8/generic_timer.o
CC arch/arm/cpu/armv8/cache_v8.o
AS arch/arm/cpu/armv8/exceptions.o
AS arch/arm/cpu/armv8/cache.o
AS arch/arm/cpu/armv8/tlb.o
AS arch/arm/cpu/armv8/transition.o
CC arch/arm/cpu/armv8/fwcall.o
CC arch/arm/cpu/armv8/cpu-dt.o
AS arch/arm/cpu/armv8/start.o
真实执行的完整命令如下:
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.cpu.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -fshort-wchar -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(cpu)" -D"KBUILD_MODNAME=KBUILD_STR(cpu)" -c -o arch/arm/cpu/armv8/cpu.o arch/arm/cpu/armv8/cpu.c
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.generic_timer.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -fshort-wchar -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(generic_timer)" -D"KBUILD_MODNAME=KBUILD_STR(generic_timer)" -c -o arch/arm/cpu/armv8/generic_timer.o arch/arm/cpu/armv8/generic_timer.c
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.cache_v8.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -fshort-wchar -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(cache_v8)" -D"KBUILD_MODNAME=KBUILD_STR(cache_v8)" -c -o arch/arm/cpu/armv8/cache_v8.o arch/arm/cpu/armv8/cache_v8.c
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.exceptions.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -D__ASSEMBLY__ -g -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -c -o arch/arm/cpu/armv8/exceptions.o arch/arm/cpu/armv8/exceptions.S
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.cache.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -D__ASSEMBLY__ -g -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -c -o arch/arm/cpu/armv8/cache.o
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.tlb.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -D__ASSEMBLY__ -g -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -c -o arch/arm/cpu/armv8/tlb.o
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.transition.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -D__ASSEMBLY__ -g -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -c -o arch/arm/cpu/armv8/transition.o
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.fwcall.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -fshort-wchar -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(fwcall)" -D"KBUILD_MODNAME=KBUILD_STR(fwcall)" -c -o arch/arm/cpu/armv8/fwcall.o
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.cpu-dt.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -fshort-wchar -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(cpu_dt)" -D"KBUILD_MODNAME=KBUILD_STR(cpu_dt)" -c -o arch/arm/cpu/armv8/cpu-dt.o
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -Wp,-MD,arch/arm/cpu/armv8/.start.o.d -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -D__ASSEMBLY__ -g -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -c -o arch/arm/cpu/armv8/start.o
-wp,-MD 会生成相应的依赖文件。-fno-pic是用来生成位置有关代码。
最后,将编译出来的.o文件使用cmd_link_o_target链接成arch/arm/cpu/armv8/build-in.o,注意参数-r 表示。
编译打印如下:
LD arch/arm/cpu/armv8/built-in.o
真实执行的完整命令如下:
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-ld.bfd -r -o arch/arm/cpu/armv8/built-in.o arch/arm/cpu/armv8/cpu.o arch/arm/cpu/armv8/generic_timer.o arch/arm/cpu/armv8/cache_v8.o arch/arm/cpu/armv8/exceptions.o arch/arm/cpu/armv8/cache.o arch/arm/cpu/armv8/tlb.o arch/arm/cpu/armv8/transition.o arch/arm/cpu/armv8/fwcall.o arch/arm/cpu/armv8/cpu-dt.o
注意链接参数-r'
--relocateable' 产生可重定位的输出, 比如,产生一个输出文件它可再次作为'ld'的输入。这经常被叫做"部分连接"。
其他目录的的执行过程也是类似的,就不做进一步分析了。
注意在编译arch/arm/cpu/armv8/目录时,同时生成了arch/arm/cpu/armv8/start.o,这是u-boot的依赖 $ (u-boot-init)==$(head-y)
注意在编译$ (u-boot-dirs)时,同时生成了 */built-in.o ,这是u-boot的依赖 $ (u-boot-main)==$(libs-y)
u-boot.lds的定义位于顶层Makefile中(参见UBOOT编译--- UBOOT编译过程目标依赖分析(八) - 5.3 依赖u-boot.lds)。上文已经讲过,如果没有定义LDSCRIPT和CONFIG_SYS_LDSCRIPT,则默认使用u-boot自带的lds文件,包括board/$ (BOARDDIR)和$ (CPUDIR)目录下定制的针对board或cpu的lds文件;如果没有定制的lds文件,则采用arch/$(ARCH)/cpu目录下默认的lds文件。针对我的开发板,u-boot.lds = arch/arm/cpu/armv8/u-boot.lds。
规则如下:
# <<<<<<<<<顶层config.mk>>>>>>>>>
quiet_cmd_cpp_lds = LDS $@
cmd_cpp_lds = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) \
-D__ASSEMBLY__ -x assembler-with-cpp -P -o $@ $<
u-boot.lds: $(LDSCRIPT) prepare FORCE
$(call if_changed_dep,cpp_lds)
编译打印如下:
在这里插入代码片
真实执行的完整命令如下:
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,./.u-boot.lds.d -D__KERNEL__ -D__UBOOT__ -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include -ansi -include ./include/u-boot/u-boot.lds.h -DCPUDIR=arch/arm/cpu/armv8 -D__ASSEMBLY__ -x assembler-with-cpp -P -o u-boot.lds arch/arm/cpu/armv8/u-boot.lds
编译选项'-E'、'-x'、-P(具体解释见本文末尾参考章节)。该编译过程主要是为了展开arch/arm/cpu/armv8/u-boot.lds中的头文件中的宏定义。重点关注引用的
# <<<<<<<<<顶层顶层Makefile>>>>>>>>>
# Rule to link u-boot
# May be overridden by arch/$(ARCH)/config.mk
quiet_cmd_u-boot__ ?= LD $@
cmd_u-boot__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_u-boot) -o $@ \
-T u-boot.lds $(u-boot-init) \
--start-group $(u-boot-main) --end-group \
$(PLATFORM_LIBS) -Map u-boot.map; \
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
quiet_cmd_smap = GEN common/system_map.o
cmd_smap = \
smap=`$(call SYSTEM_MAP,u-boot) | \
awk '$$2 ~ /[tTwW]/ {printf $$1 $$3 "\\\\000"}'` ; \
$(CC) $(c_flags) -DSYSTEM_MAP="\"$${smap}\"" \
-c $(srctree)/common/system_map.c -o common/system_map.o
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
+$(call if_changed,u-boot__) //uboot的规则
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、FORCE在前面小节已经分析过。
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-ld.bfd -pie --gc-sections -Bstatic --no-dynamic-linker -Ttext 0x40200000 -o u-boot -T u-boot.lds arch/arm/cpu/armv8/start.o --start-group arch/arm/cpu/built-in.o arch/arm/cpu/armv8/built-in.o arch/arm/lib/built-in.o arch/arm/mach-imx/built-in.o board/myzr/common/built-in.o board/myzr/myimx8mm/built-in.o cmd/built-in.o common/built-in.o disk/built-in.o drivers/built-in.o drivers/dma/built-in.o drivers/gpio/built-in.o drivers/i2c/built-in.o drivers/mtd/built-in.o drivers/mtd/onenand/built-in.o drivers/mtd/spi/built-in.o drivers/net/built-in.o drivers/net/phy/built-in.o drivers/pci/built-in.o drivers/power/built-in.o drivers/power/battery/built-in.o drivers/power/domain/built-in.o drivers/power/fuel_gauge/built-in.o drivers/power/mfd/built-in.o drivers/power/pmic/built-in.o drivers/power/regulator/built-in.o drivers/serial/built-in.o drivers/spi/built-in.o drivers/usb/cdns3/built-in.o drivers/usb/common/built-in.o drivers/usb/dwc3/built-in.o drivers/usb/emul/built-in.o drivers/usb/eth/built-in.o drivers/usb/gadget/built-in.o drivers/usb/gadget/udc/built-in.o drivers/usb/host/built-in.o drivers/usb/musb-new/built-in.o drivers/usb/musb/built-in.o drivers/usb/phy/built-in.o drivers/usb/ulpi/built-in.o env/built-in.o fs/built-in.o lib/built-in.o net/built-in.o test/built-in.o test/dm/built-in.o --end-group -L /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1 -lgcc -Map u-boot.map; true
参见:UBOOT编译--- UBOOT的$(version_h) $(timestamp_h)(七) - 3.1.1 依赖include/config/uboot.release。
参见:UBOOT编译--- make xxx_deconfig过程详解(一) - 4.2 依赖 outputmakefile。
参见:UBOOT编译--- UBOOT的$(version_h) $(timestamp_h)(七)。
没什么好讲的,就是编译一些后面会使用的工具(tools/bmp_logo、 tools/gen_eth_addr、 tools/gen_ethaddr_crc、 tools/img2srec、 tools/mkenvimage 、tools/dumpimage 、tools/mkimage、 tools/proftool 、tools/relocate-rela 、tools/fdtgrep),编译规则参见前面的章节,套路是一模一样的。
# <<<<<<<<<scripts/Makefile.autoconf>>>>>>>>>
u-boot.cfg: include/config.h FORCE
$(call cmd,u_boot_cfg)
# <<<<<<<<<顶层顶层Makefile>>>>>>>>>
u-boot.cfg spl/u-boot.cfg tpl/u-boot.cfg: include/config.h FORCE
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf $(@) //指定目标u-boot.cfg,定义在scripts/Makefile.autoconf中
cfg: u-boot.cfg
参见:UBOOT编译--- include/config.h、 include/autoconf.mk、include/autoconf.mk.dep、u-boot.cfg(三)。
# <<<<<<<<<顶层Makefile>>>>>>>>>
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
# <<<<<<<<<scripts/Kbuild.include>>>>>>>>>
# Execute command if command has changed or prerequisite(s) are updated.
# //如果命令已更改或prerequisites已更新,请执行命令
if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
@set -e; \
$(echo-cmd) $(cmd_$(1)); \
printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
1. $(strip $(any-prereq) $(arg-check) )
(1) any-prereq定义
# <<<<<<<<<scripts/Kbuild.include>>>>>>>>>
# Find any prerequisites that is newer than target or that does not exist.
# PHONY targets skipped in both cases.
//查找比目标更新或不存在的任何prerequisites。
any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)//这里为u-boot
$(filter-out $ (PHONY), $?)就是过滤掉比目标还要新的依赖文件中的伪目标;
$ (filter-out $ (PHONY) $ (wildcard $ ^ ), $^)表示过滤掉所有的依赖文件中的伪目标与存在的依赖文件。
(2) arg-check定义:
# <<<<<<<<<scripts/Kbuild.include>>>>>>>>>
ifneq ($(KBUILD_NOCMDDEP),1)
# Check if both arguments has same arguments. Result is empty string if equal.
# User may override this check using make KBUILD_NOCMDDEP=1
//检查两个参数是否具有相同的参数。如果相等,则结果为空字符串。用户可以使用make KBUILD\u NOCMDDEP=1覆盖此检查
arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
$(filter-out $(cmd_$@), $(cmd_$(1))) )
else
arg-check = $(if $(strip $(cmd_$@)),,1)
endif
KBUILD_NOCMDDEP是在make命令行中定义,我们并没有定义,所以:
arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) $(filter-out $(cmd_$@), $(cmd_$(1))) )
$ (filter-out $ (cmd_ $ (1)), $ (cmd_ $@)) 表示过滤掉 $(cmd_ $@)中符合 $(cmd_ $(1))的项。 $(1)表示if_changed函数的第一个参数objcopy, $@表示目标文件u-boot-nodtb.bin。cmd_ $(1)为cmd_objcopy,cmd_ $@为cmd_u-boot-nodtb.bin。
cmd_u-boot-nodtb.bin并没有定义,所以 $(filter-out $(cmd_ $(1)), $(cmd_ $@))为空;
cmd_objcopy 在顶层Makefile中定义:
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) <br />
$(OBJCOPYFLAGS_$(@F)) $< $@
所以arg-check = $ (filter-out $ (cmd_$ @), $ (cmd_$ (1))) = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS)
$(OBJCOPYFLAGS_ $(@F)) $< $@。
因为 $(any-prereq) $(arg-check)都为非空,所以if_changed展开为:
if_changed = @set -e; \ /如果任何语句的执行结果不是true则应该退出
$(echo-cmd) $(cmd_$(1)); \
printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
1. $(echo-cmd)定义
# <<<<<<<<<scripts/Kbuild.include>>>>>>>>>
# echo command.
# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
echo-cmd = $(if $($(quiet)cmd_$(1)),\
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
quiet=quiet_,在顶层Makefile分析过(当然如果你想看到更详细的打印,您可以通过传入V值,来改变), $(cmd_objcopy)上面分析过,存在,所以:
echo-cmd = echo ' $(call escsq,$(cmd_objcopy))$(echo-why)';
在scripts/Kbuild.include中:
# <<<<<<<<<scripts/Kbuild.include>>>>>>>>>
# Escape single quote for use in echo statements
escsq = $(subst $(squote),'\$(squote)',$1)
ifeq ($(KBUILD_VERBOSE),2)
why = \
$(if $(filter $@, $(PHONY)),- due to target is PHONY, \
$(if $(wildcard $@), \
$(if $(strip $(any-prereq)),- due to: $(any-prereq), \
$(if $(arg-check), \
$(if $(cmd_$@),- due to command line change, \
$(if $(filter $@, $(targets)), \
- due to missing .cmd file, \
- due to $(notdir $@) not in $$(targets) \
) \
) \
) \
), \
- due to target missing \
) \
)
echo-why = $(call escsq, $(strip $(why)))
endif
KBUILD_VERBOSE一般我们会采用默认值0(需要调试编译除外),所以 echo-why 为空。
2. $ (cmd_$(1))定义
# <<<<<<<<<顶层Makefile>>>>>>>>>
# Normally we fill empty space with 0xff
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \
$(OBJCOPYFLAGS_$(@F)) $< $@ //$(OBJCOPYFLAGS_$(@F)) = OBJCOPYFLAGS_u-boot-nodtb.bin
//$(@F):表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相当于函数"$(notdir $@)"
(1) $(OBJCOPYFLAGS)定义在顶层config.mk和arch/ $(ARCH)/config.mk(arch/arm/config.mk)中
# <<<<<<<<<顶层config.mk>>>>>>>>>
OBJCOPYFLAGS :=
# <<<<<<<<<arch/arm/config.mk>>>>>>>>>
# limit ourselves to the sections we want in the .bin.
ifdef CONFIG_ARM64 //定义
OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .data \
-j .u_boot_list -j .rela.dyn -j .got -j .got.plt \
-j .binman_sym_table
else
OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \
-j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn \
-j .binman_sym_table
endif
# if a dtb section exists we always have to include it
# there are only two cases where it is generated
# 1) OF_EMBEDED is turned on
# 2) unit tests include device tree blobs
OBJCOPYFLAGS += -j .dtb.init.rodata
(2) OBJCOPYFLAGS_u-boot-nodtb.bin定义在顶层Makefile中
# <<<<<<<<<顶层Makefile>>>>>>>>>
OBJCOPYFLAGS_u-boot-nodtb.bin := -O binary \
$(if $(CONFIG_X86_16BIT_INIT),-R .start16 -R .resetvec)
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy --gap-fill=0xff -j .text -j .secure_text -j .secure_data -j .rodata -j .data -j .u_boot_list -j .rela.dyn -j .got -j .got.plt -j .binman_sym_table -j .dtb.init.rodata -j .efi_runtime -j .efi_runtime_rel -O binary u-boot u-boot-nodtb.bin
整个编译过程就是把u-boot中的指定段拷贝u-boot-nodtb.bin中。
objcopy的功能:将目标文件的一部分或者全部内容拷贝到另外一个目标文件中,或者实现目标文件的格式转换。
j sectionname , --only-section=sectionname : 只将由 sectionname 指定的 section 拷贝到输出文件,可以多次指定,并且注意如果使用不当会导致输出文件不可用。
-O bfdname :--output-target= bfdname 使用指定的格式来写输出文件(即目标文件),bfdname是BFD库中描述的标准格式名。
# <<<<<<<<<顶层Makefile>>>>>>>>>
//静态应用RELA-style的重定位(目前仅 arm64)这对于需要在原始二进制文件上执行静态重定位的 arm64 很有用,但某些模拟器只接受 ELF 文件(但不执行重定位)。
# Statically apply RELA-style relocations (currently arm64 only)
# This is useful for arm64 where static relocation needs to be performed on
# the raw binary, but certain simulators only accept an ELF file (but don't
# do the relocation).
ifneq ($(CONFIG_STATIC_RELA),)
# $(1) is u-boot ELF, $(2) is u-boot bin, $(3) is text base
DO_STATIC_RELA = \
start=$$($(NM) $(1) | grep __rel_dyn_start | cut -f 1 -d ' '); \
end=$$($(NM) $(1) | grep __rel_dyn_end | cut -f 1 -d ' '); \
tools/relocate-rela $(2) $(3) $$start $$end
else
DO_STATIC_RELA =
endif
编译时具体打印:
start=$(/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-nm u-boot | grep __rel_dyn_start | cut -f 1 -d ' '); end=$(/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-nm u-boot | grep __rel_dyn_end | cut -f 1 -d ' '); tools/relocate-rela u-boot-nodtb.bin 0x40200000 $start $end
1. aarch64-linux-gnu-nm u-boot | grep __rel_dyn_start | cut -f 1 -d ' '
nm : 列出指定文件的符号表(下图只截取一点);
grep __rel_dyn_start :找到符号grep __rel_dyn_start
cut -f 1 -d ' ' :取出第1列,分隔符为' '
2. aarch64-linux-gnu-nm u-boot | grep __rel_dyn_end | cut -f 1 -d ' '
nm : 列出指定文件的符号表(下图只截取一点);
grep __rel_dyn_end:找到符号grep __rel_dyn_end
cut -f 1 -d ' ' :取出第1列,分隔符为' '
3. tools/relocate-rela u-boot-nodtb.bin 0x40200000 $start $end
重定位。
ifneq ($(CONFIG_BOARD_SIZE_LIMIT),)
BOARD_SIZE_CHECK = <br />
@actual=wc -c $@ | awk '{print $$1}'
; <br />
limit=printf "%d" $(CONFIG_BOARD_SIZE_LIMIT)
; <br />
if test $$actual -gt $$limit; then <br />
echo "$@ exceeds file size limit:" >&2 ; <br />
echo " limit: $$limit bytes" >&2 ; <br />
echo " actual: $$actual bytes" >&2 ; <br />
echo " excess: $$((actual - limit)) bytes" >&2; <br />
exit 1; <br />
fi
else
BOARD_SIZE_CHECK =
endif
如果有定义CONFIG_BOARD_SIZE_LIMIT,则检查编译出的目标文件是否超过最大值;如果没有定义,则此项为空。
# <<<<<<<<<顶层Makefile>>>>>>>>>
dts/dt.dtb: u-boot
$(Q)$(MAKE) $(build)=dts dtbs //规则
规则展开为:make -f $(srctree)/scripts/Makefile.build obj=dts dtbs。指定目标dtbs,在Makefile.build中会引用dts目录下的Makefile。
# <<<<<<<<<scripts/Makefile.build>>>>>>>>>
PHONY := __build
__build:
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) // dts/
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) // dts/Makefile
include $(kbuild-file) (1)//include dts/Makefile
......
include scripts/Makefile.lib //
......
dts目录下的Makefile内容有目标dtbs的定义:
# <<<<<<<<<dts/Makefile >>>>>>>>>
DEVICE_TREE ?= $(CONFIG_DEFAULT_DEVICE_TREE:"%"=%) //.config:193:CONFIG_DEFAULT_DEVICE_TREE="myimx8mmek240-8mm"
ifeq ($(DEVICE_TREE),)
DEVICE_TREE := unset
endif
ARCH_PATH := arch/$(ARCH)/dts //arch/arm/dts
dtb_depends := arch-dtbs
ifneq ($(EXT_DTB),)
DTB := $(EXT_DTB)
else
DTB := $(ARCH_PATH)/$(DEVICE_TREE).dtb //arch/arm/dts/myimx8mmek240-8mm.dtb
dtb_depends += $(DTB:.dtb=.dts) //dtb_depends += arch/arm/dts/myimx8mmek240-8mm.dts
endif
$(obj)/dt-spl.dtb: $(DTB) $(objtree)/tools/fdtgrep FORCE //关注dts/dt-spl.dtb
$(call if_changed,fdtgrep)
$(obj)/dt.dtb: $(DTB) FORCE //关注dts/dt.dtb
$(call if_changed,shipped)
targets += dt.dtb dt-spl.dtb
$(DTB): $(dtb_depends)
ifeq ($(EXT_DTB),)
$(Q)$(MAKE) $(build)=$(ARCH_PATH) $@
endif
$(Q)test -e $@ || ( \
echo >&2; \
echo >&2 "Device Tree Source is not correctly specified."; \
echo >&2 "Please define 'CONFIG_DEFAULT_DEVICE_TREE'"; \
echo >&2 "or build with 'DEVICE_TREE=<device_tree>' argument"; \
echo >&2; \
/bin/false)
arch-dtbs:
$(Q)$(MAKE) $(build)=$(ARCH_PATH) dtbs
.SECONDARY: $(obj)/dt.dtb.S $(obj)/dt-spl.dtb.S
ifeq ($(CONFIG_SPL_BUILD),y)
obj-$(CONFIG_OF_EMBED) := dt-spl.dtb.o
# support "out-of-tree" build for dtb-spl
$(obj)/dt-spl.dtb.o: $(obj)/dt-spl.dtb.S FORCE
$(call if_changed_dep,as_o_S)
else
obj-$(CONFIG_OF_EMBED) := dt.dtb.o
endif
dtbs: $(obj)/dt.dtb $(obj)/dt-spl.dtb //关注
@:
clean-files := dt.dtb.S dt-spl.dtb.S
# Let clean descend into dts directories
subdir- += ../arch/arm/dts ../arch/microblaze/dts ../arch/mips/dts ../arch/sandbox/dts ../arch/x86/dts
......
可以看到目标dtbs依赖于$(obj)/dt.dtb 和 $(obj)/dt-spl.dtb ,且这两个依赖又依赖于 $(DTB),
ARCH_PATH := arch/$(ARCH)/dts //arch/arm/dts
dtb_depends := arch-dtbs
ifneq ($(EXT_DTB),)
DTB := $(EXT_DTB)
else
DTB := $(ARCH_PATH)/$(DEVICE_TREE).dtb //arch/arm/dts/myimx8mmek240-8mm.dtb
dtb_depends += $(DTB:.dtb=.dts) //dtb_depends += arch/arm/dts/myimx8mmek240-8mm.dts
endif
$(DTB): $(dtb_depends)
ifeq ($(EXT_DTB),)
$(Q)$(MAKE) $(build)=$(ARCH_PATH) $@//make -f $(srctree)/scripts/Makefile.build obj=arch/arm/dts arch/arm/dts/myimx8mmek240-8mm.dtb
endif
$(Q)test -e $@ || ( \
echo >&2; \
echo >&2 "Device Tree Source is not correctly specified."; \
echo >&2 "Please define 'CONFIG_DEFAULT_DEVICE_TREE'"; \
echo >&2 "or build with 'DEVICE_TREE=<device_tree>' argument"; \
echo >&2; \
/bin/false)
arch-dtbs:
$(Q)$(MAKE) $(build)=$(ARCH_PATH) dtbs//make -f $(srctree)/scripts/Makefile.build obj=arch/arm/dts dtbs
1. arch-dtbs
规则就是执行:make -f $(srctree)/scripts/Makefile.build obj=arch/arm/dts dtbs命令。目标dtbs定义在arch/arm/dts/Makefile中。
# <<<<<<<<<scripts/Makefile.build>>>>>>>>>
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) // arch/arm/dts
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) // arch/arm/dts /Makefile
include $(kbuild-file) //include arch/arm/dts /Makefile
......
include scripts/Makefile.lib //要关注这个引用。$(obj)/%.dtb定义在这里面
......
# <<<<<<<<<arch/arm/dts/Makefile >>>>>>>>>
dtb-$(CONFIG_AT91FAMILY) += at91sam9260-smartweb.dtb \
at91sam9g20-taurus.dtb \
at91sam9g45-corvus.dtb \
......
// $(dtb-y)为各种*.dtb的集合
......
PHONY += dtbs
dtbs: $(addprefix $(obj)/, $(dtb-y)) //dtbs: $(obj)/*.dtb
@:
这里dtbs又依赖于$(obj)/*.dtb。这个目标不是在arch/arm/dts/Makefile中定义,而是在scripts/Makefile.lib中。
# <<<<<<<<<scripts/Makefile.lib >>>>>>>>>
quiet_cmd_dtc = DTC $@
# Modified for U-Boot
# Bring in any U-Boot-specific include at the end of the file
cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
(cat $<; $(if $(u_boot_dtsi),echo '\#include "$(u_boot_dtsi)"')) > $(pre-tmp); \
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $(pre-tmp) ; \
$(DTC) -O dtb -o $@ -b 0 \
-i $(dir $<) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
$(obj)/%.dtb: $(src)/%.dts FORCE
$(call if_changed_dep,dtc)
没什么好讲的,就是调用scripts/dtc/dtc 工具生成对应的dtb文件,同时生成*.d文件。
具体编译过程如下:
make -f ./scripts/Makefile.build obj=arch/arm/dts dtbs
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/myimx8mek314-8mq.dts; ) > arch/arm/dts/.myimx8mek314-8mq.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.myimx8mek314-8mq.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.myimx8mek314-8mq.dtb.dts.tmp arch/arm/dts/.myimx8mek314-8mq.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/myimx8mek314-8mq.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.myimx8mek314-8mq.dtb.d.dtc.tmp arch/arm/dts/.myimx8mek314-8mq.dtb.dts.tmp ; cat arch/arm/dts/.myimx8mek314-8mq.dtb.d.pre.tmp arch/arm/dts/.myimx8mek314-8mq.dtb.d.dtc.tmp > arch/arm/dts/.myimx8mek314-8mq.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/myimx8mevk-8mq.dts; ) > arch/arm/dts/.myimx8mevk-8mq.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.myimx8mevk-8mq.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.myimx8mevk-8mq.dtb.dts.tmp arch/arm/dts/.myimx8mevk-8mq.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/myimx8mevk-8mq.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.myimx8mevk-8mq.dtb.d.dtc.tmp arch/arm/dts/.myimx8mevk-8mq.dtb.dts.tmp ; cat arch/arm/dts/.myimx8mevk-8mq.dtb.d.pre.tmp arch/arm/dts/.myimx8mevk-8mq.dtb.d.dtc.tmp > arch/arm/dts/.myimx8mevk-8mq.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/myimx8mek300-8mq.dts; ) > arch/arm/dts/.myimx8mek300-8mq.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.myimx8mek300-8mq.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.myimx8mek300-8mq.dtb.dts.tmp arch/arm/dts/.myimx8mek300-8mq.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/myimx8mek300-8mq.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.myimx8mek300-8mq.dtb.d.dtc.tmp arch/arm/dts/.myimx8mek300-8mq.dtb.dts.tmp ; cat arch/arm/dts/.myimx8mek300-8mq.dtb.d.pre.tmp arch/arm/dts/.myimx8mek300-8mq.dtb.d.dtc.tmp > arch/arm/dts/.myimx8mek300-8mq.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/myimx8mmek240-8mm.dts; ) > arch/arm/dts/.myimx8mmek240-8mm.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.myimx8mmek240-8mm.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.myimx8mmek240-8mm.dtb.dts.tmp arch/arm/dts/.myimx8mmek240-8mm.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/myimx8mmek240-8mm.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.myimx8mmek240-8mm.dtb.d.dtc.tmp arch/arm/dts/.myimx8mmek240-8mm.dtb.dts.tmp ; cat arch/arm/dts/.myimx8mmek240-8mm.dtb.d.pre.tmp arch/arm/dts/.myimx8mmek240-8mm.dtb.d.dtc.tmp > arch/arm/dts/.myimx8mmek240-8mm.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/fsl-imx8mq-evk.dts; echo '#include "fsl-imx8mq-evk-u-boot.dtsi"') > arch/arm/dts/.fsl-imx8mq-evk.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.fsl-imx8mq-evk.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.fsl-imx8mq-evk.dtb.dts.tmp arch/arm/dts/.fsl-imx8mq-evk.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/fsl-imx8mq-evk.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.fsl-imx8mq-evk.dtb.d.dtc.tmp arch/arm/dts/.fsl-imx8mq-evk.dtb.dts.tmp ; cat arch/arm/dts/.fsl-imx8mq-evk.dtb.d.pre.tmp arch/arm/dts/.fsl-imx8mq-evk.dtb.d.dtc.tmp > arch/arm/dts/.fsl-imx8mq-evk.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/fsl-imx8mq-ddr3l-arm2.dts; echo '#include "fsl-imx8mq-ddr3l-arm2-u-boot.dtsi"') > arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.dts.tmp arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/fsl-imx8mq-ddr3l-arm2.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.d.dtc.tmp arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.dts.tmp ; cat arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.d.pre.tmp arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.d.dtc.tmp > arch/arm/dts/.fsl-imx8mq-ddr3l-arm2.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/fsl-imx8mq-ddr4-arm2.dts; echo '#include "fsl-imx8mq-ddr4-arm2-u-boot.dtsi"') > arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.dts.tmp arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/fsl-imx8mq-ddr4-arm2.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.d.dtc.tmp arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.dts.tmp ; cat arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.d.pre.tmp arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.d.dtc.tmp > arch/arm/dts/.fsl-imx8mq-ddr4-arm2.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/fsl-imx8mq-phanbell.dts; echo '#include "fsl-imx8mq-phanbell-u-boot.dtsi"') > arch/arm/dts/.fsl-imx8mq-phanbell.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.fsl-imx8mq-phanbell.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.fsl-imx8mq-phanbell.dtb.dts.tmp arch/arm/dts/.fsl-imx8mq-phanbell.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/fsl-imx8mq-phanbell.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.fsl-imx8mq-phanbell.dtb.d.dtc.tmp arch/arm/dts/.fsl-imx8mq-phanbell.dtb.dts.tmp ; cat arch/arm/dts/.fsl-imx8mq-phanbell.dtb.d.pre.tmp arch/arm/dts/.fsl-imx8mq-phanbell.dtb.d.dtc.tmp > arch/arm/dts/.fsl-imx8mq-phanbell.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/fsl-imx8mm-ddr3l-val.dts; ) > arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.dts.tmp arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/fsl-imx8mm-ddr3l-val.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.d.dtc.tmp arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.dts.tmp ; cat arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.d.pre.tmp arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.d.dtc.tmp > arch/arm/dts/.fsl-imx8mm-ddr3l-val.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/fsl-imx8mm-ddr4-evk.dts; ) > arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.dts.tmp arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/fsl-imx8mm-ddr4-evk.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.d.dtc.tmp arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.dts.tmp ; cat arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.d.pre.tmp arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.d.dtc.tmp > arch/arm/dts/.fsl-imx8mm-ddr4-evk.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/fsl-imx8mm-ddr4-val.dts; ) > arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.dts.tmp arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/fsl-imx8mm-ddr4-val.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.d.dtc.tmp arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.dts.tmp ; cat arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.d.pre.tmp arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.d.dtc.tmp > arch/arm/dts/.fsl-imx8mm-ddr4-val.dtb.d
mkdir -p arch/arm/dts/ ; (cat arch/arm/dts/fsl-imx8mm-evk.dts; ) > arch/arm/dts/.fsl-imx8mm-evk.dtb.pre.tmp; /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -E -Wp,-MD,arch/arm/dts/.fsl-imx8mm-evk.dtb.d.pre.tmp -nostdinc -I./arch/arm/dts -I./arch/arm/dts/include -Iinclude -I./include -I./arch/arm/include -include ./include/linux/kconfig.h -D__ASSEMBLY__ -undef -D__DTS__ -x assembler-with-cpp -o arch/arm/dts/.fsl-imx8mm-evk.dtb.dts.tmp arch/arm/dts/.fsl-imx8mm-evk.dtb.pre.tmp ; ./scripts/dtc/dtc -O dtb -o arch/arm/dts/fsl-imx8mm-evk.dtb -b 0 -i arch/arm/dts/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -d arch/arm/dts/.fsl-imx8mm-evk.dtb.d.dtc.tmp arch/arm/dts/.fsl-imx8mm-evk.dtb.dts.tmp ; cat arch/arm/dts/.fsl-imx8mm-evk.dtb.d.pre.tmp arch/arm/dts/.fsl-imx8mm-evk.dtb.d.dtc.tmp > arch/arm/dts/.fsl-imx8mm-evk.dtb.d
2. arch/arm/dts/myimx8mmek240-8mm.dts
文件存在即可。
make -f $(srctree)/scripts/Makefile.build obj=arch/arm/dts arch/arm/dts/myimx8mmek240-8mm.dtb
arch/arm/dts/myimx8mmek240-8mm.dtb的实际编译位置在17.1.1-1中。
# <<<<<<<<<scripts/Makefile.lib >>>>>>>>>
# Shipped files
# ===========================================================================
quiet_cmd_shipped = SHIPPED $@
cmd_shipped = cat $< > $@ //$<:第一个依赖对象arch/arm/dts/myimx8mmek240-8mm.dtb
# <<<<<<<<<dts/Makefile >>>>>>>>>
$(obj)/dt.dtb: $(DTB) FORCE //关注dts/dt.dtb
$(call if_changed,shipped)
没什么好讲的,具体编译过程如下:
cat arch/arm/dts/myimx8mmek240-8mm.dtb > dts/dt.dtb
# <<<<<<<<<scripts/Makefile.lib >>>>>>>>>
# fdtgrep
# ---------------------------------------------------------------------------
# Pass the original device tree file through fdtgrep twice. The first pass
# removes any unwanted nodes (i.e. those which don't have the
# 'u-boot,dm-pre-reloc' property and thus are not needed by SPL. The second
# pass removes various unused properties from the remaining nodes.
# The output is typically a much smaller device tree file.
ifeq ($(CONFIG_TPL_BUILD),y)
fdtgrep_props := -b u-boot,dm-pre-reloc -b u-boot,dm-tpl
else
fdtgrep_props := -b u-boot,dm-pre-reloc -b u-boot,dm-spl
endif
quiet_cmd_fdtgrep = FDTGREP $@
cmd_fdtgrep = $(objtree)/tools/fdtgrep $(fdtgrep_props) -RT $< \
-n /chosen -n /config -O dtb | \
$(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
$(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))
$(obj)/dt-spl.dtb: $(DTB) $(objtree)/tools/fdtgrep FORCE //关注
$(call if_changed,fdtgrep)
将原始设备树文件通过fdtgrep两次处理:
输出通常是一个小得多的设备树文件。
没什么好讲的,具体编译过程如下:
./tools/fdtgrep -b u-boot,dm-pre-reloc -b u-boot,dm-spl -RT arch/arm/dts/myimx8mmek240-8mm.dtb -n /chosen -n /config -O dtb | ./tools/fdtgrep -r -O dtb - -o dts/dt-spl.dtb
参数解释如下
- -b:properties in the node;
- -R :Include the root node and all properties;
- -T :Add aliases node to output
- -n :要保留的节点名;
- -O :Output formats;
- -r :Remove unused strings;
- -o:Output filename;
最终生成的dts/dt-spl.dtb对应的dts内容如下:
# <<<<<<<<<顶层Makefile>>>>>>>>>
quiet_cmd_cat = CAT $@
cmd_cat = cat $(filter-out $(PHONY), $^) > $@
......
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
$(call if_changed,cat)
没什么好讲的,就是把u-boot-nodtb.bin和dts/dt.dtb打包成u-boot-dtb.bin。具体编译过程如下:
cat u-boot-nodtb.bin dts/dt.dtb > u-boot-dtb.bin
# <<<<<<<<<顶层Makefile>>>>>>>>>
quiet_cmd_copy = COPY $@
cmd_copy = cp $< $@
......
u-boot.bin: u-boot-dtb.bin FORCE
$(call if_changed,copy)
没什么好讲的,就是把u-boot-dtb.bin 重命名为u-boot.bin。具体编译过程如下:
cp u-boot-dtb.bin u-boot.bin
# <<<<<<<<<顶层Makefile>>>>>>>>>
MKIMAGEFLAGS_u-boot.img = -f auto -A $(ARCH) -T firmware -C none -O u-boot \
-a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_UBOOT_START) \
-n "U-Boot $(UBOOTRELEASE) for $(BOARD) board" -E \
$(patsubst %,-b arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST)))
MKIMAGEFLAGS_u-boot-dtb.img = $(MKIMAGEFLAGS_u-boot.img)
quiet_cmd_mkimage = MKIMAGE $@
cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \ //$(@F)为
$(if $(KBUILD_VERBOSE:1=), >$(MKIMAGEOUTPUT))
u-boot-dtb.img u-boot.img u-boot.kwb u-boot.pbl u-boot-ivt.img: \ //CONFIG_SPL_LOAD_FIT =1
$(if $(CONFIG_SPL_LOAD_FIT),u-boot-nodtb.bin dts/dt.dtb,u-boot.bin) FORCE
$(call if_changed,mkimage)
很简单,就是调用mkimage 工具制作带有mkimage头的U-Boot映像。注意u-boot.img和u-boot-dtb.img内容相同。
用到的mkimage参数解释如下:
-A ==> set architecture to 'arch'
-O ==> set operating system to 'os'
-T ==> set image type to 'type'
-C ==> set compression type 'comp'
-a ==> set load address to 'addr' (hex)"
-e ==> set entry point to 'ep' (hex)
-n ==> set image name to 'name'
-d ==> use image data from 'datafile'
-b ==> dtb
-E => place data outside of the FIT structure
具体编译过程如下:
./tools/mkimage -f auto -A arm -T firmware -C none -O u-boot -a 0x40200000 -e 0 -n "U-Boot 2018.03"" for myimx8mm board" -E -b arch/arm/dts/myimx8mmek240-8mm.dtb -d u-boot-nodtb.bin u-boot.img
./tools/mkimage -f auto -A arm -T firmware -C none -O u-boot -a 0x40200000 -e 0 -n "U-Boot 2018.03"" for myimx8mm board" -E -b arch/arm/dts/myimx8mmek240-8mm.dtb -d u-boot-nodtb.bin u-boot-dtb.img
# <<<<<<<<<顶层Makefile>>>>>>>>>
quiet_cmd_copy = COPY $@
cmd_copy = cp $< $@
u-boot.dtb: dts/dt.dtb
$(call cmd,copy)
没什么好讲的,就是把dts/dt.dtb 重命名为u-boot.dtb。具体编译过程如下:
cp dts/dt.dtb u-boot.dtb
# <<<<<<<<<顶层Makefile>>>>>>>>>
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
上述命令:就是
# <<<<<<<<<顶层Makefile>>>>>>>>>
OBJCOPYFLAGS_u-boot.srec := -O srec
# Normally we fill empty space with 0xff
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \
$(OBJCOPYFLAGS_$(@F)) $< $@
......
u-boot.hex u-boot.srec: u-boot FORCE
$(call if_changed,objcopy)
objcopy的功能:将目标文件的一部分或者全部内容拷贝到另外一个目标文件中,或者实现目标文件的格式转换。
j sectionname , --only-section=sectionname : 只将由 sectionname 指定的 section 拷贝到输出文件,可以多次指定,并且注意如果使用不当会导致输出文件不可用。
-O bfdname :--output-target= bfdname 使用指定的格式来写输出文件(即目标文件),bfdname是BFD库中描述的标准格式名。
具体编译过程如下:
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy --gap-fill=0xff -j .text -j .secure_text -j .secure_data -j .rodata -j .data -j .u_boot_list -j .rela.dyn -j .got -j .got.plt -j .binman_sym_table -j .dtb.init.rodata -j .efi_runtime -j .efi_runtime_rel -O srec u-boot u-boot.srec
# <<<<<<<<<顶层Makefile>>>>>>>>>
quiet_cmd_sym ?= SYM $@
cmd_sym ?= $(OBJDUMP) -t $< > $@
......
u-boot.sym: u-boot FORCE
$(call if_changed,sym)
objdump的功能:是Linux下的反汇编目标文件或者可执行文件的命令:
-t /--syms :显示文件的符号表入口。类似于nm -s提供的信息 。
具体编译过程如下:
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-objdump -t u-boot > u-boot.sym
# <<<<<<<<<顶层Makefile>>>>>>>>>
SYSTEM_MAP = \
$(NM) $1 | \
grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
LC_ALL=C sort
System.map: u-boot
@$(call SYSTEM_MAP,$<) > $@
具体编译过程如下:
/home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-nm u-boot | grep -v '\(compiled\)\|\(\.o$\)\|\( [aUw] \)\|\(\.\.ng$\)\|\(LASH[RL]DI\)' | LC_ALL=C sort > System.map
- grep -v : 是反向查找的意思,比如 grep -v grep 就是查找不含有 grep 字段的行 。
- ' '中的内容 :引号中的 \ 是转义的意思,即不把 / 后面的当作命令信息解释。
- LC_ALL=C : 去除所有本地化的设置,让命令能正确执行。"C"是系统默认的locale,"POSIX"是"C"的别名
- sort : 排序
也就是将nm命令查看u-boot的输出信息经过过滤和排序后输出到System.map。
System.map表示的是地址标号到该标号表示的地址的一个映射关系。System.map每一行的格式都是“addr type name”,addr是标号对应的地址值,name是标号名,type表示标号的类型。
U-Boot的编译和运行并不一定要生成System.map,这个文件主要是提供给用户或外部程序调试时使用的。
.
由于篇幅有限这里先不讲,后面单独讲。
成功编译之后,就会在 U-Boot 源码的根目录下产生多个可执行二进制文件以及编译过程文件,这些文件都是 u-boot.xxx 的命名方式,对应目录下的.xxx.cmd 这些文件都是由编译时的具体指令(if_changed函数中生成$(dot-target).cmd)。
- -- u-boot:ELF 格式的 U-Boot 镜像文件,后续的文件都是由它产生的。具体编译过程参见u-boot.cmd ;
- -- dts/dt.dtb:设备树 (来自于 arch/arm/dts/myimx8mmek240-8mm.dtb 重命名,具体编译过程参见.myimx8mmek240-8mm.dtb.cmd);
- -- u-boot.dtb:dts/dt.dtb的重命名;
- -- u-boot-nodtb.bin: 使用编译工具链的 objcopy 工具从 u-boot 这个文件中提取来的,它只包含可执行的二进制代码。就是把 u-boot 这个文件中对于执行不需要的节区删除后剩余的仅执行需要的部分。具体编译过程参见.u-boot-nodtb.bin.cmd;
- -- u-boot-dtb.bin:在 u-boot-nodtb.bin 尾部拼接上设备树后形成的文件。具体编译过程参见 .u-boot-dtb.bin.cmd;
- -- u-boot.bin:编译出来的二进制格式的uboot可执行镜像文件 。在我使用的单板等价于 u-boot-dtb.bin。具体编译过程参见 .u-boot-dtb.bin.cmd;
- -- u-boot.cfg:uboot的另外一种配置文件 .
- -- u-boot.img/u-boot-dtb.img :调用mkimage 工具制作带有mkimage头的U-Boot映像 ,输入是u-boot-nodtb.bin。具体编译过程参见 .u-boot.img.cmd 和 .u-boot-dtb.img.cmd;
- -- u-boot.lds:链接脚本 。具体编译过程参见 .u-boot.lds.cmd;
- -- u-boot.map:uboot映射文件,可查看某个函数被链接到哪个地址上了 。具体编译过程参见u-boot.cmd ;
- -- u-boot.srec:S-Record格式的镜像文件 。具体编译过程参见 .u-boot.srec.cmd;
- -- u-boot.sym:uboot符号表文件 。具体编译过程参见 .u-boot.sym.cmd
[1] '-E' 只执行到预编译,只涉及到宏替换、头文件展开 、注释去掉(在预处理阶段结束后停止'-E');
[2] '-x' 为输入文件显式指定语言(而不是让编译器根据文件名后缀选择默认语言)(显式指定语言'-x');
[3] '-P' 删除无用的信息(预处理器控制选项 -P);
[4] 利用gcc -E -P 进行宏替换 宏展开 预处理文件;
[5] makefile中$$的使用
手机扫一扫
移动阅读更方便
你可能感兴趣的文章