uboot之makefile学习

uboot是一款嵌入式的bootloader软件,能支持多种arch、cpu、board等。uboot的编译分成几个阶段:配置和编译。配置主要是选择单板的配置参数和cpu等信息;编译主要是根据配置信息进行编译。uboot源代码目录下README中说编译两步是 make NAME_config make all两个命令。现来看看make config这个是怎么回事。

我们以分析apollon_config为例进行分析,先把相关的依赖关系贴出来:

apollon_config        : unconfig
    @mkdir -p $(obj)include
    @echo "#define CONFIG_ONENAND_U_BOOT" > $(obj)include/config.h
    @echo "CONFIG_ONENAND_U_BOOT = y" >> $(obj)include/config.mk
    @$(MKCONFIG) $@ arm arm1136 apollon - omap24xx

这里apollon_config首先是依赖于unconfig,这个主要是作一些清理工作,现不去了解。接下来生成一个$(obj)include目录,$(obj)是生成obj的目录,默认是uboot源码目录下,可以通过O=/your/obj/dir来指定,然后接下来两句是定义一些单板相关的宏输出到config.h和config.mk中,这两个非常重要,它就是生成的配置文件,接下来调用mkconfig脚本,进一步生成配置信息。首先mkconfig的入参格式可以参考boards.cfg里面的格式:

# Target                     ARCH        CPU         Board name          Vendor            SoC         Options
###########################################################################################################

integratorcp_cm1136          arm         arm1136     integrator          armltd         -           integratorcp
qong                         arm         arm1136     -                   davedenx       mx31
mx31ads                      arm         arm1136     -                   freescale      mx31
imx31_litekit                arm         arm1136     -                   logicpd        mx31
mx35pdk                      arm         arm1136     -                   freescale      mx35
omap2420h4                   arm         arm1136     -                   ti             omap24xx
tnetv107x_evm                arm         arm1176     tnetv107xevm        ti             tnetv107x
integratorap_cm720t          arm         arm720t     integrator          armltd         -           integratorap
integratorap_cm920t          arm         arm920t     integrator          armltd         -           integratorap
integratorcp_cm920t          arm         arm920t     integrator          armltd         -           integratorcp
a320evb                      arm         arm920t     -                   faraday        a320
at91rm9200ek                 arm         arm920t     at91rm9200ek        atmel          at91        at91rm9200ek
at91rm9200ek_ram             arm         arm920t     at91rm9200ek        atmel          at91        at91rm9200ek:RAMBOOT

接下来主要就是分析mkconfig这个文件它到底做了些什么事情:

if [ \( $# -eq 2 \) -a \( "$1" = "-A" \) ] ; then
    # Automatic mode
    line=`egrep -i "^[[:space:]]*${2}[[:space:]]" boards.cfg` || {
        echo "make: *** No rule to make target \`$2_config'.  Stop." >&2
        exit 1
    }

    set ${line}
    # add default board name if needed
    [ $# = 3 ] && set ${line} ${1}
fi

第一段主要是分析输入参数是否只有两个并且第一个参数是-A,上面调到boards.cfg里面已经定义好了单板的配置,因此我们如果把单板信息放在这里的话,就不需要在makefile里面些很多参数了,直接 mkconfig -A boardname即可。在mkconfig中会自动去boards.cfg中去找。接下来就是使用egrep命令把单板名字$2的那行找出来,如果失败的话说明没有找到相应的单板,退出。如果找到的话,我们需要的信息都有了,于是我们set $(line) 这句话就是将line的信息设置成系统的位置变量。解析来我们就进行解析了。

while [ $# -gt 0 ] ; do
    case "$1" in
    --) shift ; break ;;
    -a) shift ; APPEND=yes ;;
    -n) shift ; BOARD_NAME="${1%_config}" ; shift ;;
    -t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
    *)  break ;;
    esac
done

这一段还是对输入特殊符号进行处理,得到相关信息,上面的那个配置信息并没有这些特殊符号,暂时跳过。

