VERSION = 1
, r1 Y) l# T2 f5 T& W* \* mPATCHLEVEL = 1
& F9 F. n/ x2 |1 s! ISUBLEVEL = 6
( N4 K9 ] X2 q& u2 }$ v( a) qEXTRAVERSION =( v% \" Z0 R) T' \, r
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)0 Z& ]7 |# f. q. t, G
VERSION_FILE = $(obj)include/version_autogenerated.h #版本文件
% F% ?# `, \1 q1 U+ m' B9 y
# uname 命令将正在使用的操作系统名写到标准输出中
+ d- E1 a% a1 m: r$ E7 u$ h# -m 显示硬件运行系统的机器 ID 号
# 定义变量,HOSTARCH里面存储的是机器ID号,即主机架构类型, _# r7 m% p& d% N+ Q- _& x8 k- c
HOSTARCH := $(shell uname -m | \ #可以把shell脚本写到makefile里面,这是make中的shell function, 相当于shell中的命令替换。) }* U6 t' ]$ I# f' q
sed -e s/i.86/i386/ \ #shell uname -m 获得机器硬件名称
* O) t j; Q' _' p) u* S -e s/sun4u/sparc64/ \ #sed -e s/arm.*/arm/ 的意思是把前缀为arm的所有模式替换为arm。结合前面的uname命令来理解就是:2 u- h' S: L5 x0 x7 F/ W9 d% t( T
-e s/arm.*/arm/ \ #把uname -m的结果(主机架构类型或者称为机器ID号)通过管道传递给sed命令,然后把前缀为arm的所有模式替换为arm。7 P0 b8 T, v/ `& B6 A
-e s/sa110/arm/ \ #sed的语法:sed [ -n ] Script [ File ... ]
' P' n k! D5 c, ]% m* m -e s/powerpc/ppc/ \ # sed [ -n ] [ -e Script ] ... [ -f ScriptFile ] ... [ File ... ]
/ J7 b" p' _6 p1 h8 V! m -e s/macppc/ppc/) #sed 命令根据编辑脚本,去修改指定的 File 文件(这里file是作为一个输入参数的)的行,并将其写到标准输出。1 z$ L! A* F0 k5 M. G$ {5 c5 F
#sed 命令包含很多功能,用于选择要修改的行(请注意,sed是针对行进行操作的),并只对选择的行作更改。/ {' U N: X5 X* v4 ~$ ~
#sed 命令使用两个工作空间来保留修改的行:保留选定行的 "模式空间" 和暂时存储行的 "保留空间"。, o1 y# O5 f6 h" I6 x% v% [; p
#这里所谓的编辑脚本是由单独的子命令构成的,每个单独的行上对应着一个子命令。sed 子命令的一般格式如下:[address-range] function[modifiers],即:[地址范围] 函数[修改符]
" _) G1 a9 b& o1 O. o #sed 命令通过将一个输入行读入模式空间,依次应用所有的 sed 子命令(这些子命令的地址选择了该行),& v1 @- R" J; y3 H' O4 N
#并将模式空间写到标准输出来处理每个输入的 File 输入文件(file就是输入参数)。然后清除模式空间,并对输入的 File 中指定的每行重复该过程。
K) O, H2 R; N* b4 q #一些 sed 子命令使用保留空间来保存后继检索的所有的,或部分的模式空间。5 |+ r; Y3 \4 Z3 }) ?
#当命令包含地址(行号或搜索模式)时,该命令只会对被寻址的行起作用。否则,该命令适用于所有的行。! H# @5 {6 ]5 o) s( g+ ^' w
#注意,这里的参数"-e"的意思是:使用 Script 变量作为编辑脚本。如果你只使用一个 -e 标志并且不使用-f 标志,则可以省略 -e 标志。# [' p) i1 ?* o5 F7 i5 A+ k- o
#注意,这里的 "sed -e s/arm.*/arm/"表示把前缀为arm的所有模式替换为arm,也就是sed s/pattern/replacement/flags
% H3 { }0 B( [( d8 d #用 replacement 字符串代替在模式空间中首次出现的 pattern 参数。除了空格或换行符,在 s 子命令之后显示的任何字符都能代替 /(斜杠)分隔符。
1 I5 T* I/ [, J% I
1 L. {0 O- }( l- t6 u#uname -s 表示:显示系统名,标志缺省为开,即uname命令不带任何参数的输出和加参数-s输出相同,即Linux+ I" R3 o1 W3 K5 D4 R2 G
#tr是一个shell命令,这里 tr '[:upper:]' '[:lower:]'的意思是把管道中的Linux 中的大写字母L 转换成小写字母l
: w& e6 p: a. X+ r. b2 d#下面这句话的意思是定义变量HOSTOS,HOSTOS里面存放的是主机安装的,并且当前正在运行的操作系统。
* C/ u* K/ m5 n: _4 e6 E |# WHOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \0 j4 ^' w/ x) n7 G
sed -e 's/\(cygwin\).*/cygwin/') # 这一句的意思是检测出主机安装的,并且当前正在运行的操作系统名,并把这个系统名中的大写字母转换为小写字母,
F9 p9 q1 k2 s' e # 然后在通过sed流编辑器匹配所有的,这个系统名中出现的"\(cygwin\).*"模式,然后再用"cygwin"模式替换。% J- E$ H/ K/ I) C9 w% }
#export HOSTARCH HOSTOS 的意思是输出两个makefile变量HOSTARCH HOSTOS
export HOSTARCH HOSTOS
# Deal with colliding definitions from tcsh etc. 用来处理来自tcsh的互相冲突的定义等等/ O. ?& j: F' _; V
# 一般来说,shell可以分成两类。第一类是由 Bourne shell 衍生出来的包括 . Z- O, R9 O5 o/ [5 C
# sh,ksh,bash,与zsh。第二类是由 C shell 衍生出来的,包括 csh 与
+ ?- N% t; A6 F( h& f2 s# tcsh。除此之外还有一个 rc,有人认为该自成一类,有人认为该归类在Bourne shell。
VENDOR= #开发商
#########################################################################
$ X3 C; N# T* `; {/ t( {) [/ m#
6 m( s! L: P, m M* t+ z# U-boot build supports producing a object files to the separate external
( M3 a4 V+ z d9 e0 d6 l4 O/ h# U-boot 的编译过程可以支持向一个自己定义的路径生成最终的目标文件
! l- X. O5 ^3 L; S6 [1 J# W# directory. Two use cases are supported:4 P' ~+ `3 ^0 X. f7 Z) Y4 Y
# 这里提供了两种用法:( t% v! b+ [, {; d# r( R/ f
#
/ x8 j- G: ?2 k# 1) Add O= to the make command line #第一种用法:通过在终端执行命令make O=/dir(即你指定的生成的目标文件的存放目录)
0 h7 ]& R ~; o9 A. D# 'make O=/tmp/build all'6 C4 q. ?, M& U8 b# v
#+ b. z3 |. x3 n) _7 i
# 2) Set environement variable BUILD_DIR to point to the desired location #第二种用法:通过设置环境变量来指定目标文件存放目录,如下所示:/ M, R1 `; \. B: d+ h
# 'export BUILD_DIR=/tmp/build'2 k7 B, o- c, z; w. f5 i& y
# 'make'
) R( z2 ~. j0 c" B#: c' f; ~- l- X0 z' m
# The second approach can also be used with a MAKEALL script #第二种方法也可以写成一个MAKEALL脚本,然后执行MAKEALL,如下所示:
% u1 H8 J% [: I7 u* s8 E# 'export BUILD_DIR=/tmp/build'
( ?! Q. v/ k+ X( N( J2 G0 o# './MAKEALL'+ C: ], ^- }* E4 E! s6 z; n
#& X: ~( D2 t ^" W$ ?" h
# Command line 'O=' setting overrides BUILD_DIR environent variable. #命令行'O='设置会覆盖环境变量BUILD_DIR的设置
) I5 _/ @: e K7 U- k) x i9 J#
+ k/ r; C* S M3 p+ W2 Z# When none of the above methods is used, the local build is performed and #如果都不采用上面两种方法,那么目标文件最终要存放到源码顶层目录,也就是U-BOOT顶层目录+ }: O6 j$ n/ m i: `8 t% `
# the object files are placed in the source directory.; L5 _+ I, y$ M% I
#
#理解了上面一段英文,这里就不难理解了& s5 O( y4 `7 r. _ c7 t+ h, n p2 S* @
#方法1
ifdef O #如果变量'O' 已经被定义过1 j: j) a. V. J# I' p% l. u, V
ifeq ("$(origin O)", "command line") #如果变量'O' 在命令行中定义过 {6 [9 T G3 {8 [/ x5 t& ^
BUILD_DIR := $(O) #就把变量'O' 的值(目标文件存放目录)赋给BUILD_DIR+ N( J5 o m: k2 H0 m& B7 I
endif
; |9 D/ @: D6 o6 J& Iendif
" q& u3 }( _) S6 c9 h7 H
#方法2! V6 \% o1 F$ C: u. B
ifneq ($(BUILD_DIR),) #如果变量BUILD_DIR不为空,即环境变量BUILD_DIR 被定义过
4 f5 G% \3 d% [& \2 Nsaved-output := $(BUILD_DIR) #那么把它的值赋给saved-output
# Attempt to create a output directory. #生成一个输出路径,即目标文件存放目录BUILD_DIR
' M* _0 T0 Y0 D$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
#shell [ -d ${BUILD_DIR} ] 是什么意思?是不是生成一个目录的意思?
# Verify if it was successful. 测试目录是否创建成功6 c; |' Z$ e( r) S, o4 R) \. ]
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) #这又是什么意思,说明对shell还不够理解!
* N$ a0 P* ^; M P% }+ Y4 _- I W$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
! w$ x. E3 X0 x) |7 K- z4 {#这里用了一个if函数,意思是如果如果$(BUILD_DIR) 非空,则什么都不执行(返回空),否则执行error函数,输出错误信息
; Q$ n4 S e4 T% t+ c0 q, lendif
# ifneq ($(BUILD_DIR),) #意思是:如果没有定义目标文件存放目录
6 j8 z. L# R& t6 t3 H#Makefile中定义了源码以及生成目标文件存放的目录,目标文件存放目录BUILD_DIR可以通过make O=dir指定。如果没有指定,则设定为源码顶层目录。
N$ V& X; r' F0 m) i: J& L5 E3 F#一般编译的时候不指定输出目录,则BUILD_DIR为空。其他目录变量如下:
f& }0 y3 _2 Z% V, a8 [+ }OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #如果$(BUILD_DIR)不为空,则返回$(BUILD_DIR),并赋给OBJTREE,即自己定制的目标存放目录* s2 O# p, T0 V) X N; f, I2 V
SRCTREE := $(CURDIR) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE 6 l% E7 Z( K' Q8 r% x2 x# e
TOPDIR := $(SRCTREE) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE3 q2 P( Q8 R) |* f r) ^
LNDIR := $(OBJTREE) #存放生成的目录文件6 v+ Z/ _$ [7 ?2 u* C( L% F: v
export TOPDIR SRCTREE OBJTREE
@: U: Q" H% f8 o' \
! {7 V% p& C% T$ _: jMKCONFIG := $(SRCTREE)/mkconfig #MKCONFIG指向源码所在目录(U-BOOT顶层目录)下的mkconfig配置文件; u$ L* _7 s! K
export MKCONFIG
#在编译UBOOT之前,我们先要执行:
' ~4 N" d$ N3 ?4 C6 C9 U; _5 Q#make smdk2410_config
4 ]/ I4 e5 q" U3 H/ L#从本Makefile的下文可以判断出smdk2410_config为Makefile的一个目标。
1 I, B+ }& c- I+ f#smdk2410_config: unconfig的意思是为smdk2410开发板建立一个编译项。
; ?! O7 P8 U5 n) I#显然,执行#make smdk2410_config时,先执行unconfig目标(不指定输出目标时,obj,src变量均为空),unconfig下面的命令主要任务是清理上5 N0 S# l4 K& Y3 K( I1 `
#一次执行make *_config时生成的头文件和makefile的包含文件。# n) C( z: c0 P/ E
#主要是include/config.h和include/config.mk8 A' M2 G# A4 D* G1 o* W
#然后执行命令: @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x01 k, k8 g5 C5 s$ \! |
#arm 表示CPU的构架是基于ARM体系的
2 V' G" Q; G0 [#arm920t 表示CPU的类型是arm920t
9 e+ i4 T0 N5 U2 _, X#smdk2410 表示开发板的型号
6 z5 z! t! W4 @' n3 {#NULL 表示开发商或者经销商的名称,这里为空
, n4 U$ @$ e! e! _4 n#s3c24x0 表示基于S3C2410的片上系统6 {9 w$ m0 j! X! R0 x
#MKCONFIG指向UBOOT顶层目录下的mkconfig脚本配置文件,后面五个字符串是传入的参数(好像$(@:_config=)也是一个参数)。9 {' t1 K+ v4 z1 j6 P% b
#下面来分析一下mkconfig这个脚本配置文件,点击链接:+ k0 I1 M! a/ K
http://zqwt.012.blog.163.com/blog/static/120446842010325102158182/
- E6 x9 k" D' Y* F0 E7 S7 V- ^! jifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时
: a f# t5 }: X4 f7 xREMOTE_BUILD := 1 #定义变量REMOTE_BUILD := 1 这个变量算是一个flag吧7 @0 H; R7 g! S
export REMOTE_BUILD
% @; p% S; |. W4 y2 ]. P( [4 k3 ~6 k4 Pendif
# $(obj) and (src) are defined in config.mk(顶层目录下) but here in main Makefile
: ~9 X6 Q7 f$ n% Q: w# we also need them before config.mk is included which is the case for
% K$ z8 Y Q" h' g% Q0 o# some targets like unconfig, clean, clobber, distclean, etc.
$ [1 ]* ^+ }! w; A* E- d# $(obj) and $(src)都被定义在顶层目录下的config.mk脚本配置文件里面,
$ G- M" N% i1 E8 X. w8 Q \8 o# 但是在这个主Makefile里面,我们同样需要他们,2 i- W1 P7 c- M* M
# 因为在主Makefile文件包含config.mk之前,$(obj) and $(src)偶尔地会成为这些目标的case:$ e* S$ u1 |' n
# unconfig, clean, clobber, distclean, etc
9 q3 \, R r- Y% {$ nifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时
) [# B% e0 a" `/ x1 `7 Tobj := $(OBJTREE)/ #定义变量obj,让其等于目标存放目录
& z. @* b8 [. f( T F3 u8 n9 Gsrc := $(SRCTREE)/ #定义变量src,让其等于uboot顶层目录3 o3 ?4 i# z, R+ f- t; S6 P; X5 ]
else
0 R% s; D t( M- j6 Hobj := #否则,这两个变量都定义为空
. ?! a; h+ w6 fsrc :=
/ C9 ]% o# V8 oendif4 z5 N9 D& @1 f. W( {* ]# S
export obj src
' o# Z- k0 H: L# z
+ W# u- |+ H$ q( S8 }; \+ b. B
; s" P, y+ B$ t4 J#########################################################################
/ O2 q9 H2 O% _$ S& l, V. }! m5 G, ^
; t2 \8 Z Y/ k+ |4 j e( G$ E' _
3 F, M3 o& @/ H( [9 \+ Y+ @- ?
ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)) #这句话让人费解!
* W2 d6 `6 ?3 s; K# 通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展。
s8 V1 W+ H/ V& k% b, m# 如果您需要在这些场合扩展通配符,您应该使用函数wildcard,格式如下: {5 ~2 C& A, p" } l5 F' p, W
# $(wildcard pattern...)
+ H2 o6 `2 q8 h6 y7 A1 i
# load ARCH, BOARD, and CPU configuration
* h; u0 e1 O3 t" D# O+ H2 t# 加载ARCH, BOARD, and CPU 配置6 W/ i/ {% I9 a
include $(OBJTREE)/include/config.mk # 这时候,开始包含/include/config.mk的
! A2 K% I8 C+ mexport ARCH CPU BOARD VENDOR SOC
' b( U7 S: q4 g#指定交叉编译器前缀6 Y; N# H8 l" n) |/ c w
ifeq ($(ARCH),arm)
8 M, @' t' B/ A( G& aCROSS_COMPILE = arm-linux-7 s. P7 k+ G9 W( A0 V
#这里你可以把交叉编译器的安装路径加到arm-linux-之前,比如你的交叉编译器安装路径是/root/u-boot/usr/local/arm/3.3.2/bin/
+ ?2 W/ n5 Q- c" }6 p9 |( x# _9 p#你可以这样定义CROSS_COMPILE = /root/u-boot/usr/local/arm/3.3.2/bin/arm-linux-8 @* x2 j3 w+ R# Z
#这样一来,你在终端进行编译的时候就不用指定CROSS_COMPILE=arm-linux-了* j9 B' X: k# @5 \, k9 [- {
#但请注意:在编译内核的时候,交叉编译器必须安装在/usr/local/arm下,否则会发生错误!!!!!( s+ r5 {3 g: ~8 ^3 @ S; O
endif
export CROSS_COMPILE
' l+ R7 W- u& Q+ _0 X7 d1 p" ^0 R
( Q( |# `! |! c F# load other configuration 加载其他设置,这里是包含顶层目录下的config.mk配置文件,这个文件主要做了三个工作:
: Y! [5 p* a' h. x# 1、定义了交叉编译器 2、定义了编译选项 3、定义了编译规则( K! V+ O# [9 c2 k/ a: c+ B' T
# 对本文件具体的分析,请查看链接:
; f8 v, \' [* h! z& ]6 Vhttp://zqwt.012.blog.163.com/blog/static/12044684201032541139914/
include $(TOPDIR)/config.mk
#########################################################################
9 z# `" b; G7 O; m. H2 d# U-Boot objects....order is important (i.e. start must be first)
. k9 v, r6 u& M4 T/ D; _+ d* ]# uboot目标...书写顺序很重要,比如start.o必须排在第一位) D& b" p5 z$ i4 o3 K7 X
#########################################################################! _6 ?- Q# h6 t! _8 g
OBJS = cpu/$(CPU)/start.o
) `; y0 U3 n; `! _4 J: u4 A#start.o必须放在目标文件的第一位,因为uboot执行的第一段代码就是start.S+ A: ?2 E3 P8 x: T5 ~
#具体原因可以查看链接脚本/u-boot-1.1.6/board/smdk2410/u-boot.lds,点击连接:
! _7 E' J; r2 {! W Z' v4 whttp://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
5 c+ q# @* W! p' n! j
.....................................
+ h* F; f; d( P) H2 T( V% X
OBJS := $(addprefix $(obj),$(OBJS)) #这句的意思是把目标文件存放路径以前缀的形式加到start.O之前,然后再赋给OBJS
8 L" q5 `2 v, M( D- i3 X! Z
#以下是编译UBOOT需要的库文件
% W7 C( C! C" z! T7 Z* z2 d' b4 ]& _7 @LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a # 严重平台依赖的
LIBS += cpu/$(CPU)/lib$(CPU).a # 严重平台依赖的
ifdef SOC
6 z. B1 V M- F qLIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a # 严重平台依赖的' d0 e( c, z" H2 Y7 v
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a # 严重平台依赖的
% m6 K& u/ B, g% f0 tLIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
& o" V# r% ~3 {6 G3 ? fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a' t9 W. s' r# ^# ^& D, r
LIBS += net/libnet.a
( ~7 Q1 X3 v. y$ R$ X6 j( y/ I1 }LIBS += disk/libdisk.a# l3 Y! Z9 I0 G
LIBS += rtc/librtc.a+ a$ E8 S t, K
LIBS += dtt/libdtt.a
4 \$ x- x' [ {2 c% W; L3 V' QLIBS += drivers/libdrivers.a" W7 x8 |1 _1 s6 m+ w
LIBS += drivers/nand/libnand.a$ G( r Q- ^3 V3 T: n. O
LIBS += drivers/nand_legacy/libnand_legacy.a
& z2 K- s0 f! JLIBS += drivers/sk98lin/libsk98lin.a, z# S5 m& K" Y8 O# X* ? ]
LIBS += post/libpost.a post/cpu/libcpu.a7 k; h4 K3 [7 a
LIBS += common/libcommon.a. Q) w: }( s# J' {6 a- R
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) # 这是一个伪目标
#根据所生成的include/config.mk文件定义的几个变量ARCH, CPU, BOARD, SOC,我们可以. L2 D6 P2 P3 j$ j# f0 E$ L- E4 F
#确定硬件平台依赖的目录文件。smdk2410平台相关(依赖)目录以及对应生成的库文件如下:
( o8 ^" `5 m7 X s#board/smdk2410/: 库文件board/smdk2410/libsmdk2410.a
1 F7 J Z6 M# s' C N4 `$ F#cpu/arm920t/: 库文件cpu/arm920t/libarm920t.a3 a- Y. ?* `( p9 B# }
#cpu/arm920t/s3c24x0: 库文件cpu/arm920t/s3c24x0/libs3c24x0.a
% ^4 F) a0 c6 H3 v4 J L/ l+ p#lib_arm: 库文件lib_arm/libarm.a0 o C. m4 p/ r J# \% t" c( ?4 W
#include/asm-arm: 头文件$ ~6 L5 E/ x5 r" u7 T8 H8 z
#include/cnofigs/smdk2410.h:头文件
# Add GCC lib
8 s+ r2 z u4 h+ ePLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
# The "tools" are needed early, so put this first
$ r* H: j& K: K) }3 D# Don't include stuff already done in $(LIBS) 不要包含已经在 $(LIBS) 中的任何东西
) D# D7 i; x7 ` m& L9 |4 X$ e: x1 l( q#5 m% ]. U* X+ I7 n
# 伪目标SUBDIRS:用于执行tools、examples、post、post\cpu子目录下的make文件
o$ O; L( S& H3 W z9 _& O$ dSUBDIRS = tools \7 \+ |1 K3 t v; a/ e/ _! C
examples \
1 I) @2 ?( ~! i" i2 X post \- N3 T g" J5 Y4 |+ I( M1 O
post/cpu
* Z/ v& Z [" h1 o$ u( B9 v.PHONY : $(SUBDIRS)
ifeq ($(CONFIG_NAND_U_BOOT),y)1 g7 K: G8 x$ ?' l% |2 X& ~
NAND_SPL = nand_spl
# m; V) C3 ?0 E5 p# r- ?U_BOOT_NAND = $(obj)u-boot-nand.bin; G( ^: [, m" B& a2 k" T
endif
__OBJS := $(subst $(obj),,$(OBJS))
+ X _8 T- U, h- u" ___LIBS := $(subst $(obj),,$(LIBS))
#########################################################################; t6 h/ B, y$ U" L, [4 l1 o
#########################################################################
* X& w( D4 Q& f- J% D# k+ P9 z2 K4 H7 A! v
#这里是最终要生成的各种镜像文件u-boot.hex、u-boot.srec、u-boot.bin、System.map、u-boot.img. J" P+ e1 {5 ]0 Q7 k0 W2 I0 Z% ^
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
9 q6 r0 w: R2 A/ c# f2 x6 Vall: $(ALL)* n& v1 W9 T& m% a
$(obj)u-boot.hex: $(obj)u-boot
# d) _: Q- w) K9 g- e9 |( u $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ # $<,$@ 分别表示使用该规则的源文件和目标文件
$(obj)u-boot.srec: $(obj)u-boot
% m2 s2 m+ q) b# `* G% @ $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
7 `+ E; c* u/ T# x $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.img: $(obj)u-boot.bin
# X5 x8 [. _6 n9 V$ f ./tools/mkimage -A $(ARCH) -T firmware -C none \; k' R) w5 p$ B% J/ t& G# G' f7 W- \2 {
-a $(TEXT_BASE) -e 0 \
- C7 \" `( i8 \( D0 [ -n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
2 g9 {7 I& w6 ?( [5 Z9 H0 P& j sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
- T" ^9 n4 {- x; ~ -d $< $@
$(obj)u-boot.dis: $(obj)u-boot. @. T! F6 R! t3 Y+ B( ~
$(OBJDUMP) -d $< > $@
9 @$ I+ A& N: b, h#此处生成的是uboot的ELF文件镜像5 K8 C* S( E6 l5 q' {
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
+ X* |; [; d- s3 n8 e, r2 H. j UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
) s/ Y3 @1 K5 \1 l6 H: X) g4 ~: Y cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
3 y4 l5 P* m5 E2 n --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \% g" \, w: A( F2 |* \ H Y
-Map u-boot.map -o u-boot
* K5 F) }8 A2 \2 I2 c _#依赖目标$(OBJS),也就是cpu/start.o+ o0 ]2 @& p2 E+ S/ Q! w6 B
$(OBJS):
8 K: o8 y5 ?# X3 q7 F& K $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
7 Y5 [" t" c G 9 T8 _0 r6 R* S7 ~9 q |
#依赖目标$(LIBS),目标很多,都是每个子目录的库文件*.a,通过执行相应子目录下的make来完成
9 D' E9 L# c _4 ?$ |$ F$(LIBS):( m% q. t' C- N# C* }& B% z+ ^
$(MAKE) -C $(dir $(subst $(obj),,$@))
0 G4 x( X7 r$ ]6 f& M5 _ . D$ H1 M8 x2 |; b3 A
#这里解释一下这个makefile函数 $(dir names...) ; H$ e6 X- D: z# ]; t
#抽取‘names’中每一个文件名的路径部分,文件名的路径部分包括从文件名的开始到最后一个斜杠(含斜杠)
! R+ s4 t8 R# H, c2 q. f. G#之前的一切字符。如果文件名中没有斜杠,路径部分是‘./’。如:
+ B# R, I+ w9 C: ~ }( \#$(dir src/foo.c hacks)8 @, E9 M* F9 y$ C+ n- g& _$ J( H
#产生的结果为 ‘src/ ./’。
& @1 a4 j& [$ E- f8 g5 v7 u# F$(SUBDIRS):
! B3 }9 C$ t; j2 O $(MAKE) -C $@ all
$(NAND_SPL): version7 v: K; I! Y/ Q/ S) m, ^* P
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin
! m; p: c, Y9 H2 I cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
5 ~5 m/ v b @4 ?$ P2 g- K& y. O
#依赖目标version:生成版本信息到版本文件VERSION_FILE中4 V. O& E O9 j$ x+ ?/ O8 w
version:' r/ Z- X( ~ J5 W/ {9 O
@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \0 S+ [1 y+ X, n E. @7 s! A
echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \
) d Q7 p# `" `& h echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
' {! y+ x" R" _ $(TOPDIR)) >> $(VERSION_FILE); \
5 g: b( z; J( v0 e echo "\"" >> $(VERSION_FILE)
gdbtools:$ F% Y$ Z5 z3 i, z6 m, b
$(MAKE) -C tools/gdb all || exit 1
updater:
0 ^- S5 C( F! ]" [& D; C $(MAKE) -C tools/updater all || exit 1
env:" ~. w# u0 A+ J! E5 \$ E$ k4 o
$(MAKE) -C tools/env all || exit 1
! u" q7 x8 p4 q2 K
9 L& e* M. ~# P0 l% [#依赖目标depend:生成各个子目录.depend文件,.depend列出每个目标文件的依赖文件。
6 J1 |, X3 A b#生成方法:调用每个子目录的make_depend
0 A: M- q3 H4 n* F" e1 n8 Jdepend dep:2 }+ b( O q, ^3 K& D
for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
7 b/ t! D8 G5 e+ t$ e
tags ctags:. r5 R, A; b# k/ m
ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \1 ~& ~- y, j+ ?! p7 U+ v7 O
lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
: C9 ~5 F. N9 j7 i$ g fs/cramfs fs/fat fs/fdos fs/jffs2 \
# m- ]9 S& r8 c3 v. W+ [) w5 x1 U net disk rtc dtt drivers drivers/sk98lin common \7 u0 ^& b' f$ ?" F0 S! ?
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
etags:/ }) h% w- {) y1 v; a# p2 `
etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \
5 x s% `9 N. L+ S! i lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
+ D2 R8 e) R) J- ~% Y0 \* @ fs/cramfs fs/fat fs/fdos fs/jffs2 \) \& |* C) l( r
net disk rtc dtt drivers drivers/sk98lin common \
: ?* n7 d* U; Y- C6 \ \( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
$(obj)System.map: $(obj)u-boot
& X3 D, \7 k9 x# A+ `* D2 u3 M @$(NM) $< | \" A; E5 J8 L9 T+ j; o5 r) x
grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
" a: e" J) E x' r$ [ sort > $(obj)System.map
' T$ e5 L6 e4 w* g' Q
+ A5 |- \+ H7 S$ B$ A! P3 v- u#########################################################################$ G5 `& \3 t7 o4 c* O, l& P* b5 p* T
else
1 h3 P; [- Q2 A" K4 _all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \4 V3 p! u9 O# i& a
$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \
5 L5 L7 _: R: U& \: \$(SUBDIRS) version gdbtools updater env depend \
7 h2 o# R+ r/ f# Z; \dep tags ctags etags $(obj)System.map:
4 ~% E: o( ?3 v. e" d4 h @echo "System not configured - see README" >&2
; r! j6 S9 h# F6 d& R4 H) p @ exit 1% \3 N" I2 }0 K- q
endif
.PHONY : CHANGELOG: j" n& r, [* J' H6 a
CHANGELOG: j0 m2 K, o( ]/ c4 N" I. l
git log --no-merges U-Boot-1_1_5.. | \
3 |3 K, x) b: F4 L- @ unexpand -a | sed -e 's/\s\s*$$//' > $@
. A4 U% z3 N# j E. O#########################################################################; |0 z, J. Q" ^6 m* z5 h
# 这里就是我们所谓的unconfig,应该比较熟悉了!
7 E6 V( e# ?( p t! l# 很明显,它所做的工作就是清除上次生成的include/config.h和include/config.mk
]* ?- V9 s% K# 以及开发板目录下的一些临时配置文件
! ^6 G# } w. o( F6 }# unconfig: i" t* B3 B$ ^9 \' V1 q
# @rm -f $(obj)include/config.h $(obj)include/config.mk \
, x! b7 S$ t4 D- o) h# $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
- b* c, d- [& w1 v3 K# `4 \4 b#########################################################################
; ~; U( G$ A I. G4 F" O9 o: ^% v$ x; h
................................! C4 b0 s* ]' \3 C
smdk2400_config : unconfig) V2 c7 d% {. [, b$ S4 c' a5 N
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2400 NULL s3c24x0$ m% F1 C. u' L; U# D
1 c% M' j( `% I {" `; [................................
smdk2410_config : unconfig
; q8 j$ _1 l, W$ \+ }. A( U6 @& J8 g @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
* t8 h' |( }8 X4 q: s; J#我删了一部分内容,那些几乎都是各种不同板子的*_config,也就是目标的定义。
最后总结一下,当然这里也参考了前辈们的许多宝贵经验,顶层Makefile的主要任务就是组织整个u-boot工程的编译,概括可以分为一下几个步骤:
1、首先通过执行make *_config传入$(@:_config=), ARCH, CPU, BOARD, VENDOR, SOC参数(一共六个参数但不
: I+ h( A1 K ^3 \2 Q8 e! H
3 G4 ^# O9 K; N 一定同时存在),给mkconfig。
2、mkconfig接收到传递过来的参数后,将include头文件夹相应的头文件夹链接好,生成config.h
3、然后执行make分别调用各个子目录的makefile文件,以生成所有的obj文件(包括start.o)和obj库文件*.a。
4、最后,通过链接器把所有目标文件链接起来,生成uboot镜像。不同格式的镜像都是调用相应工具,经
由elf镜像间接或者直接的生成的。