uboot顶层Makefile分析

一、uboot源码目录分析

在这里插入图片描述
在这里插入图片描述
很多文件是经过编译生成的,建议编译uboot后,再进行分析。

最重要的目录:
board/freescale/mx6ullevk,这是一个板级文件,不同的平台各自不同。
configs/xxx_defconfig,,xxx 表示开发板名字,这是uboot的默认配置文件。不同的平台根据自己来配置uboot,会生成一个.config,是根据这个文件配置的结果,makefile根据.config来选择将那些模块源码编译径uboot(内核其实也是这么操作的)。

.cmd 结尾的文件,应该是uboot编译过程中执行过的命令(编译中生成)。
kconfig图形界面配置的文件(应该类似内核的菜单配置)
顶层Makefile关键!

config文件夹

此文件夹为 uboot 配置文件, uboot 是可配置的,但是你要是自己从头开始一个一个项目的配置,那就太麻烦了,因此一般半导体或者开发板厂商都会制作好一个配置文件。我们可以在这个做好的配置文件基础上来添加自己想要的功能,这些半导体厂商或者开发板厂商制作好的
配置文件统一命名为“xxx_defconfig”, xxx 表示开发板名字,这些 defconfig 文件都存放在 configs文件夹。

使用“make xxx_defconfig”命令即可配置 uboot,比如:

make mx6ull_14x14_ddr512_emmc_defconfig

在编译 uboot 之前一定要使用 defconfig 来配置 uboot!

我们在配置是指定了架构和交叉编译器:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig

.cmd 文件分析

.cmd 文件是编译过程中行成的,在uboot源码根目录下
从.cmd文件可以看出uboot.bin文件的形成过程。

.uboot.bin.cmd文件

可以看出u-boot.bin 是从u-boot-nodtb.bin 拷贝而来

cmd_u-boot.bin := cp u-boot-nodtb.bin u-boot.bin
.u-boot-nodtb.bin.cmd文件

这里使用到了arm-linux-gnueabihf-objcopy,使用 objcopy 将 ELF 格式的 u-boot 文件转换为二进制的 u-boot-nodtb.bin 文件。

cmd_u-boot-nodtb.bin := arm-linux-gnueabihf-objcopy --gap-fill=0xff  -j .text -j .secure_text -j .rodata -j .hash -j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn -O binary  u-boot u-boot-nodtb.bin
.u-boot.cmd 文件

文件 u-boot 是 ELF 格式的文件,文件.u-boot.cmd 用于生成 u-boot,文件内容如下:
在这里插入图片描述
.u-boot.cmd 使用到了 arm-linux-gnueabihf-ld.bfd,也就是链接工具,使用 ld.bfd 将各个 builtin.o 文件链接在一起就形成了 u-boot 文件。 uboot 在编译的时候会将同一个目录中的所有.c 文件都编译在一起,并命名为 built-in.o,相当于将众多的.c 文件对应的.o 文件集合在一起,这个就是 u-boot 文件的来源。

.u-boot.imx.cmd

如果我们要用 NXP 提供的 MFGTools 工具向开发板烧写 uboot,此时烧写的是 u-boot.imx文件,而不是 u-boot.bin 文件。 u-boot.imx 是在 u-boot.bin 文件的头部添加了 IVT、 DCD 等信息。
这个工作是由文件.u-boot.imx.cmd 来完成的,此文件内容如下:

 cmd_u-boot.imx := ./tools/mkimage -n
board/freescale/mx6ull_alientek_emmc/imximage.cfg.cfgtmp -T imximage -
e 0x87800000 -d u-boot.bin u-boot.imx

可以看出,这里用到了工具 tools/mkimage,而 IVT、 DCD 等数据保存在了文件board/freescale/mx6ullevk/imximage-ddr512.cfg.cfgtmp 中 ( 如 果 是 NAND 核 心 板 的 话 就 是imximage-ddr256.cfg.cfgtmp),工具 mkimage 就是读取文件 imximage-ddr512.cfg.cfgtmp 里面的
信息,然后将其添加到文件 u-boot.bin 的头部,最终生成 u-boot.imx。