[ $# -lt 4 ] && exit 1
[ $# -gt 7 ] && exit 1

这两句主要对参数总数进行判断,检查是否参数过少或者过多的情况。

CONFIG_NAME="${1%_config}"

[ "${BOARD_NAME}" ] || BOARD_NAME="${1%_config}"

第一句是获得配置名,对应到这里$1 = apollon_config,为了获取名字使用了%_config,这是一个bash字符匹配的用法,即从后面开始匹配_config字符,然后

去掉最短的匹配部分获得apollon,这就是配置的名字。第二句如果boardname没有赋值的话,那么boardname就跟配置名一样。

arch="$2"
cpu="$3"
if [ "$4" = "-" ] ; then
    board=${BOARD_NAME}
else
    board="$4"

fi

这几句主要是获取ach、cpu、board的信息,格式参考上面的boards.cfg。

[ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5"
[ $# -gt 5 ] && [ "$6" != "-" ] && soc="$6"
[ $# -gt 6 ] && [ "$7" != "-" ] && {
    # check if we have a board config name in the options field
    # the options field mave have a board config name and a list
    # of options, both separated by a colon (':'); the options are
    # separated by commas (',').
    #
    # Check for board name
    tmp="${7%:*}"
    if [ "$tmp" ] ; then
        CONFIG_NAME="$tmp"
    fi
    # Check if we only have a colon...
    if [ "${tmp}" != "$7" ] ; then
        options=${7#*:}
        TARGETS="`echo ${options} | sed 's:,: :g'` ${TARGETS}"
    fi
}

这几句是获取 vendor、soc、以及options。这里解析$7还是有点麻烦,主要是这里有两类格式:

integratorap_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorap

versatileqemu                arm         arm926ejs   versatile           armltd         versatile   versatile:ARCH_VERSATILE_QEMU,ARCH_VERSATILE_PB

这里options跟config name之间是:,options之间是用,间隔。所以获取的时候还需要转化下:即把,去掉,在这里处理的时候使用了一个sed命令sed 's:,: :g'即将所有的,全部换成空格。

if [ "${ARCH}" -a "${ARCH}" != "${arch}" ]; then
    echo "Failed: \$ARCH=${ARCH}, should be '${arch}' for ${BOARD_NAME}" 1>&2
    exit 1
fi

这里对arch进行了检查,至此我们的解析工作基本已经完成了,下面就需要根据这些信息生成配置信息了。

if [ "$SRCTREE" != "$OBJTREE" ] ; then
    mkdir -p ${OBJTREE}/include
    mkdir -p ${OBJTREE}/include2
    cd ${OBJTREE}/include2
    rm -f asm
    ln -s ${SRCTREE}/arch/${arch}/include/asm asm
    LNPREFIX=${SRCTREE}/arch/${arch}/include/asm/
    cd ../include
    mkdir -p asm
else
    cd ./include
    rm -f asm
    ln -s ../arch/${arch}/include/asm asm
fi

rm -f asm/arch

if [ -z "${soc}" ] ; then
    ln -s ${LNPREFIX}arch-${cpu} asm/arch
else
    ln -s ${LNPREFIX}arch-${soc} asm/arch
fi

if [ "${arch}" = "arm" ] ; then
    rm -f asm/proc
    ln -s ${LNPREFIX}proc-armv asm/proc
fi

上面主要是判断下是不是obj存放目录是不是跟本地一致,如果不一致的话需要另外创建文件等等。

echo "ARCH   = ${arch}"  >  config.mk
echo "CPU    = ${cpu}"   >> config.mk
echo "BOARD  = ${board}" >> config.mk

[ "${vendor}" ] && echo "VENDOR = ${vendor}" >> config.mk

[ "${soc}"    ] && echo "SOC    = ${soc}"    >> config.mk

这几句就是将解析所得到的arch、cpu、board、vendor、soc等信息输入到config.mk中,以便以后编译的时候使用。

接下来是config.h

if [ -z "${vendor}" ] ; then
    BOARDDIR=${board}
else
    BOARDDIR=${vendor}/${board}
fi

#
# Create board specific header file
#
if [ "$APPEND" = "yes" ]    # Append to existing config file
then
    echo >> config.h
else
    > config.h        # Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h

for i in ${TARGETS} ; do
    i="`echo ${i} | sed '/=/ {s/=/    /;q; } ; { s/$/    1/; }'`"
    echo "#define CONFIG_${i}" >>config.h ;
done

cat << EOF >> config.h
#define CONFIG_BOARDDIR board/$BOARDDIR
#include <config_cmd_defaults.h>
#include <config_defaults.h>
#include <configs/${CONFIG_NAME}.h>
#include <asm/config.h>
EOF

下面跟上面的类似,主要是options处理这块稍微麻烦点。这里先说下options的处理方式:变量定义两种形式:NAME ;NAME = VALUE。对于只有NAME没有赋值的默认等于1,在config.h中这些配置信息的形式是#define CONFIG_NAME    VALUE。所以需要对options进行下处理,sed '/=/ {s/=/    /;q; } ; { s/$/    1/; }‘,即对于有=符号的去掉,没有的在加个 1,也就是默认为1;然后再config信息输出到config.h中。这样我们的config.mk,config.h都有了。接下来就可以根据这些信息进行make了

我们在看看make all里面怎么怎么使用这些配置信息的:

一处是这里:include $(obj)include/config.mk
export    ARCH CPU BOARD VENDOR SOC

直接将之前生成的config.mk包进来了,然后将config.mk的几个重要的全局信息export出来。

还有一处是在:

sinclude $(obj)include/autoconf.mk.dep
sinclude $(obj)include/autoconf.mk

其中 $(obj)include/autoconf.mk的依赖在:

$(obj)include/autoconf.mk: $(obj)include/config.h
    @$(XECHO) Generating $@ ; \
    set -e ; \
    : Extract the config macros ; \
    $(CPP) $(CFLAGS) -DDO_DEPS_ONLY -dM include/common.h | \
        sed -n -f tools/scripts/define2mk.sed > $@.tmp && \
    mv $@.tmp $@

为什么还需要这个呢?不是配置已经生成了,这里我们需要留意下标准的makefile定义是CONFIG_NAME y或者其他,y表示要编译的,否则不编译。前面我们看到的处理默认是1 ,因此还需要转化下,这个任务就是 tools/scripts/define2mk.sed完成的。

/^#define CONFIG_[A-Za-z0-9_][A-Za-z0-9_]*/ {
    # Strip the #define prefix
    s/#define *//;
    # Change to form CONFIG_*=VALUE
    s/  */=/;
    # Drop trailing spaces
    s/ *$//;
    # drop quotes around string values
    s/="\(.*\)"$/=\1/;
    # Concatenate string values
    s/" *"//g;
    # Assume strings as default - add quotes around values
    s/=\(..*\)/="\1"/;
    # but remove again from decimal numbers
    s/="\([0-9][0-9]*\)"/=\1/;
    # ... and from hex numbers
    s/="\(0[Xx][0-9a-fA-F][0-9a-fA-F]*\)"/=\1/;
    # Change '1' and empty values to "y" (not perfect, but
    # supports conditional compilation in the makefiles
    s/=$/=y/;
    s/=1$/=y/;
    # print the line
    p
}

这个脚本是将宏转化成makefile的变量,最后两句就是将=1或则=后面没有赋值的赋值为=y。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值