U-boot1.1.6移植之Makefile分析(一)

3786阅读 1评论2009-12-14 shuge_guet
分类:嵌入式

   本文是针友善之臂公司出品的mini2440进行移植,其CPUARM920T架构的S3C2440,一片

64M Nand Flash (K9F1208),一片2M Nor Flash 更具体数据请参考开发板手册。

   u-boot-1.1.6有几千个文件,不可能对每一个文件都了解得非常细致,我们只需要了解自己

工程所用到的相关文件即可,这也是一贯的做法。首先大概的看一下u-boot的文件结构,对其

有个大概的了解,最好的办法是查看顶层的Makdfile由其推出其文件间的依赖关系,这样对移

植有很大的帮助。

   代码结构与功能
      board
——目标板相关文件,主要包含SDRAMFlash驱动;
      common
——独立于处理器体系结构的通用代码,如内存大小探测与故障检测;
      cpu
——与处理器相关的文件,如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件;
      driver
——通用设备驱动,如CFI Flash驱动;

      doc——U-Boot的说明文档;
      examples
——可在U-Boot下运行的示例程序;如helloworld.c,timer.c
      include
——U-Boot头文件,configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;
      lib_xxx
——处理器体系相关的文件,如libppclib_arm目录分别包含与PowerPCARM体系结构相关的文件;
      net
——与网络功能相关的文件目录,如bootpnfstftp
      post
——上电自检文件目录,尚有待于进一步完善;
      rtc
——RTC驱动程序;
      tools
——用于创建U-Boot S-RECORDBIN镜像文件的工具

 //********************************************************************************************************//

////////////////////////////////////////////////////////////////////////////////////////////////////////////

 几个重要的文件分析:
u-boot-1.1.5/Makefile
u-boot-1.1.5/mkconfig
u-boot-1.1.5/config.mk
  
u-boot根目录下的Makefile文件(u-boot-1.1.5/Makefile)它负责配置u-boot的编译方式,具体说来包括:使用何

种指令集,需包含哪些接口驱动、库等。Makefile的内容从上到下分别是:分定义编译环境:使用何种编译器、编译方式、

目标文件的生成及它们最终镜像中的链接次序等。Mkconfigconfig.mk在接下来的分析中会涉及到。

SMDK2410为例

在编译UBOOT之前,先要执行
# make smdk2410_config
smdk2410_config
Makefile的一个目标,定义如下:
smdk2410_config: unconfig
        @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0

其中,unconfig定义如下:
unconfig:
        @rm -f $(obj)include/config.h $(obj)include/config.mk \
        $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp

所以可以看到,当执行make smdk2410_config时,那么make就会先执行unconfig,由unconfig定义可得该命令是

执行清理上一次执行make *_config所生成的头文件与和Makefile包含的相关文件,主要是include/config.h include/config.mk

board/*/config.tmp board/*/*/config.tmp (此处的*为开发板的名称,例如smdk2410

          注:如果命令行中指定了编译目录,则要到自己指定的编译目录中去删除这几个文件。

接着就是执行@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0其中在这里第一个@GNU一种“所有匹配模式”规则,那么

$(MKCONFIG)相当于./mkconfig

在这里特别注意一下$(MKCONFIG)是指引用变量MKCONFIG,而在文件开头有对MKCONFIG的定义

               MKCONFIG     :=$(SRCTREE)/mkconfig

而变量SRCTREE定义在前面指定为

               SRCTREE      :=$(CURDIR)

再找到变量CURDIR的定义

Makfile里找不到其定义,因为它是GNU make的环境变量不需要我们定义

此变量代表make的工作目录当使用“-C”选项进入一个子目录后,此变量将

被重新赋值。总之,如果在Makefile中没有对此变量进行显式的赋值操作,那

么它代表make的工作目录。我们也可以在Makefile为这个变量赋一个新的值。

此时这变量将不再代表make的工作目录。

例如当在目录/

输入 make C /usr/u-boot-1.1.6/ smdk2410_config

那么CURDIR的值就是/usr/u-boot-1.1.6

而当我直接在目录/usr/u-boot-1.1.6

输入 make smdk2410_config

那么CURDIV的值就是.

由于我们直接在源代码目录下执行make一步步的向前推那就是$(MKCONFIG)相当于./mkconfig

     接着下来就到命令行的第二部分$(@:_config=)在这里更要特别的注意了,这里不是变量的引用,在Makefile文件里根本就找不到”变量,所以不能理解为变量,它是GNU make的一个函数,其实这是一个简化的函数 $(VAR:PATTERN=REPLACEMENT)

               GNU中有函数

               $(patsubst ,,)

             

函数名称:模式替换函数—patsubst

函数功能:查找中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)