.u-boot.lds.cmd

文件.u-boot.lds.cmd 就是用于生成 u-boot.lds 链接脚本的,由于.u-boot.lds.cmd 文件内容太多,这里就不列出来了。 uboot 根目录下的 u-boot.lds 链接脚本就是来源于 arch/arm/cpu/u-boot.lds文件。

Makefile文件

在根目录下的Makefile是顶层Makefile,Makefile支持嵌套,也就是顶层Makefile可以调用子目录下的Makefile。

Makefile在大项目中很常见,源码按功能模块放在各个子目录下,每一个功能模块目录都会有一个Makefile,这个 Makefile 只处理本模块的编译链接工作,这样所有的编译链接工作就不用全部放到一个 Makefile 中,可以使得 Makefile 变得简洁明了。

uboot 源码根目录下的 Makefile 是顶层 Makefile,他会调用其它的模块的 Makefile 文件,比如 drivers/adc/Makefile。
当然,顶层 Makefile 要做的工作可远不止调用子目录 Makefile 这么简单

u-boot.xxx 文件

u-boot.xxx 同样也是一系列文件,包括 u-boot、 u-boot.bin、 u-boot.cfg、 u-boot.imx、 u-boot.lds、u-boot.map、 u-boot.srec、 u-boot.sym 和 u-boot-nodtb.bin,这些文件的含义如下:

u-boot: 编译出来的 ELF 格式的 uboot 镜像文件。
u-boot.bin: 编译出来的二进制格式的 uboot 可执行镜像文件。
u-boot.cfg: uboot 的另外一种配置文件。
u-boot.imx: u-boot.bin 添加头部信息以后的文件, NXP 的 CPU 专用文件。
u-boot.lds: 链接脚本。
u-boot.map: uboot 映射文件,通过查看此文件可以知道某个函数被链接到了哪个地址上。
u-boot.srec: S-Record 格式的镜像文件。
u-boot.sym: uboot 符号文件。
u-boot-nodtb.bin: 和 u-boot.bin 一样, u-boot.bin 就是 u-boot-nodtb.bin 的复制文件。

.config 文件

uboot 配置文件, 使用命令“make xxx_defconfig”配置 uboot 以后就会自动生成, .config 内容如下:
在这里插入图片描述
可以看出.config 文件中都是以“CONFIG_”开始的配置项,这些配置项就是 Makefile 中的变量,因此后面都跟有相应的值, uboot 的顶层 Makefile 或子 Makefile 会调用这些变量值。
在.config 中会有大量的变量值为‘y’,这些为‘y’的变量一般用于控制某项功能是否使能,为‘y’的话就表示功能使能(y代表yes),比如:

CONFIG_CMD_BOOTD=y

如果使能了 bootd 这个命令的话, CONFIG_CMD_BOOTM 就为‘y’。在 cmd/Makefile 中有如下代码:
在这里插入图片描述
在示例代码 31.1.6 中,有如下所示一行代码:

obj-$(CONFIG_CMD_BOOTM) += bootm.o

CONFIG_CMD_BOOTM=y,将其展开就是:

obj-y += bootm.o

obj-y包含了所有要编译的.o文件,上述就是给obj-y追加了bootm.o。
在 uboot 和 Linux 内核中都是采用这种方法来选择使能某个功能,编译对应的源码文件。

README

文件描述了 uboot 的详细信息,包括 uboot 该如何编译、 uboot 中各文件夹的含义、相应的命令等等。建议大家详细的阅读此文件,可以进一步增加对 uboot 的认识。

二、顶层Makefile分析

版本号

顶层Makefile一开始便是版本号。
VERSION是主版本号,PATCHLEVEL 是补丁版本号, SUBLEVEL 是次版本号,这三个一起构成了 uboot 的版本号,比如当前的 uboot 版本号就是“2016.03”。 EXTRAVERSION 是附加版本信息, NAME 是和名字有关的,一般不使用这两个。
在这里插入图片描述

