在之前的文章,我们经过编译,配置工具链,编译好了uboot的内容,呈现的工程结构如下所示;
具体的内容作用也就不做过多的解析了,读者可以根据内容单个去查。
在阅读 uboot 源码之前,肯定是要先看一下顶层 Makefile,分析 gcc 版本代码的时候一定是 先从顶层 Makefile 开始的,然后再是子 Makefile,这样通过层层分析 Makefile 即可了解整个工 程的组织结构。顶层 Makefile 也就是 uboot 根目录下的 Makefile 文件,由于顶层 Makefile 文件 内容比较多,所以我们将其分开来看。
顶层 Makefile 一开始是版本号,内容如下(为了方便分析,顶层 Makefile 代码段前段行号 采用 Makefile 中的行号,因为 uboot 会更新,因此行号可能会与你所看的顶层 Makefile 有所不 同):
VERSION = 2016
PATCHLEVEL = 03
SUBLEVEL =
EXTRAVERSION =
NAME =
VERSION 是主版本号,PATCHLEVEL 是补丁版本号,SUBLEVEL 是次版本号,这三个一 起构成了 uboot 的版本号,比如当前的 uboot 版本号就是“2016.03”。EXTRAVERSION 是附加 版本信息,NAME 是和名字有关的,一般不使用这两个。
make 是支持递归调用的,也就是在 Makefile 中使用“make”命令来执行其他的 Makefile 文件,一般都是子目录中的 Makefile 文件。假如在当前目录下存在一个“subdir”子目录,这个 子目录中又有其对应的 Makefile 文件,那么这个工程在编译的时候其主目录中的 Makefile 就可 以调用子目录中的 Makefile,以此来完成所有子目录的编译。主目录的 Makefile 可以使用如下 代码来编译这个子目录:
$(MAKE) -C subdir
$(MAKE)就是调用“make”命令,-C 指定子目录。有时候我们需要向子 make 传递变量, 这个时候使用“export”来导出要传递给子 make 的变量即可,如果不希望哪个变量传递给子 make 的话就使用“unexport”来声明不导出:
export VARIABLE …… //导出变量给子 make 。
unexport VARIABLE…… //不导出变量给子 make。
有两个特殊的变量:“SHELL”和“MAKEFLAGS”,这两个变量除非使用“unexport”声明, 否则的话在整个make的执行过程中,它们的值始终自动的传递给子make。在uboot的主Makefile 中有如下代码:
MAKEFLAGS += -rR --include-dir=$(CURDIR)
上述代码使用“+=”来给变量 MAKEFLAGS 追加了一些值,“-rR”表示禁止使用内置的隐 含规则和变量定义,“--include-dir”指明搜索路径,”$(CURDIR)”表示当前目录。
顶层 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 来判断"$(origin V)"和"command line"是否相等。这里用到了 Makefile 中的函数 origin,origin 和其他的函数不一样,它不操作变量的值,origin 用于告诉你变量是哪 来的,语法为:
$(origin )
uboot 可以将编译出来的目标文件输出到单独的目录中,在 make 的时候使用“O”来指定 输出目录,比如“make O=out”就是设置目标文件输出到 out 目录中。这么做是为了将源文件 和编译产生的文件分开,当然也可以不指定 O 参数,不指定的话源文件和编译产生的文件都在 同一个目录内,一般我们不指定 O 参数。
在 uboot 中允许单独编译某个模块,使用命令“make M=dir”即可,旧语法“make SUBDIRS=dir”也是支持的。
编 译 uboot 的 时 候 需 要 设 置 目 标 板 架 构 和 交 叉 编 译 器 ,“ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-”就是用于设置 ARCH 和 CROSS_COMPILE