U-BOOT分析(二)之顶层Makefile文件(1)

U-BOOT版本

u-boot版本:    u-boot-2021.01.tar.bz2

Makefile && make简介

Makefile: 是一个描述文件定义一系列的规则来指定源文件编译的先后顺序,拥有特定的语法规则,makefile文件描述了整个工程中所有文件的__编译顺序,编译规则__,支持函数定义和函数调用,能够直接集成操作系统中的各种命令,Makefile 是支持嵌套的,也就是顶层 Makefile 可以调用子目录中的 Makefile 文件。Makefile 嵌套在大项目中很常见,一般大项目里面所有的源代码都不会放到同一个目录中,各个功能模块的源代码都是分开的,各自存放在各自的目录中。每个功能模块目录下都有一个 Makefile,这个 Makefile 只处理本模块的编译链接工作,这样所有的编译链接工作就不用全部放到一个 Makefile 中,可以使得 Makefile 变得简明容易维护。
      make: 是一个应用程序,解析源程序之间的依赖关系,根据依赖关系自动维护编译工作,执行宿主操作系统中的各种命令,它可以解释makefile中的指令或者说规则,make 支持递归调用,也就是在makefile中使用make命令执行其他的Makefile文件,这个文件一般都是子目录的Makefile文件。假如在当前目录下有一个subdir子目录,这个目录中又有Makefile文件,那么在工程编译的时候其主目录中的Makefile就可以调用子目录中的Makefile,以此来完成子目录中的Makefile编译,主目录中可以使用如下命令来执行子目录中的Makefile:

 $(MAKE) -C subdir

$(MAKE)就是调用make命令,-C是指定子目录
像我们平时使用的一些IDE的编译按钮就是将 Makefile 和make集成在一起,来编译整个工程,同样u-boot ,以及以后我们的linux内核,驱动,应用等的编译都是这么个流程。

接下来分析u-boot的顶层Makefile文件,u-boot 的顶层Makefile的以下内容将被提到

1.版本号
2.MAKEFLAG
3.HOST_ARCH
4.修改C语言区域设置
5.编译信息的输出模式以及静默输出
6.设置编译结果输出目录
7.代码检查
8.编译外部模块
9.获取主机的CPU架构和操作系统
10.设置交叉编译器,以及配置文件
11.scripts_basic 依赖的生成
12.outputmakefile的输出
13.make xxx_defconfig过程
14.make uboot的编译

1.版本号:

2.MAKEFLAG: Makefile 的特殊变量

上边介绍到make是可以递归的,在 make 递归执行的过程中,最上层的 make 称为 主控make ,它的命令行选项,如 “-k”, “-s” 等会通过环境变量 “MAKEFLAGS” 传递给子 make 进程。变量 “MAKEFLAGS” 的值会被主控 make 自动的设置为包含所执行 make 时的命令行选项的字符串。比如主控执行 make 时使用 “-k” 和 “-s” 选项,那么 “MAKEFLAGS” 的值就为 ks 。子 make 进程处理时,会把此环境变量的值作为执行的命令行选项,因此子 make 进程就使用 “-k” 和 “-s” 这两个命令行选项

MAKEFLAGS += -rR --include-dir=$(CURDIR)

这句话意思是给变量MAKEFLAGS追加了值,MAKEFLAGS,默认情况(没有用“unexport”声明),-rR表示禁止使用内置的隐含规则和表达式,–include-dir指明搜索路径.$(CURDIR)表示当前目录,CURDIR是make的内嵌变量,自动设置为当前目录。

  • 隐含规则则是内建在make 中,为make 提供了重建某一类目标文件(.o 等)的通用方法,同时这些隐含规则所用-到的变量也就是所谓的隐含变量。
  • 隐含规则的好处是在Makefile 中不需要明确给出重建某一个目标的命令,甚至可以不需要规则。make会为你自动搜寻匹配的隐含规则链。
  • 隐含规则的代价之一就是低效,系统必须搜索可能的隐含规则链。同时隐含规则也有可能应用了不是你想要的规则而引入很难debug的错误。

3.HOST_ARCH


host_arch.h定义了一些机器名字的代码符号,Makefiel包含这个文件用于下边的机器类型比较。

  • shell uname -m 表示执行uname –m的shell命令,他执行的结果是取出机器硬件名(这台机器是64位的,所以其得到的结果就是x86_64)
  • export将变量传递到子make过程,unexport禁止将变量传递到子make过程。
    23 行表示不导出这个机器平台名字
  • ifeq 等价于 if equal,ifneq 等价于 if not equal
    24-25 行 表示如果获取到的平台名字是 x86_64 就导出这个 HOST_ARCH 且 HOST_ARCH=HOST_ARCH_X86_64,值是定义于 host_arch.h这个文件的。
  • $(findstring FIND,IN)
    • 函数名称:查找字符串函数—findstring。
    • 函数功能:搜索字串“IN”,查找“FIND”字串。
    • 返回值:如果在“IN”之中存在“FIND” ,则返回“FIND”,否则返回空,
      所以26行 就是说明 空空不相等,也就是 MK_ARCH = 某个ix86的值 后边几行的判断也是一样,最后确定 d导出HOST_ARCH 是哪种机器类型。

4.修改C语言区域设置
在locale环境中,有一组变量,代表国际化环境中的不同设置,"C"是系统默认的locale:
LC_ALL是一个宏,如果该值设置了,则该值会覆盖所有LC_*的设置值。注意,LANG的值不受该宏影响。
LC_COLLATE定义该环境的排序和比较规则
LC_NUMERIC非货币的数字显示格式
5.编译信息的输出模式以及静默输出
当在命令行传入V这个变量的值为1(V=1)时,就会使能quiet、Q变量的值为空,make在执行Makefile命令时就会向屏幕输出所执行的命令;当在命令行不传入V这个变量或者V的值为0(V=0)时,就会使能quiet=quiet_、Q= @,make在执行Makefile命令时就不会向屏幕输出所执行的命令。
export quiet Q KBUILD_VERBOSE之后通过export把这三个变量传给下层makefile

应用变量的语法是:$(变量名)。如KBUILD_VERBOSE = $(V)中的$(V)。
“ifeq”语法是ifeq(; , ; ),功能是比较参数“arg1”和“arg2”的值是否相同。
函数origin并不操作变量的值,只是告诉你你的这个变量是哪里来的。
origin函数的返回值有:
"undefined"从来没有定义过、“default”是一个默认的定义、“
"environment"是一个环境变量、
"file"这个变量被定义在Makefile中
"command line"这个变量是被命令行定义的
"override"是被override指示符重新定义的
"automatic"是一个命令运行中的自动化变量