MAKEFLAGS 变量

make 是支持递归调用的,也就是在 Makefile 中使用“make”命令来执行其他的 Makefile文件,一般都是子目录中的 Makefile 文件。
假设当前目录有一个subdir子目录,这个子目录中又有其对应的Makefile,那么当前目录Makefile就可以调用subdir目录中的Makefile,如:

$(MAKE) -C subdir

$(MAKE)就是调用“make”命令, -C 指定子目录。
有时候上层Makefile需要向底层Makefile传递参数,可以使用export来导出变量(相当于扩展作用域到其它文件),不希望导出可以使用unexport来声明不导出。

export VARIABLE …… //导出变量给子 make 。
unexport VARIABLE…… //不导出变量给子 make。

有两个特殊的变量:“SHELL”和“MAKEFLAGS”,这两个变量除非使用“unexport”声明,否则的话在整个make的执行过程中,它们的值始终自动的传递给子make。

在uboot的主Makefile中有如下代码:

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

上述代码使用“+=”来给变量 MAKEFLAGS 追加了一些值,“-rR”表示禁止使用内置的隐含规则和变量定义,“–include-dir”指明搜索路径, ”$(CURDIR)”表示当前目录。

命令输出

uboot 默认编译是不会在终端中显示完整的命令,都是短命令。
在这里插入图片描述
在终端中输出短命令虽然看起来很清爽,但是不利于分析 uboot 的编译过程。可以通过设置变量“V=1“来实现完整的命令输出,这个在调试 uboot 的时候很有用。
在这里插入图片描述
顶层 Makefile 中控制命令输出的代码如下:

ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_
  Q = @
endif

上述代码中先使用 ifeq(shell脚本中判断数值相等符也是用eq) 来判断"$(origin V)"和"command line"是否相等。这里用到了Makefile的origin函数,该函数是用来判断其来源的,返回值就是它的来源,假如变量v是从命令行给出的,那么它的返回值就是command line。所以这里判断相等条件成立,那么便执行KBUILD_VERBOSE = $(V)。

$(origin <variable>)	#origin原型
ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif

如 果 没 有 在 命 令 行 输 入 V 的话KBUILD_VERBOSE=0。

根据上述代码得到结果:
V=1 的话:

KBUILD_VERBOSE=1
quiet= 空 。
Q= 空。

V=0 或者命令行不定义 V 的话:

KBUILD_VERBOSE=0
quiet= quiet_。
Q= @。

Makefile 中会用到变量 quiet 和 Q 来控制编译的时候是否在终端输出完整的命令,在顶层Makefile 中有很多如下所示的命令:

$(Q)$(MAKE) $(build)=tools

如果 V=0 的话上述命令展开就是“@ make $(build)=tools”, make 在执行的时候默认会在终端输出命令,但是在命令前面加上“@”就不会在终端输出命令了。当 V=1 的时候 Q 就为空,上述命令就是“make $(build)=tools”,因此在 make 执行的过程,命令会被完整的输出在终端上。

有些命令会有两个版本,比如:

quiet_cmd_sym ?= SYM $@
cmd_sym ?= $(OBJDUMP) -t $< > $@

sym 命令分为“quiet_cmd_sym”和“cmd_sym”两个版本,这两个命令的功能都是一样的,区别在于 make 执行的时候输出的命令不同。 quiet_cmd_xxx 命令输出信息少,也就是短命令,而 cmd_xxx 命令输出信息多,也就是完整的命令。
如果变量 quiet 为空的话,整个命令都会输出。
如果变量 quiet 为“quiet_”的话,仅输出短版本。
如果变量 quiet 为“silent_”的话,整个命令都不会输出。

静默输出

前面讲到V=0或不设置V变量,是输出简短命令提示。make -s 就是静默输出模式。
关于make -s,顶层 Makefile中相应的代码如下:

#If the user is running make -s (silent mode), suppress echoing of commands

ifneq ($(filter 4.%,$(MAKE_VERSION)),)	# make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
  quiet=silent_
