24 VERSION = 2010 25 PATCHLEVEL = 06 26 SUBLEVEL = 27 EXTRAVERSION = 28 ifneq "$(SUBLEVEL)" "" 29 U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) 30 else 31 U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL)$(EXTRAVERSION) 32 endif这部分不用多说,定义了U-B00T的版本号2010.06。
33 TIMESTAMP_FILE = $(obj)include/timestamp_autogenerated.h 34 VERSION_FILE = $(obj)include/version_autogenerated.h 35因为obj为空,所以定义TIMESTAMP_FILE为include/timestamp_autogenerated.h,定义VERSION_FILE为include/version_autogenerated.h
36 HOSTARCH := $(shell uname -m | \ 37 sed -e s/i.86/i386/ \ 38 -e s/sun4u/sparc64/ \ 39 -e s/arm.*/arm/ \ 40 -e s/sa110/arm/ \ 41 -e s/ppc64/powerpc/ \ 42 -e s/ppc/powerpc/ \ 43 -e s/macppc/powerpc/) 44 45 HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ 46 sed -e 's/\(cygwin\).*/cygwin/') 47
简化主机架构名称(HOSTARCH)和主机操作系统名称(HOSTOS)。通过shell中uname命令分别获取主机构架和系统名称,再通过sed命令进行替换。tr '[:upper:]' '[:lower:]' 命令完成大小写替换。由于我们一般都在个人电脑上进行开发和移植工作,所以HOSTARCH = i386,HOSTOS = linux。
59 # Allow for silent builds 60 ifeq (,$(findstring s,$(MAKEFLAGS))) 61 XECHO = echo 62 else 63 XECHO = : 64 endif由于MAKEFLAGS为空找不到s,条件成立XECH0 = echo
88 ifdef O 89 ifeq ("$(origin O)", "command line") 90 BUILD_DIR := $(O) 91 endif 92 endif 93 94 ifneq ($(BUILD_DIR),) 95 saved-output := $(BUILD_DIR) 96 97 # Attempt to create a output directory. 98 $(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}) 99 100 # Verify if it was successful. 101 BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) 102 $(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist)) 103 endif # ifneq ($(BUILD_DIR),) 104
这部分代码主要就是指定编译链接时目标文件的输出目录。
89-91:origin函数用于查询变量的出处,此处期望他在命令行中定义。如果是在命令行中定义,那么编译输出目录就是命令行指定目录。
94-102:如果BUILD_DIR不为空,则进行存储,然后尝试建立目录。
其中有两种方式可以指定输出目录(在这部分代码有一段注释说明,教详细的说明了):
71 # 1) Add O= to the make command line 72 # 'make O=/tmp/build all' 73 # 74 # 2) Set environement variable BUILD_DIR to point to the desired location 75 # 'export BUILD_DIR=/tmp/build' 76 # 'make'1)通过make命令参数 0直接指定输出目录
2)通过设定环境变量获得。
如果在编译时没有通过上述两种方式指定编译输出目录,则使用环境变量(即当前目录)。
105 OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) 106 SRCTREE := $(CURDIR) 107 TOPDIR := $(SRCTREE) 108 LNDIR := $(OBJTREE) 109 export TOPDIR SRCTREE OBJTREE105:if判断是一个三目函数,当BUILD_DIR存在时则将它赋值给OBJTREE(目标目录),否则使用当前环境变量
106-108:分别指定原目录、顶层目录和链接目录。
109:输出到环境变量(全局变量),留做他用。
111 MKCONFIG := $(SRCTREE)/mkconfig 112 export MKCONFIG
这句脚本的重要性,已经在前面提到了,它是“make board_name_config”命令中直接用到的变量,指定了配置执行文件mkconfig的目录。
114 ifneq ($(OBJTREE),$(SRCTREE)) 115 REMOTE_BUILD := 1 116 export REMOTE_BUILD 117 endif通过目标目录和原始目录确定是否执行远程编译,这个在上一篇 U-Boot编译过程分析(2)第二部份”创建架构相关的头文件的链接“中也提到了。
到这里建立外部目录部份就结束了。
代码119-132行代码的注释已经很清楚了,就不再赘述。对CDPATH不了解的,可以参考CDPATH学习。
136 # The "tools" are needed early, so put this first 137 # Don't include stuff already done in $(LIBS) 138 SUBDIRS = tools \ 139 examples/standalone \ 140 examples/api 141 142 .PHONY : $(SUBDIRS)伪目标SUBDIRS: 在后面编译中执行tools ,examples ,post,post/cpu 子目录下面的make文件。
144 ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk)) . . . . 450 else # !config.mk 451 all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \ 452 $(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \ 453 $(filter-out tools,$(SUBDIRS)) $(TIMESTAMP_FILE) $(VERSION_FILE) gdbtools \ 454 updater env depend dep tags ctags etags cscope $(obj)System.map: 455 @echo "System not configured - see README" >&2 456 @ exit 1 457 458 tools: 459 $(MAKE) -C tools 460 tools-all: 461 $(MAKE) -C tools HOST_TOOLS_ALL=y 462 endif # config.mk判断是否存在include/config.mk文件,从上篇文章可知,该文件是在make board_name_config命令时执行的(见 U-Boot编译过程分析(2第3部份)。
假设不存在config.mk文件,而是直接执行make all命令,进入else分支,输出错误信息并返回。
再看看正常执行”make all“命令
149 all: 150 sinclude $(obj)include/autoconf.mk.dep 151 sinclude $(obj)include/autoconf.mk
include/autoconf.mk文件中是与开发板相关的一些宏定义,make all需要通过一些宏确定执行那写操作。其依赖make <board_name>_config命令生成的include/config.h.执行make <board_name>_config后再执行make all命令就更新了include/atuoconf.mk。生成规则如下(448以后就是make <board_name>_config命令相关配置,,从3688到最后是一些清理工作相关脚步如clean命令):
428 # 429 # Auto-generate the autoconf.mk file (which is included by all makefiles) 430 # 431 # This target actually generates 2 files; autoconf.mk and autoconf.mk.dep. 432 # the dep file is only include in this top level makefile to determine when 433 # to regenerate the autoconf.mk file. 434 $(obj)include/autoconf.mk.dep: $(obj)include/config.h include/common.h 435 @$(XECHO) Generating $@ ; \ 436 set -e ; \ 437 : Generate the dependancies ; \ 438 $(CC) -x c -DDO_DEPS_ONLY -M $(HOSTCFLAGS) $(CPPFLAGS) \ 439 -MQ $(obj)include/autoconf.mk include/common.h > $@ 440 441 $(obj)include/autoconf.mk: $(obj)include/config.h 442 @$(XECHO) Generating $@ ; \ 443 set -e ; \ 444 : Extract the config macros ; \ 445 $(CPP) $(CFLAGS) -DDO_DEPS_ONLY -dM include/common.h | \ 446 sed -n -f tools/scripts/define2mk.sed > $@.tmp && \ 447 mv $@.tmp $@ 448编译选项“-dM”的作用是输出include/common.h中定义的所有宏。根据上面的规则,编译器提取include/common.h中定义的宏,然后输出给tools/scripts/define2mk.sed脚本处理,处理的结果就是include/autoconf.mk文件。其中tools/scripts/define2mk.sed脚本的主要完成了在include/common.h中查找和处理以“CONFIG_”开头的宏定义的功能。
include/common.h文件包含了include/config.h文件,而include/config.h文件又包含了config_defaults.h,configs/<board_name>.h,asm/config.h文件。因此include/autoconf.mk实质上就是config_defaults.h,configs/<board_name>.h,asm/config.h三个文件中“CONFIG_”开头的有效的宏定义的集合。
将common.h中的所有#include 的h文件并且h文件中的include文件 都放到autoconf.mk.dep中。
将common.h中的所有的#define 变量,和h文件中的#define变量,都放到autoconf.mk中。。
153 # load ARCH, BOARD, and CPU configuration 154 include $(obj)include/config.mk 155 export ARCH CPU BOARD VENDOR SOC将make <bord_name>_config命令生成的include/config.mk包含进来。
157 # set default to nothing for native builds 158 ifeq ($(HOSTARCH),$(ARCH)) 159 CROSS_COMPILE ?= 160 endif若主机与目标机器体系架构相同,则使用gcc编译器而不是交叉编译器。
162 # load other configuration 163 include $(TOPDIR)/config.mk
最后将U-Boot顶层目录下的config.mk文件包含进来,该文件包含了对编译的一些设置。对U-Boot顶层目录下的config.mk文件分析见U-Boot编译过程分析(4)
166 # U-Boot objects....order is important (i.e. start must be first) 167 168 OBJS = $(CPUDIR)/start.o . . 180 OBJS := $(addprefix $(obj),$(OBJS)) 181 182 LIBS = lib/libgeneric.a . . 247 LIBS := $(addprefix $(obj),$(LIBS)) 248 .PHONY : $(LIBS) $(TIMESTAMP_FILE) $(VERSION_FILE) 249 250 LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).a 251 LIBBOARD := $(addprefix $(obj),$(LIBBOARD)) 252 253 # Add GCC lib . . 264 export PLATFORM_LIBSLIBS变量指明了U-Boot需要的库文件,包括平台/开发板相关的目录、通用目录下相应的库,编译器的库,都通过相应的子目录编译得到的。
OBJS := $(addprefix $(obj),$(OBJS)) #addprefix是将 obj放到OBJS的前面,其实就是将所有的文件 加上 路径名 。
Makefile文件还有的最后一部分从266行到426行就是具体的编译规则了。
到这里Makefile文件就分析结束了,里面可能有很多解释不到位或者错误的地方,希望大家指正。