uboot源码分析三 编译处理过程

make xxx_defconfig 过程

$(Q)$(MAKE) $(build)=scripts/kconfig $@
# To make sure we do not include .config for any of the *config targets
# catch them early, and hand them over to scripts/kconfig/Makefile
# It is allowed to specify more targets when calling make, including
# mixing *config targets and build targets.
# For example 'make oldconfig all'.
# Detect when mixed targets is specified, and make a second invocation
# of make so .config is not included in this case either (for *config).

version_h := include/generated/version_autogenerated.h//第 422 行定义了变量 version_h,这变量保存版本号文件,此文件是自动生成的。
timestamp_h := include/generated/timestamp_autogenerated.h//第 423 行定义了变量 timestamp_h,此变量保存时间戳文件,此文件也是自动生成的。
//定义了变量 no-dot-config-targets。
no-dot-config-targets := clean clobber mrproper distclean \
			 help %docs check% coccicheck \
			 ubootversion backup

config-targets := 0//定义了变量 config-targets,初始值为 0。
mixed-targets  := 0//定义了变量 mixed-targets,初始值为 0。
dot-config     := 1//定义了变量 dot-config,初始值为 1。
/*将 MAKECMDGOALS 中不符合 no-dot-config-targets 的部分过滤掉,剩下的如果不为空的话条件就成立。 MAKECMDGOALS 是 make 的一个环境变量,这个变量会保存你所指定的终极目标列表,比如执行“make mx6ull_alientek_emmc_defconfig”,那么 MAKECMDGOALS就为 mx6ull_alientek_emmc_defconfig。很明显过滤后为空,所以条件不成立,变量 dot-config 依旧为 1。*/
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
	ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
		dot-config := 0
	endif
endif
/*判断KBUILD_EXTMOD是否为空,如果KBUILD_EXTMOD为空的话条件成立,经过前面的分析,我们知道 KBUILD_EXTMOD 为空,所以条件成立。
将 MAKECMDGOALS 中不符合“config”和“%config”的部分过滤掉,如果剩下的部分不为空条件就成立,很明显此处条件成立,变量 config-targets=1。*/
ifeq ($(KBUILD_EXTMOD),)
        ifneq ($(filter config %config,$(MAKECMDGOALS)),)
                config-targets := 1
                //第 442 行统计 MAKECMDGOALS 中的单词个数,如果不为 1 的话条件成立。此处调用Makefile 中的 words 函数来统计单词个数
                ifneq ($(words $(MAKECMDGOALS)),1)
                        mixed-targets := 1
                endif
        endif
endif
/* MAKECMDGOALS 的单词个数是 1 个,所以条件不成立, mixed-targets 继续为0。综上所述,这些变量值如下:
config-targets = 1
mixed-targets = 0
dot-config = 1 */
ifeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.
//如果变量 mixed-targets 为 1 的话条件成立,很明显,条件不成立。
PHONY += $(MAKECMDGOALS) __build_one_by_one

$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one
	@:

__build_one_by_one:
	$(Q)set -e; \
	for i in $(MAKECMDGOALS); do \
		$(MAKE) -f $(srctree)/Makefile $$i; \
	done

else
ifeq ($(config-targets),1)//第 473 行,没有目标与之匹配,所以不执行。
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target
//如果变量 config-targets 为 1 的话条件成立,很明显,条件成立,执行这个分支
KBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIG

config: scripts_basic outputmakefile FORCE
	$(Q)$(MAKE) $(build)=scripts/kconfig $@
//第 476 行,有目标与之匹配,当输入“make xxx_defconfig”的时候就会匹配到%config 目标,目标“%config”依赖于 scripts_basic、 outputmakefile 和 FORCE。 
%config: scripts_basic outputmakefile FORCE
	$(Q)$(MAKE) $(build)=scripts/kconfig $@
/*  将命令展开就是:
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig */
else
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# targets and others. In general all targets except *config targets.

ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf

# Read in dependencies to all Kconfig* files, make sure to run
# oldconfig if changes are detected.
-include include/config/auto.conf.cmd

# To avoid any implicit rule to kick in, define an empty command
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;