endif
else					# make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
  quiet=silent_
endif
endif

export quiet Q KBUILD_VERBOSE
ifneq ($(filter 4.%,$(MAKE_VERSION)),)	

这里是判断make的版本号是否为4.x(make -v查看版本号)。
判断 ( f i l t e r 4. (filter 4.%, (filter4.(MAKE_VERSION))和“ ” (空)是否相等,用到了filter 函数,类似于c语言中的查找字符串函数,%是通配符,所以只要make版本是4.x,那么filter返回值肯定不为空,条件成立。

$(filter <pattern...>,<text>)	#filter原型
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
  quiet=silent_
endif

这一行也是一个判断句,如果 ( f i l t e r (filter %s , (filter(firstword x ( M A K E F L A G S ) ) ) 不 为 空 的 话 条 件 成 立 , 变 量 q u i e t 等 于 “ s i l e n t ” 。 这 里 也 用 到 了 函 数 f i l t e r , 在 (MAKEFLAGS)))不为空的话条件成立,变量 quiet 等于“silent_”。这里也用到了函数 filter,在 (MAKEFLAGS)))quietsilentfilter(firstword x$(MAKEFLAGS)))中过滤出符合“%s”的单词。
到了函数 firstword,函数 firstword 是获取首单词,函数格式如下:

$(firstword <text>)

firstword 函数用于取出 text 字符串中的第一个单词,函数的返回值就是获取到的单词。当使用“make -s”编译的时候,“-s”会作为 MAKEFLAGS 变量的一部分传递给 Makefile。 这时候ifneq ( ( f i l t e r (filter %s , (filter(firstword x$(MAKEFLAGS))),)肯定是不为空的,条件成立,
quiet=silent_。

export quiet Q KBUILD_VERBOSE

导出quiet、Q、KBUILD_VERBOSE变量给子makefile。

设置编译结果输出目录

Makefile可以用-O 指定输出目录,如“make O=out”就是设置目标文件输出到 out 目录中。一般我们不指定输出目录。
关于指定输出目录有以下代码:

在这里插入图片描述
第 124 行判断“O”是否来自于命令行,如果来自命令行的话条件成立, KBUILD_OUTPUT就为$(O),因此变量 KBUILD_OUTPUT 就是输出目录。
第 135 行判断 KBUILD_OUTPUT 是否为空。
第 139 行调用 mkdir 命令,创建 KBUILD_OUTPUT 目录,并且将创建成功以后的绝对路径赋值给 KBUILD_OUTPUT。至此,通过 O 指定的输出目录就存在了。(&& 符号与shell中应该一样,前面一条命令执行成功才会执行后一条命令)

代码检查

uboot 支持代码检查,使用命令“make C=1”使能代码检查,检查那些需要重新编译的文件。“make C=2”用于检查所有的源码文件。

模块编译

在 uboot 中允许单独编译某个模块,使用命令“ make M=dir”即可,旧语法“ makeSUBDIRS=dir”也是支持的。

设置目标架构、交叉编译器和配置文件

编 译 uboot 的 时 候 需 要 设 置 目 标 板 架 构 和 交 叉 编 译 器 ,“ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-”就是用于设置 ARCH 和 CROSS_COMPILE,在顶层Makefile 中代码如下:

244 # set default to nothing for native builds
245 ifeq ($(HOSTARCH),$(ARCH))
246 CROSS_COMPILE ?=
247 endif
248
249 KCONFIG_CONFIG ?= .config
250 export KCONFIG_CONFIG

第 245 行判断 HOSTARCH 和 ARCH 这两个变量是否相等,主机架构(变量 HOSTARCH)是x86_64,而我们编译的是 ARM 版本 uboot,肯定不相等,所以 CROS_COMPILE= arm-linuxgnueabihf-。从示例代码可以看出,每次编译 uboot 的时候都要在 make 命令后面设置ARCH 和 CROS_COMPILE,使用起来很麻烦,可以直接修改顶层 Makefile,在里面加入 ARCH和 CROSS_COMPILE 的定义,如图 所示:
在这里插入图片描述
第 249 行定义变量 KCONFIG_CONFIG, uboot 是可以配置的,这里设置配置文件为.config, .config 默认是没有的,需要使用命令“make xxx_defconfig”对 uboot 进行配置,配置完成以后就会在 uboot 根目录下生成.config。默认情况下.config 和xxx_defconfig 内容是一样的,因为.config 就是从 xxx_defconfig 复制过来的。

调用 scripts/Kbuild.include

主 Makefile 会调用文件 scripts/Kbuild.include 这个文件,顶层 Makefile 中代码如下:

327 # We need some generic definitions (do not try to remake the file).
328 scripts/Kbuild.include: ;
329 include scripts/Kbuild.include

使用“include”包含了文件 scripts/Kbuild.include ,此文件里面定义了很多变量,在uboot编译过程中会用到。
在这里插入图片描述

交叉编译工具变量设置

上面我们只是设置了 CROSS_COMPILE 的名字,但是交叉编译器其他的工具还没有设置,顶层 Makefile 中相关代码如下:

331 # Make variables (CC, etc...)
332
333 AS = $(CROSS_COMPILE)as
334 # Always use GNU ld
335 ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),)
336 LD = $(CROSS_COMPILE)ld.bfd
337 else
338 LD = $(CROSS_COMPILE)ld
339 endif
340 CC = $(CROSS_COMPILE)gcc
341 CPP = $(CC) -E
342 AR = $(CROSS_COMPILE)ar
343 NM = $(CROSS_COMPILE)nm
344 LDR = $(CROSS_COMPILE)ldr
345 STRIP = $(CROSS_COMPILE)strip
346 OBJCOPY = $(CROSS_COMPILE)objcopy
347 OBJDUMP = $(CROSS_COMPILE)objdump

