VERSION = 17 U' ]8 V8 p7 b* G
PATCHLEVEL = 1! K' y9 Y, O, }5 Q) h
SUBLEVEL = 65 g* T* _/ i6 m# I6 I6 g9 E
EXTRAVERSION =/ j( Q- c1 ?5 x) S5 Y8 t3 L
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
; R. b9 J9 _5 {1 A" y nVERSION_FILE = $(obj)include/version_autogenerated.h #版本文件
M8 C% a* _4 T- b9 d6 k# uname 命令将正在使用的操作系统名写到标准输出中
1 j5 X4 O$ l3 m5 H" S# -m 显示硬件运行系统的机器 ID 号
# 定义变量,HOSTARCH里面存储的是机器ID号,即主机架构类型
8 b/ B2 ^) X3 D: j* ?& p. `HOSTARCH := $(shell uname -m | \ #可以把shell脚本写到makefile里面,这是make中的shell function, 相当于shell中的命令替换。9 J# p& U% t% i& V) V. J
sed -e s/i.86/i386/ \ #shell uname -m 获得机器硬件名称8 V5 k: ~$ }. Y- i2 ?
-e s/sun4u/sparc64/ \ #sed -e s/arm.*/arm/ 的意思是把前缀为arm的所有模式替换为arm。结合前面的uname命令来理解就是:
. g/ N3 y; ?- ~" |; {% z -e s/arm.*/arm/ \ #把uname -m的结果(主机架构类型或者称为机器ID号)通过管道传递给sed命令,然后把前缀为arm的所有模式替换为arm。
9 m% |' @0 Y) V t0 w -e s/sa110/arm/ \ #sed的语法:sed [ -n ] Script [ File ... ]
" k* N, d& f2 U! k& D9 r- a -e s/powerpc/ppc/ \ # sed [ -n ] [ -e Script ] ... [ -f ScriptFile ] ... [ File ... ]! i: ?$ I* C& [, j
-e s/macppc/ppc/) #sed 命令根据编辑脚本,去修改指定的 File 文件(这里file是作为一个输入参数的)的行,并将其写到标准输出。
* C, w/ J4 K! v1 v/ r3 S #sed 命令包含很多功能,用于选择要修改的行(请注意,sed是针对行进行操作的),并只对选择的行作更改。
, V# U- b6 @0 c" P$ G! s' ^! Z' `- y #sed 命令使用两个工作空间来保留修改的行:保留选定行的 "模式空间" 和暂时存储行的 "保留空间"。
3 K3 ~% I7 c8 b& G5 ~5 ?6 g/ K #这里所谓的编辑脚本是由单独的子命令构成的,每个单独的行上对应着一个子命令。sed 子命令的一般格式如下:[address-range] function[modifiers],即:[地址范围] 函数[修改符]
( s6 n4 I! S! z( I1 Y #sed 命令通过将一个输入行读入模式空间,依次应用所有的 sed 子命令(这些子命令的地址选择了该行),
" X, ~' E5 ^7 q8 ^- b #并将模式空间写到标准输出来处理每个输入的 File 输入文件(file就是输入参数)。然后清除模式空间,并对输入的 File 中指定的每行重复该过程。
, y4 l- G u5 ~ #一些 sed 子命令使用保留空间来保存后继检索的所有的,或部分的模式空间。
8 L* y Z% J2 u& g. ^ #当命令包含地址(行号或搜索模式)时,该命令只会对被寻址的行起作用。否则,该命令适用于所有的行。! D1 N( w6 S% R: y& L$ L
#注意,这里的参数"-e"的意思是:使用 Script 变量作为编辑脚本。如果你只使用一个 -e 标志并且不使用-f 标志,则可以省略 -e 标志。! u& V" m1 k; H; H# _
#注意,这里的 "sed -e s/arm.*/arm/"表示把前缀为arm的所有模式替换为arm,也就是sed s/pattern/replacement/flags
4 ]: _! c l' x/ P1 z1 F4 H5 U #用 replacement 字符串代替在模式空间中首次出现的 pattern 参数。除了空格或换行符,在 s 子命令之后显示的任何字符都能代替 /(斜杠)分隔符。
. ?3 F* d$ _, [( ~7 ~
, t/ z; P" X3 U# b3 P- |2 z1 _
#uname -s 表示:显示系统名,标志缺省为开,即uname命令不带任何参数的输出和加参数-s输出相同,即Linux
d- ~7 G! b! g; L#tr是一个shell命令,这里 tr '[:upper:]' '[:lower:]'的意思是把管道中的Linux 中的大写字母L 转换成小写字母l
# o9 |, }# |3 \7 D) G0 m. W#下面这句话的意思是定义变量HOSTOS,HOSTOS里面存放的是主机安装的,并且当前正在运行的操作系统。; u6 T/ Q: y! l; H
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
l/ L7 J- R4 \' r8 p$ q4 g sed -e 's/\(cygwin\).*/cygwin/') # 这一句的意思是检测出主机安装的,并且当前正在运行的操作系统名,并把这个系统名中的大写字母转换为小写字母,
* C' V+ n7 g& L" C* Q # 然后在通过sed流编辑器匹配所有的,这个系统名中出现的"\(cygwin\).*"模式,然后再用"cygwin"模式替换。" o1 @5 [$ p+ T+ o, n- L7 n
#export HOSTARCH HOSTOS 的意思是输出两个makefile变量HOSTARCH HOSTOS
export HOSTARCH HOSTOS
# Deal with colliding definitions from tcsh etc. 用来处理来自tcsh的互相冲突的定义等等
; Q8 l* n1 P) j+ h/ n" L9 J) a$ I# 一般来说,shell可以分成两类。第一类是由 Bourne shell 衍生出来的包括
# d& Q; U7 S, C! J1 q* o/ C- Q# Q# sh,ksh,bash,与zsh。第二类是由 C shell 衍生出来的,包括 csh 与 1 R O4 a6 L* ?% a( |
# tcsh。除此之外还有一个 rc,有人认为该自成一类,有人认为该归类在Bourne shell。
VENDOR= #开发商
#########################################################################. B8 j* d' C2 X
#4 T O5 \. [$ A! v
# U-boot build supports producing a object files to the separate external$ l# C1 n4 M9 K
# U-boot 的编译过程可以支持向一个自己定义的路径生成最终的目标文件; i6 a8 P! W8 Z0 C6 [
# directory. Two use cases are supported:
5 z5 _; z# H* T4 y# 这里提供了两种用法:
4 Q4 T& X7 t: i' ~#
% _+ |7 l5 ^) u" r& F9 @) {# 1) Add O= to the make command line #第一种用法:通过在终端执行命令make O=/dir(即你指定的生成的目标文件的存放目录)9 a& y1 ~- }/ J
# 'make O=/tmp/build all'
4 z4 O( j9 U# b#% C# w. t8 a. l% z
# 2) Set environement variable BUILD_DIR to point to the desired location #第二种用法:通过设置环境变量来指定目标文件存放目录,如下所示:3 Y5 ^( N- y; j1 r6 R
# 'export BUILD_DIR=/tmp/build'/ A* \4 t3 Q2 [2 Y
# 'make'
7 E4 H9 M1 w3 U v8 x" S) R4 c! m' e& E#: o: e; i! r% B: }, E
# The second approach can also be used with a MAKEALL script #第二种方法也可以写成一个MAKEALL脚本,然后执行MAKEALL,如下所示:3 U4 y3 G3 s8 g/ s
# 'export BUILD_DIR=/tmp/build'& I7 l# }4 {$ M1 ?" Z
# './MAKEALL'
: N6 u2 ?4 c. `% G: E- }3 v& A+ n) G' B7 e#3 N0 F7 v: u2 Q( \! q# p
# Command line 'O=' setting overrides BUILD_DIR environent variable. #命令行'O='设置会覆盖环境变量BUILD_DIR的设置
f, p9 l" K! o s$ A#
. B2 K3 h, g/ ~# When none of the above methods is used, the local build is performed and #如果都不采用上面两种方法,那么目标文件最终要存放到源码顶层目录,也就是U-BOOT顶层目录, M$ S& b, k1 J2 a4 v; I \1 x+ X
# the object files are placed in the source directory.( C, J1 U" W/ E$ j2 m
#
#理解了上面一段英文,这里就不难理解了
; w1 m& B; d | S% u( k5 O! c#方法1
ifdef O #如果变量'O' 已经被定义过 v' L. W1 b4 a- [: W
ifeq ("$(origin O)", "command line") #如果变量'O' 在命令行中定义过# U2 x7 r; C, y. q
BUILD_DIR := $(O) #就把变量'O' 的值(目标文件存放目录)赋给BUILD_DIR
& s8 h* _+ ?: ?% hendif
- O4 O9 C6 \3 ^* o3 f6 ]5 Kendif
& m+ N$ Y2 O; p# \0 l1 b% B
#方法23 t. z8 a2 F8 F' k
ifneq ($(BUILD_DIR),) #如果变量BUILD_DIR不为空,即环境变量BUILD_DIR 被定义过; F* v$ p, |9 S( a! c' m& M
saved-output := $(BUILD_DIR) #那么把它的值赋给saved-output
# Attempt to create a output directory. #生成一个输出路径,即目标文件存放目录BUILD_DIR# L$ R4 D' {1 t, `. n; p- L
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
#shell [ -d ${BUILD_DIR} ] 是什么意思?是不是生成一个目录的意思?
# Verify if it was successful. 测试目录是否创建成功0 p, X5 y0 m+ g- a) l! \( u
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) #这又是什么意思,说明对shell还不够理解!, R; t* `* C0 d) n- e
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist)) & u4 r% A6 N# F, [8 x% q* [2 ^' k! y0 X
#这里用了一个if函数,意思是如果如果$(BUILD_DIR) 非空,则什么都不执行(返回空),否则执行error函数,输出错误信息
8 r# R) u# O5 P7 n9 f% U2 N: Vendif
# ifneq ($(BUILD_DIR),) #意思是:如果没有定义目标文件存放目录
0 t; w) s+ I# q' V8 i% C+ k#Makefile中定义了源码以及生成目标文件存放的目录,目标文件存放目录BUILD_DIR可以通过make O=dir指定。如果没有指定,则设定为源码顶层目录。) q4 n; |2 `( h. V
#一般编译的时候不指定输出目录,则BUILD_DIR为空。其他目录变量如下:( X. s8 K- s/ E Q3 ?
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #如果$(BUILD_DIR)不为空,则返回$(BUILD_DIR),并赋给OBJTREE,即自己定制的目标存放目录
, |9 F7 V& M* [0 M4 s: hSRCTREE := $(CURDIR) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE
7 h" B* p' P7 `/ J5 Z# @TOPDIR := $(SRCTREE) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE; \! \; m$ Y8 O% B+ ]7 X# ^
LNDIR := $(OBJTREE) #存放生成的目录文件
( t( L, x3 g! x! gexport TOPDIR SRCTREE OBJTREE
2 K% |, M) B% S- l+ r# C$ v
+ Z: x) {8 D1 z) cMKCONFIG := $(SRCTREE)/mkconfig #MKCONFIG指向源码所在目录(U-BOOT顶层目录)下的mkconfig配置文件: _; J; `+ K0 v4 X' v8 I2 A
export MKCONFIG
#在编译UBOOT之前,我们先要执行:6 F/ ]2 Q% f- S, j" T% I. H
#make smdk2410_config% j# @* S7 f) I/ J1 e9 a4 u+ P7 r
#从本Makefile的下文可以判断出smdk2410_config为Makefile的一个目标。; N" d: C% w9 U2 @$ I
#smdk2410_config: unconfig的意思是为smdk2410开发板建立一个编译项。
" Q2 ]9 X ~/ [+ F: B- F! d- ]! V#显然,执行#make smdk2410_config时,先执行unconfig目标(不指定输出目标时,obj,src变量均为空),unconfig下面的命令主要任务是清理上
+ H1 Z; A q: g) x#一次执行make *_config时生成的头文件和makefile的包含文件。
2 S; h8 d8 y/ C- {#主要是include/config.h和include/config.mk2 c( |% A8 @- C# j8 g& @4 ]: Z m
#然后执行命令: @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x00 e% C1 y$ R7 X. h
#arm 表示CPU的构架是基于ARM体系的
( q% v: E+ e5 V5 @) O/ l3 U% i9 o#arm920t 表示CPU的类型是arm920t( G0 c3 o% C# ^3 l; x. Y
#smdk2410 表示开发板的型号
' S" x& J* ?2 S- j( M$ v#NULL 表示开发商或者经销商的名称,这里为空, M& P/ q+ e3 h1 c1 ]% |3 o
#s3c24x0 表示基于S3C2410的片上系统3 e/ h* ^/ x! \' k6 T0 v& D1 O
#MKCONFIG指向UBOOT顶层目录下的mkconfig脚本配置文件,后面五个字符串是传入的参数(好像$(@:_config=)也是一个参数)。3 y% @# ~4 Z2 x+ M* }( C
#下面来分析一下mkconfig这个脚本配置文件,点击链接:9 K+ v8 L! ?% C3 a
http://zqwt.012.blog.163.com/blog/static/120446842010325102158182/
8 U" I* x( i1 u* i; w# |( G* Q" D
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时5 f; S: _$ D! y* f
REMOTE_BUILD := 1 #定义变量REMOTE_BUILD := 1 这个变量算是一个flag吧
$ E1 q3 q1 Q* L9 [5 v; V% c9 s# A& iexport REMOTE_BUILD
% u: r( J% v3 Q: K1 z: q) ?, N Kendif
# $(obj) and (src) are defined in config.mk(顶层目录下) but here in main Makefile: C; ^& q8 M. P" D
# we also need them before config.mk is included which is the case for# d; [4 \3 \+ Y$ w9 S* ?: [0 t+ ^
# some targets like unconfig, clean, clobber, distclean, etc.
! H. I1 Z, k+ X# $(obj) and $(src)都被定义在顶层目录下的config.mk脚本配置文件里面,; z6 ^+ s) V/ R8 w K6 ^
# 但是在这个主Makefile里面,我们同样需要他们,
1 C4 g& C# ^) R* X, m/ R. N# 因为在主Makefile文件包含config.mk之前,$(obj) and $(src)偶尔地会成为这些目标的case:
6 R+ i, [4 c1 B% S# unconfig, clean, clobber, distclean, etc
" d" X& e/ U6 q4 X4 @/ cifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时/ f/ b$ i, K" {, c
obj := $(OBJTREE)/ #定义变量obj,让其等于目标存放目录
! r3 v4 e6 L' ^4 Osrc := $(SRCTREE)/ #定义变量src,让其等于uboot顶层目录+ j& \# A9 X! E4 ?2 d8 ?
else4 l! A$ c( r5 w" {; t- z- t9 c
obj := #否则,这两个变量都定义为空
2 E; {. r ?% n! X+ qsrc :=0 H# |4 w2 z" M, Q3 D
endif, l6 `; ?6 S$ S- O: p% L: |
export obj src
! G/ q- K' r& N
) F. ^: x+ Y. e2 \/ n- c& P: r \" T3 \% Q _2 a( p
#########################################################################
/ M3 y6 `! Z5 c. ]# r
: |5 Z7 i4 x& H! Z0 |8 D1 v
) B( ?1 W* V. x [/ `( L/ a4 Z2 I1 p. s# e& D' U7 z% ]" K
ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)) #这句话让人费解!3 g, G( p5 K+ V& x# S. c6 K! x/ ~
# 通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展。! @" }! z2 L/ P# p/ R
# 如果您需要在这些场合扩展通配符,您应该使用函数wildcard,格式如下:
e5 W" Y1 u& S7 ]$ J1 m# R+ ?# $(wildcard pattern...)
1 Y2 d) H! g7 Y G0 s! c0 j- g# load ARCH, BOARD, and CPU configuration
8 b l* q- K; W! F! \, q# M ^# 加载ARCH, BOARD, and CPU 配置
, ]1 ~" |$ F( D& B/ ? Minclude $(OBJTREE)/include/config.mk # 这时候,开始包含/include/config.mk的
% S9 @9 v$ ]8 H. S0 U1 C5 Aexport ARCH CPU BOARD VENDOR SOC
) _- o4 d$ } i r$ W8 C3 _#指定交叉编译器前缀/ s% L7 |$ j' i% \
ifeq ($(ARCH),arm) ( ~& X% B5 Y0 P7 R2 K
CROSS_COMPILE = arm-linux-; I* F" o5 M! E% S u) ?' Q6 x- R) B
#这里你可以把交叉编译器的安装路径加到arm-linux-之前,比如你的交叉编译器安装路径是/root/u-boot/usr/local/arm/3.3.2/bin/+ p7 ?& W0 v! Q$ ^
#你可以这样定义CROSS_COMPILE = /root/u-boot/usr/local/arm/3.3.2/bin/arm-linux-$ W! m1 L# R) `3 y
#这样一来,你在终端进行编译的时候就不用指定CROSS_COMPILE=arm-linux-了2 N9 I% H2 K* d) x& B2 q# b8 M2 [
#但请注意:在编译内核的时候,交叉编译器必须安装在/usr/local/arm下,否则会发生错误!!!!!
$ e. N/ B! u4 ?; I1 N, Sendif
export CROSS_COMPILE
/ R- X" J: @; E- q3 W. r
; j: C$ H j$ }- A# t2 a; p4 D# load other configuration 加载其他设置,这里是包含顶层目录下的config.mk配置文件,这个文件主要做了三个工作:2 }+ y% r: r8 o$ F
# 1、定义了交叉编译器 2、定义了编译选项 3、定义了编译规则) s0 C4 F; v( R1 o* _4 ]( e
# 对本文件具体的分析,请查看链接:/ k( E9 `7 z# K6 n }9 G
http://zqwt.012.blog.163.com/blog/static/12044684201032541139914/
include $(TOPDIR)/config.mk
#########################################################################1 V8 x0 `5 D( |1 ?
# U-Boot objects....order is important (i.e. start must be first)
" T X/ Z0 M' M+ k7 S, }# uboot目标...书写顺序很重要,比如start.o必须排在第一位- ^9 X [2 |+ Z; O5 ~: M- h
#########################################################################* k7 T, S9 ]9 N- r
OBJS = cpu/$(CPU)/start.o , U% O% T1 m0 S& c
#start.o必须放在目标文件的第一位,因为uboot执行的第一段代码就是start.S
( j* }8 i% C# d; [$ S2 Y#具体原因可以查看链接脚本/u-boot-1.1.6/board/smdk2410/u-boot.lds,点击连接:( `: Z, b6 ^% r) W, F/ t- K; _
http://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
. K) W( X+ S6 M.....................................
2 b5 m* L! C9 \( mOBJS := $(addprefix $(obj),$(OBJS)) #这句的意思是把目标文件存放路径以前缀的形式加到start.O之前,然后再赋给OBJS
/ A8 T4 t( ^, i' k
#以下是编译UBOOT需要的库文件
C# U/ r: q9 v1 x4 {+ y) ~: {LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a # 严重平台依赖的
LIBS += cpu/$(CPU)/lib$(CPU).a # 严重平台依赖的
ifdef SOC
+ \& H" ?, o) ]- u( `LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a # 严重平台依赖的
* ^/ e- g! N5 e7 E7 f/ l1 F5 e8 e- u ] Mendif
LIBS += lib_$(ARCH)/lib$(ARCH).a # 严重平台依赖的
+ A. a, o' I1 Y) f- w
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
5 C) r' v9 [8 b( g. u* A* L fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a6 P+ q# v2 X1 }8 T2 } {
LIBS += net/libnet.a
, `" P9 m- C8 X3 t- F! K' n+ n4 ]- hLIBS += disk/libdisk.a3 \2 Z0 c1 p3 N& g9 B( C7 @
LIBS += rtc/librtc.a) f, H9 O" t5 B2 ]8 @
LIBS += dtt/libdtt.a
9 y% A+ a1 y$ f' J8 X+ S7 |6 H4 OLIBS += drivers/libdrivers.a
7 L l7 b' B, ~2 U2 x! z/ ZLIBS += drivers/nand/libnand.a; e) w5 T# f- W( M! Z; i
LIBS += drivers/nand_legacy/libnand_legacy.a+ u) g: A# t# a% K0 ^, \* S
LIBS += drivers/sk98lin/libsk98lin.a, ~% ~8 ^. w3 _% c- @9 P7 K% Q1 f
LIBS += post/libpost.a post/cpu/libcpu.a
, h; J- k$ [! {, C# WLIBS += common/libcommon.a( G- I7 F! P! h* S3 A4 O
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) # 这是一个伪目标
#根据所生成的include/config.mk文件定义的几个变量ARCH, CPU, BOARD, SOC,我们可以$ W* F: m3 E! d# x
#确定硬件平台依赖的目录文件。smdk2410平台相关(依赖)目录以及对应生成的库文件如下:
- g' M. n' G6 }5 V$ e#board/smdk2410/: 库文件board/smdk2410/libsmdk2410.a
: C- O9 k8 e* T- H8 F#cpu/arm920t/: 库文件cpu/arm920t/libarm920t.a
7 J. c) Q7 U+ U: I#cpu/arm920t/s3c24x0: 库文件cpu/arm920t/s3c24x0/libs3c24x0.a
( a& Q0 T. U. C0 d" o: ? i P#lib_arm: 库文件lib_arm/libarm.a3 G: i [+ t9 z" M
#include/asm-arm: 头文件" m( R% R8 t( ^7 O5 D7 \: {6 w* L
#include/cnofigs/smdk2410.h:头文件
# Add GCC lib
" ]5 N; t: T3 d! l6 T' |PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
# The "tools" are needed early, so put this first
; | c/ a8 Y$ U# Don't include stuff already done in $(LIBS) 不要包含已经在 $(LIBS) 中的任何东西! N- e5 L: T) J4 h. B
#0 ~4 k+ Z0 u% c1 M& n
# 伪目标SUBDIRS:用于执行tools、examples、post、post\cpu子目录下的make文件/ ?5 I8 F! a7 I; U' y0 T
SUBDIRS = tools \
+ k6 u7 y+ ]' r% @2 o# u: g examples \
, k, D4 y. @% X post \; b2 t$ X- l* N; Z+ |
post/cpu; d$ ?9 g* X6 d2 ], Y
.PHONY : $(SUBDIRS)
ifeq ($(CONFIG_NAND_U_BOOT),y); Y8 i" w( x$ f- U& W' y
NAND_SPL = nand_spl$ I% I& q' `, m) L ^5 b* `
U_BOOT_NAND = $(obj)u-boot-nand.bin& ]7 S# R6 s/ m2 j0 L
endif
__OBJS := $(subst $(obj),,$(OBJS))
! K! ?$ y- k1 w2 U2 F; K, Z/ D__LIBS := $(subst $(obj),,$(LIBS))
#########################################################################
/ L% G2 N! @9 c0 N% B#########################################################################
' q1 Z% k# f. f2 J3 I' E$ k, t3 C. {1 q( F, f7 R, t* c6 s! z, d* e# M
#这里是最终要生成的各种镜像文件u-boot.hex、u-boot.srec、u-boot.bin、System.map、u-boot.img
: z- C: \, R! _ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)2 W1 o1 F/ {- R3 q% _5 _, u
all: $(ALL)
! F1 b; t% I N# c9 L8 m$(obj)u-boot.hex: $(obj)u-boot
3 A. E: j; q4 J: n" _# m $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ # $<,$@ 分别表示使用该规则的源文件和目标文件
$(obj)u-boot.srec: $(obj)u-boot
) V0 n! T9 Q7 k5 Y $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
* e6 o' K- H, ^3 N0 o# P% ~ $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.img: $(obj)u-boot.bin6 B# \: R) _" J
./tools/mkimage -A $(ARCH) -T firmware -C none \% f5 V' y$ o" r8 C9 G3 x3 K0 c1 ^* A
-a $(TEXT_BASE) -e 0 \
/ m+ w4 K9 v2 r3 L6 R. A) G -n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
2 c- V5 o7 `0 J1 ]! L sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
1 k3 t$ f- u6 t) A4 H% f* s ~6 Z -d $< $@
$(obj)u-boot.dis: $(obj)u-boot9 @2 u) }. O8 n; T% X/ q7 I+ C$ [
$(OBJDUMP) -d $< > $@
$ [8 I; o( i; Z2 x6 v K; ]3 s6 T#此处生成的是uboot的ELF文件镜像
& j5 B) e0 p. L: F$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
5 n; I% d1 T% K1 K+ o# Y, R UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
: r; L3 Y, E* s cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
# e* k' O% r% [ m* }! a --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
4 K/ q- u# r* p5 n -Map u-boot.map -o u-boot
8 _0 [7 o& K# }- M' j
#依赖目标$(OBJS),也就是cpu/start.o
& I# ^3 @4 u# m0 d9 v5 g- `$(OBJS):. {. O% R! _, s/ w* y7 C
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
* ]/ J+ V$ ~, H! e N ! D) Z. [% E! c/ Q+ f
#依赖目标$(LIBS),目标很多,都是每个子目录的库文件*.a,通过执行相应子目录下的make来完成0 G8 R9 b' q8 u; v( Z
$(LIBS):
- ~$ k) j/ R6 C $(MAKE) -C $(dir $(subst $(obj),,$@))
c. ]3 q0 o- ?( x 4 n& ^% D$ q/ b( u6 g' d
#这里解释一下这个makefile函数 $(dir names...) 1 E0 U% ]+ f4 w* R- i# l1 K
#抽取‘names’中每一个文件名的路径部分,文件名的路径部分包括从文件名的开始到最后一个斜杠(含斜杠)
0 M. Q& o. W- H2 ?8 \* N, `#之前的一切字符。如果文件名中没有斜杠,路径部分是‘./’。如:. U: K4 E7 f* `1 h3 N( Z) F
#$(dir src/foo.c hacks)9 \, @5 h+ _% i: [4 V
#产生的结果为 ‘src/ ./’。
" H' l' ^3 v( {- x! r$(SUBDIRS):
N" I1 p* B' f$ M) q" U% Z9 Z+ l5 m $(MAKE) -C $@ all
$(NAND_SPL): version% `) z! E: n- ~- Y1 {" K7 f. g6 F
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin' ]" ~( q4 j! t. G
cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
O3 n- ^2 C( }5 Q) c$ o& _#依赖目标version:生成版本信息到版本文件VERSION_FILE中: O) {% m1 V* ]% x9 j4 t
version:
B9 \' h: W. r2 X4 Z- y @echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \
6 e2 h8 b6 X& R* Q( o! i echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \
- b8 c2 R, U: B# d3 Q& [ echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
3 f8 S0 n/ z4 ` $(TOPDIR)) >> $(VERSION_FILE); \2 {' V0 j7 g8 I, n8 S* i4 P" g! Z
echo "\"" >> $(VERSION_FILE)
gdbtools:# k; Z; y2 Q# K! ]6 I3 z
$(MAKE) -C tools/gdb all || exit 1
updater:
) i7 e, k. H# f" \ F $(MAKE) -C tools/updater all || exit 1
env:
, }: Y) ^* C7 c$ Q8 x0 w$ a $(MAKE) -C tools/env all || exit 1
' p$ Q: Q; ?/ T- L3 |
$ w9 M8 i/ c" v8 ^/ B#依赖目标depend:生成各个子目录.depend文件,.depend列出每个目标文件的依赖文件。
0 o: y A2 w2 B9 m6 t#生成方法:调用每个子目录的make_depend
{4 \ I0 L I: {6 e I( e. kdepend dep:
) m r4 K. v2 C" u for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
1 f# d6 A/ s0 @7 s
tags ctags:- T* y3 V6 s7 G* Z
ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \
% y; ^& H) `# g) n, N lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \! _2 I. \, {' e; m- Y6 z
fs/cramfs fs/fat fs/fdos fs/jffs2 \+ q2 D/ J& P. |- D
net disk rtc dtt drivers drivers/sk98lin common \1 O+ A0 W P9 R! Y; N
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
etags:$ t+ A* g! t% K
etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \; b* Y/ p. Y9 J( E* ^, D
lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \3 |. |4 F; V7 u) p/ j* x t
fs/cramfs fs/fat fs/fdos fs/jffs2 \
) D. Y _" L5 |2 z* e net disk rtc dtt drivers drivers/sk98lin common \8 c9 D% P1 p. G a
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
$(obj)System.map: $(obj)u-boot; x& E: g0 e& O7 L2 W
@$(NM) $< | \
6 Y: f( O" Q6 t3 ~$ k. ] grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
) d8 Q8 R/ Y( S4 t: o' j sort > $(obj)System.map
% n4 e. K& h' Q- q
0 x ~4 c! D j# I8 g5 i. v
#########################################################################
: k0 v9 s5 y. W0 \& y7 Lelse1 Q. C# }" Z9 k6 z; `7 d/ H
all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \$ k3 z8 g; I+ ?0 O" f
$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \5 g2 e0 I2 L$ I9 x9 N% W/ e8 ?. O
$(SUBDIRS) version gdbtools updater env depend \
% |/ v) I5 q9 b- e# Adep tags ctags etags $(obj)System.map:! L/ A; s9 p: }7 ?% I- k: f! v
@echo "System not configured - see README" >&2
+ t& m# L0 l6 [) L @ exit 1
% }4 Y8 w2 | R3 ^8 l9 pendif
.PHONY : CHANGELOG
, Z( E. @. g; fCHANGELOG:
' \2 i# s9 j+ ^, v. U% ]2 ? git log --no-merges U-Boot-1_1_5.. | \
# X9 P1 a1 _- q8 D# I2 d1 E1 _7 V unexpand -a | sed -e 's/\s\s*$$//' > $@
) C$ W" n2 |. |) j7 [' F#########################################################################8 n4 a6 t2 g& ]" Z
# 这里就是我们所谓的unconfig,应该比较熟悉了!0 m+ m5 n0 e- h& e9 z
# 很明显,它所做的工作就是清除上次生成的include/config.h和include/config.mk; y1 D$ Y2 i2 Z1 i% ?& P, X
# 以及开发板目录下的一些临时配置文件" O' p( k9 a, \7 }% l" w
# unconfig:; M' O: G w! H
# @rm -f $(obj)include/config.h $(obj)include/config.mk \+ O$ h9 I( H) @
# $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp# z) a0 |5 [5 M1 u
#########################################################################
+ O+ F& T7 W, T- m! r................................# G9 s: S& ~& ?1 U- t; X9 o% e
smdk2400_config : unconfig9 e5 P, M6 s6 i; c0 E" [
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2400 NULL s3c24x0
' F7 w5 Y7 r; z + C1 a8 O; p' q! K0 b2 {$ g
................................
smdk2410_config : unconfig
) q( i$ O2 e8 F5 O: m$ E @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
" a! g" P, ^* D& O- q
#我删了一部分内容,那些几乎都是各种不同板子的*_config,也就是目标的定义。
最后总结一下,当然这里也参考了前辈们的许多宝贵经验,顶层Makefile的主要任务就是组织整个u-boot工程的编译,概括可以分为一下几个步骤:
1、首先通过执行make *_config传入$(@:_config=), ARCH, CPU, BOARD, VENDOR, SOC参数(一共六个参数但不5 h, x$ ]1 I0 U7 R- W
$ _/ T3 G1 R" p8 E2 S( g! s- r 一定同时存在),给mkconfig。
2、mkconfig接收到传递过来的参数后,将include头文件夹相应的头文件夹链接好,生成config.h
3、然后执行make分别调用各个子目录的makefile文件,以生成所有的obj文件(包括start.o)和obj库文件*.a。
4、最后,通过链接器把所有目标文件链接起来,生成uboot镜像。不同格式的镜像都是调用相应工具,经
由elf镜像间接或者直接的生成的。