U-boot Makefile分析
时间:2010-10-11 来源:linuxdevelop
U-boot Makefile
By: Gary Lee
2009-11-24
近来因为网络原因,给网络中心打电话,也跑了两趟,一直说我们实验室有问题,要求我们格式化,一气之下,来了个全血格式化,瞬间,所有的资料全没有了……心疼啊
这几天一直在看uboot,有兴趣的朋友可以在论坛里一起交流,不懂的问题,可以在版主上课时提问。
1、先执行make SKY2440_config
从Makefile中找到SKY2440_config,在我修改的Makefile中,大约中283行处,这里SKY2440_config所依赖的是unconfig,所以先执行unconfig,往回找目标config,查看发现,只是删除了几个文件,包括:
(1)如果命令行没有指定编译目录,有include/config.h, include/config.mk, board/*/config.tmp(*指你自己的开发板名称),board/*/*/config.tmp文件,
(2)如果命令行中指定了编译目录,则要到自己指定的编译目录中去删除这几个文件,同上。
执行完unconfig后,接下来要执行SKY2440_config下的命令了。
@$(MKCONFIG) $(@:_config=) arm arm920t SKY2440 NULL s3c24x0
这里在79行处,定义了MKCONFIG变量,为$(SRCTREE)/mkconfig,即根目录下的mkconfig,所以上述命令又可写成如下:
mkconfig $(@:_config=) arm arm920t SKY2440 NULL s3c24x0
其中make内建函数 $(@:_config=)的作用是:将当前目标中的_config去掉,所以执行完$(@:_config=)后其返回值为:SYK2440,故上述命令又可写成:
mkconfig SYK2440 arm arm920t SKY2440 NULL s3c24x0
注:$1=SKY2440(名字) $2=arm $3=arm920t $4=SKY2440 $5=NULL(vender) $6=s3c2440(soc)
回头再来查看根目录下的mkconfig文件,在其文件开头有#!/bin/sh,很显然这是一个shell脚本,所以mkconfig后面跟的SYK2440 arm arm920t SKY2440 NULL s3c24x0这些字符串都是这个脚本文件的参数,接下来分析一下这个脚本如何执行的。
14行:while [ $# -gt 0 ]是说如果参数个数大于0就执行以下命令:
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
由于命令中并没有传入--,-a,-n等参数,故执行*,也就是说这段命令不执行。接着往下看:
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
如果BOARD_NAME已定义,则重新赋值,值内容为第1个参数,即SKY2440。
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1
这两句的作用是判断参数个数,做了一个容错处理,防止参数过多或过少。
echo "Configuring for ${BOARD_NAME} board..."
当我们执行make SKY2440_config命令时,如果成功则会在屏幕上输出如下:
Configuring for SKY2440 board...
这就证明配置成功,接下来就要创建链接文件;
if [ "$SRCTREE"!="$OBJTREE" ];then # 当前目录与编译目录不同
mkdir -p ${OBJTREE}/include # 如果我们都没有指定编译目录,略过
mkdir -p ${OBJTREE}/include2 # 在编译目录下创建这两个文件夹
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm
LNPREFIX="../../include2/asm/"
cd ../include
rm -rf asm-$2
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
cd ./include # 进入到./include目录,删除asm文件夹
rm -f asm
ln -s asm-$2 asm # 将asm-$2即asm-arm软链接到asm文件夹
fi
继续:
rm -f asm-$2/arch # 删除asm-arm/arch文件夹
if [ -z "$6" -o "$6" = "NULL" ] ; then # 指如果"$6"长度为零则为真
ln -s ${LNPREFIX}arch-$3 asm-$2/arch # -O "$6"如果"$6"存在且为# 空,就 进行$3链接
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi
if [ "$2" = "arm" ] ; then # 如果参数2为arm,则删除asm-arm/proc
rm -f asm-$2/proc # 将proc-armv链接到asm-arm/proc目录
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
再接下来就要创建开发板头文件
if [ "$APPEND" = "yes" ]
then
echo >> config.h # 在config.h中添加
else
> config.h # 否则创建一个config.h文件
fi
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/$1.h>" >>config.h
到此,confih.h文件已经生成完毕,内容如下:
/* Automatically generated - do not edit */
#include <configs/$1.h>
到此,make SKY2440_config命令已经执行完成,我们再来总结一下:
当我们在命令行输入make SKY2440_config命令时:
(1) 先执行依赖unconfig,也就是删除上次执行make BOARD_NAME_config时生成的include/config.h, include/config.mk, board/*/config.tmp(*指你自己的开发板名称),board/*/*/config.tmp等文件,然后往下执行目标命令;
(2) 输入的make SKY2440_config便解析成mkconfig SKY2440 arm arm920t SKY2440 NULL s3c2440,这里实际上是执行一下shell脚本,作用是生成我们自己开发板所需要的配置文件,如执行unconfig生删除的include/config.h, include/config.mk这两个文件。具体过程是:a)设置BOARD_NAME = $1;b)创建到开发平台或开发板相关的头文件的链接如:
Ln –s arm-$2 asm
Ln –s arm-$6 asm-$2/arch
Ln –s proc-armv asm$2/proc
c)接下来创建顶层Makefile包含文件include/config.mk文件,如下内容:
ARCH = $2
CPU = $3
BOARD = $4
VENDER = $5 # 如果$5为空则这里没有VENDER
SOC = $6 # 同上
d)创建开发板相关的头文件include/config.h,内容如下:
/* Automatically generated - do not edit */
#include <configs/$1.h>
2、ALL
这时返回到Makefile从头来看,找到第一个目录,也就是主目标all。
在all之前主要是定义了一些变量,及判断编译目录等。
注:
在make的递归调用中,需要了解一下变量“CURDIR”,此变量代表make的工作目录。当使用“-C”选项进入一个子目录后,此变量将被重新赋值。总之,如果在Makefile中没有对此变量进行显式的赋值操作,那么它代表make的工作目录。我们也可以在Makefile为这个变量赋一个新的值。此时这变量将不再代表make的工作目录。
接下来看包含文件,在108行和123行处有如下文件:
include $(OBJTREE)/include/config.mk
include $(TOPDIR)/config.mk
此时make会执行这两个文件,第一个文件主要作用是:将由mkconfig生成的这个config.mk文件中定义的ARCH,BOARD,和CPU等变量进行初始化赋值,即:
ARCH=arm;BOARD=SKY2440;CPU=arm920t,而第二个根目录下的config.mk主要是定义了编译规则及编译参数变量等,现在可以不用管。
在执行第一个config.mk后,接着定义了交叉编译器的绝对路径如下:
CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-none-linux-gnueabi-
接下来就是U-boot的目标文件变量的定义,这里要注意的是,顺序很重要。如下:
OBJS = cpu/$(CPU)/start.o # 启动代码
OBJS := $(addprefix $(obj),$(OBJS)) # obj := $(OBJTREE)/
# 在94行处定义
LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a
LIBS += cpu/$(CPU)/lib$(CPU).a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += rtc/librtc.a
LIBS += dtt/libdtt.a
LIBS += drivers/libdrivers.a
LIBS += drivers/nand/libnand.a
LIBS += drivers/nand_legacy/libnand_legacy.a
LIBS += post/libpost.a post/cpu/libcpu.a
LIBS += common/libcommon.a
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
下面就要看最重要的all了,先看一下ALL是如何定义的:
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
这里ALL就是我们最后要生成的文件,其实我们中关心一个文件u-boot.bin。
而all依赖于ALL,再进一步解释,我们只关心一个就可以全部理解了,所以我们选择u-boot.bin。
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
看到又有了新的依赖,$(obj)u-boot,这里为了方便也将其列出:
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n –e \ 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
-Map u-boot.map -o u-boot
注:在旧版本的make中,使用编译器此项功能通常的做法是:在Makefile中书写一个伪目标“depend”的规则来定义自动产生依赖关系文件的命令。输入“make depend”将生成一个称为“depend”的文件,其中包含了所有源文件的依赖规则描述。Makefile中使用“include”指示符包含这个文件。
这里又有新的依赖version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT),先看第一个version:
version:
@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \
echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \
echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
$(TOPDIR)) >> $(VERSION_FILE); \
echo "\"" >> $(VERSION_FILE)
这个看起来还比较容易理解,也就是输出一些相关信息,即:
将#define U_BOOT_VERSION “U-Boot输入到$(VERSION_FILE),接着再将$(U_BOOT_VERSION)的值添加到$(VERSION_FILE)中,然后执行tools/setlocalversion输出信息再添加到$(VERSION_FILE)中。
$(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)这些则会根据规则进行编译。现在再看$(obj)u-boot:的最后一行:-o u-boot即生成u-boot。
这一块看着让人头晕……
By: Gary Lee
2009-11-24
近来因为网络原因,给网络中心打电话,也跑了两趟,一直说我们实验室有问题,要求我们格式化,一气之下,来了个全血格式化,瞬间,所有的资料全没有了……心疼啊
这几天一直在看uboot,有兴趣的朋友可以在论坛里一起交流,不懂的问题,可以在版主上课时提问。
1、先执行make SKY2440_config
从Makefile中找到SKY2440_config,在我修改的Makefile中,大约中283行处,这里SKY2440_config所依赖的是unconfig,所以先执行unconfig,往回找目标config,查看发现,只是删除了几个文件,包括:
(1)如果命令行没有指定编译目录,有include/config.h, include/config.mk, board/*/config.tmp(*指你自己的开发板名称),board/*/*/config.tmp文件,
(2)如果命令行中指定了编译目录,则要到自己指定的编译目录中去删除这几个文件,同上。
执行完unconfig后,接下来要执行SKY2440_config下的命令了。
@$(MKCONFIG) $(@:_config=) arm arm920t SKY2440 NULL s3c24x0
这里在79行处,定义了MKCONFIG变量,为$(SRCTREE)/mkconfig,即根目录下的mkconfig,所以上述命令又可写成如下:
mkconfig $(@:_config=) arm arm920t SKY2440 NULL s3c24x0
其中make内建函数 $(@:_config=)的作用是:将当前目标中的_config去掉,所以执行完$(@:_config=)后其返回值为:SYK2440,故上述命令又可写成:
mkconfig SYK2440 arm arm920t SKY2440 NULL s3c24x0
注:$1=SKY2440(名字) $2=arm $3=arm920t $4=SKY2440 $5=NULL(vender) $6=s3c2440(soc)
回头再来查看根目录下的mkconfig文件,在其文件开头有#!/bin/sh,很显然这是一个shell脚本,所以mkconfig后面跟的SYK2440 arm arm920t SKY2440 NULL s3c24x0这些字符串都是这个脚本文件的参数,接下来分析一下这个脚本如何执行的。
14行:while [ $# -gt 0 ]是说如果参数个数大于0就执行以下命令:
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
由于命令中并没有传入--,-a,-n等参数,故执行*,也就是说这段命令不执行。接着往下看:
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
如果BOARD_NAME已定义,则重新赋值,值内容为第1个参数,即SKY2440。
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1
这两句的作用是判断参数个数,做了一个容错处理,防止参数过多或过少。
echo "Configuring for ${BOARD_NAME} board..."
当我们执行make SKY2440_config命令时,如果成功则会在屏幕上输出如下:
Configuring for SKY2440 board...
这就证明配置成功,接下来就要创建链接文件;
if [ "$SRCTREE"!="$OBJTREE" ];then # 当前目录与编译目录不同
mkdir -p ${OBJTREE}/include # 如果我们都没有指定编译目录,略过
mkdir -p ${OBJTREE}/include2 # 在编译目录下创建这两个文件夹
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm
LNPREFIX="../../include2/asm/"
cd ../include
rm -rf asm-$2
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
cd ./include # 进入到./include目录,删除asm文件夹
rm -f asm
ln -s asm-$2 asm # 将asm-$2即asm-arm软链接到asm文件夹
fi
继续:
rm -f asm-$2/arch # 删除asm-arm/arch文件夹
if [ -z "$6" -o "$6" = "NULL" ] ; then # 指如果"$6"长度为零则为真
ln -s ${LNPREFIX}arch-$3 asm-$2/arch # -O "$6"如果"$6"存在且为# 空,就 进行$3链接
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi
if [ "$2" = "arm" ] ; then # 如果参数2为arm,则删除asm-arm/proc
rm -f asm-$2/proc # 将proc-armv链接到asm-arm/proc目录
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
再接下来就要创建开发板头文件
if [ "$APPEND" = "yes" ]
then
echo >> config.h # 在config.h中添加
else
> config.h # 否则创建一个config.h文件
fi
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/$1.h>" >>config.h
到此,confih.h文件已经生成完毕,内容如下:
/* Automatically generated - do not edit */
#include <configs/$1.h>
到此,make SKY2440_config命令已经执行完成,我们再来总结一下:
当我们在命令行输入make SKY2440_config命令时:
(1) 先执行依赖unconfig,也就是删除上次执行make BOARD_NAME_config时生成的include/config.h, include/config.mk, board/*/config.tmp(*指你自己的开发板名称),board/*/*/config.tmp等文件,然后往下执行目标命令;
(2) 输入的make SKY2440_config便解析成mkconfig SKY2440 arm arm920t SKY2440 NULL s3c2440,这里实际上是执行一下shell脚本,作用是生成我们自己开发板所需要的配置文件,如执行unconfig生删除的include/config.h, include/config.mk这两个文件。具体过程是:a)设置BOARD_NAME = $1;b)创建到开发平台或开发板相关的头文件的链接如:
Ln –s arm-$2 asm
Ln –s arm-$6 asm-$2/arch
Ln –s proc-armv asm$2/proc
c)接下来创建顶层Makefile包含文件include/config.mk文件,如下内容:
ARCH = $2
CPU = $3
BOARD = $4
VENDER = $5 # 如果$5为空则这里没有VENDER
SOC = $6 # 同上
d)创建开发板相关的头文件include/config.h,内容如下:
/* Automatically generated - do not edit */
#include <configs/$1.h>
2、ALL
这时返回到Makefile从头来看,找到第一个目录,也就是主目标all。
在all之前主要是定义了一些变量,及判断编译目录等。
注:
在make的递归调用中,需要了解一下变量“CURDIR”,此变量代表make的工作目录。当使用“-C”选项进入一个子目录后,此变量将被重新赋值。总之,如果在Makefile中没有对此变量进行显式的赋值操作,那么它代表make的工作目录。我们也可以在Makefile为这个变量赋一个新的值。此时这变量将不再代表make的工作目录。
接下来看包含文件,在108行和123行处有如下文件:
include $(OBJTREE)/include/config.mk
include $(TOPDIR)/config.mk
此时make会执行这两个文件,第一个文件主要作用是:将由mkconfig生成的这个config.mk文件中定义的ARCH,BOARD,和CPU等变量进行初始化赋值,即:
ARCH=arm;BOARD=SKY2440;CPU=arm920t,而第二个根目录下的config.mk主要是定义了编译规则及编译参数变量等,现在可以不用管。
在执行第一个config.mk后,接着定义了交叉编译器的绝对路径如下:
CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-none-linux-gnueabi-
接下来就是U-boot的目标文件变量的定义,这里要注意的是,顺序很重要。如下:
OBJS = cpu/$(CPU)/start.o # 启动代码
OBJS := $(addprefix $(obj),$(OBJS)) # obj := $(OBJTREE)/
# 在94行处定义
LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a
LIBS += cpu/$(CPU)/lib$(CPU).a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += rtc/librtc.a
LIBS += dtt/libdtt.a
LIBS += drivers/libdrivers.a
LIBS += drivers/nand/libnand.a
LIBS += drivers/nand_legacy/libnand_legacy.a
LIBS += post/libpost.a post/cpu/libcpu.a
LIBS += common/libcommon.a
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
下面就要看最重要的all了,先看一下ALL是如何定义的:
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
这里ALL就是我们最后要生成的文件,其实我们中关心一个文件u-boot.bin。
而all依赖于ALL,再进一步解释,我们只关心一个就可以全部理解了,所以我们选择u-boot.bin。
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
看到又有了新的依赖,$(obj)u-boot,这里为了方便也将其列出:
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n –e \ 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
-Map u-boot.map -o u-boot
注:在旧版本的make中,使用编译器此项功能通常的做法是:在Makefile中书写一个伪目标“depend”的规则来定义自动产生依赖关系文件的命令。输入“make depend”将生成一个称为“depend”的文件,其中包含了所有源文件的依赖规则描述。Makefile中使用“include”指示符包含这个文件。
这里又有新的依赖version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT),先看第一个version:
version:
@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \
echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \
echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
$(TOPDIR)) >> $(VERSION_FILE); \
echo "\"" >> $(VERSION_FILE)
这个看起来还比较容易理解,也就是输出一些相关信息,即:
将#define U_BOOT_VERSION “U-Boot输入到$(VERSION_FILE),接着再将$(U_BOOT_VERSION)的值添加到$(VERSION_FILE)中,然后执行tools/setlocalversion输出信息再添加到$(VERSION_FILE)中。
$(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)这些则会根据规则进行编译。现在再看$(obj)u-boot:的最后一行:-o u-boot即生成u-boot。
这一块看着让人头晕……
图片:155.jpg
相关阅读 更多 +