7个关于cpu的变量

我们来看一下下面这几个变量:

ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR

这 7 个变量在顶层 Makefile 是找不到的,在 uboot 根目录下有个文件叫做 config.mk,这 7 个变量就是在 config.mk 里面定义的。
config.mk中有下面一段代码:

25 ARCH := $(CONFIG_SYS_ARCH:"%"=%)
26 CPU := $(CONFIG_SYS_CPU:"%"=%)
……
32 BOARD := $(CONFIG_SYS_BOARD:"%"=%)
33 ifneq ($(CONFIG_SYS_VENDOR),)
34 VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
35 endif
36 ifneq ($(CONFIG_SYS_SOC),)
37 SOC := $(CONFIG_SYS_SOC:"%"=%)
38 endif
……
44 CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)
45
46 sinclude $(srctree)/arch/$(ARCH)/config.mk
47 sinclude $(srctree)/$(CPUDIR)/config.mk
48
49 ifdef SOC
50 sinclude $(srctree)/$(CPUDIR)/$(SOC)/config.mk
51 endif
52 ifneq ($(BOARD),)
53 ifdef VENDOR
54 BOARDDIR = $(VENDOR)/$(BOARD)
55 else
56 BOARDDIR = $(BOARD)
57 endif
58 endif
59 ifdef BOARD
60 sinclude $(srctree)/board/$(BOARDDIR)/config.mk # include board
specific rules
61 endif

