VERSION = 19 i' |* T- B( z6 [3 Z
PATCHLEVEL = 1
! D' K+ f' h) u: P2 p- q. BSUBLEVEL = 6
) ^& R2 y$ _5 q, Z' u9 SEXTRAVERSION =
4 t p& v& [: L& EU_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+ O! ~ A- C2 HVERSION_FILE = $(obj)include/version_autogenerated.h #版本文件
% O$ J8 S( ]3 g0 y- Z5 x
# uname 命令将正在使用的操作系统名写到标准输出中- `# m; y, R7 L7 B0 j6 N2 r
# -m 显示硬件运行系统的机器 ID 号
# 定义变量,HOSTARCH里面存储的是机器ID号,即主机架构类型
5 Y% e4 ~3 H# ~HOSTARCH := $(shell uname -m | \ #可以把shell脚本写到makefile里面,这是make中的shell function, 相当于shell中的命令替换。/ w1 o. ?. ]: K% S
sed -e s/i.86/i386/ \ #shell uname -m 获得机器硬件名称
7 S. \/ b# q$ f2 z2 x -e s/sun4u/sparc64/ \ #sed -e s/arm.*/arm/ 的意思是把前缀为arm的所有模式替换为arm。结合前面的uname命令来理解就是:
, `* n" D3 a& Y$ I3 }- A7 g -e s/arm.*/arm/ \ #把uname -m的结果(主机架构类型或者称为机器ID号)通过管道传递给sed命令,然后把前缀为arm的所有模式替换为arm。
5 |. [6 @7 V8 y -e s/sa110/arm/ \ #sed的语法:sed [ -n ] Script [ File ... ]) E! s0 h* x& e: \& e
-e s/powerpc/ppc/ \ # sed [ -n ] [ -e Script ] ... [ -f ScriptFile ] ... [ File ... ]9 h' Z0 p, A# q, y8 B. p
-e s/macppc/ppc/) #sed 命令根据编辑脚本,去修改指定的 File 文件(这里file是作为一个输入参数的)的行,并将其写到标准输出。
/ b6 K" i6 F) n2 S #sed 命令包含很多功能,用于选择要修改的行(请注意,sed是针对行进行操作的),并只对选择的行作更改。
1 g7 d& \3 I8 ^5 r& X S #sed 命令使用两个工作空间来保留修改的行:保留选定行的 "模式空间" 和暂时存储行的 "保留空间"。
" m. x7 r# ] J* t #这里所谓的编辑脚本是由单独的子命令构成的,每个单独的行上对应着一个子命令。sed 子命令的一般格式如下:[address-range] function[modifiers],即:[地址范围] 函数[修改符]& P# |- c1 X- i# ?! `$ {
#sed 命令通过将一个输入行读入模式空间,依次应用所有的 sed 子命令(这些子命令的地址选择了该行),
9 w x9 n+ e% w #并将模式空间写到标准输出来处理每个输入的 File 输入文件(file就是输入参数)。然后清除模式空间,并对输入的 File 中指定的每行重复该过程。
7 w4 f9 I" ^# b$ r' L f #一些 sed 子命令使用保留空间来保存后继检索的所有的,或部分的模式空间。
" @& F9 r1 t9 p* J #当命令包含地址(行号或搜索模式)时,该命令只会对被寻址的行起作用。否则,该命令适用于所有的行。
; M7 ~9 G2 @" X, _/ T" u# K' {7 k #注意,这里的参数"-e"的意思是:使用 Script 变量作为编辑脚本。如果你只使用一个 -e 标志并且不使用-f 标志,则可以省略 -e 标志。
" b0 j+ j: K" f' |+ m! e; L6 d! e0 e #注意,这里的 "sed -e s/arm.*/arm/"表示把前缀为arm的所有模式替换为arm,也就是sed s/pattern/replacement/flags ) ?3 }! z! h7 j$ Q
#用 replacement 字符串代替在模式空间中首次出现的 pattern 参数。除了空格或换行符,在 s 子命令之后显示的任何字符都能代替 /(斜杠)分隔符。
6 _6 {2 k4 Y* E# Y9 v! r( A/ p& V
& Y2 r( S; t! G& l* L P. i }
#uname -s 表示:显示系统名,标志缺省为开,即uname命令不带任何参数的输出和加参数-s输出相同,即Linux
9 F3 g5 r9 R! J& A1 C$ N#tr是一个shell命令,这里 tr '[:upper:]' '[:lower:]'的意思是把管道中的Linux 中的大写字母L 转换成小写字母l
5 h& S" u7 p- D K' l w8 L2 ^#下面这句话的意思是定义变量HOSTOS,HOSTOS里面存放的是主机安装的,并且当前正在运行的操作系统。
4 l# Y4 z R, R! f; mHOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
( w( i- s/ c1 C* W1 Z4 b sed -e 's/\(cygwin\).*/cygwin/') # 这一句的意思是检测出主机安装的,并且当前正在运行的操作系统名,并把这个系统名中的大写字母转换为小写字母,
( Y. V& v0 h6 z( @# s- C. J4 e # 然后在通过sed流编辑器匹配所有的,这个系统名中出现的"\(cygwin\).*"模式,然后再用"cygwin"模式替换。& `/ a9 N5 ^. M; \* `+ c% K5 a" ]
#export HOSTARCH HOSTOS 的意思是输出两个makefile变量HOSTARCH HOSTOS
export HOSTARCH HOSTOS
# Deal with colliding definitions from tcsh etc. 用来处理来自tcsh的互相冲突的定义等等
( c: p6 f& Y1 v$ J6 r5 a* v/ e# 一般来说,shell可以分成两类。第一类是由 Bourne shell 衍生出来的包括 ' `3 e& D( _. r
# sh,ksh,bash,与zsh。第二类是由 C shell 衍生出来的,包括 csh 与
" ]- e! `, _5 N; n$ m$ f4 x# tcsh。除此之外还有一个 rc,有人认为该自成一类,有人认为该归类在Bourne shell。
VENDOR= #开发商
#########################################################################; i5 R/ e m; b/ x" R
#6 H3 W! m! A( z1 i" T; q4 a# N1 o) e2 [
# U-boot build supports producing a object files to the separate external
/ A& q( H' b I; b m5 E* E# U-boot 的编译过程可以支持向一个自己定义的路径生成最终的目标文件7 @! J @1 L) @" C1 ~+ p6 V
# directory. Two use cases are supported:
l& a' O6 q- f# 这里提供了两种用法:
1 X7 z+ Z! X$ w* F: v z, _#
0 N2 o, k4 v( G9 }) [) T" {# 1) Add O= to the make command line #第一种用法:通过在终端执行命令make O=/dir(即你指定的生成的目标文件的存放目录)+ n5 x& }4 l& a; t1 M
# 'make O=/tmp/build all'
% [# v: V: r6 t u' C1 m#
$ ^9 A. E1 U( w- Q+ n* m# 2) Set environement variable BUILD_DIR to point to the desired location #第二种用法:通过设置环境变量来指定目标文件存放目录,如下所示:/ q+ w2 N9 [+ F% |
# 'export BUILD_DIR=/tmp/build'
4 a% X2 A) K" I8 }2 ~# 'make'* f0 l2 F, O p- u
#
, B7 O4 w* ~: x- y2 G, z& B# The second approach can also be used with a MAKEALL script #第二种方法也可以写成一个MAKEALL脚本,然后执行MAKEALL,如下所示:
) N& t9 r0 D9 n" o, y: k# 'export BUILD_DIR=/tmp/build'; s' N9 k# A! w4 E# c
# './MAKEALL'! K$ l. H& f& g
#0 ~* a. l' X2 @, N l
# Command line 'O=' setting overrides BUILD_DIR environent variable. #命令行'O='设置会覆盖环境变量BUILD_DIR的设置
. W$ J* i- k4 [#
% E6 O' b7 P9 a w) z# When none of the above methods is used, the local build is performed and #如果都不采用上面两种方法,那么目标文件最终要存放到源码顶层目录,也就是U-BOOT顶层目录6 W* Z4 J7 F! q1 s6 t G
# the object files are placed in the source directory.
- t+ Z3 V# E2 t* j#
#理解了上面一段英文,这里就不难理解了5 u- i4 k. m2 M' X' i- S! q
#方法1
ifdef O #如果变量'O' 已经被定义过
$ z/ d w: t0 x6 u8 F& q+ Aifeq ("$(origin O)", "command line") #如果变量'O' 在命令行中定义过
9 z( V# Q; A+ u; ^BUILD_DIR := $(O) #就把变量'O' 的值(目标文件存放目录)赋给BUILD_DIR3 u* |+ M# [. d
endif9 B6 Z6 \. `9 _8 W
endif
0 h, R- u( ^7 y ?/ z: `# J. X- H
#方法2
- R) Q) K7 P! X9 _5 a* Xifneq ($(BUILD_DIR),) #如果变量BUILD_DIR不为空,即环境变量BUILD_DIR 被定义过3 v6 G- u$ s% ?% q5 B1 j4 N S
saved-output := $(BUILD_DIR) #那么把它的值赋给saved-output
# Attempt to create a output directory. #生成一个输出路径,即目标文件存放目录BUILD_DIR1 x0 s/ I( V8 I
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
#shell [ -d ${BUILD_DIR} ] 是什么意思?是不是生成一个目录的意思?
# Verify if it was successful. 测试目录是否创建成功" O7 a4 N5 d; C
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) #这又是什么意思,说明对shell还不够理解!
8 o5 A" Q4 n$ |0 p2 V+ n6 K$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
; C; M- b( I% t+ ^2 P6 f$ v#这里用了一个if函数,意思是如果如果$(BUILD_DIR) 非空,则什么都不执行(返回空),否则执行error函数,输出错误信息
! e! |7 F! c* ^( K. g4 {/ [6 Rendif
# ifneq ($(BUILD_DIR),) #意思是:如果没有定义目标文件存放目录
* C% V9 }: l: r% h# ?2 B7 L/ Z#Makefile中定义了源码以及生成目标文件存放的目录,目标文件存放目录BUILD_DIR可以通过make O=dir指定。如果没有指定,则设定为源码顶层目录。
: E- M5 O, o% a' r/ ?#一般编译的时候不指定输出目录,则BUILD_DIR为空。其他目录变量如下:5 o; u& p) [8 n5 l
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #如果$(BUILD_DIR)不为空,则返回$(BUILD_DIR),并赋给OBJTREE,即自己定制的目标存放目录
# W, G& d2 e. O, B$ Z9 U' i0 ASRCTREE := $(CURDIR) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE # \/ i5 @. L+ p" w
TOPDIR := $(SRCTREE) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE* c# x+ a0 J7 \. l) X
LNDIR := $(OBJTREE) #存放生成的目录文件
- Y+ Y; t1 n' U: a+ V( `, Nexport TOPDIR SRCTREE OBJTREE
; [9 G: f& G- Y1 x# A; i
, \+ n, E- W1 M* `$ WMKCONFIG := $(SRCTREE)/mkconfig #MKCONFIG指向源码所在目录(U-BOOT顶层目录)下的mkconfig配置文件
( o8 x) }* X& R6 ^/ @$ T& m( eexport MKCONFIG
#在编译UBOOT之前,我们先要执行: F j3 `* A# g" X$ n2 W' N
#make smdk2410_config
, K0 y9 F% A8 G( b# f f3 P+ T" _#从本Makefile的下文可以判断出smdk2410_config为Makefile的一个目标。
( \: B9 }6 U1 ~% l& E#smdk2410_config: unconfig的意思是为smdk2410开发板建立一个编译项。
0 e' s! G: A3 h4 f) Z4 y' `#显然,执行#make smdk2410_config时,先执行unconfig目标(不指定输出目标时,obj,src变量均为空),unconfig下面的命令主要任务是清理上
( C# V' B0 a: h2 s#一次执行make *_config时生成的头文件和makefile的包含文件。
' P! E! o \7 M5 R4 A- T#主要是include/config.h和include/config.mk0 w2 \3 k' i0 T' K' D8 v
#然后执行命令: @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
7 a7 H+ ?5 q( a/ A2 j#arm 表示CPU的构架是基于ARM体系的
, r, T4 d& u( F8 a#arm920t 表示CPU的类型是arm920t. ?" N1 P( \: @ r) u& `
#smdk2410 表示开发板的型号
) P, J. b: e+ c+ ~#NULL 表示开发商或者经销商的名称,这里为空8 O* T, k' N. M: M" e6 r% v+ K
#s3c24x0 表示基于S3C2410的片上系统
1 v; v% W8 a& U5 d. f# m#MKCONFIG指向UBOOT顶层目录下的mkconfig脚本配置文件,后面五个字符串是传入的参数(好像$(@:_config=)也是一个参数)。
. N5 L. i' S6 }: H& y2 U#下面来分析一下mkconfig这个脚本配置文件,点击链接:
2 u$ Z- b s/ g6 l3 q4 D( Rhttp://zqwt.012.blog.163.com/blog/static/120446842010325102158182/
7 ~0 G }8 l, b0 l, W8 w$ ]5 Y/ Z
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时
& ?0 U; `) z6 Y ]& ^REMOTE_BUILD := 1 #定义变量REMOTE_BUILD := 1 这个变量算是一个flag吧
8 G: O+ x% R T" v- j, o; d' B4 Vexport REMOTE_BUILD' n |9 q! ]8 {% i
endif
# $(obj) and (src) are defined in config.mk(顶层目录下) but here in main Makefile' e3 |! K2 ~9 v6 z
# we also need them before config.mk is included which is the case for) S% i. p+ H9 W9 a. N: L# p
# some targets like unconfig, clean, clobber, distclean, etc.
( G! T3 W1 a* k0 O4 p: q# $(obj) and $(src)都被定义在顶层目录下的config.mk脚本配置文件里面,
4 v7 l9 V9 g: ^) g: f4 I+ P3 o# 但是在这个主Makefile里面,我们同样需要他们,
4 j) C! s" d) ~$ D( X) q# s/ k4 p# 因为在主Makefile文件包含config.mk之前,$(obj) and $(src)偶尔地会成为这些目标的case:3 U9 m* J4 @' Q, J; T3 `
# unconfig, clean, clobber, distclean, etc
% ^1 {8 U' J0 m7 i3 g l5 A
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时
. f+ F3 {, U v* f, yobj := $(OBJTREE)/ #定义变量obj,让其等于目标存放目录
* ^! ^: f0 e" L' [8 S: ?1 d4 S- lsrc := $(SRCTREE)/ #定义变量src,让其等于uboot顶层目录9 D- K7 l( G! e
else' T* b. \, B! T$ s$ l5 A. M
obj := #否则,这两个变量都定义为空
8 X0 Q: R4 b% }4 [3 s1 Jsrc :=+ J% V* p7 e# v, {' V
endif) U# E' n8 C/ P6 l
export obj src
& P* v. {7 ^# J4 `7 `
2 u: v1 a+ \5 b: D9 n
6 J: Z) [7 S" A* M# |+ v#########################################################################
7 w P, v" U2 z9 q
0 U5 }) ]4 }' h) Z$ h1 L3 X, A, ?+ x4 h+ e4 ], g, u* O
" `3 D. ~+ Q$ W1 q' E0 x) zifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)) #这句话让人费解!
% } P9 C: c) G9 k0 P# 通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展。4 d, i6 O1 y/ k' ^, }1 P
# 如果您需要在这些场合扩展通配符,您应该使用函数wildcard,格式如下:% ~1 W& h4 s. l
# $(wildcard pattern...)
* ~9 O; r( k3 r+ Z
# load ARCH, BOARD, and CPU configuration
4 X; J' m6 l3 X# 加载ARCH, BOARD, and CPU 配置0 {8 w: T! {" c# k
include $(OBJTREE)/include/config.mk # 这时候,开始包含/include/config.mk的
1 ?' W" ~* W7 U! G6 H: Cexport ARCH CPU BOARD VENDOR SOC
5 z5 o% h% J) W9 x#指定交叉编译器前缀
8 Y" p. Z# p5 \2 O* Eifeq ($(ARCH),arm)
) f7 X& W3 B) @- B6 ?9 M" ~CROSS_COMPILE = arm-linux-2 d0 c9 {. p6 e
#这里你可以把交叉编译器的安装路径加到arm-linux-之前,比如你的交叉编译器安装路径是/root/u-boot/usr/local/arm/3.3.2/bin/$ b3 ]+ {0 _5 U
#你可以这样定义CROSS_COMPILE = /root/u-boot/usr/local/arm/3.3.2/bin/arm-linux- y) {9 F% w/ E: T6 Z
#这样一来,你在终端进行编译的时候就不用指定CROSS_COMPILE=arm-linux-了
5 f0 j+ `$ }7 e) J& \9 Z! ]#但请注意:在编译内核的时候,交叉编译器必须安装在/usr/local/arm下,否则会发生错误!!!!!
o9 \. s( ~' mendif
export CROSS_COMPILE
0 s% S [" k' V* w! Y
* j2 x2 g9 v2 K! e6 g* V# load other configuration 加载其他设置,这里是包含顶层目录下的config.mk配置文件,这个文件主要做了三个工作:
4 S& i8 t0 M& s7 F, I# {3 J* `# 1、定义了交叉编译器 2、定义了编译选项 3、定义了编译规则8 o/ E+ _3 K" d( A
# 对本文件具体的分析,请查看链接: [) J: X0 f) ^
http://zqwt.012.blog.163.com/blog/static/12044684201032541139914/
include $(TOPDIR)/config.mk
#########################################################################; i6 ^. Z( }3 c# i
# U-Boot objects....order is important (i.e. start must be first)5 R* y* f5 I+ m: y# b# H
# uboot目标...书写顺序很重要,比如start.o必须排在第一位" i9 L$ q! ~1 }" ~' z& x
######################################################################### Y: g3 t4 x& w
OBJS = cpu/$(CPU)/start.o ; t2 h* V' q- k9 B- d- b0 M
#start.o必须放在目标文件的第一位,因为uboot执行的第一段代码就是start.S" I5 j: m# ~0 H, u/ L" [4 y, v- g
#具体原因可以查看链接脚本/u-boot-1.1.6/board/smdk2410/u-boot.lds,点击连接:
: v3 w0 M& `" O! h* ~7 e; K, S' ^: Vhttp://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
/ f* [- K4 O3 l* p1 Z.....................................
: e0 E6 D1 B3 K2 d. IOBJS := $(addprefix $(obj),$(OBJS)) #这句的意思是把目标文件存放路径以前缀的形式加到start.O之前,然后再赋给OBJS
$ Z# D5 j. n+ R4 R7 q
#以下是编译UBOOT需要的库文件
% V9 e* ^+ V- `, _LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a # 严重平台依赖的
LIBS += cpu/$(CPU)/lib$(CPU).a # 严重平台依赖的
ifdef SOC
5 D, W( {, y+ i5 E6 oLIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a # 严重平台依赖的( S8 I6 a' u J& Y6 x
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a # 严重平台依赖的
' J- N$ a; v3 b4 | I2 m
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \: c% C9 ]. g# n0 A9 T5 V0 B
fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
/ S8 D: c9 R( a A% Y1 y3 oLIBS += net/libnet.a
0 \+ e4 P5 w. O7 q4 X OLIBS += disk/libdisk.a) X# Y% l# I3 B, I( U! D2 q* y
LIBS += rtc/librtc.a3 d; c0 r* r0 h9 w C
LIBS += dtt/libdtt.a, e$ J! N9 ?4 |8 F+ T
LIBS += drivers/libdrivers.a
3 U: L7 L2 U/ _# f3 S; }LIBS += drivers/nand/libnand.a
$ H8 K# n0 d6 N2 `LIBS += drivers/nand_legacy/libnand_legacy.a
. x7 @9 {; s+ q" V) zLIBS += drivers/sk98lin/libsk98lin.a
. [- Z: N, I9 v3 A( F2 `8 U( }LIBS += post/libpost.a post/cpu/libcpu.a
4 _. k# b7 c7 V" FLIBS += common/libcommon.a0 `6 a2 E0 W9 \7 p6 e! M
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) # 这是一个伪目标
#根据所生成的include/config.mk文件定义的几个变量ARCH, CPU, BOARD, SOC,我们可以2 ^, f/ k- V2 e" F a/ B( o- Q& i7 F
#确定硬件平台依赖的目录文件。smdk2410平台相关(依赖)目录以及对应生成的库文件如下:
/ r' r/ R4 M- o2 n#board/smdk2410/: 库文件board/smdk2410/libsmdk2410.a
0 X+ l/ p7 G1 A#cpu/arm920t/: 库文件cpu/arm920t/libarm920t.a
0 w& K$ N) K3 r! L$ e: d#cpu/arm920t/s3c24x0: 库文件cpu/arm920t/s3c24x0/libs3c24x0.a4 Z8 Y( E5 [1 e
#lib_arm: 库文件lib_arm/libarm.a" {0 x5 q: Q) m) i. D
#include/asm-arm: 头文件( T9 z( O" O( ^- j4 E
#include/cnofigs/smdk2410.h:头文件
# Add GCC lib# L1 g; c4 c1 H- u( h2 [5 ?) u0 H
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
# The "tools" are needed early, so put this first0 W: I1 d+ X3 Z& z/ d
# Don't include stuff already done in $(LIBS) 不要包含已经在 $(LIBS) 中的任何东西1 v; g+ h. O& b- H N
#0 [5 {1 l5 `- p% _* a4 J) E
# 伪目标SUBDIRS:用于执行tools、examples、post、post\cpu子目录下的make文件
! R5 E5 U5 x* c; u* D* E8 CSUBDIRS = tools \
& h" h7 D0 D+ r examples \# E+ a |( R5 |. @
post \$ A7 U' Z* I! I2 g8 D
post/cpu
% k( p7 e9 f) h% `+ I0 s& ?.PHONY : $(SUBDIRS)
ifeq ($(CONFIG_NAND_U_BOOT),y)
! C! V( s, u& v4 [3 U6 fNAND_SPL = nand_spl, T( @! {$ }& ^6 t6 f9 F
U_BOOT_NAND = $(obj)u-boot-nand.bin
2 g/ B; r' Y; q8 zendif
__OBJS := $(subst $(obj),,$(OBJS))7 d3 d# U8 |- A5 a% i% s; }$ a
__LIBS := $(subst $(obj),,$(LIBS))
#########################################################################
' m+ ^/ q* \+ x; ]#########################################################################
1 i! k/ _6 c# `2 P( S$ X+ @/ X* `3 M
, g4 i! c6 r' x% Q# `#这里是最终要生成的各种镜像文件u-boot.hex、u-boot.srec、u-boot.bin、System.map、u-boot.img h, E; r4 o+ @. b
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)% g1 Z3 B! n* B6 P
all: $(ALL)
3 C+ S4 x0 c1 ^) m& i9 p: R$(obj)u-boot.hex: $(obj)u-boot
2 G( A5 X+ v$ A5 r N $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ # $<,$@ 分别表示使用该规则的源文件和目标文件
$(obj)u-boot.srec: $(obj)u-boot
" E9 J: a! @0 z( R% G. j* ]: M $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
: ]! `$ `6 c6 }& w+ q/ V! J $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.img: $(obj)u-boot.bin
# L3 S2 z) J0 m ./tools/mkimage -A $(ARCH) -T firmware -C none \ r0 m' v0 c) L5 `/ e
-a $(TEXT_BASE) -e 0 \3 Y V( D, s; Q* l+ `! g$ ] S1 V
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
& Z2 H4 b+ p8 r7 z0 k sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
' ^3 M0 H; r2 W1 b1 V% S' [( J! I -d $< $@
$(obj)u-boot.dis: $(obj)u-boot
% m- a, f: b: h1 n $(OBJDUMP) -d $< > $@
/ z5 _" h- C4 _4 d4 B8 E! s* s#此处生成的是uboot的ELF文件镜像8 z: s; ]1 l0 _1 h2 r5 b
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT); q$ s8 y0 r7 G
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\1 `# z4 o) M: @- d! n) i1 _
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \) F" N+ x. C/ @! Z' ^
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
+ n/ K+ ]2 X% D a; E0 e( A -Map u-boot.map -o u-boot
Y/ I/ [' _3 \+ b- h7 W& j; }
#依赖目标$(OBJS),也就是cpu/start.o
* M/ f; u- W! C$(OBJS):
# w. g7 |3 m6 g$ a3 ? $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
; h/ @: G% U. t. T% J- T
+ ^! L" j2 L, h! }: W+ p#依赖目标$(LIBS),目标很多,都是每个子目录的库文件*.a,通过执行相应子目录下的make来完成
p' s' q8 s3 P4 I8 x- {' _9 X, B$(LIBS):
1 i$ ~' | s9 A2 W3 G: {+ Q2 W7 { $(MAKE) -C $(dir $(subst $(obj),,$@))2 t: a2 A7 z. m1 B
0 J6 j, i$ f* v: |! J2 T( K! j8 h% P: m9 k#这里解释一下这个makefile函数 $(dir names...) 0 J N( Z( Z' r+ `
#抽取‘names’中每一个文件名的路径部分,文件名的路径部分包括从文件名的开始到最后一个斜杠(含斜杠)) ]$ \: |" u1 b# I% w" k
#之前的一切字符。如果文件名中没有斜杠,路径部分是‘./’。如:
, j2 e* ?: m `% E Y; b#$(dir src/foo.c hacks)% f" Y+ H- T: r7 t8 p
#产生的结果为 ‘src/ ./’。
( T+ P+ _5 F7 z3 l9 x1 s$(SUBDIRS):
; w. a* W- _' k $(MAKE) -C $@ all
$(NAND_SPL): version9 U3 h. [! I1 o; E/ T H+ d3 ]
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin3 I' G; N& p1 V+ y
cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
; o/ X' H8 w5 c# [/ [" N
#依赖目标version:生成版本信息到版本文件VERSION_FILE中 S) }4 v1 d3 y9 ], c& }; M9 f6 u! g
version:
) c( x2 j! z7 g( L+ ?! O @echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \3 X1 \& d- W3 d6 d3 R& o5 V
echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \) R$ O G t X2 D8 x, `
echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \$ k" }% @2 O' l, f4 x: Z
$(TOPDIR)) >> $(VERSION_FILE); \
" `$ c# j" k: a+ k: f; Z9 b& m- D echo "\"" >> $(VERSION_FILE)
gdbtools:- l( z. ?4 W: e* f* @( R
$(MAKE) -C tools/gdb all || exit 1
updater:" |2 ?/ {# T0 C2 P/ }4 J4 B3 f9 F
$(MAKE) -C tools/updater all || exit 1
env:5 ^0 u2 i% E, {2 m8 r2 S
$(MAKE) -C tools/env all || exit 1
0 A, O, k9 E$ O; A" L4 V: g5 w. H. J: N$ O/ l8 {3 A# H3 Y
#依赖目标depend:生成各个子目录.depend文件,.depend列出每个目标文件的依赖文件。
6 K# X$ w9 X* G7 I* u y#生成方法:调用每个子目录的make_depend
* U8 m4 j" K$ K& A$ e2 Wdepend dep:
2 o8 ?" ~' G$ Y0 f for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
+ x: n( I0 q0 J' w$ xtags ctags:6 C6 X0 }8 G! A R
ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \
/ K1 i# M) b! j- Z# q lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
7 G8 t' X# _! g0 t! H# N fs/cramfs fs/fat fs/fdos fs/jffs2 \
/ O9 o8 c; u3 `: Z9 e: H1 _ net disk rtc dtt drivers drivers/sk98lin common \
2 t+ f7 M4 I! b- X0 j \( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
etags:
" D/ o8 G0 i) F( `0 O9 {8 w; R etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \
& L$ p3 G* `9 E4 M* a4 u0 b+ } lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \9 l% b7 e8 C2 y( P
fs/cramfs fs/fat fs/fdos fs/jffs2 \( t2 W# ~- Z5 A+ B
net disk rtc dtt drivers drivers/sk98lin common \7 l8 C7 g9 j/ Q$ s( R2 C% Q+ ]
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
$(obj)System.map: $(obj)u-boot8 f2 ^0 J9 D$ {4 `4 Q+ I3 p9 f* y
@$(NM) $< | \
0 U8 g# q5 a7 a8 z grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
% v5 \3 x2 E# v# ]; r- j sort > $(obj)System.map
& p, V0 L; G/ i
5 g' [5 x4 Q0 F1 |#########################################################################7 M4 Q/ \; w- s0 k
else# {2 H6 M( r f( W: r2 F; f0 L2 L
all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \: L' e" L/ `& N
$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \
; w4 g; V# m7 A4 L1 P( Q- \$(SUBDIRS) version gdbtools updater env depend \
8 T9 x; K( i! x3 Wdep tags ctags etags $(obj)System.map:
2 B- ?* t$ l9 q2 e" S# O" A @echo "System not configured - see README" >&22 b2 T3 ~# j! Z, k
@ exit 18 Q$ L. [3 u2 \$ q% P, I& j
endif
.PHONY : CHANGELOG3 r2 |- `( `; K+ Y! Z! Z
CHANGELOG:. B/ P9 S. e9 q
git log --no-merges U-Boot-1_1_5.. | \
. I, O1 b" ]+ I, }* t unexpand -a | sed -e 's/\s\s*$$//' > $@
% T2 m' Q7 P7 O& K; M7 Z
#########################################################################
+ S' b8 H7 x( O2 U1 ?# 这里就是我们所谓的unconfig,应该比较熟悉了!
3 f, S1 u1 d0 c3 |' \5 A# 很明显,它所做的工作就是清除上次生成的include/config.h和include/config.mk1 R [1 S5 e: h. V, ]. m; Y$ ?
# 以及开发板目录下的一些临时配置文件, U# v' Q) D3 ?) t$ T5 e) A
# unconfig:: k. B: b* X! z/ U
# @rm -f $(obj)include/config.h $(obj)include/config.mk \
' z, w0 Q- `' f$ m0 x# $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
- {% V2 P9 w! r9 D0 p' Y8 h#########################################################################
) K6 W% O# m" b( @3 a
................................
A9 _, x7 |, t8 d6 E6 ^* L5 `3 ssmdk2400_config : unconfig
/ ?5 t) x4 c) L) [8 H6 s @$(MKCONFIG) $(@:_config=) arm arm920t smdk2400 NULL s3c24x05 J& n' m& @: Y
% a7 _. S: l( H% |" D6 s
................................
smdk2410_config : unconfig8 [# n- Q7 U: ~+ w( y
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
: k5 z9 O2 S, |/ q ]8 N% _#我删了一部分内容,那些几乎都是各种不同板子的*_config,也就是目标的定义。
最后总结一下,当然这里也参考了前辈们的许多宝贵经验,顶层Makefile的主要任务就是组织整个u-boot工程的编译,概括可以分为一下几个步骤:
1、首先通过执行make *_config传入$(@:_config=), ARCH, CPU, BOARD, VENDOR, SOC参数(一共六个参数但不
! K7 p/ n5 A& Z+ ~, e% M- p9 l
0 x: s& j) j, ` 一定同时存在),给mkconfig。
2、mkconfig接收到传递过来的参数后,将include头文件夹相应的头文件夹链接好,生成config.h
3、然后执行make分别调用各个子目录的makefile文件,以生成所有的obj文件(包括start.o)和obj库文件*.a。
4、最后,通过链接器把所有目标文件链接起来,生成uboot镜像。不同格式的镜像都是调用相应工具,经
由elf镜像间接或者直接的生成的。