Chinaunix首页 | 论坛 | 博客
  • 博客访问: 149113
  • 博文数量: 72
  • 博客积分: 3680
  • 博客等级: 中校
  • 技术积分: 1051
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-22 13:51
文章分类
文章存档

2010年(72)

我的朋友

分类: LINUX

2010-10-11 16:37:52

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-$2asm-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      # 如果参数2arm,则删除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 " >>config.h

到此,confih.h文件已经生成完毕,内容如下:

/* Automatically generated - do not edit */

#include

到此,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

2ALL

    这时返回到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
阅读(1040) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-10-11 17:53:16

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com