第 25 行 定 义 变 量 ARCH , 值 为 ( C O N F I G S Y S A R C H : " 第 26 行 定 义 变 量 C P U , 值 为 (CONFIG_SYS_ARCH:"%"=%) , 也 就 是 提 取CONFIG_SYS_ARCH 里面双引号“”之间的内容。比如 CONFIG_SYS_ARCH=“arm”的话,ARCH=arm。 第 26 行定义变量 CPU,值为 (CONFIGSYSARCH:"26CPU(CONFIG_SYS_CPU:"%"=%)。
第 32 行定义变量 BOARD,值为(CONFIG_SYS_BOARD:"%"=%)。
第 34 行定义变量 VENDOR,值为 ( C O N F I G S Y S V E N D O R : " 第 37 行 定 义 变 量 S O C , 值 为 (CONFIG_SYS_VENDOR:"%"=%)。 第 37 行定义变量 SOC,值为 (CONFIGSYSVENDOR:"37SOC(CONFIG_SYS_SOC:"%"=%)。
第 44 行定义变量 CPUDIR,值为 arch/ ( A R C H ) / c p u (ARCH)/cpu (ARCH)/cpu(if ( C P U ) , / (CPU),/ (CPU),/(CPU),)。
第 46 行 sinclude 和 include 的功能类似,在 Makefile 中都是读取指定文件内容 ,这里读取文件 ( s r c t r e e ) / a r c h / (srctree)/arch/ (srctree)/arch/(ARCH)/config.mk 的内容。 sinclude 读取的文件如果不存在的话不会报错。
第 47 行读取文件 ( s r c t r e e ) / (srctree)/ (srctree)/(CPUDIR)/config.mk 的内容。
第 50 行读取文件 ( s r c t r e e ) / (srctree)/ (srctree)/(CPUDIR)/ ( S O C ) / c o n f i g . m k 的 内 容 。 第 54 行 定 义 变 量 B O A R D D I R , 如 果 定 义 了 V E N D O R 那 么 B O A R D D I R = (SOC)/config.mk 的内容。 第 54 行 定 义 变 量 BOARDDIR , 如 果 定 义 了 VENDOR 那 么BOARDDIR= (SOC)/config.mk54BOARDDIRVENDORBOARDDIR=(VENDOR)/ ( B O A R D ) , 否 则 的 B O A R D D I R = (BOARD),否则的 BOARDDIR= (BOARD)BOARDDIR=(BOARD)。
第 60 行读取文件 ( s r c t r e e ) / b o a r d / (srctree)/board/ (srctree)/board/(BOARDDIR)/config.mk。

接下来需要找到 CONFIG_SYS_ARCH、 CONFIG_SYS_CPU、 CONFIG_SYS_BOARD、CONFIG_SYS_VENDOR 和CONFIG_SYS_SOC 这 5 个变量的值。
这 5 个变量在 uboot 根目录下的.config 文件中有定义,定义如下:

CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="mx6"
CONFIG_SYS_VENDOR="freescale"
CONFIG_SYS_BOARD="mx6ullevk"
CONFIG_SYS_CONFIG_NAME="mx6ullevk"

所以最后它们的值是:

ARCH = arm
CPU = armv7
BOARD = mx6ullevk
VENDOR = freescale
SOC = mx6
CPUDIR = arch/arm/cpu/armv7
BOARDDIR = freescale/mx6ullevk

在 config.mk 中读取的文件有:

arch/arm/config.mk
arch/arm/cpu/armv7/config.mk
arch/arm/cpu/armv7/mx6/config.mk (此文件不存在)
board/ freescale/mx6ullevk/config.mk (此文件不存在)

make编译的过程

make distclean

在开始编译之前需要清理工程(删除上一次编译产生的文件)
在这里插入图片描述

make xxx_defconfig 过程

在编译 uboot 之前要使用“make xxx_defconfig”命令来配置 uboot,那么这个配置过程是如何运行的呢?

当执行make mx6ull_alientek_emmc_defconfig 命令时会匹配到以下命令(%是通配符):
在这里插入图片描述
可以看到%config有scripts_basic、outputmakefile、FORCE这3个依赖。

FORCE:

可以看出 FORCE 是没有规则和依赖的,所以每次都会重新生成 FORCE。当 FORCE 作为其他目标的依赖时,由于 FORCE 总是被更新过的,因此依赖所在的规则总是会执行的。
在这里插入图片描述

outputmakefile:

这里判断了KBUILD_SRC是否为空,实际上是空的所以,outputmakefile也为空。
在这里插入图片描述

scripts_basic:

前面两个依赖都是空的,所以关键的操作肯定是在scripts_basic的规则中。
在这里插入图片描述

$(Q)$(MAKE) $(build)=scripts/basic

Q是用来控制输出信息的,MAKE=make,build在 scripts/Kbuild.include 文件中有定义,定义如下:

177 ###
178 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
179 # Usage:
180 # $(Q)$(MAKE) $(build)=dir
181 build := -f $(srctree)/scripts/Makefile.build obj

变量 srctree 为”.”,因此:

build := -f ./scripts/Makefile.build obj

scripts_basic 展开以后如下:

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

scripts_basic会调用到 ./scripts/Makefile.build文件(之后再叙述)。

回到%config:

%config: scripts_basic outputmakefile FORCE
	$(Q)$(MAKE) $(build)=scripts/kconfig $@

makefile基础参考
$@ 就是目标文件
展开后就是:

make -f ./scripts/Makefile.build obj=scripts/kconfig  mx6ull_alientek_emmc_defconfig

同样也会调用到./scripts/Makefile.build文件。

我们可以查看详细的uboot配置过程:
在这里插入图片描述
实际上就是执行了以上分析的3条语句。

./scripts/Makefile.build文件

scripts_basic 目标和%config 都调用到了./scripts/Makefile.build文件。
scripts_basic命令

make -f ./scripts/Makefile.build obj=scripts/basic

%config 命令

make -f ./scripts/Makefile.build obj=scripts/kconfig  mx6ull_alientek_emmc_defconfig

./scripts/Makefile.build文件中又如下的代码片段:

8 # Modified for U-Boot
9 prefix := tpl
10 src := $(patsubst $(prefix)/%,%,$(obj))
11 ifeq ($(obj),$(src))
12 prefix := spl
13 src := $(patsubst $(prefix)/%,%,$(obj))
14 ifeq ($(obj),$(src))
15 prefix := .
16 endif
17 endif

第10行展开后得到:

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

patsubst这是一个替换函数(详细看原子文档759页),最后返回的结果就是obj变量的值,所以src=obj=scripts/basic。

继续分析./scripts/Makefile.build中有如下代码:

56 # The filename Kbuild has precedence over Makefile
57 kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
58 kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuilddir)/Kbuild,$(kbuild-dir)/Makefile)
59 include $(kbuild-file)

