• U-Boot Makefile分析(1)配置脚本mkconfig分析


      我们在编译U-Boot之前,需要根据当前使用的板子进行配置,例如make s5p_goni_config,接着才能进行编译make。下面首先分析配置阶段U-Boot做了哪些事情。

      由于执行这些命令是在源码根目录下,所以需要到主Makefile中找一下s5p_goni_config这个目标,搜索结果显示没有匹配的信息,后来发现其实U-Boot设计者已经将配置选项设计成通用模式了:

    %_config:: unconfig

      @$(MKCONFIG) -A $(@:_config=)

      上面的写法比较通用,因为U-Boot支持很多板卡,不同使用者会使用不同的配置,如make mini2440_config; make smdk2410_config; make zynq_config等等,假如每个板卡都在Makefiile中占用一个目标,那么整个Makefile显得很冗余,不如用脚本处理下。

      回到上面的配置目标和依赖描述,显然s5p_goni_config是一个伪目标,依赖是unconfig,不知道为什么这里目标和依赖之间是两个冒号,小纠结。。。unconfig也是一个伪目标:

    unconfig:
      @rm -f $(obj)include/config.h $(obj)include/config.mk
      $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
      $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep

      伪目标下面的命令总是要执行的:删除include/config.h include/config.mk include/autoconf.mk include/autoconf.mk.dep,以及各个板卡的临时配置信息文件config.tmp。因此,每次我们执行make s5p_goni_config之类的配置命令时,都会先清除之前的配置。接下来呢?接下就要执行@$(MKCONFIG) -A $(@:_config=)了,$(MKCONFIG) 是在主Makefile前面部分定义的变量:

    MKCONFIG := $(SRCTREE)/mkconfig

      mkconfig是源码根目录下的一个脚本文件,$(@:_config=)是makefile中变量替换的一种方式,表示把目标$@变量的_config部分替换为空,效果上就是删除_config后缀,因此我们就得到了下面的信息:

    s5p_goni_config:: unconfig

      mkconfig -A s5p_goni

     接下来,我们的任务是分析mkconfig脚本,下面分析主要流程。

      首先定义以下变量,概括地说,mkconfig脚本的主要功能就是根据用户传入的参数,获取以下各变量的值,然后再自动产生一些头文件。

     1 APPEND=no 
     2 BOARD_NAME="" 
     3 TARGETS=""
     4 
     5 
     6 arch=""
     7 cpu=""
     8 board=""
     9 vendor=""
    10 soc=""
    11 options=""

      下面是关键的一步。

     1 if [ ( $# -eq 2 ) -a ( "$1" = "-A" ) ] ; then
     2     # Automatic mode
     3     line=`egrep -i "^[[:space:]]*${2}[[:space:]]" boards.cfg` || {
     4         echo "make: *** No rule to make target \`$2_config'.  Stop." >&2
     5         exit 1
     6     }
     7 
     8     set ${line}
     9     
    10     [ $# = 3 ] && set ${line} ${1}
    11 elif [ "${MAKEFLAGS+set}${MAKELEVEL+set}" = "setset" ] ; then
    12     # only warn when using a config target in the Makefile
    13     cat <<-EOF
    14 
    15     warning: Please migrate to boards.cfg.  Failure to do so will
    16              mean removal of your board in the next release.
    17 
    18     EOF
    19     sleep 5
    20 fi

      显然我们的参数个数和内容是符合分支判断要求的,因此执行那条文本数据处理命令,目的是在boards.cfg文件中根据s5p_goni匹配一行信息,这条信息放在line变量中,如果返回值为空字符串那么就报错退出,提示没有用户所说的这块板子的相关配置。那么boards.cfg文件中是什么内容呢?它是目前U-Boot支持板卡的信息汇总,通过这个文件,我们可以知道U-Boot支持哪些架构、哪些处理器、哪些SoC、哪些board,是一个很好的参考,它的每一个entry都是有格式要求的:

    Target   ARCH   CPU   Board name   Vendor   SoC     Option

    s5p_goni  arm    armv7    goni    samsung  s5pc1xx 

    zynq    arm    armv7    zynq     xilinx   zynq 

    mini2440   arm    arm920t  mini2440  friendlyARM s3c24x0

     

      上面的格式很简单,不多说,如果将来想支持自己的板卡,那么加入自己的选项就好了。比如

    tiny210 arm armv7   tiny210 frirndlyARM s5pc1xx

      

      回到脚本分析,set ${line}这条语句不简单,我由于不知道这句话的含义,纠结了很久,后来做实验才明白这句话的作用:改变当前脚本的参数$# $1 $2 $3...,这些参数的内容完全由{line}决定。此时它的内容就是s5p_goni那一行,那么

    $# = 6

    $1 = s5p_goni  $2 = arm  $3 = armv7  $4 = goni  $5 = samsung  $6 = s5pc1xx

     1 while [ $# -gt 0 ] ; do
     2     case "$1" in
     3     --) shift ; break ;;
     4     -a) shift ; APPEND=yes ;;
     5     -n) shift ; BOARD_NAME="${1%_config}" ; shift ;;
     6     -t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
     7     *)  break ;;
     8     esac
     9 done
    10 
    11 [ $# -lt 4 ] && exit 1
    12 [ $# -gt 7 ] && exit 1
    13 
    14 # Strip all options and/or _config suffixes
    15 CONFIG_NAME="${1%_config}"
    16 
    17 [ "${BOARD_NAME}" ] || BOARD_NAME="${1%_config}"
    18 
    19 arch="$2"
    20 cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $1}'`
    21 spl_cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $2}'`
    22 if [ "$4" = "-" ] ; then
    23     board=${BOARD_NAME}
    24 else
    25     board="$4"
    26 fi
    27 [ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5"
    28 [ $# -gt 5 ] && [ "$6" != "-" ] && soc="$6"
    29 [ $# -gt 6 ] && [ "$7" != "-" ] && {
    30     tmp="${7%:*}"
    31     if [ "$tmp" ] ; then
    32         CONFIG_NAME="$tmp"
    33     fi
    34     # Check if we only have a colon...
    35     if [ "${tmp}" != "$7" ] ; then
    36         options=${7#*:}
    37         TARGETS="`echo ${options} | sed 's:,: :g'` ${TARGETS}"
    38     fi
    39 }
    40 
    41 if [ "${ARCH}" -a "${ARCH}" != "${arch}" ]; then
    42     echo "Failed: $ARCH=${ARCH}, should be '${arch}' for ${BOARD_NAME}" 1>&2
    43     exit 1
    44 fi
    45 
    46 if [ "$options" ] ; then
    47     echo "Configuring for ${BOARD_NAME} - Board: ${CONFIG_NAME}, Options: ${options}"
    48 else
    49     echo "Configuring for ${BOARD_NAME} board..."
    50 fi

      上面代码的while循环对于当前这个板卡是没有作用的,且明显参数个数是满足继续运行的要求的,接下来就开始赋值了

    CONFIG_NAME = s5p_goni

    BOARD_NAME = s5p_goni

    arch = arm

    cpu = armv7

    spl_cpu = 

    board = goni

    vendor = samsung

    soc = s5pc1xx

      这里我们没有第七个参数,因此相关的option置空,那么配置的时候屏幕会输出一句“Configuring for s5p_goni board...”。

      重要的变量都得到了,下面开始第二项重要工作,建立相关软链接和头文件。

     1 if [ "$SRCTREE" != "$OBJTREE" ] ; then
     2     mkdir -p ${OBJTREE}/include
     3     mkdir -p ${OBJTREE}/include2
     4     cd ${OBJTREE}/include2
     5     rm -f asm
     6     ln -s ${SRCTREE}/arch/${arch}/include/asm asm
     7     LNPREFIX=${SRCTREE}/arch/${arch}/include/asm/
     8     cd ../include
     9     mkdir -p asm
    10 else
    11     cd ./include
    12     rm -f asm
    13     ln -s ../arch/${arch}/include/asm asm
    14 fi

      上面SRCTREE与OBJTREE是相同的,代表所有源码都在本地,再本地编译链接,得到目标,因此执行else分支:再当前shell运行的子进程中进入include文件夹下,删除其下面的asm(asm是一个软链接文件),接着为arch/arm/include/asm文件夹建立软链接asm。

     1 rm -f asm/arch
     2 
     3 if [ -z "${soc}" ] ; then
     4     ln -s ${LNPREFIX}arch-${cpu} asm/arch
     5 else
     6     ln -s ${LNPREFIX}arch-${soc} asm/arch
     7 fi
     8 
     9 if [ "${arch}" = "arm" ] ; then
    10     rm -f asm/proc
    11     ln -s ${LNPREFIX}proc-armv asm/proc
    12 fi

      首先删除asm/arch,注意!此处的asm已经是软链接了,所以删除的是arch/arm/include/asm/arch(其实arch也是软链接文件)。soc变量长度非零,因此为arch/arm/include/asm/arch-s5pc1xx 建立软链接asm/arch。其实上面两段代码的作用就是建立asm和arch两个软链接,以后在C语言包含头文件时,头文件的路径写起来就比较方便。

     1 ( echo "ARCH   = ${arch}"
     2     if [ ! -z "$spl_cpu" ] ; then
     3     echo 'ifeq ($(CONFIG_SPL_BUILD),y)'
     4     echo "CPU    = ${spl_cpu}"
     5     echo "else"
     6     echo "CPU    = ${cpu}"
     7     echo "endif"
     8     else
     9     echo "CPU    = ${cpu}"
    10     fi
    11     echo "BOARD  = ${board}"
    12 
    13     [ "${vendor}" ] && echo "VENDOR = ${vendor}"
    14     [ "${soc}"    ] && echo "SOC    = ${soc}"
    15     exit 0 ) > config.mk
    16 
    17 # Assign board directory to BOARDIR variable
    18 if [ -z "${vendor}" ] ; then
    19     BOARDDIR=${board}
    20 else
    21     BOARDDIR=${vendor}/${board}
    22 fi

      向include/config.mk中写入一些信息:

    ARCH = arm
    CPU = armv7
    BOARD = goni
    VENDOR = samsung
    SOC = s5pc1xx

      打开include/config.mk发现其内容和上述一致。上面最后一句BOARDDIR=samsung/goni,其实这就提示我们,在boards.cfg文件中添加信息后,还要在board目录下建立vendor/board目录,两者都要有,mkdir -p vendor/board。

     1 if [ "$APPEND" = "yes" ]    # Append to existing config file
     2 then
     3     echo >> config.h
     4 else
     5     > config.h      # Create new config file
     6 fi
     7 echo "/* Automatically generated - do not edit */" >>config.h
     8 
     9 for i in ${TARGETS} ; do
    10     i="`echo ${i} | sed '/=/ {s/=/  /;q; } ; { s/$/ 1/; }'`"
    11     echo "#define CONFIG_${i}" >>config.h ;
    12 done
    13 
    14 cat << EOF >> config.h
    15 #define CONFIG_BOARDDIR board/$BOARDDIR
    16 #include <config_cmd_defaults.h>
    17 #include <config_defaults.h>
    18 #include <configs/${CONFIG_NAME}.h>
    19 #include <asm/config.h>
    20 EOF
    21 
    22 exit 0

      我们这块板子并没有append option,所以直接建立config.h文件,建立的方式比较简单:> config.h,第一次见到这种建立空白文件的方式,新技能get!接着在该文件的头部添加一句提示语。最后,向config.h写入一些信息,这里只是包含一些其他头文件:

    #define CONFIG_BOARDDIR  board/samsung/goni

    #include <config_cmd_defaults.h>

    #define <config_defaults.h>

    #define <configs/s5p_goni.h>  //这就对应当前板子的头文件,应该放在include/configs目录下。

    #include <asm/config.h>

    注意脚本中向文件写内容方式:

    cat << EOF >> filename

    line1

    line2

    ....

    EOF

  • 相关阅读:
    二叉树的镜像(剑指offer-18)
    树的子结构(剑指offer-17)
    合并两个有序链表(剑指offer-16)
    OutOfMemory相关问题(内存溢出异常OOM)
    Java内存区域
    招银网络(一面06.29)
    反转链表(剑指offer-15)
    链表中倒数第k个节点(剑指offer-14)
    调整数组顺序使奇数位于偶数前面(剑指offer-13)
    数值的整数次方(剑指offer-12)
  • 原文地址:https://www.cnblogs.com/tech-lqh/p/8404456.html
Copyright © 2020-2023  润新知