第105行代码注释:make -s 使用静默方式编译其原理就是构建quiet =silent_。
filter 函数表示以 pattern(样式)模式过滤 text 字符串中的单词,仅保留符合模式 pattern 的单词,可以有多个模式。函数返回值就是符合 pattern 的字符串。
第 108 行判断当前正在使用的编译器版本号是否为 4.x,判断 ( f i l t e r 4. (filter 4.%, (filter4.(MAKE_VERSION))和“ ”(空)是否相等,如果不相等的话就成立,执行里面的语句。
第 109 行firstword函数用于去除text字符串中的第一个单词,函数的返回值就是获取到的单词,同样113行也是匹配 MAKEFLAG 的 -s字符串构建quiet =silent_。

6.设置编译结果输出目录
编译复杂项目,Makefile 有2种编译方法:
1.原地编译:默认情况下是当前文件夹中的.c文件,编译出来的.o文件会放在同一文件夹下,原地编译的好处就是处理起来简单.原地编译有一些坏处:第一,污染了源文件目录。第二的缺陷就是一套源代码只能按照一种配置和编译方法进行处理,无法同时维护2个或2个以上的配置编译方式。
2.单独编译:编译时另外指定一个输出目录,将来所有的编译生成的.o文件或生成的其他文件全部丢到那个输出目录下去。源代码目录不做任何污染,这样输出目录就承载了本次配置编译的所有结果,这样就解决以上2种缺陷。

uboot 可以将编译出来的目标文件输出到单独的目录中,在 make 的时候使用“O”来指定
输出目录,比如“make O=out”就是设置目标文件输出到 out 目录中。

因为默认的就是原地编译。如果需要指定具体的输出目录编译则有2种方式来指定输出目录。
第一种:make O=输出目录
第二种:export KBUILD_OUTPUT=输出目录 然后再make
如果两个都指定了(既有KBUILD_OUTPUT环境变量存在,又有O=xx),则O=xx具有更高优先级(参考源码注释 124-133行的介绍)
7.代码检查

使用参数​​C=​​来使能代码检查:
1:检查需要重新编译的文件
2:检查所有的源码文件
同样,如果参数C来源于命令行,就将C赋值给环境变量 ​​KBUILD_CHECKSRC​​​,如果没有则变量​​KBUILD_CHECKSRC​​为0
8.编译外部模块

如果编译外部模块,则对命令行参数变量M进行赋值
操作符比较:
操作符“:=”与操作符 “+=”的功能相同,只是操作符“:=”后面的用来定义变量(KBUILD_EXTMOD)的变量M只能是前面定义好的,
如果操作符“?=”前面的变量KBUILD_EXTMOD没有定义过,那么就将SUBDIRS赋给KBUILD_EXTMOD;
如果定义过,则语句KBUILD_EXTMOD ?= $(SUBDIRS)什么也不做。
‘?=’’ 为条件赋值操作符仅仅在变量还没有定义的情况下有效。
9.获取主机的CPU架构和操作系统

HOSTARCH:获取主机架构与系统名 | 表示管道,管道前的输出作为管道后的输入,sed -e表示替换 ,uname —m表示获取主机架构x86_64,uname -s表示获取系统名称linux
HOSTOS :uname -s 获取主机OS tr ‘[:upper:]’ ‘[:lower:]’ 表示将大写字母替换小写字母。
10.设置交叉编译器,以及配置文件
编译uboot的时候需要设置目标板架构和交叉编译器
“make ARCH=arm
CROSS_COMPILE=arm-linux-gnueabihf-”
就是用于设置 ARCH 和 CROSS_COMPILE
CROSS_COMPILE是定义交叉编译工具链的前缀的。定义这些前缀是为了在后面用(用前缀加上后缀来定义编译过程中用到的各种工具链中的工具)。我们把前缀和后缀分开还有一个原因就是:在不同CPU架构上的交叉编译工具链,只是前缀不一样,后缀都是一样的。因此定义时把前缀和后缀分开,只需要在定义前缀时区分各种架构即可实现可移植性。

第266行 KCONFIG_CONFIG,如果没定义的话用 KCONFIG_CONFIG =.config,而.config默认是没有的,需要
使用命令“make xxx_defconfig” 对 uboot 进行配置,配置完成以后就会在 uboot 根目录下生成.config。默认情况下.config 和xxx_defconfig 内容是一样的,因为.config 就是从 xxx_defconfig 复制过来的。如果后续调整了 uboot 的一些配置参数,那么这些新的配置参数就添加到了.config 中,而不是 xxx_defconfig。因此xxx_defconfig 只是一些初始配置,而.config 里面的才是实时最新有效的配置。
如果主机操作是darwin(MAC OS的内核),则进行相关设置

引入kbuild系统的文件定义

build变量的定义在scripts/Kbuild.include 中定义:

设置CC ,LD,LDR,等的编译套件,其实就是设置前缀 如果前边设置的 CROSS_COMPILE = arm-linux-gnueabi- ,CC=arm-linux-gnueabi-gcc。

这其中有的变量已经定义了,有的变量从未出现,比如第二行的变量,而这几个变量就是从根目录下的config.mk来的。config.mk 的内容定义

ARCH := $(CONFIG_SYS_ARCH:"%"=%)
CPU := $(CONFIG_SYS_CPU:"%"=%)
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_ARCH_TEGRA
CPU := arm720t
endif
endif
BOARD := $(CONFIG_SYS_BOARD:"%"=%)
ifneq ($(CONFIG_SYS_VENDOR),)
VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
endif
ifneq ($(CONFIG_SYS_SOC),)
SOC := $(CONFIG_SYS_SOC:"%"=%)
endif

这里面的​​CONFIG_SYS_xxx​​​变量是从配置文件​​.config​​来的
11.scripts_basic 依赖的生成

# ===========================================================================
# Rules shared between *config targets and build targets# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:$(Q)$(MAKE) $(build)=scripts/basic$(Q)rm -f .tmp_quiet_recordmcount# To avoid any implicit rule to kick in, define an empty command.
scripts/basic/%: scripts_basic ;

Q默认=@ ,MAKE =make,build =-f ./scripts/Makefile.build obj,这里obj就是传入的 scripts/basic,上边说过build变量的定义在scripts/Kbuild.include 中定义:因此要生成目标scripts_basic要执行:make -f ./scripts/Makefile.build obj=scripts/basic
12.outputmakefile的输出

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

ln是linux中一个非常重要命令,它的功能是为某一个文件在另外一个位置建立一个同不的链接,这个命令最常用的参数是-s,具体用法是:ln –s 源文件 目标文件。当我们需要在不同的目录,用到相同的文件时,我们不需要在每一个需要的目录下都放一个必须相同的文件,我们只要在某个固定的目录,放上该文件,然后在 其它的目录下用ln命令链接(link)它就可以,不必重复的占用磁盘空间。例如:ln –s /bin/less /usr/local/bin/less 在这里由于KBUILD_SRC =空,不执行命令,
13.make xxx_defconfig过程

version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.h
defaultenv_h := include/generated/defaultenv_autogenerated.h
dt_h := include/generated/dt.hno-dot-config-targets := clean clobber mrproper distclean \help %docs check% coccicheck \ubootversion backup tests check qcheck tcheckconfig-targets := 0
mixed-targets  := 0
dot-config     := 1ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)dot-config := 0endif
endififeq ($(KBUILD_EXTMOD),)ifneq ($(filter config %config,$(MAKECMDGOALS)),)config-targets := 1ifneq ($(words $(MAKECMDGOALS)),1)mixed-targets := 1endifendif
endififeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.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; \doneelse
ifeq ($(config-targets),1)
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config targetKBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIGconfig: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@%config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@else

xxx_config的目标是%config, %是通配符,依赖是​​scripts_basic outputmakefile FORCE​​这三项,​scripts_basic outputmakefile前边都定义了,FORCE 在文件最后定义

PHONY += FORCE
FORCE:
# Declare the contents of the PHONY variable as phony.  We keep that
# information in a variable so we can use it in if_changed and friends.
.PHONY: $(PHONY)

FORCE是没有规则和依赖的,所以每次都会重新生成FORCE,​当FORCE作为其它目标的依赖时,由于FORCE总是被更新过的,所以依赖所在的规则总是会执行的​,因此.config 生成都会 调用2次 Makefile.build脚本
第一次是生成 script_basic目标 make -f ./scripts/Makefile.build obj=scripts/basic
第二次是 %config目标 make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
目的是将xxx_defconfig文件的内容输出到配置文件.config中,生成.config文件。

#mermaid-svg-A2cP2Sdhdbfv809A {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-A2cP2Sdhdbfv809A .error-icon{fill:#552222;}#mermaid-svg-A2cP2Sdhdbfv809A .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-A2cP2Sdhdbfv809A .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-A2cP2Sdhdbfv809A .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-A2cP2Sdhdbfv809A .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-A2cP2Sdhdbfv809A .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-A2cP2Sdhdbfv809A .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-A2cP2Sdhdbfv809A .marker{fill:#333333;stroke:#333333;}#mermaid-svg-A2cP2Sdhdbfv809A .marker.cross{stroke:#333333;}#mermaid-svg-A2cP2Sdhdbfv809A svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-A2cP2Sdhdbfv809A .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-A2cP2Sdhdbfv809A .cluster-label text{fill:#333;}#mermaid-svg-A2cP2Sdhdbfv809A .cluster-label span{color:#333;}#mermaid-svg-A2cP2Sdhdbfv809A .label text,#mermaid-svg-A2cP2Sdhdbfv809A span{fill:#333;color:#333;}#mermaid-svg-A2cP2Sdhdbfv809A .node rect,#mermaid-svg-A2cP2Sdhdbfv809A .node circle,#mermaid-svg-A2cP2Sdhdbfv809A .node ellipse,#mermaid-svg-A2cP2Sdhdbfv809A .node polygon,#mermaid-svg-A2cP2Sdhdbfv809A .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-A2cP2Sdhdbfv809A .node .label{text-align:center;}#mermaid-svg-A2cP2Sdhdbfv809A .node.clickable{cursor:pointer;}#mermaid-svg-A2cP2Sdhdbfv809A .arrowheadPath{fill:#333333;}#mermaid-svg-A2cP2Sdhdbfv809A .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-A2cP2Sdhdbfv809A .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-A2cP2Sdhdbfv809A .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-A2cP2Sdhdbfv809A .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-A2cP2Sdhdbfv809A .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-A2cP2Sdhdbfv809A .cluster text{fill:#333;}#mermaid-svg-A2cP2Sdhdbfv809A .cluster span{color:#333;}#mermaid-svg-A2cP2Sdhdbfv809A div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-A2cP2Sdhdbfv809A :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-A2cP2Sdhdbfv809A .node>*{stroke:black!important;}#mermaid-svg-A2cP2Sdhdbfv809A .node span{stroke:black!important;}#mermaid-svg-A2cP2Sdhdbfv809A .classX>*{fill:#f96!important;}#mermaid-svg-A2cP2Sdhdbfv809A .classX span{fill:#f96!important;}#mermaid-svg-A2cP2Sdhdbfv809A .classY>*{fill:cyan!important;}#mermaid-svg-A2cP2Sdhdbfv809A .classY span{fill:cyan!important;}#mermaid-svg-A2cP2Sdhdbfv809A .classZ>*{fill:green!important;}#mermaid-svg-A2cP2Sdhdbfv809A .classZ span{fill:green!important;}

make xxx_config
%config目标
依赖
scripts_basic
outputmakefile
FORCE
规则
命令:make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
作用:根据 xxx_deconfig 生成.config文件
命令:make -f ./scripts/Makefile.build obj=scripts/basic
作用:编译scripts/bastic/fixdep.c

上图基本流程是uboot编译之前make xxx_defconfig是生成.config文件的过程。​
14.make uboot的编译

PHONY += inputs
inputs: $(INPUTS-y)all: .binman_stamp inputs
ifeq ($(CONFIG_BINMAN),y)$(call if_changed,binman)
endif# Timestamp file to make sure that binman always runs
.binman_stamp: FORCE@touch $@ifeq ($(CONFIG_DEPRECATED),y)$(warning "You have deprecated configuration options enabled in your .config! Please check your configuration.")
ifeq ($(CONFIG_SPI),y)
ifneq ($(CONFIG_DM_SPI)$(CONFIG_OF_CONTROL),yy)$(warning "The relevant config item with associated code will remove in v2019.07 release.")
endif
endif
endif
ifneq ($(CONFIG_DM),y)@echo >&2 "===================== WARNING ======================"@echo >&2 "This board does not use CONFIG_DM. CONFIG_DM will be"@echo >&2 "compulsory starting with the v2020.01 release."@echo >&2 "Failure to update may result in board removal."@echo >&2 "See doc/driver-model/migration.rst for more info."@echo >&2 "===================================================="
endif
......

all目标依赖 INPUTS-y

# Always append INPUTS so that arch config.mk's can add custom ones
INPUTS-y += u-boot.srec u-boot.bin u-boot.sym System.map binary_size_checkINPUTS-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin
ifeq ($(CONFIG_SPL_FSL_PBL),y)
INPUTS-$(CONFIG_RAMBOOT_PBL) += u-boot-with-spl-pbl.bin
else
ifneq ($(CONFIG_NXP_ESBC), y)
# For Secure Boot The Image needs to be signed and Header must also
# be included. So The image has to be built explicitly
INPUTS-$(CONFIG_RAMBOOT_PBL) += u-boot.pbl
endif
endif
INPUTS-$(CONFIG_SPL) += spl/u-boot-spl.bin
ifeq ($(CONFIG_MX6)$(CONFIG_IMX_HAB), yy)
INPUTS-$(CONFIG_SPL_FRAMEWORK) += u-boot-ivt.img
else
ifeq ($(CONFIG_MX7)$(CONFIG_IMX_HAB), yy)
INPUTS-$(CONFIG_SPL_FRAMEWORK) += u-boot-ivt.img
else
INPUTS-$(CONFIG_SPL_FRAMEWORK) += u-boot.img
endif
endif
INPUTS-$(CONFIG_TPL) += tpl/u-boot-tpl.bin
INPUTS-$(CONFIG_OF_SEPARATE) += u-boot.dtb
ifeq ($(CONFIG_SPL_FRAMEWORK),y)
INPUTS-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img
endif
INPUTS-$(CONFIG_OF_HOSTFILE) += u-boot.dtb
ifneq ($(CONFIG_SPL_TARGET),)
INPUTS-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%)
endif
INPUTS-$(CONFIG_REMAKE_ELF) += u-boot.elf
INPUTS-$(CONFIG_EFI_APP) += u-boot-app.efi
INPUTS-$(CONFIG_EFI_STUB) += u-boot-payload.efi# Generate this input file for binman
ifeq ($(CONFIG_SPL),)
INPUTS-$(CONFIG_ARCH_MEDIATEK) += u-boot-mtk.bin
endif# Add optional build target if defined in board/cpu/soc headers
ifneq ($(CONFIG_BUILD_TARGET),)
INPUTS-y += $(CONFIG_BUILD_TARGET:"%"=%)
endififeq ($(CONFIG_INIT_SP_RELATIVE)$(CONFIG_OF_SEPARATE),yy)
INPUTS-y += init_sp_bss_offset_check
endififeq ($(CONFIG_MPC85xx)$(CONFIG_OF_SEPARATE),yy)
INPUTS-y += u-boot-with-dtb.bin
endififeq ($(CONFIG_ARCH_ROCKCHIP),y)
# On ARM64 this target is produced by binman so we don't need this dep
ifeq ($(CONFIG_ARM64),y)
ifeq ($(CONFIG_SPL),y)
# TODO: Get binman to generate this too
INPUTS-y += u-boot-rockchip.bin
endif
else
ifeq ($(CONFIG_SPL),y)
# Generate these inputs for binman which will create the output files
INPUTS-y += idbloader.img u-boot.img
endif
endif
endifINPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \$(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \$(if $(CONFIG_TPL_X86_16BIT_INIT),tpl/u-boot-tpl.bin)

u-boot.bin目标

MKIMAGEFLAGS_fit-dtb.blob = -f auto -A $(ARCH) -T firmware -C none -O u-boot \-a 0 -e 0 -E \$(patsubst %,-b arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) -d /dev/nullifneq ($(EXT_DTB),)
u-boot-fit-dtb.bin: u-boot-nodtb.bin $(EXT_DTB)$(call if_changed,cat)
else
u-boot-fit-dtb.bin: u-boot-nodtb.bin $(FINAL_DTB_CONTAINER)$(call if_changed,cat)
endifu-boot.bin: u-boot-fit-dtb.bin FORCE$(call if_changed,copy)u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE$(call if_changed,cat)else ifeq ($(CONFIG_OF_SEPARATE),y)
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE$(call if_changed,cat)u-boot.bin: u-boot-dtb.bin FORCE$(call if_changed,copy)
else
u-boot.bin: u-boot-nodtb.bin FORCE$(call if_changed,copy)
endif

u-boot-nodtb.bin 目标


u-boot-nodtb.bin: u-boot FORCE$(call if_changed,objcopy_uboot)$(BOARD_SIZE_CHECK)u-boot.ldr:    u-boot$(CREATE_LDR_ENV)$(LDR) -T $(CONFIG_CPU) -c $@ $< $(LDR_FLAGS)$(BOARD_SIZE_CHECK)

u-boot 目标

u-boot:  $(u-boot-init) $(u-boot-main) u-boot.lds FORCE+$(call if_changed,u-boot__)
ifeq ($(CONFIG_KALLSYMS),y)$(call cmd,smap)$(call cmd,u-boot__) common/system_map.o
endififeq ($(CONFIG_RISCV),y)@tools/prelink-riscv $@ 0
endif

u-boot-init和u-boot-main


libs-y += lib/
...libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)libs-y := $(sort $(libs-y))u-boot-dirs  := $(patsubst %/,%,$(filter %/, $(libs-y))) tools examplesu-boot-alldirs   := $(sort $(u-boot-dirs) $(patsubst %/,%,$(filter %/, $(libs-))))libs-y        := $(patsubst %/, %/built-in.o, $(libs-y))u-boot-init := $(head-y)
u-boot-main := $(libs-y)