最后得到kbuilddir=./scripts/basic, kbuild-file= ./scripts/basic/Makefile。
59行include引用了./scripts/basic/Makefile文件。

观察之前scripts_basic的语句:

make -f ./scripts/Makefile.build obj=scripts/basic

这个语句没有要制作的目标,所以使用默认目标__build。
在 scripts/Makefile.build中定义了默认目标:

在这里插入图片描述__build的规则如下:

116 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target)
$(extra-y)) \
117 $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
118 $(subdir-ym) $(always)
119 @:

经过分析__build最终为:

__build: scripts/basic/fixdep
@:

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

%config命令语句

make -f ./scripts/Makefile.build obj=scripts/kconfig  mx6ull_alientek_emmc_defconfig

和之前一样调用了./scripts/Makefile.build文件,不同的是obj=scripts/kconfig。
那么./scripts/Makefile.build文件中的各个变量值是:

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

最后就会调用./scripts/kconfig/Makefile文件,此文件有如下所示内容:

113 %_defconfig: $(obj)/conf
114 $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
115
116 # Added for U-Boot (backward compatibility)
117 %_config: %_defconfig
118 @:

目标%_defconfig 刚好和我们输入的 mx6ull_alientek_emmc_defconfig 匹配,所以会执行这条规则。依赖为$(obj)/conf,展开后就是 scripts/kconfig/conf。接下来就是检查并生成依赖 scripts/kconfig/conf。

得到 scripts/kconfig/conf 以后就要执行目标%_defconfig 的命令:

$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)

将其展开后:

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

这里会将mx6ull_alientek_emmc_defconfig 中的配置输出到.config 文件中,最终生成 uboot 根目录下的.config 文件。

这个就是命令 make xxx_defconfig 执行流程,总结一下如图 31.3.14.4 所示:
在这里插入图片描述
至此,make xxx_defconfig 就分析完了,接下来就要分析一下 u-boot.bin 是怎么生成的了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值