1.前言
本文主要就Hi3556v200的U-boot+Liteos方案的编译流程做简要介绍,主要通过make过程的打印来逐步理清编译的过程,本文主要介绍u-boot config的编译过程
U-boot版本:u-boot-2016.11
2.编译信息
make[2]: Entering directory `/data_old/chenbo/Hi3559V200_SmartCam_V5.0.0.1/osdrv/opensource/uboot/u-boot-2016.11'
第一次进入u-boot主目录
make -f ./scripts/Makefile.build obj=scripts/basic
cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c
rm -f .tmp_quiet_recordmcount
make -f ./scripts/Makefile.build obj=scripts/kconfig hi3556v200_config
cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_GNU_SOURCE -DCURSES_LOC="<ncurses.h>" -DLOCALE -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c
cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_GNU_SOURCE -DCURSES_LOC="<ncurses.h>" -DLOCALE -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c
cc -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o
scripts/kconfig/conf --defconfig=arch/../configs/hi3556v200_defconfig Kconfig
#
# configuration written to .config
#
3. 编译过程分析
编译config发生在osdrv/Makefile中编译hiboot目标时:
#osdrv/Makefile
hiboot:hiregbin_prepare
......
make -C $(OSDRV_DIR)/opensource/uboot/$(UBOOT_VER) ARCH=arm CROSS_COMPILE=$(OSDRV_CROSS)- $(UBOOT_CONFIG)
......
根据打印信息,这里的UBOOT_CONFIG为hi3556v200_config,之后将会进入uboot主目录的Makefile,当执行make hi3556v200_config的时候,因此会匹配执行如下的规则:
#u-boot/Makefile
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
3.1 编译scripts_basic
首先会编译依赖目标scripts_basic
#u-boot/Makefile
PHONY += scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
因为在顶层Makeifle中会include scripts/Kbuild.include,build就定义在Kbuild.include
build展开后为:build := -f ./scripts/Makefile.build obj
因此
(
Q
)
(Q)
(Q)(MAKE)
(
b
u
i
l
d
)
=
s
c
r
i
p
t
s
/
b
a
s
i
c
转
换
为
:
m
a
k
e
−
f
.
/
s
c
r
i
p
t
s
/
M
a
k
e
f
i
l
e
.
b
u
i
l
d
o
b
j
=
s
c
r
i
p
t
s
/
b
a
s
i
c
在
M
a
k
e
f
i
l
e
.
b
u
i
l
d
中
,
如
果
指
定
了
o
b
j
,
则
实
际
会
通
过
如
下
的
语
句
来
包
含
(build)=scripts/basic转换为: make -f ./scripts/Makefile.build obj=scripts/basic 在Makefile.build中,如果指定了obj,则实际会通过如下的语句来包含
(build)=scripts/basic转换为:make−f./scripts/Makefile.buildobj=scripts/basic在Makefile.build中,如果指定了obj,则实际会通过如下的语句来包含(obj)下的Makefile文件:
此处src := $(obj),因此对于obj=scripts/basic,则实际会包含scripts/basic/Makefile
# 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)
继续看make -f ./scripts/Makefile.build obj=scripts/basic,由于此处没有明确指明目标,因此会执行scripts/Makefile.build 中默认目标__build的编译:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
此处KBUILD_BUILTIN为1,KBUILD_MODULES为空,因此__build目标最终转换为:
__build: $(builtin-target) $(lib-target) $(extra-y) $(subdir-ym) $(always)
@:
此处又产生了$(builtin-target) $(lib-target) $(extra-y) $(subdir-ym) $(always)依赖:
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
$(lib-target): $(lib-y) FORCE
$(call if_changed,link_l_target)
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
#scripts/Makefile.lib
extra-y := $(addprefix $(obj)/,$(extra-y))
scripts/basic/Makefile
hostprogs-y := fixdep
always := $(hostprogs-y)
如果构建的最终目标是主机程序,如上述fixdep的构建规则 :
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
Makefile.build除了要inclue $(obj)/Makefile即scripts/basic/Makefile文件外,还会include scripts/Makefile.host,在Makefile.build 对包含scripts/Makefile.host的处理如下:
#scripts/Makefile.build
ifneq ($(hostprogs-y)$(hostprogs-m),)
include scripts/Makefile.host #编译主机程序时,要包含Makefile.host文件
endif
因为在此之前已经包含了scripts/basic/Makefile,且在该Makefile文件里,hostprogs-y被赋值为fixdep,那么上述ifneq分支为真。即会包含scripts/Makefile.host。
在scripts/basic/Makefile里,有如下语句:
scripts/basic/Makefile
always := $(hostprogs-y)
那么回到不指定目标的make命令里,接下来在Makefile.build中的默认目标__build中,会匹配到重建的依赖always。注意这里变量$(always)的值为fixdep。由此触发依赖fixdep的重建,而它的重建规则在上面包含的scripts/Makefile.host中。
就是重复这样一个递归的“规则----> 规则目标–>依赖—>重建依赖—>规则---->”…的过程,直至最后的目标文件被构建,然后逆推,由依赖层层重建其规则目标。
总结一下:
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
被转换为:
make -f ./scripts/Makefile.build obj=scripts/basic
- 编译scripts_basic目标时,scripts/Makefile.build会包含scripts/basic下的Makefile;
- 由于没有指定编译目标,因此会编译scripts/Makefile.build的__build默认目标
- __build默认目标依赖于多个目标:$(builtin-target) $(lib-target) $(extra-y) $(subdir-ym) $(always)
- 只有$(always)目标会得到编译,它就是fixdep工具
3.2 outputmakefile
#u-boot/Makefile
PHONY += outputmakefile
# outputmakefile generates a Makefile in the output directory, if using a
# separate output directory. This allows convenient use of make in the
# output directory.
outputmakefile:
ifneq ($(KBUILD_SRC),)
$(Q)ln -fsn $(srctree) source
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif
由于KBUILD_SRC 为空,所以ifneq 中的语句不会执行。 outputmakefile 为空
3.3 FORCE
FORCE被定义为一个空目标。如果一个目标添加 FORCE 依赖,每次编译都会去先去执 FORCE(实际上什么都不做),然后运行命令更新目标,这样就能确保目标每次都会被更新
3.4 编译hi3556v200_config
分析完前面hi3556v200_config的依赖,当依赖的目标生成后就会执行hi3556v200_config目标的命令,通过前面的分析
(
Q
)
(Q)
(Q)(MAKE) $(build)=scripts/kconfig $@
直接可以回显:
make -f ./scripts/Makefile.build obj=scripts/kconfig hi3556v200_config
根据前面对scripts_basic的分析,总结一下:
- 编译hi3556v200_config目标时,scripts/Makefile.build会包含scripts/kconfig下的Makefile;
- 编译目标为hi3556v200_config,因此会编译scripts/kconfig下的Makefile的%_defconfig目标;
#scripts/kconfig/Makefile
%_defconfig: $(obj)/conf
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
- 由于依赖于 ( o b j ) / c o n f , 因 此 (obj)/conf,因此 (obj)/conf,因此(obj)/conf会得到编译,$(obj)/conf依赖于conf.c和zconf.tab.c,后者进一步包含所需要的词法分析文件
- 执行%_defconfig目标的命令
在命令中将会进行conf调用:
scripts/kconfig/conf --defconfig=arch/arm/configs/vexpress_defconfig Kconfig
生成.config
4. 总结
可以看到在执行了make vexpress_defconfig之后,主要生成了如下文件:
- 在根目录下生成.config文件;
- 在scripts/basic下生成fixdep工具
- 在scripts/kconfig下生成conf工具