VERSION = 1
- J: b p+ y) d1 q/ sPATCHLEVEL = 1
) r6 s, P' k6 C7 ?SUBLEVEL = 62 a @- t w3 S) M
EXTRAVERSION =3 a; i2 j# D6 m5 Q9 B1 C
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)- ~+ v0 W, U5 |$ ]) v1 u8 c
VERSION_FILE = $(obj)include/version_autogenerated.h #版本文件
/ X! ?1 g4 ?6 s. `, T# uname 命令将正在使用的操作系统名写到标准输出中+ l- b) t- ?1 F% |$ d6 H
# -m 显示硬件运行系统的机器 ID 号
# 定义变量,HOSTARCH里面存储的是机器ID号,即主机架构类型
9 y. d9 ]$ y* C' T7 s) a9 z# cHOSTARCH := $(shell uname -m | \ #可以把shell脚本写到makefile里面,这是make中的shell function, 相当于shell中的命令替换。
. ^) w0 z( e" Y sed -e s/i.86/i386/ \ #shell uname -m 获得机器硬件名称3 i2 w& W, k1 G- I; R( \$ U
-e s/sun4u/sparc64/ \ #sed -e s/arm.*/arm/ 的意思是把前缀为arm的所有模式替换为arm。结合前面的uname命令来理解就是:
, a; b$ L i0 {( o* u/ L1 e, J$ L% Y -e s/arm.*/arm/ \ #把uname -m的结果(主机架构类型或者称为机器ID号)通过管道传递给sed命令,然后把前缀为arm的所有模式替换为arm。
3 q0 D1 _& g( {: u -e s/sa110/arm/ \ #sed的语法:sed [ -n ] Script [ File ... ]2 Q) C7 x; \, |( z
-e s/powerpc/ppc/ \ # sed [ -n ] [ -e Script ] ... [ -f ScriptFile ] ... [ File ... ]
4 [: x. J. a/ q9 ` N q2 | -e s/macppc/ppc/) #sed 命令根据编辑脚本,去修改指定的 File 文件(这里file是作为一个输入参数的)的行,并将其写到标准输出。; U7 ~% `1 ^# c/ c
#sed 命令包含很多功能,用于选择要修改的行(请注意,sed是针对行进行操作的),并只对选择的行作更改。% A( W+ D4 w2 J% u. c+ ?
#sed 命令使用两个工作空间来保留修改的行:保留选定行的 "模式空间" 和暂时存储行的 "保留空间"。
* H6 m7 n/ N3 g #这里所谓的编辑脚本是由单独的子命令构成的,每个单独的行上对应着一个子命令。sed 子命令的一般格式如下:[address-range] function[modifiers],即:[地址范围] 函数[修改符]( u0 t; C; B! e( |* x3 x9 L
#sed 命令通过将一个输入行读入模式空间,依次应用所有的 sed 子命令(这些子命令的地址选择了该行)," l9 S. e# ?! E1 y+ n2 x7 E; `
#并将模式空间写到标准输出来处理每个输入的 File 输入文件(file就是输入参数)。然后清除模式空间,并对输入的 File 中指定的每行重复该过程。8 o* Y4 r+ J: A. X3 j' W9 Q5 M
#一些 sed 子命令使用保留空间来保存后继检索的所有的,或部分的模式空间。
- c) W0 q: ?% c- [( o' S0 p7 f' V #当命令包含地址(行号或搜索模式)时,该命令只会对被寻址的行起作用。否则,该命令适用于所有的行。
, l( w: Z+ C: E x- V' P* p #注意,这里的参数"-e"的意思是:使用 Script 变量作为编辑脚本。如果你只使用一个 -e 标志并且不使用-f 标志,则可以省略 -e 标志。
" ^2 E6 m6 _8 F! G( `& J0 E #注意,这里的 "sed -e s/arm.*/arm/"表示把前缀为arm的所有模式替换为arm,也就是sed s/pattern/replacement/flags
1 m1 u# F' M0 x g# c$ k) z #用 replacement 字符串代替在模式空间中首次出现的 pattern 参数。除了空格或换行符,在 s 子命令之后显示的任何字符都能代替 /(斜杠)分隔符。
' _; j8 h$ O0 q. y4 {7 G/ x
3 s3 k+ i7 S& _/ c, D- r8 S2 b5 C#uname -s 表示:显示系统名,标志缺省为开,即uname命令不带任何参数的输出和加参数-s输出相同,即Linux
$ p( @2 F/ o4 `" E( F0 S#tr是一个shell命令,这里 tr '[:upper:]' '[:lower:]'的意思是把管道中的Linux 中的大写字母L 转换成小写字母l9 j( n0 ]" m- k' r6 L
#下面这句话的意思是定义变量HOSTOS,HOSTOS里面存放的是主机安装的,并且当前正在运行的操作系统。2 R7 M4 Z; T& P M
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \8 R* l% c1 _* D- k# E. F% J
sed -e 's/\(cygwin\).*/cygwin/') # 这一句的意思是检测出主机安装的,并且当前正在运行的操作系统名,并把这个系统名中的大写字母转换为小写字母,
* F: y; X3 W1 z # 然后在通过sed流编辑器匹配所有的,这个系统名中出现的"\(cygwin\).*"模式,然后再用"cygwin"模式替换。
: Q4 U, N1 d5 I; {#export HOSTARCH HOSTOS 的意思是输出两个makefile变量HOSTARCH HOSTOS
export HOSTARCH HOSTOS
# Deal with colliding definitions from tcsh etc. 用来处理来自tcsh的互相冲突的定义等等
) j! `$ H& N7 f1 R9 o* l# 一般来说,shell可以分成两类。第一类是由 Bourne shell 衍生出来的包括
) o; z2 h* Y- l* Z# sh,ksh,bash,与zsh。第二类是由 C shell 衍生出来的,包括 csh 与
# \" B6 J+ m6 n" A; F# tcsh。除此之外还有一个 rc,有人认为该自成一类,有人认为该归类在Bourne shell。
VENDOR= #开发商
#########################################################################
( |1 f) B$ X/ @7 r7 j" t/ a#
1 g0 _( } u) D: F4 {8 p# U-boot build supports producing a object files to the separate external
+ X6 w' d$ h: F1 u# U-boot 的编译过程可以支持向一个自己定义的路径生成最终的目标文件
8 P: R5 S+ d: ?5 A+ R# directory. Two use cases are supported:9 t1 x. |6 A0 q$ i* o
# 这里提供了两种用法:* y6 ^! q& L- Y3 h5 ^# E
#
l0 s$ m! f+ m; h& C# 1) Add O= to the make command line #第一种用法:通过在终端执行命令make O=/dir(即你指定的生成的目标文件的存放目录)! m5 ^ X5 q* s" K0 o- N1 y9 m2 ^
# 'make O=/tmp/build all'8 Y" b/ j! V8 a
#
2 H% h0 m. q& c% X8 F, ~1 M' \# 2) Set environement variable BUILD_DIR to point to the desired location #第二种用法:通过设置环境变量来指定目标文件存放目录,如下所示:/ V6 C: c7 ?0 i" D
# 'export BUILD_DIR=/tmp/build'
' w5 [6 \9 _% N$ j+ a# 'make'
! `- C0 n3 g) U# g#+ n* |: Y! z. S3 u `
# The second approach can also be used with a MAKEALL script #第二种方法也可以写成一个MAKEALL脚本,然后执行MAKEALL,如下所示:
5 e; I' l: b. O. s9 N) c# 'export BUILD_DIR=/tmp/build'& t; U. f1 q1 w8 ]( C; e
# './MAKEALL'6 m; g* L, I3 Z/ f y2 W
#. c, Y- x( i' {# i9 Z; ^
# Command line 'O=' setting overrides BUILD_DIR environent variable. #命令行'O='设置会覆盖环境变量BUILD_DIR的设置0 a6 e( k0 X8 D
#: C8 j9 ?3 B; R; i; [. g# V
# When none of the above methods is used, the local build is performed and #如果都不采用上面两种方法,那么目标文件最终要存放到源码顶层目录,也就是U-BOOT顶层目录% E. ?# `1 u9 o8 t. F2 N
# the object files are placed in the source directory.( z3 ~- T! @/ A2 i) x" F3 [+ b3 H
#
#理解了上面一段英文,这里就不难理解了
0 l: m2 l0 G Q( ]( N1 h. s/ e#方法1
ifdef O #如果变量'O' 已经被定义过
& x. d& h0 n8 W9 Rifeq ("$(origin O)", "command line") #如果变量'O' 在命令行中定义过' e/ A; N* `2 ~; | ~
BUILD_DIR := $(O) #就把变量'O' 的值(目标文件存放目录)赋给BUILD_DIR2 @" v" S/ q Z& n2 {
endif9 E/ L' a1 \ u
endif
5 [- |3 [/ I) X/ V4 b! S( f6 u: d
#方法2
" n7 o7 Y" L0 [" zifneq ($(BUILD_DIR),) #如果变量BUILD_DIR不为空,即环境变量BUILD_DIR 被定义过
! D- i6 [5 o: b% R( tsaved-output := $(BUILD_DIR) #那么把它的值赋给saved-output
# Attempt to create a output directory. #生成一个输出路径,即目标文件存放目录BUILD_DIR3 Z I9 m8 y) V$ {* l7 s
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
#shell [ -d ${BUILD_DIR} ] 是什么意思?是不是生成一个目录的意思?
# Verify if it was successful. 测试目录是否创建成功2 r: G! O; y5 \
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) #这又是什么意思,说明对shell还不够理解!
5 w$ r: o% S# Q* C6 ?' S9 ?) ]4 o$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
, o: L2 X/ U; v+ J# h! d; P8 R#这里用了一个if函数,意思是如果如果$(BUILD_DIR) 非空,则什么都不执行(返回空),否则执行error函数,输出错误信息$ f% s' u! N- V' s! N: l
endif
# ifneq ($(BUILD_DIR),) #意思是:如果没有定义目标文件存放目录 M; P) F6 T4 G+ p
#Makefile中定义了源码以及生成目标文件存放的目录,目标文件存放目录BUILD_DIR可以通过make O=dir指定。如果没有指定,则设定为源码顶层目录。: l' v5 G" F9 L
#一般编译的时候不指定输出目录,则BUILD_DIR为空。其他目录变量如下:! g5 P2 o- B, r, @6 R7 G
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #如果$(BUILD_DIR)不为空,则返回$(BUILD_DIR),并赋给OBJTREE,即自己定制的目标存放目录
+ C2 z8 ~; I( o5 j3 q+ w+ zSRCTREE := $(CURDIR) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE
) T# a2 x1 x: z& ZTOPDIR := $(SRCTREE) #把当前源码所在目录 $(CURDIR) 赋给SRCTREE/ H* I* g6 X# f; J" }' _+ ^" u/ h
LNDIR := $(OBJTREE) #存放生成的目录文件
1 N7 ]7 M, ^6 `) ], B- bexport TOPDIR SRCTREE OBJTREE
4 C$ r. u4 O# y+ i
: F9 z8 }* v+ B% Y/ f: FMKCONFIG := $(SRCTREE)/mkconfig #MKCONFIG指向源码所在目录(U-BOOT顶层目录)下的mkconfig配置文件
- _. I* X) n- b4 W, rexport MKCONFIG
#在编译UBOOT之前,我们先要执行:9 h; t2 M S; s. o
#make smdk2410_config p! w- l9 l0 p l5 g! G7 a2 q2 `4 w
#从本Makefile的下文可以判断出smdk2410_config为Makefile的一个目标。
2 Y8 E7 g r, n#smdk2410_config: unconfig的意思是为smdk2410开发板建立一个编译项。& V6 s& [4 X3 T! { j! Z
#显然,执行#make smdk2410_config时,先执行unconfig目标(不指定输出目标时,obj,src变量均为空),unconfig下面的命令主要任务是清理上: k6 ]' L4 t( e
#一次执行make *_config时生成的头文件和makefile的包含文件。
+ w1 ]8 u. i) e: N5 T3 p/ t#主要是include/config.h和include/config.mk4 Q# W* f1 r% {9 F, N! @9 ?. R
#然后执行命令: @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
& t8 u% W; f# ` w5 r# f#arm 表示CPU的构架是基于ARM体系的
. T# \+ f9 K+ j2 g3 W9 ^# b#arm920t 表示CPU的类型是arm920t6 K! ^" ^8 _2 k( [1 } t4 ?
#smdk2410 表示开发板的型号 R/ t2 Q- l& J. J
#NULL 表示开发商或者经销商的名称,这里为空
6 q7 ~( Y; r' Y#s3c24x0 表示基于S3C2410的片上系统
+ W+ P% ?- R3 u( z5 \9 ^#MKCONFIG指向UBOOT顶层目录下的mkconfig脚本配置文件,后面五个字符串是传入的参数(好像$(@:_config=)也是一个参数)。
0 D! @1 j5 Q* E$ @#下面来分析一下mkconfig这个脚本配置文件,点击链接:
# }% g5 k& z- y: P% r% J, t" Ehttp://zqwt.012.blog.163.com/blog/static/120446842010325102158182/
3 I; p0 _# W: q
ifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时
% X+ s$ o- _6 U. T" h$ v1 d6 T h* cREMOTE_BUILD := 1 #定义变量REMOTE_BUILD := 1 这个变量算是一个flag吧
, X9 X% w0 Q! U; oexport REMOTE_BUILD
& u6 Y5 K: j) O ~* `endif
# $(obj) and (src) are defined in config.mk(顶层目录下) but here in main Makefile" n- @. z& Z: @8 S
# we also need them before config.mk is included which is the case for5 |) f4 O9 x D7 `5 _: K4 T8 B
# some targets like unconfig, clean, clobber, distclean, etc.# Z+ p" F3 O* X: {# B$ }
# $(obj) and $(src)都被定义在顶层目录下的config.mk脚本配置文件里面,$ ?: L( a5 v! ]5 u2 t! q0 t1 r" P
# 但是在这个主Makefile里面,我们同样需要他们,
r( L9 l9 ~+ _/ d# 因为在主Makefile文件包含config.mk之前,$(obj) and $(src)偶尔地会成为这些目标的case:
' i3 _: f1 e8 I7 \1 @# unconfig, clean, clobber, distclean, etc
' ^ X) y$ Z, pifneq ($(OBJTREE),$(SRCTREE)) #当目标存放目录不是U-BOOT顶层目录(源码目录)时
: { M" ~4 U( f% I8 m0 P+ gobj := $(OBJTREE)/ #定义变量obj,让其等于目标存放目录
) w2 `5 V, D( N: z- L. o. a osrc := $(SRCTREE)/ #定义变量src,让其等于uboot顶层目录
5 d! H! d: k( ~else* Z5 v0 h' F" ]: G; L( X
obj := #否则,这两个变量都定义为空! ]. ?' V8 ]) U }1 q J3 T
src :=! h- y3 [ m' C& j
endif# J9 z. I/ n- k1 I6 M! X
export obj src
2 Q6 ^7 E- h2 J2 E$ m6 k, g% D5 _ c; H- U2 D/ W% ~+ K4 }. Q: y; A) E; `
- B( Z0 G. I( R
#########################################################################
! R8 @3 Q' B6 |5 U$ j; v0 D/ h
6 H7 s& D. K6 u4 ~2 w$ [ s* A, x# l* l" F
. G* g5 A. L0 n% g, }* Y/ }8 Z
ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)) #这句话让人费解!7 C7 Y" b, E& q1 Q
# 通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展。5 h1 J) L! E0 |7 g0 n
# 如果您需要在这些场合扩展通配符,您应该使用函数wildcard,格式如下:8 V: U9 i- r3 h
# $(wildcard pattern...)
! S/ q9 e8 \0 }# load ARCH, BOARD, and CPU configuration8 p2 ?8 w7 z# R7 b+ g6 n; `) X- [
# 加载ARCH, BOARD, and CPU 配置. X; y) {) \- k9 D- @: T
include $(OBJTREE)/include/config.mk # 这时候,开始包含/include/config.mk的
2 A+ \2 W; c( f5 Z5 pexport ARCH CPU BOARD VENDOR SOC
9 N0 t1 u a" s3 T5 U#指定交叉编译器前缀* Y: ?/ ^! J: w
ifeq ($(ARCH),arm)
; }! {2 V. P7 ^CROSS_COMPILE = arm-linux-
! P' q4 N9 N! Z4 g) a( z#这里你可以把交叉编译器的安装路径加到arm-linux-之前,比如你的交叉编译器安装路径是/root/u-boot/usr/local/arm/3.3.2/bin/& Z0 Y; a( d4 |1 _ l( L# K3 o
#你可以这样定义CROSS_COMPILE = /root/u-boot/usr/local/arm/3.3.2/bin/arm-linux-/ ]% u+ q# E# D* M. f' q
#这样一来,你在终端进行编译的时候就不用指定CROSS_COMPILE=arm-linux-了; H% D/ ], T4 K& ^
#但请注意:在编译内核的时候,交叉编译器必须安装在/usr/local/arm下,否则会发生错误!!!!!
; Y4 }- O. A3 c3 p7 ?. Lendif
export CROSS_COMPILE
7 _0 s$ Y6 s2 R% m: ]2 I
0 p# F' V# S& s
# load other configuration 加载其他设置,这里是包含顶层目录下的config.mk配置文件,这个文件主要做了三个工作:3 y& H; t5 r: V% ~
# 1、定义了交叉编译器 2、定义了编译选项 3、定义了编译规则* o% L/ [, x7 d' T% Y
# 对本文件具体的分析,请查看链接:
; k% E5 C6 r/ N) @1 Nhttp://zqwt.012.blog.163.com/blog/static/12044684201032541139914/
include $(TOPDIR)/config.mk
#########################################################################5 x; q# C9 X: v
# U-Boot objects....order is important (i.e. start must be first)
+ v) u1 W* _+ @* l5 a& z: G# uboot目标...书写顺序很重要,比如start.o必须排在第一位; L4 e5 N* N% H' l9 a: L
#########################################################################
_: b- X9 N0 I7 UOBJS = cpu/$(CPU)/start.o - {: \8 `; H; u4 o$ @& ?
#start.o必须放在目标文件的第一位,因为uboot执行的第一段代码就是start.S
; B; o5 R. T9 l; W8 o( c6 {#具体原因可以查看链接脚本/u-boot-1.1.6/board/smdk2410/u-boot.lds,点击连接:
/ z, M+ ~6 P+ M% Q2 ]5 R5 ihttp://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
/ j+ w4 Z8 g) W0 i3 I6 ?& X5 O
.....................................
1 {8 n/ P( o/ N7 n2 C1 z9 bOBJS := $(addprefix $(obj),$(OBJS)) #这句的意思是把目标文件存放路径以前缀的形式加到start.O之前,然后再赋给OBJS
6 u9 c! D' v% j4 y% N4 m0 T
#以下是编译UBOOT需要的库文件9 J; I6 C6 E. Q% z) |
LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a # 严重平台依赖的
LIBS += cpu/$(CPU)/lib$(CPU).a # 严重平台依赖的
ifdef SOC
% @+ m+ z- S( H# V( L+ K7 FLIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a # 严重平台依赖的
# ~' x' W9 F1 H! Z# X; _endif
LIBS += lib_$(ARCH)/lib$(ARCH).a # 严重平台依赖的
" A h- y5 I% d) z2 I
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
" u/ c/ V5 H- q# l3 {. ~6 ] fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a% d2 V- Q0 p4 j8 X* R6 h" f
LIBS += net/libnet.a
. c# [% D' i. ^$ k: o/ LLIBS += disk/libdisk.a
* R7 H0 g, X3 m9 Y) ^% lLIBS += rtc/librtc.a6 N& Z( \2 @% u' c
LIBS += dtt/libdtt.a- P- k& A1 _7 o e1 R
LIBS += drivers/libdrivers.a0 e3 d; y; s6 B. N
LIBS += drivers/nand/libnand.a
& K2 M- P' a7 F$ kLIBS += drivers/nand_legacy/libnand_legacy.a
1 P8 I/ N% ?+ j3 Q1 k: FLIBS += drivers/sk98lin/libsk98lin.a
* {! i0 f, g cLIBS += post/libpost.a post/cpu/libcpu.a
& B" `1 p& Z2 o; G, c! f. uLIBS += common/libcommon.a: e! w. e% Z: ^; J
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) # 这是一个伪目标
#根据所生成的include/config.mk文件定义的几个变量ARCH, CPU, BOARD, SOC,我们可以* |) Z- ^& K0 S3 t1 Z/ Y, ?3 U
#确定硬件平台依赖的目录文件。smdk2410平台相关(依赖)目录以及对应生成的库文件如下:
. B+ U+ u1 J6 h3 i+ C#board/smdk2410/: 库文件board/smdk2410/libsmdk2410.a
; a5 H0 p! W5 I- v# {+ {+ V#cpu/arm920t/: 库文件cpu/arm920t/libarm920t.a2 w2 v1 ?9 R4 U* {6 U9 u
#cpu/arm920t/s3c24x0: 库文件cpu/arm920t/s3c24x0/libs3c24x0.a
1 J- t+ a$ @5 [#lib_arm: 库文件lib_arm/libarm.a
) l& p2 \. ^0 u) L, Z#include/asm-arm: 头文件
! a+ U+ l2 n. W$ _#include/cnofigs/smdk2410.h:头文件
# Add GCC lib
# R; C! l& ~5 Q5 QPLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
# The "tools" are needed early, so put this first
3 s2 s) ^& [& |# Don't include stuff already done in $(LIBS) 不要包含已经在 $(LIBS) 中的任何东西
5 y: K: G+ p' ]2 h! X#( f9 ~2 k; ?" y: U/ c. a6 C; I/ m
# 伪目标SUBDIRS:用于执行tools、examples、post、post\cpu子目录下的make文件
' e6 c' p2 a3 T% ISUBDIRS = tools \
6 v; @2 k; \5 t. b4 A1 N V- K examples \5 M9 Q' V8 B# }- l/ D; O, M- D
post \$ Q1 T: Q" _7 Z( U9 i }
post/cpu
4 p x8 R+ O& f' y1 o4 D.PHONY : $(SUBDIRS)
ifeq ($(CONFIG_NAND_U_BOOT),y)
+ _5 s) V1 T [5 x2 r' }NAND_SPL = nand_spl" {! i7 n4 i/ L6 B2 J) r
U_BOOT_NAND = $(obj)u-boot-nand.bin2 E, j3 X& i, ~7 |) r
endif
__OBJS := $(subst $(obj),,$(OBJS))
" T; r! ?9 K7 \- C" K7 n8 L& E% G4 t__LIBS := $(subst $(obj),,$(LIBS))
#########################################################################6 b" Z5 v/ B: @) s
#########################################################################
) b- _. S* R+ V+ y; @
) b- B& {6 F/ l0 V5 @" G$ K+ B0 ^( V#这里是最终要生成的各种镜像文件u-boot.hex、u-boot.srec、u-boot.bin、System.map、u-boot.img
3 B; t9 m z+ \ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)! v+ E% v% [; Q. S
all: $(ALL)7 L/ ?8 v+ a; Q
$(obj)u-boot.hex: $(obj)u-boot X8 I9 O# M8 Q* y$ g M- ^
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ # $<,$@ 分别表示使用该规则的源文件和目标文件
$(obj)u-boot.srec: $(obj)u-boot & X5 {) B( b0 T. y6 T) E6 k
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot/ t6 Z: Z9 V! ?. K5 }- m
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.img: $(obj)u-boot.bin N- } P# ]- l* c( q7 j
./tools/mkimage -A $(ARCH) -T firmware -C none \
0 z' n: s( U* Y) H# `% u -a $(TEXT_BASE) -e 0 \
! l) E4 b1 u* Y- o* d' B, [ -n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
5 K! q E8 b+ d0 Z2 ~8 G sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \2 i+ }. E$ R4 O
-d $< $@
$(obj)u-boot.dis: $(obj)u-boot+ E: m3 r6 P9 q; j
$(OBJDUMP) -d $< > $@
# f- @* ]4 i) D. Z& ?
#此处生成的是uboot的ELF文件镜像: d# v0 h' M+ d& y
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)# r& `; k( j( ~/ e8 k" R2 M1 d! P
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
- e* V( T/ S1 w7 C" Z1 o1 u' { cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \4 b" t1 U" \! y# o3 g( t% W
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \+ J$ T! r0 t, O/ \# X( t& ?
-Map u-boot.map -o u-boot
4 \0 F3 q% k# |/ }( L5 ~9 h1 S#依赖目标$(OBJS),也就是cpu/start.o) U D/ Z! R9 d8 j" {
$(OBJS):6 u9 ]8 A0 [- P3 z4 \3 _* E
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
0 v( v9 b& l$ k* p+ v( h8 F, {9 c
! S! O2 Y9 v5 O0 f1 ?6 s#依赖目标$(LIBS),目标很多,都是每个子目录的库文件*.a,通过执行相应子目录下的make来完成
$ G. x) a- ]4 ^% _$(LIBS):
% V" V+ e8 L8 y& n $(MAKE) -C $(dir $(subst $(obj),,$@))0 m6 b5 @9 a: D6 a) J9 h
1 M4 k. a4 `; i, L" ?#这里解释一下这个makefile函数 $(dir names...) # F: f1 n' E, L, H' B* `
#抽取‘names’中每一个文件名的路径部分,文件名的路径部分包括从文件名的开始到最后一个斜杠(含斜杠)
7 M+ {8 _3 {" x% W, d#之前的一切字符。如果文件名中没有斜杠,路径部分是‘./’。如:% Z D9 ` m5 N7 L
#$(dir src/foo.c hacks)' Q% p) _9 n4 d
#产生的结果为 ‘src/ ./’。
p0 O' E# q2 Y) }( E9 Y9 @$(SUBDIRS):$ N* L; |) e) z( ]% m
$(MAKE) -C $@ all
$(NAND_SPL): version$ c. J/ W( z. i i
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin6 U2 h+ S/ u' T: y; |3 O) b
cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
' i, T6 L: z3 m" j' I# y#依赖目标version:生成版本信息到版本文件VERSION_FILE中" a# `9 J6 A$ g# O* |
version:4 B/ ^# L9 @' S, U
@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \
) K) g6 @- m% @" k8 [ echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \5 h$ A* j4 I( m6 @9 v
echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
5 ?; `4 {1 w" B: S# n' ]. O" Q* B9 _ $(TOPDIR)) >> $(VERSION_FILE); \& S3 M Q; d+ E/ E, ]" U; K8 @' u
echo "\"" >> $(VERSION_FILE)
gdbtools:
+ A, |: b0 @! h( g $(MAKE) -C tools/gdb all || exit 1
updater:9 ^! d3 ]% A3 w2 g/ R* }
$(MAKE) -C tools/updater all || exit 1
env:
+ q, w' k- S, d5 H+ T3 E5 i! K. N $(MAKE) -C tools/env all || exit 1
$ ?# n' y" J( A8 v7 W2 u9 {0 }1 t0 P& f. ]) [- D# s
#依赖目标depend:生成各个子目录.depend文件,.depend列出每个目标文件的依赖文件。
: s/ \# x2 d: }6 W9 p% ?& j& U#生成方法:调用每个子目录的make_depend. y/ v& x/ r0 R' d1 }! O0 Q
depend dep: m4 i3 J$ {7 U2 g
for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
1 X2 x( E/ I9 v" ~7 c0 Q0 b
tags ctags:7 _- w7 I& }2 e9 ]/ y; a7 K% t, r
ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \
! h1 a6 v7 {) }* o lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
$ \% p7 r+ [3 R& J* g4 g o fs/cramfs fs/fat fs/fdos fs/jffs2 \ y3 p# z" M5 b& Z
net disk rtc dtt drivers drivers/sk98lin common \: S4 W) ~9 C) i( L0 b) r5 L m: o) Z
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
etags:
4 F& ~3 P! F" J3 G) j" [ etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \
6 @( M$ j8 V8 b! f: M( y lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
' ?6 g7 m$ v4 M$ g7 Q h0 z fs/cramfs fs/fat fs/fdos fs/jffs2 \
+ I K! D: f9 _6 X6 f) R" u) n) O net disk rtc dtt drivers drivers/sk98lin common \
: W7 f, W" W* i, f* i2 V \( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
$(obj)System.map: $(obj)u-boot. o- T) E9 f$ I% b; h* }
@$(NM) $< | \
9 @( g0 H! b5 z) N2 j; y9 \) ` grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \! F0 q) r5 ~3 W5 P$ W" T: s! I
sort > $(obj)System.map
1 ~$ R! n, ?9 r* ~# J
" G; f" a* _$ |7 S- V \#########################################################################
1 n7 a6 y' Z7 |1 g# uelse
5 C; @$ W2 L9 [, ~2 f- Zall $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \" Q$ [4 A" V% Z: h" s0 k8 g
$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \
/ ?8 z! a9 p* T$(SUBDIRS) version gdbtools updater env depend \& O' E, T9 T6 r; |" V
dep tags ctags etags $(obj)System.map:7 e5 E& S- |7 V0 l) j
@echo "System not configured - see README" >&2
. M) a6 i9 k) @8 X- X9 { ]- ? @ exit 1* U+ [0 W& ?( g, J
endif
.PHONY : CHANGELOG& C5 x3 {2 _. y9 N- |
CHANGELOG:
9 y& l \1 d+ V9 [2 @4 o" `/ _& ~& t git log --no-merges U-Boot-1_1_5.. | \
( O8 {0 K% |% C3 u unexpand -a | sed -e 's/\s\s*$$//' > $@
8 m; B2 E4 ^3 T. W9 T3 C: t
#########################################################################3 k ^1 C: M! ^) D
# 这里就是我们所谓的unconfig,应该比较熟悉了!
! |4 n0 A; ]( {. o6 J0 r# 很明显,它所做的工作就是清除上次生成的include/config.h和include/config.mk
# c, V2 O' t4 x0 k# 以及开发板目录下的一些临时配置文件2 g. }& ^' S p9 v. _* N) Y* Y
# unconfig:
) n; a: Z4 c5 a; {) A" Y# @rm -f $(obj)include/config.h $(obj)include/config.mk \( O9 W( ~8 K$ G" L; ]
# $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp9 [/ |; ^# |5 v' q% C" d8 |
#########################################################################
: m; C3 Q. Z' P- D/ G................................) Y; `3 l( @6 B
smdk2400_config : unconfig
! F9 |. q0 r0 @" } @$(MKCONFIG) $(@:_config=) arm arm920t smdk2400 NULL s3c24x0& b o- G3 D3 [% N3 @
: h% Z% S' s9 M) k t$ P3 T& S5 _................................
smdk2410_config : unconfig$ Q- c' }. K: W
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
l# B5 ~# k! d8 N/ e& M
#我删了一部分内容,那些几乎都是各种不同板子的*_config,也就是目标的定义。
最后总结一下,当然这里也参考了前辈们的许多宝贵经验,顶层Makefile的主要任务就是组织整个u-boot工程的编译,概括可以分为一下几个步骤:
1、首先通过执行make *_config传入$(@:_config=), ARCH, CPU, BOARD, VENDOR, SOC参数(一共六个参数但不
, Q% T/ Z8 A! x6 y1 z% A ) \; ]/ H+ x& e, u% s$ o" x
一定同时存在),给mkconfig。
2、mkconfig接收到传递过来的参数后,将include头文件夹相应的头文件夹链接好,生成config.h
3、然后执行make分别调用各个子目录的makefile文件,以生成所有的obj文件(包括start.o)和obj库文件*.a。
4、最后,通过链接器把所有目标文件链接起来,生成uboot镜像。不同格式的镜像都是调用相应工具,经
由elf镜像间接或者直接的生成的。