当我们在编译uboot的时候,要分为两个阶段,一个阶段是配置,配置用的命令是 make x210_sd_config
。配置完成后开始正式的编译,命令为 make
,当然,编译命令可以加什么的参数,比如多线程编译:make -j4
,比如静默编译:make -s
等。在这一篇文章中,我将单独详细分析uboot的配置过程。
1、主Makefile中配置相关部分
首先,目光转向主Makefile,在2589行有如下程序:
x210_sd_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk
显然,x210_sd_config
是Makefile的一个目标。其依赖为unconfig
,在主Makefile的473行可以看到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 \
$(obj)board/$(VENDOR)/$(BOARD)/config.mk
这里插播一句:make中命令行前面加上at符号@,就是在make执行时候,输出的信息中,不要显示此行命令。
可以看出,unconfig其实是执行了一个删除命令,将配置过程中生成的文件全部删掉,达到未配置的效果。保证重新配置时输出文件的纯粹性。
而x210_sd_config下面执行了两句指令,首先看第二条:创建了文件config.mk
,并将字符串"TEXT_BASE = 0xc3e00000"
写入到该文件中。 TEXT_BASE 变量实际上指定了链接地址,在此不赘述。
重点分析第一条指令,MKCONFIG
变量出现在Makefile的第101行,其定义如下,其代表了根目录下的mkconfig脚本文件:
MKCONFIG := $(SRCTREE)/mkconfig
所以说第一条指令的意思就是执行mkconfig文件,并且传进了6个参数,尤其需要分析的是第一个参数$(@:_config=)
,其实这里是用了一个比较高级的Makefile语法,$(a:patternA=patternB)
,这样的语法表示把a变量里的形式为patternA的换成为patternB,然后输出。那么在这个例子里,a变量换成了@,它的意思与shell里@的意思是一样的,就是输入进来的所有的参数。在这里,@就是x210_sd_config,patternA就是_config,patternB就是空,所以$(@:_config=)
的实际表示为x210_sd
。
传参 | 含义 |
---|---|
x210_sd | Target |
arm | Architecture |
s5pc11x | CPU |
x210 | Board |
samsung | VENDOR |
s5pc110 | SOC |
2、mkconfig脚本文件
从第一部分可以看出,配置过程其实就是执行了根目录下的mkconfig文件,所以,这一小部分详细分析该shell脚本。
2.1 前期准备
APPEND=no # Default: Create new config file
BOARD_NAME="" # Name to print in make output
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
esac
done
#如果BOARD_NAME为空,那么就执行后边的赋值
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
#传入参数的数量应该在4到6之间,因为[VENDOR] [SOC]这两个参数可以不传。
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1
echo "Configuring for ${BOARD_NAME} board..."
这一部分代码主要是对传入的参数数目进行了校验,给BOARD_NAME变量赋值。
2.2 创建符号链接文件
mkconfig的33-118行都在创建符号链接文件,由于使用的是条件编译,针对不同CPU有不同的执行,所以在这里只列出跟我们CPU相关的。
#
# Create link to architecture specific headers
#
#在编译的时候uboot支持原地编译(编译结果跟.c/.S文件等混在一起)和自己定义输出文件夹两种方式
#如果[ "$SRCTREE" != "$OBJTREE" ]成立代表使用的是后者。我们现在暂时考虑原地编译的这种情况。
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
rm -f asm
ln -s asm-$2 asm
fi
# create link for s5pc11x SoC
if [ "$3" = "s5pc11x" ] ; then
rm -f regs.h
ln -s $6.h regs.h
rm -f asm-$2/arch
ln -s arch-$3 asm-$2/arch
fi
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
上面的程序创建了以下符号链接文件:
第一个:在include目录下创建asm文件,指向asm-arm。
第二个:在include目录下创建regs.h文件,指向include/s5pc110.h
第三个:在inlcude/asm-arm下创建一个arch文件,指向include/arch-s5pc11x
第四个:在include/asm-arm下创建一个proc文件,指向include/asm-arm/proc-armv
上面的过程在uboot实现可移植上非常重要,比如在include文件夹下每个Soc都会有自己的.h,里面放置着自己的寄存器的定义,例如s5pc110.h,该头文件会被很多.c文件所包含。如果我们的Soc现在不是S5PC110了,换成别的了,相应的头文件就要一个个修改,很麻烦且易出错。
而现在建立一个符号链接文件regs.h代替这个头文件,那么在移植的时候就只需要更改下regs.h指向的文件就好了。这就是uboot实现可移植性的一个重要手段——建立符号链接文件。
2.3 其他输出文件
# Create include file for Make
echo "ARCH = $2" > config.mk
echo "CPU = $3" >> config.mk
echo "BOARD = $4" >> config.mk
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
#
# 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
echo "#include <configs/$1.h>" >>config.h
上面对两个文件进行了操作:include/config.mk和include/config.h。
- config.mk。将ARCH、CPU、BOARD、VENDOR、SOC五个参数写入该文件中,该文件将在主Makefile中引用并使用其中的变量。
- config.h。该文件的主要内容只有一行,
#include <configs/x210_sd.h>
,x210_sd.h这个头文件是相当相当重要的,里面全都是宏定义,这些宏定义就是我们对当前开发板的移植。
shell中>
表示创建文件,>>
表示在该文件中追加内容。