​head-y​​没有定义,该变量和CPU架构有关,在相关架构下的子Makefile中定义,比如arch/arm/Makefile中定义如下:
head-y := arch/arm/cpu/$(CPU)/start.o
​​libs-y​​是uboot各子目录中built-in.o的集合
u-boot.lds在各个架构目录下,比如arch/arm/cpu/u-boot.lds
built-in.o文件的生成
以driver/gpio/built-in.o为例,在drivers/gpio/目录下有个名为.built-in.o.cmd的文件,

build-in.o的规则在 Makefile.build文件里边


# ===========================================================================ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a
endififneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif

builtin-target 的依赖 obj-y

$(builtin-target): $(obj-y) FORCE$(call if_changed,link_o_target)targets += $(builtin-target)
endif # builtin-target

这个规则依赖$(obj-y),obj-y变量实际上是Makefile.build里面根据obj参数包含另外的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)# Added for U-Boot
asflags-y  += $(PLATFORM_CPPFLAGS)
ccflags-y  += $(PLATFORM_CPPFLAGS)
cppflags-y += $(PLATFORM_CPPFLAGS)

综上,u-boot目标是以u-boot.lds为链接脚本,将arch/arm/cpu/armv7/start.o和各个子目录下的built-in.o链接在一起生成u-boot​,最后放一张生成下uboot.bin的依赖图:

