您的位置:首页 > 其它

U-Boot移植(二)——U-Boot编译过程分析(3)

2013-09-10 18:39 519 查看
在上一篇文章U-Boot编译过程分析(2)中,已经分析了“make borad_name_config”的作用,现在就分析下Makefile剩下的一些代码。

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 OBJTREE
105: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_LIBS
LIBS变量指明了U-Boot需要的库文件,包括平台/开发板相关的目录、通用目录下相应的库,编译器的库,都通过相应的子目录编译得到的。

OBJS := $(addprefix $(obj),$(OBJS)) #addprefix是将 obj放到OBJS的前面,其实就是将所有的文件 加上 路径名 。

Makefile文件还有的最后一部分从266行到426行就是具体的编译规则了。

到这里Makefile文件就分析结束了,里面可能有很多解释不到位或者错误的地方,希望大家指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: