UBOOT编译--- UBOOT全部目标的编译过程详解(九)
1. 前言
UBOOT版本:uboot2018.03,开发板myimx8mmek240。
2. 概述
本文接续上篇文章,采用自下而上的方法,先从最原始的依赖开始,一步一步,执行命令生成目标。这里先把上节所有依赖关系再次列在这里:
--------------------------------------------|
| 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
3. 构建include/config/auto.conf
参见:UBOOT编译--- include/config/auto.conf、 include/config/auto.conf.cmd、 include/generated/autoconf.h (二)。auto.conf 和 .config 的差别是:auto.conf 里去掉了 .config 中的注释项目以及空格行,其它的都一样。
4. 构建scripts_basic 、scripts
4.1 构建scripts_basic
参见:UBOOT编译--- make xxx_deconfig过程详解(一) - 4.1 依赖 scripts_basic。
4.2 构建scripts
<<<<<<<<<顶层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。
4.2.1 make -f $(srctree)/scripts/Makefile.build obj=scripts分析
# <<<<<<<<<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。
4.2.1.1 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
- @:
5. 构建prepare、prepare0、prepare1、prepare2、prepare3、archprepare
# 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为空,没有规则。涉及的具体目标链接:
- UBOOT编译--- UBOOT的$(version_h) $(timestamp_h)(七) - 3.1.1 依赖include/config/uboot.release;
- UBOOT编译--- UBOOT的$(version_h) $(timestamp_h)(七)
- UBOOT编译--- include/config/auto.conf、 include/config/auto.conf.cmd、 include/generated/autoconf.h (二);
除了prepare0有具体规则外,其它都是伪目标。
5.1 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)。
5.1.1 include/generated/generic-asm-offsets.h的编译(通用)
# <<<<<<<<<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文件如下:
5.1.2 include/generated/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文件如下:
6. 构建$(u-boot-dirs)
关于$(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为例:
6.1 构建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)
6.1.1 %.o文件的编译
.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是用来生成位置有关代码。
6.1.2 %/build-in.o文件的编译
最后,将编译出来的.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'的输入。这经常被叫做"部分连接"。
其他目录的的执行过程也是类似的,就不做进一步分析了。
7. 构建$ (u-boot-init)
注意在编译arch/arm/cpu/armv8/目录时,同时生成了arch/arm/cpu/armv8/start.o,这是u-boot的依赖 $ (u-boot-init)==$(head-y)
8. 构建$(u-boot-dirs)
注意在编译$ (u-boot-dirs)时,同时生成了 */built-in.o ,这是u-boot的依赖 $ (u-boot-main)==$(libs-y)
9. 构建u-boot.lds
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中的头文件中的宏定义。重点关注引用的<config.h>,这个头文件是我们在编译的过程中产生的include/config.h,里面又会引用其它头文件,都会递归展开并进行对应的宏替换。这里我截取了一部分,如下:
10. u-boot编译
# <<<<<<<<<顶层顶层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
- -pie: 生成position-independent executable (ET_EXEC)。
- -Bstatic:在-L指定的目录列表中查找 xxx.a
- --no-dynamic-linker : Produce an executable with no program interpreter header
- -T :指定链接脚本就是u-boot.lds
- –start-group archives --end-group :正常情况,链接的时候库文件只会按它们出现在命令行的顺序搜索一遍,如果包里有未定义的引用标号,而且该包还被放在命令行的后面,这样链接器就无法解决该标号的引用问题。通过给包分组,这些包可以被循环搜索直到所有的引用都可以解决为止。使用该选项将降低性能。只有在无法避免多个包之间互相引用的情况下才使用。
- -Ttext 0x40200000 ’-T’命令行选项只能用于设置 “text” 、“data” 和 “bss” 段的基址,这里是把text段基址设为0x40200000。
- -Map FILE :Write a map file。主要是一些段的信息。
11. 构建include/config/uboot.release
参见:UBOOT编译--- UBOOT的$(version_h) $(timestamp_h)(七) - 3.1.1 依赖include/config/uboot.release。
12. 构建outputmakefile
参见:UBOOT编译--- make xxx_deconfig过程详解(一) - 4.2 依赖 outputmakefile。
13. 构建$(version_h)、 $(timestamp_h)
参见:UBOOT编译--- UBOOT的$(version_h) $(timestamp_h)(七)。
14. 构建tool
没什么好讲的,就是编译一些后面会使用的工具(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),编译规则参见前面的章节,套路是一模一样的。
15. cfg
# <<<<<<<<<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(三)。
16. u-boot-nodtb.bin
# <<<<<<<<<顶层Makefile>>>>>>>>>
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
16.1 规则$(call if_changed,objcopy)
16.1.1 if_changed定义
# <<<<<<<<<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中定义:
# <<<<<<<<<顶层Makefile>>>>>>>>>
# Normally we fill empty space with 0xff
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \
$(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)
16.1.2 $(echo-cmd) $(cmd_ $(1))等价于 $(echo-cmd) $(cmd_objcopy)
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)
16.1.3 编译时具体打印
/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库中描述的标准格式名。
16.2 规则 $(call DO_STATIC_RELA, $ <, $@, $(CONFIG_SYS_TEXT_BASE))
# <<<<<<<<<顶层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
重定位。
16.3 规则 $(BOARD_SIZE_CHECK)
# <<<<<<<<<顶层Makefile>>>>>>>>>
ifneq ($(CONFIG_BOARD_SIZE_LIMIT),)
BOARD_SIZE_CHECK = \
@actual=`wc -c $@ | awk '{print $$1}'`; \
limit=`printf "%d" $(CONFIG_BOARD_SIZE_LIMIT)`; \
if test $$actual -gt $$limit; then \
echo "$@ exceeds file size limit:" >&2 ; \
echo " limit: $$limit bytes" >&2 ; \
echo " actual: $$actual bytes" >&2 ; \
echo " excess: $$((actual - limit)) bytes" >&2; \
exit 1; \
fi
else
BOARD_SIZE_CHECK =
endif
如果有定义CONFIG_BOARD_SIZE_LIMIT,则检查编译出的目标文件是否超过最大值;如果没有定义,则此项为空。
17. dts/dt.dtb
# <<<<<<<<<顶层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),
17.1 $(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
17.1.1 $(DTB)的依赖arch-dtbs和arch/arm/dts/myimx8mmek240-8mm.dts
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
文件存在即可。
17.1.2 $(DTB)规则
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中。
17.2 $(obj)/dt.dtb(dts/dt.dtb)
# <<<<<<<<<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
17.3 $(obj)/dt-spl.dtb(dts/dt-spl.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两次处理:
- 第一个过程:删除任何不需要的节点(比如去掉不含“u-boot,dm pre reloc”属性的节点,因为SPL不需要这些节点)。
- 第二个过程:从其余节点中删除各种未使用的属性。
输出通常是一个小得多的设备树文件。
没什么好讲的,具体编译过程如下:
./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内容如下:
18. u-boot-dtb.bin
# <<<<<<<<<顶层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
19. u-boot.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
20. u-boot.img/u-boot-dtb.img
# <<<<<<<<<顶层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
21. u-boot.dtb
# <<<<<<<<<顶层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
22. binary_size_check
# <<<<<<<<<顶层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
- shell wc -c : wc命令的功能为统计指定文件中的字节数、字数、行数, 并将统计结果显示输出。- c 统计字节数;
- $$1 : makefile中展开为$1,shell中$1表示第一个参数;
- sed 's/0X//g' :把每一行的'0X'替换为空,即去掉地址的0X前缀;
- toupper :转换为大写;
- ibase=16 :设置输入为16进制,默认值为10;
- sed 's/0X//g':'0X'替换为空;
- bc :能够对计算公式的语法进行解释并返回出结果
- test -ne :不等于则为真
上述命令:就是
- 把 u-boot.map中的_image_copy_start去掉0X赋值给start,_image_binary_end地址值去掉0X赋值给end;
- 如果start 不为空且end 不为空,则计算end-start的差值,并赋值给map_size,这时未指定输出格式,默认为10进制数据。
- 然后把十六进制的0X去掉;
- 输出10进制数值;
- 判断map_size是否为空,如果不为空。则继续判断map_size是否等于file_size(u-boot-nodtb.bin的大小);
23. u-boot.srec
# <<<<<<<<<顶层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
24. u-boot.sym
# <<<<<<<<<顶层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
25. System.map
# <<<<<<<<<顶层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,这个文件主要是提供给用户或外部程序调试时使用的。
.
26. 关于SPL镜像
由于篇幅有限这里先不讲,后面单独讲。
27. 总结
成功编译之后,就会在 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
28. 参考
[1] '-E' 只执行到预编译,只涉及到宏替换、头文件展开 、注释去掉(在预处理阶段结束后停止'-E');
[2] '-x' 为输入文件显式指定语言(而不是让编译器根据文件名后缀选择默认语言)(显式指定语言'-x');
[3] '-P' 删除无用的信息(预处理器控制选项 -P);
[4] 利用gcc -E -P 进行宏替换 宏展开 预处理文件;
[5] makefile中$$的使用
UBOOT编译--- UBOOT全部目标的编译过程详解(九)的更多相关文章
- uboot主Makefile分析(t配置和编译过程详解)
1.编译uboot前需要三次make make distcleanmake x210_sd_configmake -j4 make distclean为清楚dist文件. make x210_sd_c ...
- uboot配置和编译过程详解【转】
本文转载自:http://blog.csdn.net/czg13548930186/article/details/53434566 uboot主Makefile分析1 1.uboot version ...
- uboot配置和编译过程详解
根据朱有鹏老师讲解整理 一.uboot主Makefile分析 1.uboot version确定(Makefile的24-29行) include/version_autogenerated.h文件是 ...
- UBOOT编译--- make xxx_deconfig过程详解(一)
make xxx_deconfig过程详解 1. 前言 2. 概述 3. build变量的定义 4. 目标%config的定义 4.1 依赖 scripts_basic 4.1.1 语句$(if $ ...
- Android编译过程详解(一)
Android编译过程详解(一) 注:本文转载自Android编译过程详解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359 ...
- GCC 概述:C 语言编译过程详解
Tags: C Description: 关于 GCC 的个人笔记 GCC 概述 对于 GCC 6.1 以及之后的版本,默认使用的 C++ 标准是 C++ 14:使用 -std=c++11 来指定使用 ...
- cegui-0.8.2编译过程详解
cegui 编译过程详解(cegui-0.8.2) cegui配置整了好长时间了,在一位大牛帮助下终于搞定了,网上的教程大多是老版本的,cegui-0.8.2版的配置寥寥无几,现在总结一下,献给正在纠 ...
- gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解
摘自http://blog.csdn.net/elfprincexu/article/details/45043971 gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解 C和C+ ...
- 转载:C/C++源代码到可执行程序的过程详解
C/C++源代码到可执行程序的过程详解 编译,编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格 ...
- Android的init过程详解(一)(转)
本文使用的软件版本 Android:4.2.2 Linux内核:3.1.10 本文及后续几篇文章将对Android的初始化(init)过程进行详细地.剥丝抽茧式地分析,并且在其中穿插了大量的知识,希望 ...
随机推荐
- KingbaseES 局部索引
一个列要不要建立btree索引,判断条件是其键值分布是否够离散,比如主键.唯一键,可以建立索引.如果这个列有大量重复的值,则建立索引没有意义. 在生产环境中常会碰到键值分布不均匀的列,如表t1有一个名 ...
- linux 运维有趣的实用工具
1.实时监控磁盘 IO-IOTop IOTop 命令是专门显示硬盘 IO 的命令, 界面风格类似 top 命令. [root@localhost ~]# yum -y install iotop` 2 ...
- 15. Fluentd输入插件:in_tail用法详解
in_tail输入插件内置于Fluentd中,无需安装. 它允许fluentd从文本文件尾部读取日志事件,其行为类似linux的tail -F命令(按文件名来tail). 这几乎是最常用的一个输入插件 ...
- Lock 锁底层实现
★ 1.讲讲 Lock 锁 是一个接口,有三个实现类,分别是常用的 可重入锁,读锁.写锁.常用的是可重入锁. 加锁使用lock() 方法,解锁使用 unlock() 方法.Lock的底层是 AQS+C ...
- (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
一.注意要点 1:输入字符串的的编码双方保持统一,如:UTF8: 2:HASH计算输出结果 byte[] 数组转String 时,编码要统一,如:转16进制小写字符串.当然也可以转Base64. 3: ...
- JS 模块化- 04 CMD 规范与 Sea JS
1 CMD 规范介绍 CMD: Common Module Definition, 通用模块定义.与 AMD 规范类似,也是用于浏览器端,异步加载模块,一个文件就是一个模块,当模块使用时才会加载执行. ...
- 自然语言处理NLP程序包(NLTK/spaCy)使用总结
NLTK和SpaCy是NLP的Python应用,提供了一些现成的处理工具和数据接口.下面介绍它们的一些常用功能和特性,便于对NLP研究的组成形式有一个基本的了解. NLTK Natural Langu ...
- C#并发编程-2 异步编程基础-Task
一 异步延迟 在异步方法中,如果需要让程序延迟等待一会后,继续往下执行,应使用Task.Delay()方法. //创建一个在指定的毫秒数后完成的任务. public static Task Delay ...
- P3402 可持久化并查集
P3402 通过主席树维护不同版本的并查集,注意要采用按秩合并的方式,路径压缩可能会爆. 1 #include <bits/stdc++.h> 2 using namespace std; ...
- AdaBoost:自适应提升算法的原理及其实现
AdaBoost:通过改变训练样本权重来学习多个弱分类器并线性组合成强分类器的Boosting算法. Boosting方法要解答的两个关键问题:一是在训练过程中如何改变训练样本的权重或者概率分布,二是 ...