VERSION = 11 V" O$ [- j, O
PATCHLEVEL = 1
2 {! o# S; [6 |' K- bSUBLEVEL = 65 d: N7 p% j2 S, T0 A1 @
EXTRAVERSION =
* ]8 u4 T8 O! v. WU_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)! h: m2 U W7 c8 Q9 ^1 p2 g' r9 o
VERSION_FILE = $(obj)include/version_autogenerated.h #版本文件
9 X' V" q: z. m3 M# uname 命令将正在使用的操作系统名写到标准输出中
1 |7 U" W8 i1 x# W% c# -m 显示硬件运行系统的机器 ID 号
# 定义变量,HOSTARCH里面存储的是机器ID号,即主机架构类型
$ T2 I6 v. j0 y& l2 Y4 |- NHOSTARCH := $(shell uname -m | \ #可以把shell脚本写到makefile里面,这是make中的shell function, 相当于shell中的命令替换。1 i/ b- x& i" Y3 j# u4 K# g
sed -e s/i.86/i386/ \ #shell uname -m 获得机器硬件名称
% g4 J) @, h! D1 p -e s/sun4u/sparc64/ \ #sed -e s/arm.*/arm/ 的意思是把前缀为arm的所有模式替换为arm。结合前面的uname命令来理解就是:
4 b ^4 P v5 F6 c) ^! k" j -e s/arm.*/arm/ \ #把uname -m的结果(主机架构类型或者称为机器ID号)通过管道传递给sed命令,然后把前缀为arm的所有模式替换为arm。
6 Y! |+ U ]3 L' u -e s/sa110/arm/ \ #sed的语法:sed [ -n ] Script [ File ... ]/ m$ L3 k( ^2 E; i
-e s/powerpc/ppc/ \ # sed [ -n ] [ -e Script ] ... [ -f ScriptFile ] ... [ File ... ]
* u) o, Y @/ ^ -e s/macppc/ppc/) #sed 命令根据编辑脚本,去修改指定的 File 文件(这里file是作为一个输入参数的)的行,并将其写到标准输出。2 E% @, r4 Y4 u
#sed 命令包含很多功能,用于选择要修改的行(请注意,sed是针对行进行操作的),并只对选择的行作更改。
8 l! Y6 G, g8 x' L! o: Q #sed 命令使用两个工作空间来保留修改的行:保留选定行的 "模式空间" 和暂时存储行的 "保留空间"。
( K) v& d8 v, d! R) e1 q$ k #这里所谓的编辑脚本是由单独的子命令构成的,每个单独的行上对应着一个子命令。sed 子命令的一般格式如下:[address-range] function[modifiers],即:[地址范围] 函数[修改符]
: g" z B/ x/ I" M6 _# J2 a% E #sed 命令通过将一个输入行读入模式空间,依次应用所有的 sed 子命令(这些子命令的地址选择了该行),
0 a/ R. A0 `. M5 ^8 m4 e' @ #并将模式空间写到标准输出来处理每个输入的 File 输入文件(file就是输入参数)。然后清除模式空间,并对输入的 File 中指定的每行重复该过程。
$ o% y: m- m& j2 Z6 H #一些 sed 子命令使用保留空间来保存后继检索的所有的,或部分的模式空间。
1 N* i, a) I4 c; m #当命令包含地址(行号或搜索模式)时,该命令只会对被寻址的行起作用。否则,该命令适用于所有的行。' b6 K7 n+ G$ C+ V' {9 U1 N
#注意,这里的参数"-e"的意思是:使用 Script 变量作为编辑脚本。如果你只使用一个 -e 标志并且不使用-f 标志,则可以省略 -e 标志。
$ s8 |- n& l' c4 W: G #注意,这里的 "sed -e s/arm.*/arm/"表示把前缀为arm的所有模式替换为arm,也就是sed s/pattern/replacement/flags
$ o' B2 e) @: M8 V4 [ } #用 replacement 字符串代替在模式空间中首次出现的 pattern 参数。除了空格或换行符,在 s 子命令之后显示的任何字符都能代替 /(斜杠)分隔符。
. v. r: K) h v* Q7 M1 k: r4 F( I
3 ]& T5 q' i2 [; e. u* t
#uname -s 表示:显示系统名,标志缺省为开,即uname命令不带任何参数的输出和加参数-s输出相同,即Linux4 H5 ~# _' k* Z1 c
#tr是一个shell命令,这里 tr '[:upper:]' '[:lower:]'的意思是把管道中的Linux 中的大写字母L 转换成小写字母l- W) _* `2 S% \% W+ @
#下面这句话的意思是定义变量HOSTOS,HOSTOS里面存放的是主机安装的,并且当前正在运行的操作系统。
$ i: v3 o0 j6 L8 I% i) nHOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
+ H& N: K2 a4 s/ i! Q: S7 y7 @ sed -e 's/\(cygwin\).*/cygwin/') # 这一句的意思是检测出主机安装的,并且当前正在运行的操作系统名,并把这个系统名中的大写字母转换为小写字母, % ?; E9 M9 J1 `! K2 x/ e4 t
# 然后在通过sed流编辑器匹配所有的,这个系统名中出现的"\(cygwin\).*"模式,然后再用"cygwin"模式替换。
4 e6 }* U9 }9 S. F! v3 \' @#export HOSTARCH HOSTOS 的意思是输出两个makefile变量HOSTARCH HOSTOS
export HOSTARCH HOSTOS
# Deal with colliding definitions from tcsh etc. 用来处理来自tcsh的互相冲突的定义等等
. S2 p% X1 L! x! m9 i# 一般来说,shell可以分成两类。第一类是由 Bourne shell 衍生出来的包括 # b6 @& o" ]& c2 y
# sh,ksh,bash,与zsh。第二类是由 C shell 衍生出来的,包括 csh 与 % g' F! z$ |+ G0 y. J
# tcsh。除此之外还有一个 rc,有人认为该自成一类,有人认为该归类在Bourne shell。
VENDOR= #开发商
#########################################################################4 w, X2 P0 w4 Z/ P- Q0 X# b8 h ^
#
) j' w+ x1 L% B1 J% ] P5 k5 d1 D# U-boot build supports producing a object files to the separate external! U4 z3 j, a2 f6 r: V. M
# U-boot 的编译过程可以支持向一个自己定义的路径生成最终的目标文件
, A7 ]$ w3 u' Z4 T4 Z! t' @# directory. Two use cases are supported:( R1 F/ N0 |+ u: v5 k( d) j
# 这里提供了两种用法:' Z' O; n% w) V; U
#
# T3 A5 m4 |5 P( @8 i. k V! K- k' n# 1) Add O= to the make command line #第一种用法:通过在终端执行命令make O=/dir(即你指定的生成的目标文件的存放目录)
6 b$ ]# c7 A" J5 e( V# 'make O=/tmp/build all') y l: J+ g& Q0 E. |
#+ h& ^0 I' Q! L6 G
# 2) Set environement variable BUILD_DIR to point to the desired location #第二种用法:通过设置环境变量来指定目标文件存放目录,如下所示:1 \8 Q( V+ _/ w a1 t, i K4 D
# 'export BUILD_DIR=/tmp/build'
B" T% z) {' ~9 Z! \1 i+ }& V& h# 'make'
, q2 W+ H0 N: M2 B( E1 |#
% |/ R" V% R% K$ L$ x# The second approach can also be used with a MAKEALL script #第二种方法也可以写成一个MAKEALL脚本,然后执行MAKEALL,如下所示:
) Q% c5 h* E( y, r! H+ U$ ^ Q3 x# 'export BUILD_DIR=/tmp/build'" g' o! a0 Y- \- I. X
# './MAKEALL'
0 ^% `: H' |9 |" i- U0 a#2 N- U0 `1 n, i5 I7 |
# Command line 'O=' setting overrides BUILD_DIR environent variable. #命令行'O='设置会覆盖环境变量BUILD_DIR的设置: l2 G1 u! E1 j
#
) u0 n: g( M) J# h8 L# When none of the above methods is used, the local build is performed and #如果都不采用上面两种方法,那么目标文件最终要存放到源码顶层目录,也就是U-BOOT顶层目录
* ^8 o2 p) `# x. b% r# the object files are placed in the source directory., `1 v6 u, |# A# T: c0 r
#
#理解了上面一段英文,这里就不难理解了
$ l% L6 b$ Z' u K: [#方法1
ifdef O #如果变量'O' 已经被定义过3 }% i" A( K' f- ]6 ?* M7 Q
ifeq ("$(origin O)", "command line") #如果变量'O' 在命令行中定义过" s5 j# u2 \( n4 Q% e9 z
BUILD_DIR := $(O) #就把变量'O' 的值(目标文件存放目录)赋给BUILD_DIR
( I: J; H8 w" ~endif8 O+ f/ t% [* i- ]4 F- B
endif
* r" N6 o2 f9 f5 [0 P$ }: D5 w#方法26 p. K5 X, m$ _1 D' F& ^
ifneq ($(BUILD_DIR),) #如果变量BUILD_DIR不为空,即环境变量BUILD_DIR 被定义过4 `+ W* }" [" n A; B
saved-output := $(BUILD_DIR) #那么把它的值赋给saved-output
# Attempt to create a output directory. #生成一个输出路径,即目标文件存放目录BUILD_DIR
0 ~0 `1 G* \, @# B$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
#shell [ -d ${BUILD_DIR} ] 是什么意思?是不是生成一个目录的意思?
# Verify if it was successful. 测试目录是否创建成功
1 [2 `6 Z# |. c* r- D1 a9 HBUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) #这又是什么意思,说明对shell还不够理解!
$ s, k; c/ O9 d+ t4 h6 ? q$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist)) ! p9 u( s2 y4 z$ o5 E
#这里用了一个if函数,意思是如果如果$(BUILD_DIR) 非空,则什么都不执行(返回空),否则执行error函数,输出错误信息
$ r# _% y( a; d- `7 Pendif
# ifneq ($(BUILD_DIR),) #意思是:如果没有定义目标文件存放目录
0 x5 |* {2 v8 B F#Makefile中定义了源码以及生成目标文件存放的目录,目标文件存放目录BUILD_DIR可以通过make O=dir指定。如果没有指定,则设定为源码顶层目录。. u7 T) v1 Z' e; P& U
#一般编译的时候不指定输出目录,则BUILD_DIR为空。其他目录变量如下:( n) K) q8 r" B
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #如果$(BUILD_DIR)不为空,则返回$(BUILD_DIR),并赋给OBJTREE,即自己定制的目标存放目录, G$ u- ` a8 N- P3 ~' C) P2 }
SRCTREE := $(CURDIR) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE ' l* \/ e( G: @" R
TOPDIR := $(SRCTREE) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE5 A5 t G- i9 {1 F8 j/ L+ w& b/ m* {
LNDIR := $(OBJTREE) #存放生成的目录文件5 i/ d8 w0 P/ H. [. N
export TOPDIR SRCTREE OBJTREE
) c+ O, p5 w7 X2 `4 Z: d& w
9 f7 C+ g h# t# [# K4 GMKCONFIG := $(SRCTREE)/mkconfig #MKCONFIG指向源码所在目录(U-BOOT顶层目录)下的mkconfig配置文件
9 y5 x. H6 N8 |7 l2 J1 K& D9 q0 bexport MKCONFIG
#在编译UBOOT之前,我们先要执行:
( ^- ^' H' n; M! K4 C" G" Y#make smdk2410_config& f: p, I, r1 i$ d0 Z& v4 [
#从本Makefile的下文可以判断出smdk2410_config为Makefile的一个目标。
: [# [1 \ _ n! n7 M. Y* g7 C#smdk2410_config: unconfig的意思是为smdk2410开发板建立一个编译项。, b% A" k/ \! _- V$ z/ L
#显然,执行#make smdk2410_config时,先执行unconfig目标(不指定输出目标时,obj,src变量均为空),unconfig下面的命令主要任务是清理上% s2 `, t' T. H- v7 w B5 i x
#一次执行make *_config时生成的头文件和makefile的包含文件。- ^5 r7 h, P6 g2 \
#主要是include/config.h和include/config.mk
+ O N- {- ]- V8 v- a#然后执行命令: @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0; z8 n) i, j- l7 m1 t
#arm 表示CPU的构架是基于ARM体系的8 }7 `0 a3 d3 n" C$ f( \, J7 N; |
#arm920t 表示CPU的类型是arm920t# q# [4 [! [8 A! G' t& ~
#smdk2410 表示开发板的型号2 b% P F% C% S* D* R' v
#NULL 表示开发商或者经销商的名称,这里为空) U1 {! P0 U2 o6 I, ~1 I8 i
#s3c24x0 表示基于S3C2410的片上系统, _- U. j) Y3 H E# j1 A1 {) \5 R
#MKCONFIG指向UBOOT顶层目录下的mkconfig脚本配置文件,后面五个字符串是传入的参数(好像$(@:_config=)也是一个参数)。4 V/ e2 H/ v; `) I
#下面来分析一下mkconfig这个脚本配置文件,点击链接:! R- }( K3 \# y# L, v C
http://zqwt.012.blog.163.com/blog/static/120446842010325102158182/
9 A: T: e, R" W3 c$ u; v! a
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时+ h+ i5 d& h$ b+ _
REMOTE_BUILD := 1 #定义变量REMOTE_BUILD := 1 这个变量算是一个flag吧+ ]2 w) H" J4 }$ k
export REMOTE_BUILD: A; U0 e! R# L, m4 p
endif
# $(obj) and (src) are defined in config.mk(顶层目录下) but here in main Makefile
# ^. Q6 A8 |* {7 }4 a# we also need them before config.mk is included which is the case for+ G; z% }; f! ~0 `
# some targets like unconfig, clean, clobber, distclean, etc.
: r9 a; T6 f* K' k# $(obj) and $(src)都被定义在顶层目录下的config.mk脚本配置文件里面,
$ i+ q) Y* N1 \* Q4 J ~. L6 v# 但是在这个主Makefile里面,我们同样需要他们,- G2 o( e$ q( B( p
# 因为在主Makefile文件包含config.mk之前,$(obj) and $(src)偶尔地会成为这些目标的case:+ |% e2 Q; L! _: ?2 b" M
# unconfig, clean, clobber, distclean, etc
. [% e$ w. E- C4 q0 O
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时& L( |0 |3 w' `: \
obj := $(OBJTREE)/ #定义变量obj,让其等于目标存放目录9 @8 u$ g, l9 H( `# ^# E) {/ G
src := $(SRCTREE)/ #定义变量src,让其等于uboot顶层目录
4 w2 i& n; E! L) \else' W4 t4 f3 n- {- u
obj := #否则,这两个变量都定义为空
% S, [# e6 | ]% e$ rsrc :=& `( \3 ?7 `4 s6 q$ D
endif
, T' O |+ \1 D9 Hexport obj src
/ X! q8 F9 K' w9 l6 J
n2 J8 i X5 S+ j! g2 _7 C/ ?1 z3 ]" Z2 F# a( U; J" @5 r
#########################################################################
, A/ s* q! r* q+ ?1 `$ j: Q7 _
0 u6 i) e- o! ~2 N9 g* C% ]: W
7 h& G8 s# G/ ?9 K" V
. Q+ |2 D5 E4 eifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)) #这句话让人费解!
$ n- x! }4 f/ D* \( ~# 通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展。! s) a9 C' M1 g+ z1 R+ i! [ K
# 如果您需要在这些场合扩展通配符,您应该使用函数wildcard,格式如下:
+ Q4 Z) T7 f- @$ S1 U9 N# $(wildcard pattern...)
+ P$ c4 D! y+ o
# load ARCH, BOARD, and CPU configuration9 n- ~ _1 d; b8 u8 e
# 加载ARCH, BOARD, and CPU 配置
. b q' C. n1 H7 a/ B/ Oinclude $(OBJTREE)/include/config.mk # 这时候,开始包含/include/config.mk的 ( j# U) b" x$ v% m
export ARCH CPU BOARD VENDOR SOC
* c* W- ~9 r- [% V9 e1 k#指定交叉编译器前缀* f% d5 m# x+ Q6 F/ z
ifeq ($(ARCH),arm)
/ ]8 h; |% k+ V* o# S; i9 Y( A8 V+ aCROSS_COMPILE = arm-linux-
$ ^& u; Z1 Y5 a% ], P+ _( r#这里你可以把交叉编译器的安装路径加到arm-linux-之前,比如你的交叉编译器安装路径是/root/u-boot/usr/local/arm/3.3.2/bin/
0 f9 z2 @9 G, N$ }9 F#你可以这样定义CROSS_COMPILE = /root/u-boot/usr/local/arm/3.3.2/bin/arm-linux-
! f( k* @# h' D3 g# e; S! x#这样一来,你在终端进行编译的时候就不用指定CROSS_COMPILE=arm-linux-了
$ P/ j% Q# y+ _#但请注意:在编译内核的时候,交叉编译器必须安装在/usr/local/arm下,否则会发生错误!!!!!& |8 N7 B5 N% R+ l
endif
export CROSS_COMPILE
: h; s. L8 l# w( n9 L/ W' i5 \
8 H5 V j+ \, B+ [. ~1 {: D3 D$ Y# load other configuration 加载其他设置,这里是包含顶层目录下的config.mk配置文件,这个文件主要做了三个工作:
9 H% _) j+ [4 [8 h3 B; N5 z8 H# 1、定义了交叉编译器 2、定义了编译选项 3、定义了编译规则; e5 E$ L- ~8 r; w8 l
# 对本文件具体的分析,请查看链接:
f) ~, Y. H/ v& L/ n: Shttp://zqwt.012.blog.163.com/blog/static/12044684201032541139914/
include $(TOPDIR)/config.mk
######################################################################### Y( q1 H/ }+ H7 A6 O
# U-Boot objects....order is important (i.e. start must be first)! |4 G5 y& T- ^$ D" z
# uboot目标...书写顺序很重要,比如start.o必须排在第一位
g! f1 H" ?( p/ L. [0 K& C$ Y#########################################################################0 ^+ N4 ^3 o# i7 G' r. o
OBJS = cpu/$(CPU)/start.o ( k# F5 Z4 _- C- B1 v" [
#start.o必须放在目标文件的第一位,因为uboot执行的第一段代码就是start.S
% M- C5 Z; {4 c2 f! a, ?#具体原因可以查看链接脚本/u-boot-1.1.6/board/smdk2410/u-boot.lds,点击连接:
4 ~5 D$ [( P( {7 mhttp://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
# R3 d4 \: C$ M8 T
.....................................
. h: P* |: k0 I; ZOBJS := $(addprefix $(obj),$(OBJS)) #这句的意思是把目标文件存放路径以前缀的形式加到start.O之前,然后再赋给OBJS
/ j( L6 O5 |' {2 ?6 S# ^; d+ C#以下是编译UBOOT需要的库文件* ~. T A) W* M
LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a # 严重平台依赖的
LIBS += cpu/$(CPU)/lib$(CPU).a # 严重平台依赖的
ifdef SOC5 R+ c9 y7 R; c2 S" R+ V7 X, S# P
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a # 严重平台依赖的2 }) ^& F8 d& a& O
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a # 严重平台依赖的
2 ]9 M. _: g4 m0 iLIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \9 ], ?! I/ Z. |$ e, n/ |, A& V
fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
( f Z2 c. i/ c" E6 Z2 R$ GLIBS += net/libnet.a
5 h# w/ t4 R6 [3 C; o) r5 PLIBS += disk/libdisk.a
& n) L, I4 i+ J' @LIBS += rtc/librtc.a
- X0 M7 y' o8 J4 M6 _; Z7 a' oLIBS += dtt/libdtt.a
) F9 ^6 M$ _$ g& [3 |LIBS += drivers/libdrivers.a: k4 u& x7 x$ i( @' P
LIBS += drivers/nand/libnand.a4 y% y2 F* ]1 v1 ?; r7 M1 |4 N* g- P
LIBS += drivers/nand_legacy/libnand_legacy.a
+ H" |% `" n, wLIBS += drivers/sk98lin/libsk98lin.a. n$ }4 e% Q9 X, R* d, r$ F" F% k
LIBS += post/libpost.a post/cpu/libcpu.a" u+ ?8 \# @/ ?: W; v9 q
LIBS += common/libcommon.a
4 d+ d8 Z: s% M9 `( }LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) # 这是一个伪目标
#根据所生成的include/config.mk文件定义的几个变量ARCH, CPU, BOARD, SOC,我们可以
+ P) B6 y8 m! A+ s0 s, G#确定硬件平台依赖的目录文件。smdk2410平台相关(依赖)目录以及对应生成的库文件如下:
9 f s$ t2 X- ^1 _6 F* c! @' r! E! e#board/smdk2410/: 库文件board/smdk2410/libsmdk2410.a. I* S( u* }# v9 W
#cpu/arm920t/: 库文件cpu/arm920t/libarm920t.a
2 j8 v. @) h8 Y' O0 q% ^5 s#cpu/arm920t/s3c24x0: 库文件cpu/arm920t/s3c24x0/libs3c24x0.a2 a3 P x8 Y \; D
#lib_arm: 库文件lib_arm/libarm.a
& N B! q. X% h#include/asm-arm: 头文件
- N- F* P& Q) X0 {9 R#include/cnofigs/smdk2410.h:头文件
# Add GCC lib
1 X/ g0 W P6 C7 Z( mPLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
# The "tools" are needed early, so put this first$ P1 }* K- P! E. ~+ H! {* w
# Don't include stuff already done in $(LIBS) 不要包含已经在 $(LIBS) 中的任何东西8 {' D7 T' F. v" Y2 @
#
X' L9 B. Y1 j8 K# 伪目标SUBDIRS:用于执行tools、examples、post、post\cpu子目录下的make文件8 W2 q/ C( Y& R' h' O/ {
SUBDIRS = tools \! M+ T: Z# s9 Q) q
examples \
! B8 _. [0 C5 Y8 L& f& I9 V post \- b# e$ |3 P. A" S
post/cpu! V' Z) |$ c Q' d+ X
.PHONY : $(SUBDIRS)
ifeq ($(CONFIG_NAND_U_BOOT),y)
5 x1 s" I+ Q& L i/ lNAND_SPL = nand_spl! @5 d) L7 |- ^
U_BOOT_NAND = $(obj)u-boot-nand.bin/ p9 }+ V4 ~9 f% h9 h: _
endif
__OBJS := $(subst $(obj),,$(OBJS))7 @7 Q% Z) Y q" L6 U
__LIBS := $(subst $(obj),,$(LIBS))
#########################################################################; w4 d* P/ k! q- Y5 M( |
#########################################################################
/ O7 m6 ]0 P) F: `; I) `
6 U3 _1 c+ c( l2 O#这里是最终要生成的各种镜像文件u-boot.hex、u-boot.srec、u-boot.bin、System.map、u-boot.img! d/ ?* \+ O; d
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)4 j! ^' N& j% Z3 r2 S! Z5 |# O
all: $(ALL)
& @2 D; U& Q, o' P6 {0 m+ L$(obj)u-boot.hex: $(obj)u-boot
' G. R) F/ s4 L. N: d $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ # $<,$@ 分别表示使用该规则的源文件和目标文件
$(obj)u-boot.srec: $(obj)u-boot # A1 u- v L& D, F: i/ r6 x: x
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot9 y4 G9 @" f( {" Z
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.img: $(obj)u-boot.bin
4 `9 K+ A- w! K ./tools/mkimage -A $(ARCH) -T firmware -C none \
7 e! {) W9 W8 p( r0 @; O. y -a $(TEXT_BASE) -e 0 \
" f* x* J G/ Z6 D2 O/ E- T0 I3 z -n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \% t+ U+ ~" P6 |* {; U) [. N
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
, c- R7 v- z- c, @0 } -d $< $@
$(obj)u-boot.dis: $(obj)u-boot) ]* A/ D) x2 ~, l3 Q
$(OBJDUMP) -d $< > $@
1 O8 M" b) q; s. d) H+ F
#此处生成的是uboot的ELF文件镜像
# ?! F/ x+ Y0 r, C$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)4 _* {/ F+ C5 M6 v* _6 O
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
6 g" E+ O( i! J. ^ cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \; T7 h9 C/ y3 {+ ^! s
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \* T6 |. K2 P, F; R; S' a% u
-Map u-boot.map -o u-boot
2 b# W H% x/ x/ g/ a( J
#依赖目标$(OBJS),也就是cpu/start.o5 h4 }* o5 g: A' C% p# G) F
$(OBJS):' V9 |. A, k+ e- \" k& }6 [
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@)) t( ?. {" t; K& G Z
h0 \: t' ~* s
#依赖目标$(LIBS),目标很多,都是每个子目录的库文件*.a,通过执行相应子目录下的make来完成
2 H1 I, y; ?& k2 u* [$(LIBS):
~: R, g. f5 _3 t $(MAKE) -C $(dir $(subst $(obj),,$@))- q+ d+ M1 @+ ^% q; \2 {- e; {
$ e# {: z. P7 J8 _7 S/ x) I#这里解释一下这个makefile函数 $(dir names...) 1 l, e5 _% _/ }5 H. ^
#抽取‘names’中每一个文件名的路径部分,文件名的路径部分包括从文件名的开始到最后一个斜杠(含斜杠)% l' p6 X$ z/ @% D
#之前的一切字符。如果文件名中没有斜杠,路径部分是‘./’。如:2 o9 j; y8 j3 F- S
#$(dir src/foo.c hacks)
8 } R, R' @2 O. T#产生的结果为 ‘src/ ./’。
4 }" _3 m: A9 ~ r
$(SUBDIRS):
+ ], C2 B3 O6 U! _; O7 a t $(MAKE) -C $@ all
$(NAND_SPL): version/ y) }" \; s0 i: w
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin3 Y8 m( I' |4 U6 v2 R- M9 r
cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
$ z4 a4 l0 F' x3 K# }
#依赖目标version:生成版本信息到版本文件VERSION_FILE中
' I/ S* x/ C$ C( J5 {8 mversion:/ q% F4 ^4 E) q- q9 g
@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \. Z; e: J4 H1 @2 K, _) g- U
echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \
( g4 V( c6 y0 Z" A echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
: A7 p( V& D% O" i S $(TOPDIR)) >> $(VERSION_FILE); \
6 ?+ W4 K6 e2 I8 [3 b% Y4 N echo "\"" >> $(VERSION_FILE)
gdbtools:( U8 Q, I& a3 Z m0 @) |& W. b$ C1 f
$(MAKE) -C tools/gdb all || exit 1
updater:( p& l5 X0 x) r; O% }% R) i) W' h
$(MAKE) -C tools/updater all || exit 1
env:* W+ o H+ \! q7 ~& B+ k
$(MAKE) -C tools/env all || exit 1
# V# `0 A4 ?4 t! g
( f" g8 A7 E% M; P0 I
#依赖目标depend:生成各个子目录.depend文件,.depend列出每个目标文件的依赖文件。
, M0 _8 w/ k# p#生成方法:调用每个子目录的make_depend) p5 j5 o S* r
depend dep:
. X% f& o% W( b! | for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
" l/ y; a% I/ wtags ctags:2 j% P) b. J# |5 Y
ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \
* j( s' K6 \/ E+ f3 Z$ V" m0 ` lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \0 H( v. p$ \+ @8 x; i4 k
fs/cramfs fs/fat fs/fdos fs/jffs2 \
Q) W8 Q/ {9 d! N$ R net disk rtc dtt drivers drivers/sk98lin common \
; ]0 f$ [ Q2 t& I F( P* o" h0 H \( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
etags:) E7 z6 ?# K! U u4 L2 D
etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \) M, }* Q2 \9 n# Q* e& A7 s
lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
9 [3 w3 H: h4 P M- O2 W fs/cramfs fs/fat fs/fdos fs/jffs2 \, b8 N. `4 k7 j6 O1 E2 j( ]9 }
net disk rtc dtt drivers drivers/sk98lin common \. ^+ `, k+ Q7 e5 ~0 y
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
$(obj)System.map: $(obj)u-boot
C- X0 j8 y6 C. H0 ]$ u% Z1 w @$(NM) $< | \
* h; n H6 _ w: V. o t' K grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
* x% I9 k, n' Z& T* x sort > $(obj)System.map
8 [8 f, r! k a: ^8 ?
; N+ X, N) X0 E3 k! @# u7 @#########################################################################
8 e( J- X( [' V- N/ Gelse
- B: b8 J# K9 fall $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \1 o5 \; K$ h' P1 k
$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \
+ s0 N- k: m- P; T/ T& W$(SUBDIRS) version gdbtools updater env depend \. b0 Z9 ]0 W+ g' V( u
dep tags ctags etags $(obj)System.map:: Z2 q3 M2 m) R# v
@echo "System not configured - see README" >&2
3 L! X# k; y$ [6 D @ exit 1
0 P( [. B5 n% A- Aendif
.PHONY : CHANGELOG5 C+ E! Q: a; N" Y$ {& R: r
CHANGELOG:
. p O) B3 b, f5 F# g2 m2 K; Q, j git log --no-merges U-Boot-1_1_5.. | \# [9 R. [& X3 x7 @2 K- V9 y
unexpand -a | sed -e 's/\s\s*$$//' > $@
8 B$ X3 c! q; l; U7 R. z! D1 I1 P#########################################################################
6 H- C" [( q- n, k# e9 k# 这里就是我们所谓的unconfig,应该比较熟悉了!
+ f$ W/ A- A0 r n8 v# 很明显,它所做的工作就是清除上次生成的include/config.h和include/config.mk
1 ?0 B6 R5 [8 Q- r D: u2 n4 g# 以及开发板目录下的一些临时配置文件, b1 h: f$ |+ b) U' w( N3 F
# unconfig:& L4 u6 c _7 d1 L, O- I
# @rm -f $(obj)include/config.h $(obj)include/config.mk \
8 ?% Y7 m9 a% T6 S# $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
2 M: l8 y4 r% k" H6 z#########################################################################
+ ?$ i: P) X/ e3 B. Z
................................6 m# y6 T: d5 R1 T# j
smdk2400_config : unconfig
) C" ~ S+ V6 q, E4 \ @$(MKCONFIG) $(@:_config=) arm arm920t smdk2400 NULL s3c24x0
& C& O& O4 y/ G4 V 6 i* L0 F7 j" p: W0 o
................................
smdk2410_config : unconfig
4 n& [0 m4 P+ Z: m9 n% a @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
, D4 ~+ a) w- j( B) m& w, E0 I- @
#我删了一部分内容,那些几乎都是各种不同板子的*_config,也就是目标的定义。
最后总结一下,当然这里也参考了前辈们的许多宝贵经验,顶层Makefile的主要任务就是组织整个u-boot工程的编译,概括可以分为一下几个步骤:
1、首先通过执行make *_config传入$(@:_config=), ARCH, CPU, BOARD, VENDOR, SOC参数(一共六个参数但不
S3 p$ P- u( o6 t/ L, E 9 A/ @8 O6 {0 Q. J, o I
一定同时存在),给mkconfig。
2、mkconfig接收到传递过来的参数后,将include头文件夹相应的头文件夹链接好,生成config.h
3、然后执行make分别调用各个子目录的makefile文件,以生成所有的obj文件(包括start.o)和obj库文件*.a。
4、最后,通过链接器把所有目标文件链接起来,生成uboot镜像。不同格式的镜像都是调用相应工具,经
由elf镜像间接或者直接的生成的。