# If .config is newer than include/config/auto.conf, someone tinkered
# with it and forgot to run make oldconfig.
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
	$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
	@# If the following part fails, include/config/auto.conf should be
	@# deleted so "make silentoldconfig" will be re-run on the next build.
	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \
		{ rm -f include/config/auto.conf; false; }
	@# include/config.h has been updated after "make silentoldconfig".
	@# We need to touch include/config/auto.conf so it gets newer
	@# than include/config.h.
	@# Otherwise, 'make silentoldconfig' would be invoked twice.
	$(Q)touch include/config/auto.conf

-include include/autoconf.mk
-include include/autoconf.mk.dep

# We want to include arch/$(ARCH)/config.mk only when include/config/auto.conf
# is up-to-date. When we switch to a different board configuration, old CONFIG
# macros are still remaining in include/config/auto.conf. Without the following
# gimmick, wrong config.mk would be included leading nasty warnings/errors.
ifneq ($(wildcard $(KCONFIG_CONFIG)),)
ifneq ($(wildcard include/config/auto.conf),)
autoconf_is_old := $(shell find . -path ./$(KCONFIG_CONFIG) -newer \
						include/config/auto.conf)
ifeq ($(autoconf_is_old),)
include config.mk
include arch/$(ARCH)/Makefile
endif
endif
endif

# If board code explicitly specified LDSCRIPT or CONFIG_SYS_LDSCRIPT, use
# that (or fail if absent).  Otherwise, search for a linker script in a
# standard location.

ifndef LDSCRIPT
	#LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds.debug
	ifdef CONFIG_SYS_LDSCRIPT
		# need to strip off double quotes
		LDSCRIPT := $(srctree)/$(CONFIG_SYS_LDSCRIPT:"%"=%)
	endif
endif

# If there is no specified link script, we look in a number of places for it
ifndef LDSCRIPT
	ifeq ($(wildcard $(LDSCRIPT)),)
		LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds
	endif
	ifeq ($(wildcard $(LDSCRIPT)),)
		LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot.lds
	endif
	ifeq ($(wildcard $(LDSCRIPT)),)
		LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot.lds
	endif
endif

else
# Dummy target needed, because used as prerequisite
include/config/auto.conf: ;
endif # $(dot-config)

ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS	+= -Os
else
KBUILD_CFLAGS	+= -O2
endif

KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks)

KBUILD_CFLAGS	+= -g
# $(KBUILD_AFLAGS) sets -g, which causes gcc to pass a suitable -g<format>
# option to the assembler.
KBUILD_AFLAGS	+= -g

第 476 行,有目标与之匹配,当输入“make xxx_defconfig”的时候就会匹配到%config 目标,目标“%config”依赖于 scripts_basic、 outputmakefile 和 FORCE。 FORCE 在顶层 Makefile的 1610 行有如下定义

1610 PHONY += FORCE
1611 FORCE:

以看出 FORCE 是没有规则和依赖的,所以每次都会重新生成 FORCE。当 FORCE 作为其他目标的依赖时,由于 FORCE 总是被更新过的,因此依赖所在的规则总是会执行的。
依赖 scripts_basic
在这里插入图片描述
第 396~398 行是 scripts_basic 的规则,其对应的命令用到了变量 Q、 MAKE 和 build

Q=@或为空
MAKE=make
build变量在kbuild.include

scripts_basic 展开以后如下:

scripts_basic:
@make -f ./scripts/Makefile.build obj=scripts/basic //也可以没有@,视配置而定
@rm -f . tmp_quiet_recordmcount //也可以没有@

依赖 outputmakefile
在这里插入图片描述
第 408 行,判断 KBUILD_SRC 是否为空,只有变量 KBUILD_SRC 不为空的时候outputmakefile 才有意义,经过我们前面的分析 KBUILD_SRC 为空,所以 outputmakefile 无效。只有 scripts_basic 是有效的。

最终输出:
①、 scripts_basic 目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/basic
②、 %config 目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

在这里插入图片描述

Makefile.build 脚本分析

“ make xxx_defconfig“配置 uboot 的时候如下两行命令会执行脚本scripts/Makefile.build:

@make -f ./scripts/Makefile.build obj=scripts/basic
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

在这里插入图片描述
第 9 行定义了变量 prefix 值为 tpl。
第 10 行定义了变量 src,这里用到了函数 patsubst,此行代码展开后为:

$(patsubst tpl/%,%, scripts/basic)

patsubst 是替换函数,格式如下:

$(patsubst ,, )