#mermaid-svg-1PRtG57NxO4bugNi {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-1PRtG57NxO4bugNi .error-icon{fill:#552222;}#mermaid-svg-1PRtG57NxO4bugNi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1PRtG57NxO4bugNi .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-1PRtG57NxO4bugNi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1PRtG57NxO4bugNi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1PRtG57NxO4bugNi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1PRtG57NxO4bugNi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1PRtG57NxO4bugNi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1PRtG57NxO4bugNi .marker.cross{stroke:#333333;}#mermaid-svg-1PRtG57NxO4bugNi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1PRtG57NxO4bugNi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1PRtG57NxO4bugNi .cluster-label text{fill:#333;}#mermaid-svg-1PRtG57NxO4bugNi .cluster-label span{color:#333;}#mermaid-svg-1PRtG57NxO4bugNi .label text,#mermaid-svg-1PRtG57NxO4bugNi span{fill:#333;color:#333;}#mermaid-svg-1PRtG57NxO4bugNi .node rect,#mermaid-svg-1PRtG57NxO4bugNi .node circle,#mermaid-svg-1PRtG57NxO4bugNi .node ellipse,#mermaid-svg-1PRtG57NxO4bugNi .node polygon,#mermaid-svg-1PRtG57NxO4bugNi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1PRtG57NxO4bugNi .node .label{text-align:center;}#mermaid-svg-1PRtG57NxO4bugNi .node.clickable{cursor:pointer;}#mermaid-svg-1PRtG57NxO4bugNi .arrowheadPath{fill:#333333;}#mermaid-svg-1PRtG57NxO4bugNi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1PRtG57NxO4bugNi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1PRtG57NxO4bugNi .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-1PRtG57NxO4bugNi .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-1PRtG57NxO4bugNi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1PRtG57NxO4bugNi .cluster text{fill:#333;}#mermaid-svg-1PRtG57NxO4bugNi .cluster span{color:#333;}#mermaid-svg-1PRtG57NxO4bugNi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1PRtG57NxO4bugNi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-1PRtG57NxO4bugNi .node>*{stroke:black!important;}#mermaid-svg-1PRtG57NxO4bugNi .node span{stroke:black!important;}#mermaid-svg-1PRtG57NxO4bugNi .classX>*{fill:#f96!important;}#mermaid-svg-1PRtG57NxO4bugNi .classX span{fill:#f96!important;}#mermaid-svg-1PRtG57NxO4bugNi .classY>*{fill:cyan!important;}#mermaid-svg-1PRtG57NxO4bugNi .classY span{fill:cyan!important;}#mermaid-svg-1PRtG57NxO4bugNi .classZ>*{fill:green!important;}#mermaid-svg-1PRtG57NxO4bugNi .classZ span{fill:green!important;}

