VERSION = 1
; v1 N4 z9 r+ ]) j& Q" R. m. hPATCHLEVEL = 1
8 J- o$ M6 z9 `: E7 B) eSUBLEVEL = 6( C9 A8 Z. q @
EXTRAVERSION =
( P& v5 [9 O. D7 Q( L( rU_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)+ @5 r* e% r# L- \9 p5 n6 e
VERSION_FILE = $(obj)include/version_autogenerated.h #版本文件
% t2 B4 f3 L! O) ]2 \) g' z# uname 命令将正在使用的操作系统名写到标准输出中
8 h$ o8 L. ?0 T& Q8 d" }# -m 显示硬件运行系统的机器 ID 号
# 定义变量,HOSTARCH里面存储的是机器ID号,即主机架构类型: v; r' y: ~3 Q8 I0 m/ B
HOSTARCH := $(shell uname -m | \ #可以把shell脚本写到makefile里面,这是make中的shell function, 相当于shell中的命令替换。$ C9 _- j- r: r2 {! l
sed -e s/i.86/i386/ \ #shell uname -m 获得机器硬件名称2 Z* e4 M0 X' h/ v: n. z! o! R: u+ l
-e s/sun4u/sparc64/ \ #sed -e s/arm.*/arm/ 的意思是把前缀为arm的所有模式替换为arm。结合前面的uname命令来理解就是:. M( Y) l) g: @% L
-e s/arm.*/arm/ \ #把uname -m的结果(主机架构类型或者称为机器ID号)通过管道传递给sed命令,然后把前缀为arm的所有模式替换为arm。
, w' m$ w0 a* A. F7 H -e s/sa110/arm/ \ #sed的语法:sed [ -n ] Script [ File ... ]
2 q; _# O f! P) c -e s/powerpc/ppc/ \ # sed [ -n ] [ -e Script ] ... [ -f ScriptFile ] ... [ File ... ]
& s; K* T+ J- Q -e s/macppc/ppc/) #sed 命令根据编辑脚本,去修改指定的 File 文件(这里file是作为一个输入参数的)的行,并将其写到标准输出。; `8 O8 g- h. P" R/ ~
#sed 命令包含很多功能,用于选择要修改的行(请注意,sed是针对行进行操作的),并只对选择的行作更改。9 H1 ~$ X, i2 y' T% Y9 N: Q6 S
#sed 命令使用两个工作空间来保留修改的行:保留选定行的 "模式空间" 和暂时存储行的 "保留空间"。, z! ^- w* p4 [
#这里所谓的编辑脚本是由单独的子命令构成的,每个单独的行上对应着一个子命令。sed 子命令的一般格式如下:[address-range] function[modifiers],即:[地址范围] 函数[修改符]
' `! ^# v" r. f+ Q% x #sed 命令通过将一个输入行读入模式空间,依次应用所有的 sed 子命令(这些子命令的地址选择了该行),
0 A" z4 m' M* g. S: \( ` #并将模式空间写到标准输出来处理每个输入的 File 输入文件(file就是输入参数)。然后清除模式空间,并对输入的 File 中指定的每行重复该过程。
8 _) ]5 Z% h3 h( ?6 h1 o #一些 sed 子命令使用保留空间来保存后继检索的所有的,或部分的模式空间。
4 f- S: T0 X7 o1 R4 m #当命令包含地址(行号或搜索模式)时,该命令只会对被寻址的行起作用。否则,该命令适用于所有的行。& v) `( A( N% q8 c8 o! @1 S% v
#注意,这里的参数"-e"的意思是:使用 Script 变量作为编辑脚本。如果你只使用一个 -e 标志并且不使用-f 标志,则可以省略 -e 标志。2 q1 b8 F! Z P3 V6 C* u- P) c
#注意,这里的 "sed -e s/arm.*/arm/"表示把前缀为arm的所有模式替换为arm,也就是sed s/pattern/replacement/flags
8 A! M% O9 T- R1 W& k4 i0 Z* Z+ k #用 replacement 字符串代替在模式空间中首次出现的 pattern 参数。除了空格或换行符,在 s 子命令之后显示的任何字符都能代替 /(斜杠)分隔符。
% i. j0 ^: W+ b# O2 M9 g) @( L: {
S9 m Y0 p! { d( `5 n& m5 q
#uname -s 表示:显示系统名,标志缺省为开,即uname命令不带任何参数的输出和加参数-s输出相同,即Linux0 F6 {/ p3 k. b& a
#tr是一个shell命令,这里 tr '[:upper:]' '[:lower:]'的意思是把管道中的Linux 中的大写字母L 转换成小写字母l+ m7 X* E' x* Y. {! z+ ^
#下面这句话的意思是定义变量HOSTOS,HOSTOS里面存放的是主机安装的,并且当前正在运行的操作系统。
! v& Q% J5 A$ m# V+ ^. f- r7 B( [HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \) w8 b- @- |/ M [5 J
sed -e 's/\(cygwin\).*/cygwin/') # 这一句的意思是检测出主机安装的,并且当前正在运行的操作系统名,并把这个系统名中的大写字母转换为小写字母, : o# e4 Z, d1 L5 J& V
# 然后在通过sed流编辑器匹配所有的,这个系统名中出现的"\(cygwin\).*"模式,然后再用"cygwin"模式替换。5 ]0 [, T. M7 B6 r/ A
#export HOSTARCH HOSTOS 的意思是输出两个makefile变量HOSTARCH HOSTOS
export HOSTARCH HOSTOS
# Deal with colliding definitions from tcsh etc. 用来处理来自tcsh的互相冲突的定义等等( r& M! L) p) }) t1 k
# 一般来说,shell可以分成两类。第一类是由 Bourne shell 衍生出来的包括
6 B& N4 M. p# I# sh,ksh,bash,与zsh。第二类是由 C shell 衍生出来的,包括 csh 与 3 M1 ]! X: f; T5 J3 W% N
# tcsh。除此之外还有一个 rc,有人认为该自成一类,有人认为该归类在Bourne shell。
VENDOR= #开发商
#########################################################################
6 o; ^9 v0 S) k4 v& j. Y#/ P( q8 ~! d6 ~* F1 c" V
# U-boot build supports producing a object files to the separate external* V( n) B" _6 c
# U-boot 的编译过程可以支持向一个自己定义的路径生成最终的目标文件 K7 J. Q3 Z6 C. {4 ~& i
# directory. Two use cases are supported:& O7 i! e/ R" P* D1 [9 I; d2 K
# 这里提供了两种用法:
, ]( Y/ y V+ O2 ]#6 X4 a6 \5 g' K! E
# 1) Add O= to the make command line #第一种用法:通过在终端执行命令make O=/dir(即你指定的生成的目标文件的存放目录)5 R+ |* p. K) U! O# K5 |6 k5 F( b
# 'make O=/tmp/build all'
& i- E H; E% u2 V8 p1 [3 k) N5 g#( i( _' I0 g( R9 d1 V/ k
# 2) Set environement variable BUILD_DIR to point to the desired location #第二种用法:通过设置环境变量来指定目标文件存放目录,如下所示:1 T# J0 B( O: Q" u; f
# 'export BUILD_DIR=/tmp/build'
& p( r, `. M2 M8 F7 f% s# 'make'$ p( }) }4 ^0 Z* B. w! Y
#
- {9 G( u2 {! e7 t# The second approach can also be used with a MAKEALL script #第二种方法也可以写成一个MAKEALL脚本,然后执行MAKEALL,如下所示:
0 C% Q3 g9 K) N# Y! ^3 K7 u# 'export BUILD_DIR=/tmp/build'
* O" v9 e; R, X4 k2 g- E# './MAKEALL'! O+ l9 g0 g1 k# c' {/ j
#
1 J/ i: `# \4 d# Command line 'O=' setting overrides BUILD_DIR environent variable. #命令行'O='设置会覆盖环境变量BUILD_DIR的设置
/ g3 @0 f. c+ v2 Y#
% P: d9 J5 w5 {% M7 d/ `! w# When none of the above methods is used, the local build is performed and #如果都不采用上面两种方法,那么目标文件最终要存放到源码顶层目录,也就是U-BOOT顶层目录; F/ G7 A; y' B* t7 \/ ~' }
# the object files are placed in the source directory. w. U. Q8 @0 d# @" E6 L' h
#
#理解了上面一段英文,这里就不难理解了
6 Q1 O# u2 K2 x- m& S; D" z#方法1
ifdef O #如果变量'O' 已经被定义过* t5 X0 _3 ^* O" |
ifeq ("$(origin O)", "command line") #如果变量'O' 在命令行中定义过
: ?9 K7 @+ w, o' E1 Q3 L! w3 HBUILD_DIR := $(O) #就把变量'O' 的值(目标文件存放目录)赋给BUILD_DIR0 t) |6 i; V) d. e8 N) Z
endif
) b' a& A9 E8 ^, p2 h7 nendif
" o p- } q$ w
#方法2, O1 m- e- a o' j& y
ifneq ($(BUILD_DIR),) #如果变量BUILD_DIR不为空,即环境变量BUILD_DIR 被定义过
/ n& C; p* G, A! l/ W8 e8 bsaved-output := $(BUILD_DIR) #那么把它的值赋给saved-output
# Attempt to create a output directory. #生成一个输出路径,即目标文件存放目录BUILD_DIR
' e( L4 A; k: k' }. N& g$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
#shell [ -d ${BUILD_DIR} ] 是什么意思?是不是生成一个目录的意思?
# Verify if it was successful. 测试目录是否创建成功% T! }& q% H5 @4 O& D. Q* h
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) #这又是什么意思,说明对shell还不够理解!4 t; w, J4 A: C* Q
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist)) 2 t' z* z+ h' n- Q5 m% o4 Z
#这里用了一个if函数,意思是如果如果$(BUILD_DIR) 非空,则什么都不执行(返回空),否则执行error函数,输出错误信息
% _: Z7 {- Z% H# x Mendif
# ifneq ($(BUILD_DIR),) #意思是:如果没有定义目标文件存放目录8 E5 g% F1 k. C/ R- }9 t
#Makefile中定义了源码以及生成目标文件存放的目录,目标文件存放目录BUILD_DIR可以通过make O=dir指定。如果没有指定,则设定为源码顶层目录。0 ^ ?, l3 n" U4 b; }6 c) t
#一般编译的时候不指定输出目录,则BUILD_DIR为空。其他目录变量如下:# P: Q- u- v Z1 ^8 K; K
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #如果$(BUILD_DIR)不为空,则返回$(BUILD_DIR),并赋给OBJTREE,即自己定制的目标存放目录
% V. G, I" F) V5 [SRCTREE := $(CURDIR) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE 1 m9 r! B' [1 f u1 M
TOPDIR := $(SRCTREE) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE
3 |% f% x4 U% i# w1 k0 O9 ?& P2 z% ?LNDIR := $(OBJTREE) #存放生成的目录文件/ g8 Z& y3 O% t# p
export TOPDIR SRCTREE OBJTREE
* |; n( h" B# F! ~. G; ?
2 J' N) W# d! XMKCONFIG := $(SRCTREE)/mkconfig #MKCONFIG指向源码所在目录(U-BOOT顶层目录)下的mkconfig配置文件
7 d" s n; c! h; ^2 Fexport MKCONFIG
#在编译UBOOT之前,我们先要执行:
! H1 L |. Y# R+ S7 N#make smdk2410_config
1 w$ P, q1 ?- O- U" v#从本Makefile的下文可以判断出smdk2410_config为Makefile的一个目标。& g. [6 Z/ {; A8 h- t$ j
#smdk2410_config: unconfig的意思是为smdk2410开发板建立一个编译项。
$ t6 M5 B4 M, k. z9 x#显然,执行#make smdk2410_config时,先执行unconfig目标(不指定输出目标时,obj,src变量均为空),unconfig下面的命令主要任务是清理上( z( E! E7 _) R6 v/ s; Q* p
#一次执行make *_config时生成的头文件和makefile的包含文件。3 [% R9 l1 D6 d' x; `
#主要是include/config.h和include/config.mk' f5 _( }- ~$ E7 m; H! P* i$ r
#然后执行命令: @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0. r5 w6 h; Q( B, k
#arm 表示CPU的构架是基于ARM体系的* C! T4 m, L8 ]! U: A) M
#arm920t 表示CPU的类型是arm920t
" Q3 n8 n- M% D$ f! b#smdk2410 表示开发板的型号* T1 w9 }1 ?& c( N. K
#NULL 表示开发商或者经销商的名称,这里为空* _1 N+ }+ ?9 m
#s3c24x0 表示基于S3C2410的片上系统
n# @+ [7 U7 f2 L#MKCONFIG指向UBOOT顶层目录下的mkconfig脚本配置文件,后面五个字符串是传入的参数(好像$(@:_config=)也是一个参数)。
- }: K( I. ~1 a; W% v+ }5 @3 J& O#下面来分析一下mkconfig这个脚本配置文件,点击链接:
% Z! }( D. {& `. S' t, C) P' Shttp://zqwt.012.blog.163.com/blog/static/120446842010325102158182/
. s3 v3 S# _! Q* W+ E: o( u2 T& V
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时
( m, |9 ~: w8 E( E' C, L9 mREMOTE_BUILD := 1 #定义变量REMOTE_BUILD := 1 这个变量算是一个flag吧4 p! T! g$ U' ^1 S$ M' g
export REMOTE_BUILD6 |6 Q& E4 a; q8 I7 x
endif
# $(obj) and (src) are defined in config.mk(顶层目录下) but here in main Makefile
0 \' X5 d- N3 c5 S4 z. L) t# we also need them before config.mk is included which is the case for, `% _) Y0 @" Q; s7 x
# some targets like unconfig, clean, clobber, distclean, etc.
2 w: d3 b6 I7 O( h" r# $(obj) and $(src)都被定义在顶层目录下的config.mk脚本配置文件里面,6 c4 ]. y0 ~. [- y# x; |6 U( k4 ~, m
# 但是在这个主Makefile里面,我们同样需要他们,
0 N1 s( ?1 {* \1 C1 D# 因为在主Makefile文件包含config.mk之前,$(obj) and $(src)偶尔地会成为这些目标的case:" q: ~* z) X! G( ~* W- {% ]9 s
# unconfig, clean, clobber, distclean, etc
! V3 B, ^' c' ~
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时
$ Y1 b( M' W6 Mobj := $(OBJTREE)/ #定义变量obj,让其等于目标存放目录0 d8 f9 ]9 w$ Z$ _4 h7 q; _
src := $(SRCTREE)/ #定义变量src,让其等于uboot顶层目录
' U) ?$ l9 q3 R zelse: W; M# Y0 ?1 a. I
obj := #否则,这两个变量都定义为空
$ q3 }% h. `" j }) q6 g) Osrc :=
. C, F6 V" e9 [endif
, F3 g' _, H1 Yexport obj src
+ B5 E% Y* Z2 r {9 p
) m. F& _5 p9 w! P0 j9 q! d; j# q' J/ k! R1 _# J i% X0 u
#########################################################################
6 ]& u! ~/ u+ z+ x# P* ]8 E
W* r7 q0 F0 e# `% h; P
4 o) L' c1 u; z5 }2 s6 s9 W* @$ A
ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)) #这句话让人费解!! t% A) N9 [ `, H- P
# 通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展。
) `/ z( M8 z( h1 S. S# 如果您需要在这些场合扩展通配符,您应该使用函数wildcard,格式如下:1 f) H$ U1 m& X8 j" p4 q4 Q
# $(wildcard pattern...)
; L1 R6 O) d$ c# load ARCH, BOARD, and CPU configuration8 D. n" v/ W0 w
# 加载ARCH, BOARD, and CPU 配置7 f. G- ?+ a4 I
include $(OBJTREE)/include/config.mk # 这时候,开始包含/include/config.mk的
9 w; L0 ~: L5 i# cexport ARCH CPU BOARD VENDOR SOC
+ J! C% R1 R( m3 n0 u#指定交叉编译器前缀6 m$ A) Z0 \0 @: x
ifeq ($(ARCH),arm)
- W5 C* b# e7 A; pCROSS_COMPILE = arm-linux-
- D! R' k+ b1 r( w. l) \ x* I2 q#这里你可以把交叉编译器的安装路径加到arm-linux-之前,比如你的交叉编译器安装路径是/root/u-boot/usr/local/arm/3.3.2/bin/
( q; u8 Y$ g: m' N$ g: u% c, X#你可以这样定义CROSS_COMPILE = /root/u-boot/usr/local/arm/3.3.2/bin/arm-linux-
' e7 W: ^" C$ x#这样一来,你在终端进行编译的时候就不用指定CROSS_COMPILE=arm-linux-了# [" T- O9 m0 G8 [- t
#但请注意:在编译内核的时候,交叉编译器必须安装在/usr/local/arm下,否则会发生错误!!!!!
6 v& M$ `- B/ E* qendif
export CROSS_COMPILE
6 h5 H) M; P* N5 ~: p3 c/ ~% J% I( v4 N: a" Z N3 e
# load other configuration 加载其他设置,这里是包含顶层目录下的config.mk配置文件,这个文件主要做了三个工作:
" M4 J* M3 f# l- ?# 1、定义了交叉编译器 2、定义了编译选项 3、定义了编译规则1 `8 V* e6 b2 M- ^ M; i
# 对本文件具体的分析,请查看链接:
$ K& }! \' h2 W1 g1 }+ H6 n& whttp://zqwt.012.blog.163.com/blog/static/12044684201032541139914/
include $(TOPDIR)/config.mk
#########################################################################7 L: @% `% x; _7 E
# U-Boot objects....order is important (i.e. start must be first)
7 V% i M5 Y- J5 i# uboot目标...书写顺序很重要,比如start.o必须排在第一位
* i# y! p7 v, C% _/ L' I#########################################################################
! o4 r2 C5 b. J C4 x7 fOBJS = cpu/$(CPU)/start.o 3 S' J/ T' ]6 c, k4 w9 F
#start.o必须放在目标文件的第一位,因为uboot执行的第一段代码就是start.S0 Y" o6 s2 w8 A) S0 f! Y& b
#具体原因可以查看链接脚本/u-boot-1.1.6/board/smdk2410/u-boot.lds,点击连接:
* T! ]) b8 x5 g) {8 Bhttp://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
& o+ ?/ w" e& s7 @! k
.....................................
0 ~0 m9 ]" ~: [1 z* d6 U3 K
OBJS := $(addprefix $(obj),$(OBJS)) #这句的意思是把目标文件存放路径以前缀的形式加到start.O之前,然后再赋给OBJS
% e j( g: i3 g* g- Y7 f
#以下是编译UBOOT需要的库文件
* U* n! ^* \0 I) C; A8 q: qLIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a # 严重平台依赖的
LIBS += cpu/$(CPU)/lib$(CPU).a # 严重平台依赖的
ifdef SOC
* j8 ~# z& m7 o9 KLIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a # 严重平台依赖的0 G1 Y, b: D& m- E- V8 Q: v
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a # 严重平台依赖的
5 Y* T& e g; f8 P+ X% H% u: T; s
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
7 t( y# E& V/ _6 w3 A! v- D fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
6 h! w( e# g' `* _4 i& T ELIBS += net/libnet.a
- I% Y: d" c8 `: E4 \) GLIBS += disk/libdisk.a
7 H8 j+ i( N( r1 vLIBS += rtc/librtc.a" p+ A! _" F: _/ H6 l8 p0 ?
LIBS += dtt/libdtt.a1 C, G: O4 c2 ^3 U5 h" p
LIBS += drivers/libdrivers.a
! N) |* M8 M/ c5 oLIBS += drivers/nand/libnand.a
- [3 w$ f" q& q) H0 c/ I) jLIBS += drivers/nand_legacy/libnand_legacy.a
( f3 ~5 W3 i1 iLIBS += drivers/sk98lin/libsk98lin.a
1 I* ?7 D% z W4 @* l+ x2 I% BLIBS += post/libpost.a post/cpu/libcpu.a
2 x2 Q3 G/ b' b' j6 L: O& GLIBS += common/libcommon.a' q3 A* ?/ j9 I
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) # 这是一个伪目标
#根据所生成的include/config.mk文件定义的几个变量ARCH, CPU, BOARD, SOC,我们可以1 T$ a- X: f; E2 l- B; r: h" y
#确定硬件平台依赖的目录文件。smdk2410平台相关(依赖)目录以及对应生成的库文件如下:
4 {4 v! \% ~& ?! w#board/smdk2410/: 库文件board/smdk2410/libsmdk2410.a G7 H! e; s: u z
#cpu/arm920t/: 库文件cpu/arm920t/libarm920t.a5 }8 _ `, t" u% j
#cpu/arm920t/s3c24x0: 库文件cpu/arm920t/s3c24x0/libs3c24x0.a t7 A; |- q. ^, ^
#lib_arm: 库文件lib_arm/libarm.a
' G- v. p1 g5 }6 i4 f$ {, n#include/asm-arm: 头文件& c; R5 N$ J8 p$ d
#include/cnofigs/smdk2410.h:头文件
# Add GCC lib8 \5 e* F7 {3 l) V5 ?! h
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
# The "tools" are needed early, so put this first6 I1 Z% B: j& b
# Don't include stuff already done in $(LIBS) 不要包含已经在 $(LIBS) 中的任何东西7 S& f, ^! w% I% t& ~- }: }
#" D9 v: e5 s5 _6 O
# 伪目标SUBDIRS:用于执行tools、examples、post、post\cpu子目录下的make文件
- P! M \5 p2 ?SUBDIRS = tools \& T) s1 \4 D% k4 w6 [8 J; K
examples \4 k. ~8 c/ t: Q) t* c2 d! b9 T8 ?
post \
( i" t; O! }$ v* B post/cpu/ v: z l) ?( D6 r5 ^8 U! D" C
.PHONY : $(SUBDIRS)
ifeq ($(CONFIG_NAND_U_BOOT),y)7 v) h$ Q: G$ j& Z
NAND_SPL = nand_spl
6 s4 N, h' C) ~$ L/ `: S$ mU_BOOT_NAND = $(obj)u-boot-nand.bin
6 `% d: T: x5 B ~- m/ x' Wendif
__OBJS := $(subst $(obj),,$(OBJS))& H1 G+ n r" X1 I$ v
__LIBS := $(subst $(obj),,$(LIBS))
#########################################################################
1 P1 X9 i0 P$ q) l; o#########################################################################
0 d5 \* J6 j5 d9 I
9 t1 E$ j! s7 p# ]#这里是最终要生成的各种镜像文件u-boot.hex、u-boot.srec、u-boot.bin、System.map、u-boot.img, v; L& L0 B8 |/ \
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
' |8 F9 e4 s/ t( f2 s4 @all: $(ALL)0 _9 \( h1 y4 f; u4 f
$(obj)u-boot.hex: $(obj)u-boot6 F1 K% z* F; I; ^0 t" }. u' W( L
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ # $<,$@ 分别表示使用该规则的源文件和目标文件
$(obj)u-boot.srec: $(obj)u-boot
* i+ r, j$ a; m. p3 z5 G$ h $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
, y9 h1 U4 D6 E0 y( f8 X $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.img: $(obj)u-boot.bin# M3 Z. C6 p; ]
./tools/mkimage -A $(ARCH) -T firmware -C none \4 K' b% ?' Q7 e
-a $(TEXT_BASE) -e 0 \& _3 c6 e% ?9 z7 s' c' t& d
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
# }/ X0 t- x1 s% q0 y/ Y sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
M- i3 v( G8 A0 Y5 K9 Z -d $< $@
$(obj)u-boot.dis: $(obj)u-boot
3 D1 |! f% r) I; f7 L. Z $(OBJDUMP) -d $< > $@
! r8 l0 A+ {( W3 k( `* H2 C
#此处生成的是uboot的ELF文件镜像( ~5 u( N/ T- Y& I- T: c
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)( J# ~# @" O: k4 q# t
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
+ x: E ]2 e, i% L' v cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \( Y) i# F' k2 l+ ^+ Y% U/ a o3 J
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
9 ?8 ?3 v! R0 }, z -Map u-boot.map -o u-boot
; |, N: z$ x6 O) C1 `5 M#依赖目标$(OBJS),也就是cpu/start.o
1 Q) _5 z7 q3 X$ @, O' }$(OBJS):
* J% m' d o7 `* l $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
1 e+ h' w2 g1 F- h+ x* }* m/ Z
3 r. L! Q. j( k: t+ `( d; a#依赖目标$(LIBS),目标很多,都是每个子目录的库文件*.a,通过执行相应子目录下的make来完成
$ C& e& g3 e% Z) |$(LIBS):% R- [. k, U% J7 m6 d3 b
$(MAKE) -C $(dir $(subst $(obj),,$@))
4 L+ q: n# @* U4 l, z 4 L3 ?1 A8 }7 @6 r% [. D$ z1 T
#这里解释一下这个makefile函数 $(dir names...)
) @8 ?8 t! J1 e#抽取‘names’中每一个文件名的路径部分,文件名的路径部分包括从文件名的开始到最后一个斜杠(含斜杠) L2 e5 o2 }8 | H$ t4 x
#之前的一切字符。如果文件名中没有斜杠,路径部分是‘./’。如:
5 d2 L. h6 w2 f+ F& _#$(dir src/foo.c hacks) F3 v5 Q! r, E9 F1 r
#产生的结果为 ‘src/ ./’。
. |. B) `; q( F! }
$(SUBDIRS):
$ L- N' c# P: A: _ $(MAKE) -C $@ all
$(NAND_SPL): version% Q" _" u; Y$ n. y$ b
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin
% ]) G- `/ R5 ?3 J f- s* r cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
! H4 p2 f/ c0 P5 M+ A4 b#依赖目标version:生成版本信息到版本文件VERSION_FILE中. _# f+ i: K% w6 M7 E/ r
version:
) Y+ ~* Q5 \2 p( x; ]0 p9 T @echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \
5 c8 ]: h& g6 E; p3 Y% b/ d3 S echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \' q1 ]0 `4 r8 _; m, q! P
echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \4 h. u1 T, Y5 z/ L/ G
$(TOPDIR)) >> $(VERSION_FILE); \# Z7 @% d5 U8 r$ z
echo "\"" >> $(VERSION_FILE)
gdbtools:
1 ^! j3 t3 J. n! P+ j) t; U $(MAKE) -C tools/gdb all || exit 1
updater:
8 a! c5 a0 Q I* ^6 N $(MAKE) -C tools/updater all || exit 1
env:
& _. ^; Z& z" d- B; d% a $(MAKE) -C tools/env all || exit 1
3 c) O, c7 W! T u0 I4 N0 H
0 _9 c8 h/ D: _3 ~8 Q& c#依赖目标depend:生成各个子目录.depend文件,.depend列出每个目标文件的依赖文件。& s" b% b* R$ n" d/ C# {! Z
#生成方法:调用每个子目录的make_depend) I- ?8 X3 \& e \; C) J
depend dep:1 z7 ?$ d. k3 c; C% e0 \* _ i# l1 @
for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
( g8 s; I5 K7 w6 z" M
tags ctags:
$ H) U* @/ K: R" Y% L# B ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \: O1 j6 Y% V- T9 f
lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
6 I) }. ?+ L# x! _( Y ` fs/cramfs fs/fat fs/fdos fs/jffs2 \
! `1 X, q% B% K$ g3 W7 c. h6 y net disk rtc dtt drivers drivers/sk98lin common \) |) O O9 _1 m8 ^' [
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
etags:, x! w: H5 r- U, T; F. C6 X
etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \
# o! P) i- b; }/ B& P lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
: t8 N5 i- t/ M: J8 W fs/cramfs fs/fat fs/fdos fs/jffs2 \: p% c6 t4 k ]
net disk rtc dtt drivers drivers/sk98lin common \7 `) {* m7 }0 D( z
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
$(obj)System.map: $(obj)u-boot
# f: ~- I( @6 `+ Z @$(NM) $< | \6 ?( g4 [, M1 d C) @2 e
grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
; d4 u( W7 d* G2 C- p sort > $(obj)System.map
9 I4 P" k1 x8 M/ K% h- u5 Z
' |: n+ d8 G. X% ~
#########################################################################
" X+ _9 D/ O/ @else# v2 W' U3 \( r8 O+ G/ e/ F8 i" L
all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \
7 X1 k# g2 ?2 z! {# n$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \, Q" ]9 }8 s q8 \8 r
$(SUBDIRS) version gdbtools updater env depend \
) k- W( k0 @5 E" U6 f) f6 i3 [# mdep tags ctags etags $(obj)System.map:; ^( x9 @% c A
@echo "System not configured - see README" >&21 O2 J% C' H5 m
@ exit 12 d5 H+ j/ r3 k! D9 w, T+ l; E
endif
.PHONY : CHANGELOG
5 ^ E; \+ _3 R8 oCHANGELOG:$ ?; o @" S4 U( @ Y
git log --no-merges U-Boot-1_1_5.. | \! g, C% w' u- [# L2 ?- Y8 k6 K) ]
unexpand -a | sed -e 's/\s\s*$$//' > $@
" Y; k& c2 `' ]#########################################################################+ O- q) H- m7 n' m
# 这里就是我们所谓的unconfig,应该比较熟悉了!# I& w* q P- r6 m% {
# 很明显,它所做的工作就是清除上次生成的include/config.h和include/config.mk G7 f9 x# K" A, i2 G6 e
# 以及开发板目录下的一些临时配置文件! K" Z) o- a3 g |
# unconfig:. }/ H3 N* ~1 ?- E, [
# @rm -f $(obj)include/config.h $(obj)include/config.mk \
@0 L1 y6 W' x$ v3 V, N% R' [# $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
: X3 [( ], s" d8 P( e( q#########################################################################
9 K( d- F- a6 U: B% M# a................................
) C1 e; u8 d( H* a. K0 `smdk2400_config : unconfig
, I" C! o: R2 p& o" t0 S @$(MKCONFIG) $(@:_config=) arm arm920t smdk2400 NULL s3c24x0
- o5 D$ h5 u9 h; @: g
3 l* [( ]7 R& J% Y) d................................
smdk2410_config : unconfig
- @; @- [( F1 N- d @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
( m: L' f5 h) G; y#我删了一部分内容,那些几乎都是各种不同板子的*_config,也就是目标的定义。
最后总结一下,当然这里也参考了前辈们的许多宝贵经验,顶层Makefile的主要任务就是组织整个u-boot工程的编译,概括可以分为一下几个步骤:
1、首先通过执行make *_config传入$(@:_config=), ARCH, CPU, BOARD, VENDOR, SOC参数(一共六个参数但不7 W9 G& f% Q5 m6 e* u2 X
; n* x/ w: W3 I, c 一定同时存在),给mkconfig。
2、mkconfig接收到传递过来的参数后,将include头文件夹相应的头文件夹链接好,生成config.h
3、然后执行make分别调用各个子目录的makefile文件,以生成所有的obj文件(包括start.o)和obj库文件*.a。
4、最后,通过链接器把所有目标文件链接起来,生成uboot镜像。不同格式的镜像都是调用相应工具,经
由elf镜像间接或者直接的生成的。