VERSION = 1
) `' S2 i/ L7 X: q1 D- mPATCHLEVEL = 1! Z; M3 v! E: r( ^- P, e5 E; A
SUBLEVEL = 6
/ [" F+ O& Z. e6 u2 J3 J0 D" K7 GEXTRAVERSION =' H; v0 u) X' c) I
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)+ U9 f8 N" G8 _
VERSION_FILE = $(obj)include/version_autogenerated.h #版本文件
1 b, u6 S4 H5 e( F$ ?% p9 w
# uname 命令将正在使用的操作系统名写到标准输出中
; } V* M5 N/ L+ ~5 P# Q4 \8 i3 d2 v# -m 显示硬件运行系统的机器 ID 号
# 定义变量,HOSTARCH里面存储的是机器ID号,即主机架构类型
/ u- }5 P& m! t, L8 ZHOSTARCH := $(shell uname -m | \ #可以把shell脚本写到makefile里面,这是make中的shell function, 相当于shell中的命令替换。5 S- C9 p8 z: S9 V! f
sed -e s/i.86/i386/ \ #shell uname -m 获得机器硬件名称& {" T) q4 Y% H8 q/ t h) k1 M% y1 J! u/ L
-e s/sun4u/sparc64/ \ #sed -e s/arm.*/arm/ 的意思是把前缀为arm的所有模式替换为arm。结合前面的uname命令来理解就是:# c- Y; D; V! v) W' `
-e s/arm.*/arm/ \ #把uname -m的结果(主机架构类型或者称为机器ID号)通过管道传递给sed命令,然后把前缀为arm的所有模式替换为arm。
7 u H/ Y( P3 B) F -e s/sa110/arm/ \ #sed的语法:sed [ -n ] Script [ File ... ]$ Y5 B% y. G/ [4 s, w `9 _
-e s/powerpc/ppc/ \ # sed [ -n ] [ -e Script ] ... [ -f ScriptFile ] ... [ File ... ]# R5 O0 W( E$ x( d
-e s/macppc/ppc/) #sed 命令根据编辑脚本,去修改指定的 File 文件(这里file是作为一个输入参数的)的行,并将其写到标准输出。7 n2 h4 @, B9 L5 N8 I/ m }( P
#sed 命令包含很多功能,用于选择要修改的行(请注意,sed是针对行进行操作的),并只对选择的行作更改。
1 ]" g! G% M, a #sed 命令使用两个工作空间来保留修改的行:保留选定行的 "模式空间" 和暂时存储行的 "保留空间"。& S% L: {2 P% d' ?! e
#这里所谓的编辑脚本是由单独的子命令构成的,每个单独的行上对应着一个子命令。sed 子命令的一般格式如下:[address-range] function[modifiers],即:[地址范围] 函数[修改符]
4 \8 z8 o/ r8 m5 a: H #sed 命令通过将一个输入行读入模式空间,依次应用所有的 sed 子命令(这些子命令的地址选择了该行),
4 d, C9 I4 Q2 J8 v0 ` [ #并将模式空间写到标准输出来处理每个输入的 File 输入文件(file就是输入参数)。然后清除模式空间,并对输入的 File 中指定的每行重复该过程。
& |. ?3 [; M) Z. y% [( G# k #一些 sed 子命令使用保留空间来保存后继检索的所有的,或部分的模式空间。
7 R0 R0 f( i' }$ D! j #当命令包含地址(行号或搜索模式)时,该命令只会对被寻址的行起作用。否则,该命令适用于所有的行。
, M! [; l! e0 p8 k- R+ U' v #注意,这里的参数"-e"的意思是:使用 Script 变量作为编辑脚本。如果你只使用一个 -e 标志并且不使用-f 标志,则可以省略 -e 标志。
3 E7 I. }; p9 a6 i6 | #注意,这里的 "sed -e s/arm.*/arm/"表示把前缀为arm的所有模式替换为arm,也就是sed s/pattern/replacement/flags 4 b) _+ G- x* J o' [/ J
#用 replacement 字符串代替在模式空间中首次出现的 pattern 参数。除了空格或换行符,在 s 子命令之后显示的任何字符都能代替 /(斜杠)分隔符。
. Y7 e( G) ~ L. C' c
. i7 @* F7 \8 x" d/ y) p9 g# Q#uname -s 表示:显示系统名,标志缺省为开,即uname命令不带任何参数的输出和加参数-s输出相同,即Linux
. M' k& @1 }3 \( i0 D#tr是一个shell命令,这里 tr '[:upper:]' '[:lower:]'的意思是把管道中的Linux 中的大写字母L 转换成小写字母l
& J6 c5 z' n$ n# o* S7 [, p1 N#下面这句话的意思是定义变量HOSTOS,HOSTOS里面存放的是主机安装的,并且当前正在运行的操作系统。% s) f b# o. c& C
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
/ E6 D* \! ]7 W; l0 v r+ g; C sed -e 's/\(cygwin\).*/cygwin/') # 这一句的意思是检测出主机安装的,并且当前正在运行的操作系统名,并把这个系统名中的大写字母转换为小写字母, 5 D' X3 M; Q* H( v
# 然后在通过sed流编辑器匹配所有的,这个系统名中出现的"\(cygwin\).*"模式,然后再用"cygwin"模式替换。
: o& v* y4 \$ |/ ?#export HOSTARCH HOSTOS 的意思是输出两个makefile变量HOSTARCH HOSTOS
export HOSTARCH HOSTOS
# Deal with colliding definitions from tcsh etc. 用来处理来自tcsh的互相冲突的定义等等+ ?; K/ E: W6 C8 s+ R
# 一般来说,shell可以分成两类。第一类是由 Bourne shell 衍生出来的包括
$ c' V: I( E0 G" b/ S# sh,ksh,bash,与zsh。第二类是由 C shell 衍生出来的,包括 csh 与 1 L9 Z# l0 g8 x( \$ F* d, k
# tcsh。除此之外还有一个 rc,有人认为该自成一类,有人认为该归类在Bourne shell。
VENDOR= #开发商
#########################################################################
0 E6 t5 g3 [9 d' s3 x#
/ ^0 x# n' d6 W; q: B, V! C1 s; _( ?# U-boot build supports producing a object files to the separate external
* E# s( z- f4 ^6 S$ e, Z3 z: N* O# U-boot 的编译过程可以支持向一个自己定义的路径生成最终的目标文件5 f) q7 @9 ?- x- V' ]. e
# directory. Two use cases are supported:9 d7 M3 _* C# T5 F& h$ q( H
# 这里提供了两种用法:
. P3 S& f& G+ C$ D7 z; \; l, s' C#0 h' E8 f' J, x
# 1) Add O= to the make command line #第一种用法:通过在终端执行命令make O=/dir(即你指定的生成的目标文件的存放目录)( I1 R+ J& m; I K5 w* v
# 'make O=/tmp/build all'
* b5 `, r" k. T$ ?8 a3 `; S#
6 W; T. c2 |! r# 2) Set environement variable BUILD_DIR to point to the desired location #第二种用法:通过设置环境变量来指定目标文件存放目录,如下所示:
3 x6 J. s+ B9 i; K5 V# 'export BUILD_DIR=/tmp/build'; H1 U" |4 D0 U. g* z' I
# 'make'
# x. S, w9 P# w" Z1 _6 j#! ?! w% Z% F: p6 R: `8 `' g
# The second approach can also be used with a MAKEALL script #第二种方法也可以写成一个MAKEALL脚本,然后执行MAKEALL,如下所示:
. v. p4 Q! l! K2 N# 'export BUILD_DIR=/tmp/build'
3 x3 e7 e% v" s3 d" r/ s# './MAKEALL'
' s0 ?0 }# D& U#9 j( _! J8 j b; p
# Command line 'O=' setting overrides BUILD_DIR environent variable. #命令行'O='设置会覆盖环境变量BUILD_DIR的设置4 s- M& E& S; B
#: _9 R' B6 Z4 U- z* e
# When none of the above methods is used, the local build is performed and #如果都不采用上面两种方法,那么目标文件最终要存放到源码顶层目录,也就是U-BOOT顶层目录! C7 e/ o3 t7 E0 i
# the object files are placed in the source directory.
- p l0 z9 N D! b- j#
#理解了上面一段英文,这里就不难理解了) h5 v. _5 U% [, t# x: u
#方法1
ifdef O #如果变量'O' 已经被定义过
- G& M. v- e" X9 h) [& X% cifeq ("$(origin O)", "command line") #如果变量'O' 在命令行中定义过
7 q% H# ~% [* P+ m" PBUILD_DIR := $(O) #就把变量'O' 的值(目标文件存放目录)赋给BUILD_DIR
4 s. X: T. }& G9 a7 Fendif
9 G4 d2 P7 F4 t8 q- C( Aendif
9 M, v2 W9 ^$ W" O' x* I% W" T
#方法2# R( M2 {! O2 y1 C _
ifneq ($(BUILD_DIR),) #如果变量BUILD_DIR不为空,即环境变量BUILD_DIR 被定义过
9 |! T3 x9 y, j4 \0 |+ o9 w" i- ksaved-output := $(BUILD_DIR) #那么把它的值赋给saved-output
# Attempt to create a output directory. #生成一个输出路径,即目标文件存放目录BUILD_DIR- I# \( R9 a' k6 E
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
#shell [ -d ${BUILD_DIR} ] 是什么意思?是不是生成一个目录的意思?
# Verify if it was successful. 测试目录是否创建成功
. X) _& d8 o4 I! lBUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) #这又是什么意思,说明对shell还不够理解!
$ P: ?7 j3 L) @7 }% Z$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
7 {1 O: H C& N#这里用了一个if函数,意思是如果如果$(BUILD_DIR) 非空,则什么都不执行(返回空),否则执行error函数,输出错误信息
% O5 u' X. g. S! ^: s& `6 {. [3 ~endif
# ifneq ($(BUILD_DIR),) #意思是:如果没有定义目标文件存放目录* ~: V* J1 |$ q
#Makefile中定义了源码以及生成目标文件存放的目录,目标文件存放目录BUILD_DIR可以通过make O=dir指定。如果没有指定,则设定为源码顶层目录。
$ r3 r2 `3 w& M- d% w#一般编译的时候不指定输出目录,则BUILD_DIR为空。其他目录变量如下:# |+ r5 y1 q) `% c) `
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #如果$(BUILD_DIR)不为空,则返回$(BUILD_DIR),并赋给OBJTREE,即自己定制的目标存放目录9 X# A0 U+ B) g6 `* U4 Q. h4 p+ D
SRCTREE := $(CURDIR) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE $ ^3 K- _; N: v- B
TOPDIR := $(SRCTREE) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE
% Y- ?" ~# b" F. I- r5 I% ]LNDIR := $(OBJTREE) #存放生成的目录文件# X- ` S- i5 p% j6 @( I i
export TOPDIR SRCTREE OBJTREE
% \7 Q' c5 M6 O1 C( n x
1 s8 U: h1 S$ W- t, }1 m0 jMKCONFIG := $(SRCTREE)/mkconfig #MKCONFIG指向源码所在目录(U-BOOT顶层目录)下的mkconfig配置文件
7 t2 {. |8 N$ o. m: Eexport MKCONFIG
#在编译UBOOT之前,我们先要执行:
" U7 r9 X! V, t3 [; ]#make smdk2410_config
) `- K( W( H/ t7 }9 u, x#从本Makefile的下文可以判断出smdk2410_config为Makefile的一个目标。( G8 p! |5 R3 m6 [$ b$ f
#smdk2410_config: unconfig的意思是为smdk2410开发板建立一个编译项。
! t+ X9 ^3 W& {1 H8 [+ G#显然,执行#make smdk2410_config时,先执行unconfig目标(不指定输出目标时,obj,src变量均为空),unconfig下面的命令主要任务是清理上6 ^5 `3 x$ U) a% J; Z# [6 C
#一次执行make *_config时生成的头文件和makefile的包含文件。! e% O8 c$ E7 y& a! q* |% ^2 C- k4 _
#主要是include/config.h和include/config.mk; m: D$ S6 x( |# q& _, T6 @8 C3 ~
#然后执行命令: @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x02 \$ _! y. C9 F3 G) z; f
#arm 表示CPU的构架是基于ARM体系的$ ~& [4 ~8 e' P% z. y
#arm920t 表示CPU的类型是arm920t4 Z/ \1 i! h0 U [
#smdk2410 表示开发板的型号# I) D4 k' u+ H5 w
#NULL 表示开发商或者经销商的名称,这里为空! u% u9 j" Q& b( L- i' _8 O/ x
#s3c24x0 表示基于S3C2410的片上系统, M4 _7 g6 m9 y
#MKCONFIG指向UBOOT顶层目录下的mkconfig脚本配置文件,后面五个字符串是传入的参数(好像$(@:_config=)也是一个参数)。
1 u2 ]6 j9 o6 i+ {5 m% |& c#下面来分析一下mkconfig这个脚本配置文件,点击链接:
0 W' u# O6 e! v& T; ehttp://zqwt.012.blog.163.com/blog/static/120446842010325102158182/
! L2 `" \1 G+ N3 B/ S8 t
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时- x; {3 f* S1 P# g2 T/ m6 B. Z
REMOTE_BUILD := 1 #定义变量REMOTE_BUILD := 1 这个变量算是一个flag吧# Z) l. G) Z* m9 q& s7 D9 V! K
export REMOTE_BUILD/ Z1 T& x+ `3 v6 h$ e: R
endif
# $(obj) and (src) are defined in config.mk(顶层目录下) but here in main Makefile
. Z" q9 L3 s* M& K$ X7 U. ]# we also need them before config.mk is included which is the case for
9 T% s+ _9 Q$ q0 E. u: o8 e# some targets like unconfig, clean, clobber, distclean, etc.
, O# v! [' q- P6 H/ ?# $(obj) and $(src)都被定义在顶层目录下的config.mk脚本配置文件里面,6 X9 d9 Z& O8 A) [5 V) R, C
# 但是在这个主Makefile里面,我们同样需要他们,
7 V% [. f5 X* c( R0 D" J+ W# 因为在主Makefile文件包含config.mk之前,$(obj) and $(src)偶尔地会成为这些目标的case:
4 _8 U. T$ k1 ], O. R, p+ C o# unconfig, clean, clobber, distclean, etc
Q/ _5 j6 v5 t3 e) f
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时& h. Y* ^6 U" Y" Z1 L
obj := $(OBJTREE)/ #定义变量obj,让其等于目标存放目录* w' V- ]8 [- X8 C6 e! \
src := $(SRCTREE)/ #定义变量src,让其等于uboot顶层目录0 Y6 H9 K, U/ h0 f4 A" J
else
+ l" ~- N; W' o) z- u) G- G8 ^obj := #否则,这两个变量都定义为空
; _( K n5 H- A" h9 j, }( {src :=
! d, @7 Z9 ?- a" p$ ?endif
/ L( I$ ]2 c: D" }7 |5 U' w- Zexport obj src
( N+ {+ {) E- e0 y% E
9 K4 v9 R8 h# X% X% a: R& v8 }$ P. y9 `7 U, q
#########################################################################
( e: _% g# P9 P* Y7 }( z. k( V
8 E& ]7 W# I! n( W+ t6 P1 y- p" D+ i' X+ c# k. y
5 o1 T, \1 _4 X# uifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)) #这句话让人费解!5 t( R( i7 z6 |+ R8 P$ o* }
# 通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展。# {% T, b% I7 n. Z9 t
# 如果您需要在这些场合扩展通配符,您应该使用函数wildcard,格式如下:& A1 p' M0 @. p q
# $(wildcard pattern...)
9 E7 b+ _1 t1 Y6 U
# load ARCH, BOARD, and CPU configuration
( [# {: h* l4 w5 D+ ?$ y4 e# 加载ARCH, BOARD, and CPU 配置
" M1 t0 g7 w2 |! S/ F) ninclude $(OBJTREE)/include/config.mk # 这时候,开始包含/include/config.mk的
9 t! b1 i- w9 _export ARCH CPU BOARD VENDOR SOC
B$ n9 i& d- I9 B, u) e" f: m8 [* J#指定交叉编译器前缀
5 h3 o6 |% ?) n1 r- N! Jifeq ($(ARCH),arm) 2 _7 f* g5 E: M9 q
CROSS_COMPILE = arm-linux-2 s# M2 ~0 g- a- P
#这里你可以把交叉编译器的安装路径加到arm-linux-之前,比如你的交叉编译器安装路径是/root/u-boot/usr/local/arm/3.3.2/bin/
7 E# t9 u5 H. I+ `# g/ Q#你可以这样定义CROSS_COMPILE = /root/u-boot/usr/local/arm/3.3.2/bin/arm-linux-
# z9 s# G+ G* Z1 p! K9 p#这样一来,你在终端进行编译的时候就不用指定CROSS_COMPILE=arm-linux-了
" o8 y& d. s) M2 b( l#但请注意:在编译内核的时候,交叉编译器必须安装在/usr/local/arm下,否则会发生错误!!!!!
3 |7 l; S# Z% }- U! d4 ]" bendif
export CROSS_COMPILE
+ v* |0 T, J3 H; `: u& G
/ c6 |( D5 d- {# _/ i
# load other configuration 加载其他设置,这里是包含顶层目录下的config.mk配置文件,这个文件主要做了三个工作:
* `2 [4 ~/ U& F" y& l5 D# 1、定义了交叉编译器 2、定义了编译选项 3、定义了编译规则
! n' `+ u9 T3 O4 x6 q+ v/ ^+ ~; V# 对本文件具体的分析,请查看链接:
0 [2 V( R% J8 J, w6 ]http://zqwt.012.blog.163.com/blog/static/12044684201032541139914/
include $(TOPDIR)/config.mk
#########################################################################
% G" ~4 L/ k% }$ M( f# U-Boot objects....order is important (i.e. start must be first)# \+ U* B& b# x h8 w% @
# uboot目标...书写顺序很重要,比如start.o必须排在第一位9 B6 G6 O' ^% k* A& }+ _
#########################################################################
3 u0 Q3 q/ c7 @7 rOBJS = cpu/$(CPU)/start.o
$ Q' v) R( \2 g" n+ I4 ?0 a#start.o必须放在目标文件的第一位,因为uboot执行的第一段代码就是start.S
2 | a: H! z% ?( r, ^( m#具体原因可以查看链接脚本/u-boot-1.1.6/board/smdk2410/u-boot.lds,点击连接:9 ?% q# g4 l2 C0 R" r5 A, }! @
http://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
# j: q! `! K6 S' c
.....................................
" N" D: F) u( o" P: U
OBJS := $(addprefix $(obj),$(OBJS)) #这句的意思是把目标文件存放路径以前缀的形式加到start.O之前,然后再赋给OBJS
: @& v2 s" u% k! ?) E4 G
#以下是编译UBOOT需要的库文件
% c) h9 [- b. }3 W4 U% y& \: HLIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a # 严重平台依赖的
LIBS += cpu/$(CPU)/lib$(CPU).a # 严重平台依赖的
ifdef SOC
# \/ a: t! o* R& h( r, O7 V! tLIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a # 严重平台依赖的
- M$ z$ F+ P2 Kendif
LIBS += lib_$(ARCH)/lib$(ARCH).a # 严重平台依赖的
8 q- B- h7 e9 P; ?4 w% p1 Z3 E( ?LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
7 W" I' v! P; R' n. ~2 m fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
7 a9 s C* ? V% N5 q0 i+ @! }0 }LIBS += net/libnet.a- l% ~2 `2 e3 o e: N. {' @$ }
LIBS += disk/libdisk.a
+ u+ c% M( ]3 E4 qLIBS += rtc/librtc.a4 ^9 C/ ]/ W) t# d' Q: e
LIBS += dtt/libdtt.a% U( R6 A7 b5 y- L- F8 L# ?6 G- O
LIBS += drivers/libdrivers.a
% a" F3 J y, A! WLIBS += drivers/nand/libnand.a
3 a0 F8 [/ v' B( o# q7 U* NLIBS += drivers/nand_legacy/libnand_legacy.a
2 M* ~3 H4 q+ SLIBS += drivers/sk98lin/libsk98lin.a
3 j4 @0 e- Z" LLIBS += post/libpost.a post/cpu/libcpu.a* R' K: v2 m4 G7 z3 \: ^
LIBS += common/libcommon.a" `. S; y, V$ ?
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) # 这是一个伪目标
#根据所生成的include/config.mk文件定义的几个变量ARCH, CPU, BOARD, SOC,我们可以
0 c9 Q; x! e* b#确定硬件平台依赖的目录文件。smdk2410平台相关(依赖)目录以及对应生成的库文件如下:
W) i+ [5 [. n3 x#board/smdk2410/: 库文件board/smdk2410/libsmdk2410.a$ s9 x i7 ?" F" G5 C
#cpu/arm920t/: 库文件cpu/arm920t/libarm920t.a
. M- f2 A) e+ u8 ]4 L1 |7 p! j" `#cpu/arm920t/s3c24x0: 库文件cpu/arm920t/s3c24x0/libs3c24x0.a
$ H8 Y" ?; V- N3 i2 g# c! L9 ^#lib_arm: 库文件lib_arm/libarm.a' N: k% D3 U4 i3 Q+ P8 Z
#include/asm-arm: 头文件
n( _) [* p! f i#include/cnofigs/smdk2410.h:头文件
# Add GCC lib
3 X# P* X0 @4 \PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
# The "tools" are needed early, so put this first/ l1 `# F, X4 W; F
# Don't include stuff already done in $(LIBS) 不要包含已经在 $(LIBS) 中的任何东西
7 f& k& e7 {" o7 t#
' z3 i# |3 o; z, Y) B+ U% j# 伪目标SUBDIRS:用于执行tools、examples、post、post\cpu子目录下的make文件9 [4 M/ N# B* G6 `5 n; w
SUBDIRS = tools \
( N8 N! H( x. r9 k examples \
5 @, U( O: V# g' @ post \2 Z; X6 S8 @$ D% Z8 Q4 a
post/cpu
; {" t0 z% ~7 ~- y1 a.PHONY : $(SUBDIRS)
ifeq ($(CONFIG_NAND_U_BOOT),y); k' R! R+ i. |4 ]7 F
NAND_SPL = nand_spl+ G" j% c+ j+ S% {1 a# v+ f
U_BOOT_NAND = $(obj)u-boot-nand.bin/ h. G% M ?, u% M! K p
endif
__OBJS := $(subst $(obj),,$(OBJS))& Q4 D* ]+ i6 o3 U
__LIBS := $(subst $(obj),,$(LIBS))
#########################################################################
4 B! R: r( z; n- v8 s# f4 [- h#########################################################################
3 {6 [+ f3 ]# y# l' [1 ^& e" |$ N( a; X
#这里是最终要生成的各种镜像文件u-boot.hex、u-boot.srec、u-boot.bin、System.map、u-boot.img& \, u" Y; H. M
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
) Z1 T/ k2 u* ^1 l7 Tall: $(ALL)
( Y3 ?8 q8 B3 B6 _$(obj)u-boot.hex: $(obj)u-boot1 J* ]2 z8 x/ d
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ # $<,$@ 分别表示使用该规则的源文件和目标文件
$(obj)u-boot.srec: $(obj)u-boot
4 i7 N3 z* `' \+ k0 t1 b $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
6 y5 ]/ E- f+ `2 X) P2 m- I8 m/ @& } $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.img: $(obj)u-boot.bin
+ k6 w, H% D% H3 Y( H ./tools/mkimage -A $(ARCH) -T firmware -C none \
$ M' m5 f' K7 H1 z. `- G -a $(TEXT_BASE) -e 0 \6 p& `5 m' ^& w+ u0 d
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
+ T0 r4 P1 e/ y& y { sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \' R R( s. _) u0 c8 @
-d $< $@
$(obj)u-boot.dis: $(obj)u-boot
6 C5 a8 X% E5 _: Q $(OBJDUMP) -d $< > $@
1 g) k% ?5 [4 o2 { K6 z, P
#此处生成的是uboot的ELF文件镜像
, a! B0 t2 ], A$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)" b* c6 H8 T u" N, U, v8 X2 f4 [
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\8 p& z, }* |) h: g
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ `# H: g7 n% m3 ?
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \9 ^ a" _% T' N( D, l4 {- m) Y
-Map u-boot.map -o u-boot
- D! ~ j* i2 ~- H; J" J* N' i1 p#依赖目标$(OBJS),也就是cpu/start.o7 ]" _0 Y$ N* a7 r0 W/ q
$(OBJS):
2 }- \( ~" [; ]3 m& _' F $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
7 s) }: Q1 `9 j6 z
8 _7 w9 Z/ s* ~#依赖目标$(LIBS),目标很多,都是每个子目录的库文件*.a,通过执行相应子目录下的make来完成
, j) v/ I3 G: }$ `$(LIBS):
, N; _5 }( J* k, [: l" z $(MAKE) -C $(dir $(subst $(obj),,$@))
1 s6 ]! R" s2 E 2 M h) b; L8 { N* f7 ?# H
#这里解释一下这个makefile函数 $(dir names...)
) {/ d8 y7 x4 }& e8 K) `5 q0 Z#抽取‘names’中每一个文件名的路径部分,文件名的路径部分包括从文件名的开始到最后一个斜杠(含斜杠)
0 r9 J% C1 ]1 o#之前的一切字符。如果文件名中没有斜杠,路径部分是‘./’。如:
2 U5 }5 E8 ]! `! ^% ~9 R" N#$(dir src/foo.c hacks)) Z: T4 A: C6 x" l7 V3 p. b/ D$ ^
#产生的结果为 ‘src/ ./’。
* k( J' P; d) |- Q' P4 W$(SUBDIRS):8 C2 E5 m. ]; a) A9 W5 _
$(MAKE) -C $@ all
$(NAND_SPL): version0 A* L- {2 Y, }% E) G
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin
4 b- o( I' P8 k+ v+ u0 N7 V N cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
8 a" @7 O5 j/ e' n: _
#依赖目标version:生成版本信息到版本文件VERSION_FILE中
, W8 d1 N! l. B) e! rversion:6 f- i0 q, l: G* S0 `
@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \0 x D2 R, H3 |$ L4 }% J
echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \
) }0 P5 B' D1 O* d c echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
1 R$ V/ V6 W8 C' o- j $(TOPDIR)) >> $(VERSION_FILE); \
, R" o+ A: K# U7 T echo "\"" >> $(VERSION_FILE)
gdbtools:0 m" K: ~( T9 Z- S; d* I
$(MAKE) -C tools/gdb all || exit 1
updater:( T" X2 ?8 L+ z! B
$(MAKE) -C tools/updater all || exit 1
env:+ n! ?6 e# e K
$(MAKE) -C tools/env all || exit 1
6 }) X, N: i+ i- V
9 N4 d* l. p& o7 E
#依赖目标depend:生成各个子目录.depend文件,.depend列出每个目标文件的依赖文件。
^/ T/ E; l0 @ B, f#生成方法:调用每个子目录的make_depend! E2 N7 N# b8 t% _+ B9 i3 i6 U% O
depend dep:6 ~: O, @5 Z C: b, \5 v
for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
5 j3 ]0 _5 a3 j
tags ctags:
( Z3 @) g: ~, \2 ]9 \8 h/ q ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \& Q5 S9 [* @7 i) {5 y& z% P
lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \! Y5 V, x+ D5 s& r6 k0 [1 `
fs/cramfs fs/fat fs/fdos fs/jffs2 \$ Z* M5 t7 [2 S
net disk rtc dtt drivers drivers/sk98lin common \
+ n# {, l* g1 S; T: m% K4 x \( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
etags:$ g0 t9 B' `' }# F$ F* i. i0 Y' H
etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \; s1 r; h/ R& f H+ E
lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \7 P9 V, S' I f1 X3 Q ]$ c6 {
fs/cramfs fs/fat fs/fdos fs/jffs2 \
, i% n9 W+ [, L1 \ net disk rtc dtt drivers drivers/sk98lin common \
% }8 _" k& H9 e' I6 d4 {& L' _ \( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
$(obj)System.map: $(obj)u-boot
% i( k) `$ V8 b6 \4 s9 B @$(NM) $< | \
4 M1 o0 o/ I- T+ G% N grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \3 x( a3 X. c, t1 p4 v& ~8 y
sort > $(obj)System.map
$ S5 i* c% y+ q! r2 M3 G
% n& a; ~# w: z7 _9 }/ C
#########################################################################4 ]1 j4 F" ^7 H! b q; f6 G8 T
else4 K9 X+ ^4 {' J$ n! G* I* x
all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \/ T/ W$ ?" `% ]4 u+ m0 Z
$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \5 p: i8 T o- Y# ]# D
$(SUBDIRS) version gdbtools updater env depend \" j4 O' U- Z1 k- [
dep tags ctags etags $(obj)System.map:5 J2 |: Y' F9 z0 Z& M7 S
@echo "System not configured - see README" >&2" F% z* a; g. g, A1 c
@ exit 1( h: T( [/ x1 G7 w
endif
.PHONY : CHANGELOG
# s2 _7 p7 y3 f3 l" cCHANGELOG:
, q. z- D G/ m git log --no-merges U-Boot-1_1_5.. | \
( L5 t2 O4 u5 ]. \ unexpand -a | sed -e 's/\s\s*$$//' > $@
5 j* N3 L6 t. {0 u#########################################################################, X/ x2 ]' ^2 Y5 Y6 }3 v
# 这里就是我们所谓的unconfig,应该比较熟悉了!
6 u, }% ?* i( `& ~3 {2 N7 k5 M# 很明显,它所做的工作就是清除上次生成的include/config.h和include/config.mk! u- i$ o) X+ @/ q
# 以及开发板目录下的一些临时配置文件, Y9 \; S$ N4 a3 [3 z# m% ]' i
# unconfig:
9 a+ }4 q4 _0 \/ j# @rm -f $(obj)include/config.h $(obj)include/config.mk \
, w1 o6 P7 b! F1 Q# $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
- ]8 r: c8 d. L3 ^8 f2 w#########################################################################
7 M3 \+ `+ _$ @5 M3 o W3 q
................................
2 _; C, T3 h: h2 dsmdk2400_config : unconfig1 h. L3 W. X; T) W$ I6 _ t
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2400 NULL s3c24x00 ~7 z% p& T. [
7 i0 a- W4 E5 {( D: J$ a8 R$ p
................................
smdk2410_config : unconfig
8 E$ N3 n2 f. p; e @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
& q+ Y6 Q0 S9 g#我删了一部分内容,那些几乎都是各种不同板子的*_config,也就是目标的定义。
最后总结一下,当然这里也参考了前辈们的许多宝贵经验,顶层Makefile的主要任务就是组织整个u-boot工程的编译,概括可以分为一下几个步骤:
1、首先通过执行make *_config传入$(@:_config=), ARCH, CPU, BOARD, VENDOR, SOC参数(一共六个参数但不
, V( R. ]- f( i7 |8 F o5 ]+ X' \, v6 P5 r8 f2 W) h9 A, |
一定同时存在),给mkconfig。
2、mkconfig接收到传递过来的参数后,将include头文件夹相应的头文件夹链接好,生成config.h
3、然后执行make分别调用各个子目录的makefile文件,以生成所有的obj文件(包括start.o)和obj库文件*.a。
4、最后,通过链接器把所有目标文件链接起来,生成uboot镜像。不同格式的镜像都是调用相应工具,经
由elf镜像间接或者直接的生成的。