是否符合模式< pattern>,如果匹配的话,则以替换。这

里,可以包括通配符 “%”,表示任意长度的字串。如果

中也包含“%”,那么,中的这个 “%”将是

的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)

返 回 值:替换后的新字符串

函数说明:参数“TEXT”单词之间的多个空格在处理时被合并为一个空格,并忽略前导和结尾空格

例如:

                 $(patsubst %.c,%.o,x.c.c bar.c)

把字串“x.c.c bar.c”中以.c结尾的单词替换成以.o结尾的字符。函数的返回结果是“x.c.o bar.o

               $(var:=)就是简化的$(patsubst ,,)

所以在$(@:_config=)中就是$(smdk2410_config:_config=)

转为$(patsubst _config,,smdk2410_config)

依定义为把字符串“smdk2410_config”的字符串“_config”用空代替,等于是去除“_config

返回值为“smdk2410

到此为止先看一下“@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0”变成什么样了,下面就是真实的命令了

               ./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0

此命令是执行当前目录下mkconfig脚本,并传入参数,在这里有六个参数,分别为smdk2410 arm arm920t smdk2410 NULL s3c24x0

而这六个参数分别代表什么含义就要到mkconfig里看一看了

                使用vim查看 vim mkconfig

//****************************************************************************************************//

////////////////////////////////////////////////////////////////////////////////////////////////////////

下面着重分析一下mkconfig

(一)首先mkconfig第一行就是#!/bin/sh e它的用途就是指出本脚本是用的哪种shell写的,执行时系统应该用哪种

shell来解释执行它,显然这里是用目录下/bin/sh shell来解释这个脚本。其实每一个文件我应该先认真读一下前面的注解信息

               

 

 

                这一句就简单明了说出该脚的作用是“为一个特定的开发板创建一些相关的头文件和相关配置链接”

                下一句 #Parameters: Target Architecture CPU Board [VENDOR] [SOC]说明了各种参数的意义

Target        宿主机平台

Architecture  定义芯片架构(如MIPSPOWERPCARM等)

CPU           定义芯片指令集版本(如ARM7ARM9ARM11等)

Board         芯片厂商,它细分为两类

[VENDOR]      按厂商划分(如AT9200S3C44B0等)

[SOC]         SOC类型(如S3C2440S3C2410等)

对于#make smdk2410_config命令,由上面分析可以传入参数为

smdk2410 arm arm920t smdk2410 NULL s3c24x0

Target Architecture CPU Board [WENDOR] [SOC]

一一对应[VENDOR]为空,即是NULL 同时注意到上面六个参数与下面的

$1 $2 $3 $4 $5 $6也是一一对应的关系

//****************************************************************************************************//

////////////////////////////////////////////////////////////////////////////////////////////////////////

()接着下来分析mkconfig中的各个语句

               

                下面的语中

   11 APPEND=no # Default: Create new config file

           默认情况下创建一个新的config文件

12 BOARD_NAME="" # Name to print in make output

           显示输出的开发板名字,此时为空

13

14 while [ $# -gt 0 ] ; do   #  [ ]Bash里的一个测试命令,在这里是如果参

数变量个数大于(-gt)零则执行do后的语句

注:Bash里“$#”是传到脚本里的位置参数的个数

15       case "$1" in      #  第一个参数为下列值中的一个

16       --) shift ; break ;;   如果$1为“--”时,所有参数向左移一位,

即把原$1丢弃,原$2补上$1<-$2<-$3<-$4<-$5<-$6

但要注意的是$0即脚本名,保持不变,只

是把原$1丢弃,接着跳出

17       -a) shift ; APPEND=yes ;;  如果“$1为“-a”则APPEND的值

no改成yes 接着跳出(这里;;相当于break;)

18       -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;

                                如果“$1为“-n”则BOARD_NAME

为“$1(注意此时的$1已不是刚传入的

-n”)去掉从右往左算起最后一个“_config

字符串剩下的字符串,接着所有参数再

左移一位,然后跳出循环与case语句

注:在Bash${1%%_config}是一种字符串操作,其标准

形式:${string%%substring}  $string 的右边截掉最后一个匹配的$substring

19       *) break ;;  如果为其他值则直接跳出

20       esac

21 done

22

23 [ "${BOARD_NAME}" ] || BOARD_NAME="$1"

                                这里主要是给BOARD_NAME 赋值,当为空时

赋值为“$1当不为空这保持不变

24

