*这里先组织一些分析过程中产生的疑问与解答,待日后有时间再补充完整
1)三种变量声明方式
=
:=
?=
=为递归式推导。只有当调用时才递归展开。则其值具有不稳定性。由于是递归,不能再引用自己。
:= 直接推导。和我们其他编程语言中的赋值相同,直接取得结果。不易产生岐意。(推荐使用)
?= 当该变量已被定义,则本行赋值语句不起作用。若该变量未定义,则定义该变量。u-boot Makefile中主要用于交叉编译器的自动选择。
2)变量的表时方法
a.所有变量均使用$(变量名)或${变量名}引用,所有变量不分类型,均为字符串。
b.对于类似于foreach的语句中,可以区分变量中以 空格 或 "tab" 符相隔的值作为多个变量来轮循。如查找一个目录中的所有文件名,赋值给一个变量后就会是一个以空格隔开的多个文件名的队列,可以集体引用。
3)一行后面的"/"起连接行的作用,主要目的是便于阅读。
4)Makefile是逐行解析的。对于所有内容对会逐行解析。除非遇到条件执行才有可能使中间的部分不被解析。
5)sinclude 和 include都是用来包含其他文件的。区别是sinclude当找不到文件时,也不会影响make的执行。
include 最后找不到文件,则会产生致命错误而中止执行。
6)sinclude 和 include 当被包含的文件不存在时,会尝试以该文件名为目标去MAKEFILE中查找目标,若目标存在,就执行目标的依懒和命令。
7)对于sinclude 和 include ,当语句被包含在 if endif 语句块中时。若条件不成立,则文件包含不会被展开。该被包含的文件也不会去查找目标自动生成(原因是make是逐行解析的,解析不到的自然不会去执行)。
8)u-boot 中 有两个 all:目标的原因。
makefile 会以第一个目标作为默认目标,并且会被视为一个伪目标。在第一个all:之前有一段说明:
# Include autoconf.mk before config.mk so that the config options are available
# to all top level build files. We need the dummy all: target to prevent the
# dependency target in autoconf.mk.dep from being the default.
"前两句没什么好说的。关键是后一句:我们需要伪目标all:以防止autoconf.mk.dep中的目标成为默认目标。"
换句话说,如果这里不加上一个all:,则会产生一个结果,被包含进makefile中的autoconf.mk.dep中的第一个目标就有可能成为默认目标。这样,如果我们执行 make all,不会有什么问题。但只执行make,默认目标就不是all:目标了。
9)从8中,我们还能得到一个结论:
在一个makefile中,对于一个目标,可以多次重复的定义,可以多次定义其依赖,但只能定义一个目标动作,这样,可以利用条件执行对目标的依赖动态加载。
如 all: depend1
all: depend2
all:
command....
这样最终会先执行depend1然后depend2,最后去执行command...
10)可以在一个目标中定义多个目标,依赖多个依赖。以使结构更清晰
如:
test1 test2 : test3
test1 : test4
command...
test2 :
command...
这样,test1:成为默认目标 且 执行make时,先执行test3,test4,最后才执行test1的command。而执行make test2 也会先执行test3目标。
11)Makefile中的变量很多,可以在后面多加一个目标,用于输出变量,这样有助于理解makefile。但是前提是要先进行make xxxx_config
这里简单记录一下输出变量的目标:
.PHONY:showVars
showVars:
@echo "U_BOOT_VERSION=$(U_BOOT_VERSION)"
@echo "obj=$(obj)"
@echo "src=$(src)"
@echo "TIMESTAMP_FILE=$(TIMESTAMP_FILE)"
@echo "VERSION_FILE=$(VERSION_FILE)"
@echo "HOSTARCH=$(HOSTARCH)"
@echo "HOSTOS=$(HOSTOS)"
@echo "SHELL=$(SHELL)"
@echo "save-output=$(save-output)"
@echo "BUILD_DIR=$(BUILD_DIR)"
@echo "OBJTREE=$(OBJTREE)"
@echo "SRCTREE=$(SRCTREE)"
@echo "TOPDIR=$(TOPDIR)"
@echo "LNDIR=$(LNDIR)"
@echo "MKCONFIG=$(MKCONFIG)"
@echo "SUBDIRS=$(SUBDIRS)"
@echo "BOARD(Target)=$(BOARD)"
@echo "ARCH=$(ARCH)"
@echo "CPU=$(CPU)"
@echo "VENDOR=$(VENDOR)"
@echo "SOC=$(SOC)"
@echo "LDSCRIPT=$(LDSCRIPT)"
@echo "TEXT_BASE=$(TEXT_BASE)"
@echo "AFLAGS=$(AFLAGS)"
@echo "CFLAGS=$(CFLAGS)"
执行 make showVars就可以输出变量的内容。
12)autoconf.dep.mk 和 autoconf.mk这两个文件,是利用脚本从 include/config.h 和 include/common.h 以及展开其中的所有引用的头文件,根据tools/scripts/define2mk.sed提供的格式,利用sed以及gcc指令生成的,可被makefile引用的变量定义文件。被包含进makefile中,就可以进行条件编译和条件执行。
13)在makefile中会生成所有需要目录中的dep文件。
具体定义在
depend dep: $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk
for dir in $(SUBDIRS) $(CPUDIR) $(dir $(LDSCRIPT)) ; do /
$(MAKE) -C $$dir _depend ; done
注意这里的for命令,是一个遍例命令。
14)根目录中u-boot.lds 文件的生成
这个是根据不同的体系结构来拷贝的。对于arm体系结构,其定义在arch/arm/config.mk中:
LDSCRIPT := $(SRCTREE)/$(CPUDIR)/u-boot.lds
之后在顶层makefile中会将该文件拷贝到源码根目录。以供链接文件使用。
对于有其他要求的板子,如s3c24x0想从nand起动使,由于需要搬运代码在4k之内存在,所以必须要重定义链接脚本。这时可以在板级支持部分的config.mk中重新定义LDSCRIPT变量,并在板级支持的目录中放置属于该板的脚本文件,这样就可以达到通用和特殊用途的目的。
如smdk2410的板级的config.mk在
board/samsung/smdk2410/
这个文件同时还定义了TEXT_BASE,内存中的基地址。