此函数用于在 text 中查找符合 pattern 的部分,如果匹配的话就用 replacement 替换掉。
pattenr 是可以包含通配符“%”,如果 replacement 中也包含通配符“%”,那么 replacement 中的这个“%”将是 pattern 中的那个“%”所代表的字符串。函数的返回值为替换后的字符串。因此,第 10 行就是在“scripts/basic”中查找符合“tpl/%”的部分,然后将“tpl/”取消掉,但“scripts/basic”没有“tpl/”,所以 src= scripts/basic。
第 11 行判断变量 obj 和 src 是否相等,相等的话条件成立,很明显,此处条件成立。
第 12 行和第 9 行一样,只是这里处理的是“spl”,“scripts/basic”里面也没有“spl/”,所以src 继续为 scripts/basic。
第 15 行因为变量 obj 和 src 相等,所以 prefix=.。
在这里插入图片描述
将 kbuild-dir 展开后为:

$(if $(filter /%, scripts/basic), scripts/basic, ./scripts/basic),

因为没有以“ /”为开头的单词,所以$(filter /%, scripts/basic)的结果为空, kbuilddir=./scripts/basic。
将 kbuild-file 展开后为:

$(if $(wildcard ./scripts/basic/Kbuild), ./scripts/basic/Kbuild,./scripts/basic/Makefile)

因为 scrpts/basic 目录中没有 Kbuild 这个文件,所以 kbuild-file= ./scripts/basic/Makefile。最后将 59 行展开,即:

include ./scripts/basic/Makefile

也就是读取 scripts/basic 下面的 Makefile 文件。
在这里插入图片描述
__build 是默认目标,因为命令“@make -f ./scripts/Makefile.build obj=scripts/basic”没有指定目标,所以会使用到默认目标: __build。在顶层 Makefile 中, KBUILD_BUILTIN 为 1,KBUILD_MODULES 为 0,因此展开后目标__build 为:

__build:$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
@:

可以看出目标__build 有 5 个依赖: builtin-target、 lib-target、 extra-y、 subdir-ym 和 always。
这 5 个依赖的具体内容打印出来发现为只有 always 有效,因此__build 最终为:

__build: scripts/basic/fixdep
@:

__build 依赖于 scripts/basic/fixdep,所以要先 scripts/basic/fixdep.c 编译,生成 fixdep,前面已经读取了 scripts/basic/Makefile 文件。
综上所述, scripts_basic 目标的作用就是编译出 scripts/basic/fixdep 这个软件。

%config 目标对应的命令

%config 目 标 对 应 的 命 令 为 :

@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

各个变量值如下:

src= scripts/kconfig
kbuild-dir = ./scripts/kconfig
kbuild-file = ./scripts/kconfig/Makefile
include ./scripts/kconfig/Makefile

可以看出, Makefilke.build 会读取 scripts/kconfig/Makefile 中的内容,此文件有如下所示内容:
在这里插入图片描述
目标%_defconfig 刚好和我们输入的 xxx_defconfig 匹配,所以会执行这条规则。依赖为$(obj)/conf,展开后就是 scripts/kconfig/conf。接下来就是检查并生成依赖 scripts/kconfig/conf。conf 是主机软件,到这里我们就打住,不要纠结 conf 是怎么编译出来的,否则就越陷越深,太绕了,像 conf 这种主机所使用的工具类软件我们一般不关心它是如何编译产生的。如果一定要看是 conf 是怎么生成的,可以输入如下命令重新配置 uboot,在重新配置 uboot 的过程中就会输出 conf 编译信息。

make distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_
defconfig V=1

在这里插入图片描述
得到 scripts/kconfig/conf 以后就要执行目标%_defconfig 的命令:

( Q ) (Q) (Q)< ( s i l e n t ) − − d e f c o n f i g = a r c h / (silent) --defconfig=arch/ (silent)defconfig=arch/(SRCARCH)/configs/$@ $(Kconfig)

silent=-s 或为空
SRCARCH=…
Kconfig=Kconfig

将其展开就是:

@ scripts/kconfig/conf --defconfig=arch/…/configs/xxx_defconfig Kconfig

上述命令用到了 xxx_defconfig 文件,比如 mx6ull_alientek_emmc_defconfig。这里会将mx6ull_alientek_emmc_defconfig 中的配置输出到.config 文件中,最终生成 uboot 根目录下的.config 文件。
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值