默认目标
依赖
依赖
设备树依赖
依赖
依赖
依赖
依赖
依赖
变量
变量
make
_all
all
INPUTS-y
uboot.srec
uboot.bin
uboot.sym
System.map
binary_size_check
u-boot.*
u-bootdtb.bin
u-bootnodtb.bin
u-boot
u-boot-init
u-boot-main
u-boot.lds
head-y
arch/xxx/.../start.o
libs-y
所有子目录下build-in.o集合
arch/xxx/cpu/u-boot.lds
u-boot-onenand.bin
u-boot-with-spl-pbl.bin
u-boot-tpl.bin
u-boot.* .etc

U-BOOT分析(二)之顶层Makefile文件(1)相关推荐

  1. 【光链路分析二】OTDR 测量文件 SOR文件解析

    OTDR 测量文件 SOR文件 解析 OTDR 标准格式文件是遵守Bellcore 标准的 概要[文件名称.测量时间.光缆标识.纤芯标识.起点.终点.设备型号.设备序列号等] 测量结果[长度.总损耗. ...

  2. U-Boot顶层Makefile分析

    参考:U-Boot顶层Makefile介绍 作者:一只青木呀 发布时间: 2020-10-22 16:22:17 网址:https://blog.csdn.net/weixin_45309916/ar ...

  3. linux内核顶层Makefile详解

    文章目录 一.linux内核获取 二.linux内核初次编译 三.linux工程目录分析 1.获取源码 2.目录介绍 1.总体浏览 2.arch 目录 3.block 目录 4.crypto 目录 5 ...

  4. U-Boot 顶层 Makefile 详解

    U-Boot 顶层 Makefile 详解 1.U-Boot 工程目录分析 我们在分析 uboot 源码之前一定要 先在 Ubuntu 中编译一下 uboot 源码,因为编译过程会生成一些文件,而生成 ...

  5. Linux 内核顶层Makefile 详解

    目录 前602行分析 make xxx_defconfig 过程 Makefile.build 脚本分析 make 过程 built-in.o 文件编译生成过程 make zImage 过程 前几章我 ...

  6. U-Boot源码目录分析(VScode工程创建及文件夹过滤)

    参考:U-Boot工程目录介绍 作者:一只青木呀 发布时间: 2020-10-21 14:47:30 网址:https://blog.csdn.net/weixin_45309916/article/ ...

  7. 【正点原子Linux连载】第三十五章 Linux内核顶层Makefile详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  8. Linux 内核顶层 Makefile 详解

    Linux 内核获取 Linux 由 Linux 基金会管理与发布, Linux 官网为 https://www.kernel.org,所以你想获取最新的 Linux 版本就可以在这个网站上下载 最新 ...

  9. 【正点原子Linux连载】第三十一章 U-Boot顶层Makefile详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

最新文章

  1. 【数据库】将Excel导入达梦数据库,并执行表合并
  2. 进击的 Kubernetes 调度系统(一):Kubernetes scheduling framework
  3. 解决通过 Visual Studio 打不开 ui 文件的问题
  4. Hive集成Tez引擎跑任务出现的问题(Java heap space问题)
  5. ant centos环境下 编译没有将配置文件加载_你可能忽略的macOS下brew安装nginx细节解读,干货
  6. Spring(二)scope、集合注入、自动装配、生命周期
  7. c语言实现bf算法的定位函数,数据结构c语言版严蔚敏清华大学出版社第四章串.ppt...
  8. 我一定要找到它FreeEIM
  9. 常用图像处理相关图像数据库
  10. python 直方图均衡化_直方图均衡化-Python实现
  11. java学习之springcloud之服务注册与发现篇
  12. 快讯分类_如何从Google快讯创建RSS Feed
  13. python 采用数值方法计算最速曲线
  14. 如何在头条做营销:2022今日头条营销价值洞察报告.pdf(附下载链接)
  15. 微信公众号开发使用测试号不能测试支付接口的解决方案
  16. android 三星调用拍照功能吗,玩转Galaxy S3拍照功能全解析
  17. JSON解析基础使用知识-Java
  18. 京东API开发系列:京东按关键字搜索商品 API / item_search - 按关键字搜索商品 API返回值说明
  19. Java技能点--基本类型与非基本类型
  20. mysql 一 、关系模型——主键——外键——索引

热门文章

  1. 直播app开发解决方案
  2. Fun Encryption Hero - Source GoDapp
  3. 【ansys workbench】在ansys2020版本的mechanical中怎么施加约束或载荷?结构约束和载荷?fixed support
  4. 微信为什么不支持android4,解决android4.4.4手机不能正常调起微信支付问题
  5. 少壮不努力,长大写代码。。
  6. 美景本天成,妙笔偶得之——“妙笔”是怎样炼成的?
  7. ❤️学懂C语言文件操作读这篇就够了(万字总结,附习题)❤️
  8. 中科院 鲁士文 计算机网络,《计算机网络-鲁士文》10_基于IP的多协议标记交换技术.pptx...
  9. JS实现番茄钟倒计时
  10. 番茄工作法计时器发布