25 [ $# -lt 4 ] && exit 1             如果位置参数的个数小于4则退出

26 [ $# -gt 6 ] && exit 1             #  如果位置参数的个数大于6则退出

27

28 echo "Configuring for ${BOARD_NAME} board..."

在终端上显示Configuring for ${BOARD_NAME} board...

现在回头看一下,总结到目前为止脚本到底做了哪些事情。主要是根据传入的参数做一些简单的配置,对

一些变量进行设置,使之可以为后面所用,让我看下两个例子:

              当输入为make smdk2410_config

               

                u-boot-1.1.6的根目录下输入make smdk2410_config由前面对Makefile粗浅认识

                相当于执行了./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0 此时传入的

                位置参数

$1 = smdk2410

                         $2 = arm

                         $3 = arm920t

                         $4 = smdk2410

                         $5 = NULL(为空)

                         $6 = s3c24x0

                接着进入while部分,执行while [ $# -gt 0 ]    ($#6,大于0)

                进入case执行 *) break ;;                      (因为$1smdk2410)

                然后执行[ "${BOARD_NAME}" ] || BOARD_NAME="$1"  (此时BOARD_NAME= smdk2410)

                跳过[ $# -lt 4 ] && exit 1

                跳过[ $# -gt 6 ] && exit 1

                紧接执行echo "Configuring for ${BOARD_NAME} board..."

(在屏幕上可以看Configuring for ${BOARD_NAME} board.. )

                当输入为 make cpci5200_config

               

                相当于执行了./mkconfig -a cpci5200 ppc mpc5xxx cpci5200 esd此时传入的

位置参数

$1 = -a

                         $2 = cpci5200

                         $3 = ppc

                         $4 = mpc5xxx

                         $5 = cpci5200

                         $6 = esd

            当执行完echo "Configuring for ${BOARD_NAME} board..."

                此时

BOARD_NAME = cpci5200

                APPEND=yes

//****************************************************************************************************//

////////////////////////////////////////////////////////////////////////////////////////////////////////

()接着下来分析mkconfig里的下一部分代码

              

               # Create link to architecture specific headers可知这一部分是

               “为指定的芯片架构创建文件链接”

33 if [ "$SRCTREE" != "$OBJTREE" ] ; then  测试$SRCTREE$OBJTREE不相等依情况执行不同分支

34      mkdir -p ${OBJTREE}/include      如果不等,则创建目录文件夹${OBJTREE}/include

35      mkdir -p ${OBJTREE}/include2     创建目录文件夹${OBJTREE}/include2

36      cd ${OBJTREE}/include2          进入目录文件夹${OBJTREE}/include2

37      rm -f asm                       #  删除当前目录下的asm

38      ln -s ${SRCTREE}/include/asm-$2 asm  建立${SRCTREE}/include/asm-$2文件的符号链接,并命名为asm

39      LNPREFIX="../../include2/asm/"    LNPREFIX赋值为../../include2/asm/

40      cd ../include                     #  进入目录${OBJTREE}/include

41      rm -rf asm-$2                    删除目录asm-$2及下所有东西

42      rm -f asm                       删除asm

43      mkdir asm-$2                    创建目录asm-$2(当前在目录${OBJTREE}/include/)

44      ln -s asm-$2 asm                 建立asm-$2文件的符号链接,并命名为asm

45 else

46      cd ./include                     #  如果$SRCTREE$OBJTREE相等,则进入./include

47      rm -f asm                      删除asrm

48      ln -s asm-$2 asm                 #  建立asm-$2文件的符号链接,并命名为asm(在当前目录下有asm)

49 fi

50

51 rm -f asm-$2/arch                     #  删除目录include/ asm-$2/下的arch

52

53 if [ -z "$6" -o "$6" = "NULL" ] ; then     如果$6的长度为0或为NULL则执行then分支

                                              #  这里说明一下“-z 字符串为"null".就是长度为0

                                      #  -o 逻辑或”

54      ln -s ${LNPREFIX}arch-$3 asm-$2/arch   建立${LNPREFIX}arch-$3文件的符号链接,并命名为asm-$2/arch

55 else

56      ln -s ${LNPREFIX}arch-$6 asm-$2/arch   建立${LNPREFIX}arch-$6文件的符号链接,并命名为asm-$2/arch

57 fi

58

59 if [ "$2" = "arm" ] ; then                如果第二个参数为arm则执行then分支

60     rm -f asm-$2/proc                删除目录asm-$2/proc(当前所在目录为${OBJTREE}/include/)

61     ln -s ${LNPREFIX}proc-armv asm-$2/proc   建立${LNPREFIX}proc-armv文件

的符号链接,并命名为asm-$2/ proc

62 fi

63

64 #

对于make smdk2410_config

执行cd ./include  (当前目录为/usr/u-boot-1.1.6/include)

     rm -f asm  (别忘了是在目录/usr/u-boot-1.1.6/include下的asm)

     ln -s asm-$2 asm  ($2arm)

     rm -f asm-$2/arch  ($2arm)

  ln -s ${LNPREFIX}arch-$6 asm-$2/arch (LNPREFIX../../include/asm/)

  rm -f asm-$2/proc  (当前目录为/usr/u-boot-1.1.6/include)

  ln -s ${LNPREFIX}proc-armv asm-$2/proc (LNPREFIX../../include/asm/,当前目录为/usr/u-boot-1.1.6/include)

结果如下

//****************************************************************************************************//

////////////////////////////////////////////////////////////////////////////////////////////////////////

 

 ()文件链接先告一段落,接着往下看另一部分

            

             # Create include file for Make可知这里为Make创建一些相关的包含文件

             67 echo "ARCH = $2" > config.mk    #  ARCH = $2重定向到文件config.mk

                                                #  如果没有这个文件则创建,有这个文

件就覆盖原来的文件内容,config.mk

在当前目录下

 

68 echo "CPU = $3" >> config.mk    #  重定向CPU = $3到文件config.mk,如

果没有则创建一个新的,并将信息输

入;如果存在,就在原文件后面追加

上要输入的信息。

69 echo "BOARD = $4" >> config.mk

70

71 [ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk

72

73 [ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk

上面的依照分析即行

注:

         bash里有> >>IO重定向1 COMMAND_OUTPUT >

2 # 重定向stdout 到一个文件.

3 # 如果没有这个文件就创建, 否则就覆盖.

 

18 COMMAND_OUTPUT >>

19 # 重定向stdout 到一个文件.

20 # 如果文件不存在, 那么就创建它, 如果存在, 那么就追加到文件后边.

 

所以这一部分就是将

                         ARCH  = arm

                         CPU   = arm920t

                         BOARD = smdk2410

                         SOC   = s3c24x0

             重定向到文件config.mk,即将其输入到config.mk,这时在../include目录下生成一个文件config.mk

             如下图所示:

            

             打印其中的信息:

            

             这文件就是记录一些开发板的信息,被Makefile所用,打开Makefile在前面那里可以找到相关的信息:

             从这里我们可以看到,把./include下的文件config.mk包含进Makefile

             然后声明一些环境变量 ARCH CPU BOARD VENDOR SOC

      注:

当一个变量使用export进行声明后,变量和它的值将被加入到当前工作的

环境变量中,以后在make执行的所有规则的命令都可以使用这个变量。而当没

有使用指示符export对任何变量进行声明的情况下,上层make只将那些已经

初始化的环境变量(在执行make之前已经存在的环境变量)和使用命令行指定

的变量(如命令make CFLAGS +=-g或者make e CFLAGS +=-g)传递给子

make程序,在这里主要是传递给MAKEALL

//****************************************************************************************************//

////////////////////////////////////////////////////////////////////////////////////////////////////////

()接下就要分析mkconfig最后的一部分了,很快就把mkconfig文件分析完:

            

这一部分里主要的工作是创建对特定开以板的头文件

            

             从上面可以看到相应的结果

//******************************************************************************************************//

//////////////////////////////////////////////////////////////////////////////////////////////////////////

到此为止就反mkconfig文件就全部分析完毕,也就是对于Makdfile里的smdk2410_config作用分析也完成了,显然这

样有点乱,因为在这过程中穿插了许多相关知识这些主要参考了《GNU中文手册》《GCC中文手册》《高级Bash 脚本编程指南》

现在认我们再从重头总结一下命令执行的过程以及相关的结果,以smdk2410开发板为例:

                                      在终端下输入make smdk2410_config

|

             进入Makefile执行相关的命令即

smdk2410_config: unconfig
                     @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0

|

             先执行uconfig删除上次生成的相关文件

|

             紧接执行./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0

此时进入mkconfig文件里执行相关语句

|

             变量APPEND=no   BOARD_NAME=smdk24410

在终端上显示Configuring for ${BOARD_NAME} board...

|

             在目录./include下创建文件链接

asm-arm -> asm

../include/asm/arch-s3c24x0 -> asm-arm/arch

../include/asm/proc-armv -> asm-arm/proc

|

             ./include/config.mk文件里写入

ARCH  = arm

CPU   = arm920t

BOARD = smdk2410

SOC   = s3c24x0

|

             接下来就在./include/config.h文件里写入

/* Automatically generated - do not edit */

#include

|

⑨完成./mkconfig

附件:

文件: U-boot1.1.6移植之Makefile分析(一).pdf
大小: 402KB
下载: 下载

 

上一篇:Vim中使用Taglist
下一篇:对.lds连接脚本文件的分析

文章评论