解析u-boot基于I.MX51_BBG的编译过程
目录说明:u-boot顶层目录(TOPLEVEL):~/myandroid/bootable/bootable/uboot-imx 我们在编译过程中,在ubuntu命令行,使用的是如下命令: $ cd ~/myandroid/bootable/bootable/uboot-imx $ make mx51_bbg_android_config $ make uImage 编译完成后,在~/myandroid/bootable/bootable/uboot-imx目录中,就得到了u-boot.bin这个我们所需要的二进制文件。 我们要分析的是,当make mx51_bbg_android_config这个命令执行时,内部都经过了那些过程,有哪些关键的相关文件参与编译。 make mx51_bbg_android_config执行时,以下过程会发生:
一、执行顶层Makefile文件中的“目标”
这可以从Makefile文件中查到。 第一步(第一段代码): mx51_bbg_android_config \\ mx51_bbg_mfg_config \\ mx51_bbg_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 mx51_bbg freescale mx51 从这段代码中,可以看到,编译时执行以下3个命令,会是同样的效果: (1)$ make mx51_bbg_android_config (2)$ make mx51_bbg_mfg_config (3)$ mx51_bbg_config 上述三个不同的执行方式,其结果,都会去找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 这段脚本代码,其作用很明显是为了删除上一次编译产生的所有文件,为本次编译进一次clean操作。 在Makefile文件中,第一段代码位置在注释为“ARM1136 Systems”,大约第3248行前后,本来I.MX51是arm_cortexa8的CPU核,不知道为什么U-BOOT的编写者,把I.MX51对应的目标放在了这里。 第二段代码的位置在Makefile文件开头不远的地方,大约493行前后的位置。 第三部(执行第一段代码最后一句命令) 在执行完unconfig目标对应的清理工作后,再回来执行第一段代码的最后一句: @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 mx51_bbg freescale mx51 稍微解释一下:
MKCONFIG变量的值,是指向顶层目录的./mkconfig脚本文件。紧跟其后面的是6个要传给./mkconfig脚本文件的参数,其中$(@:_config=)的值应该是“mx51_bbg_android”,其他5个分别对应着变量ARCH,CPU,BOARD,VENDOR,SOC。 由此可以看出,当make解析这句代码时,其实就是在终端里执行这样的命令:
$ ./mkconfig mx51_bbg_android arm arm_cortexa8 mx51_bbg freescale mx51 即,给mkconfig脚本运行时带上6个参数。
二、执行./mkconfig命令
从上面的分析,可以知道,现在开始执行: $ ./mkconfig mx51_bbg_android arm arm_cortexa8 mx51_bbg freescale mx51 此时,mkconfig脚本文件,究竟做了那些工作呢,我们就有必要对mkconfig这个可执行脚本进行重点分析一下,用Source Insight打开顶层目录的mkconfig文件,从头开始看它所做的工作:
* mkconfig文件内容 Mkconfig分析第一步: #!/bin/sh –e
# Script to create header files and links to configure # U-Boot for a specific board. #
# Parameters: Target Architecture CPU Board [VENDOR] [SOC] #
# (C) 2002-2006 DENX Software Engineering, Wolfgang Denk
APPEND=no # Default: Create new config file BOARD_NAME=\# Name to print in make output
while [ $# -gt 0 ] ; do case \ --) shift ; break ;; -a) shift ; APPEND=yes ;; -n) shift ; BOARD_NAME=\ *) break ;; esac done 首先,注意到上面的:Parameters这一行,文档中做了解释,就是要接收后面的6个参数进来。“#”是注释用的。 开头的注释,说明了该文件的作用:让u-boot为特定的板卡,创建.H头文件和config配置文件。 上面的2个变量APPEND和BOARD_NAME,有英文做了注释,很清楚。接下来,是一段循环语句和分支语句构成的脚本代码,进行如下解释: (1)“$#”,在脚本规则中,表示命令行参数的数量。 如果$ ./mkconfig mx51_bbg_android arm arm_cortexa8 mx51_bbg freescale mx51这条命令执行时,那么有:$0 =./mkconfig ;$1 = mx51_bbg_android;$2=arm ;$3 = arm_cortexa8 $4=mx51_bbg;$5=freescale;$6=mx51 这样,就形成了一个线性参数表,类似一个数组: $1 , $2 , $3 , $4 , $5 , $6(注意:$0不在这个参数表里) (2)“gt”表示大于的意思
[ $# -gt 0 ]表示参数的数量大于0时。(每循环一次,做减1操作)
(3)“shift”做的动作。 Shift是一个命令,它的前面--),-a),-n)等字符串,是case的比较条件。如果条件满足,比如$1 = -a,那么执行-a) shift ; APPEND=yes ;;这句话,首先shift把参数表中的$1删除,把后面的挨个往前移动,原来的$2变成了现在的$1,然后,把APPEND变量修改为yes,这样循环判断并移动,直到循环条件不成立为止。 显然,我们所执行的参数中,没有上面的--,-a,-n等参数,那么,进入循环后,会执行*)break;;语句,直接终止循环,继续往下执行。
[ \#给BOARD_NAME赋值,不再是空
[ $# -lt 4 ] && exit 1 #参数数量<4时,退出 [ $# -gt 6 ] && exit 1 #参数数量>6时,退出
echo \#终端显示的内容 运行至此,BOARD_NAME的值应为mx51_bbg_android,并且在终端上会显示: Configuring for mx51_bbg_android board...
Mkconfig分析第二步 以下是mkconfig所作的核心工作: 1、创建必须的链接
# Create link to architecture specific headers #
if [ \ mkdir -p ${OBJTREE}/include mkdir -p ${OBJTREE}/include2 cd ${OBJTREE}/include2 rm -f asm ln -s ${SRCTREE}/include/asm-$2 asm LNPREFIX=\ 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 上面的if语句判断,是否在编译的时候指定了输出路径,SRCTREE和OBJTREE分别是源码路径及目标文件输出路径,如果2个变量值不等,那么就说明指定了obj文件的输出路径,否则,obj文件的输出和源码是相同的路径,即没有特殊指定。 我们在编译的时候,没有为obj文件指定路径,因此.o文件会和源码在一个路径下,所
以将会执行上面代码的else后面的部分。它做了3个动作:进去include目录,删除asm这个链接文件(硬链接及符号链接),建立新的符号链接,把asm?asm-arm目录。注意这里的$2=arm。
rm -f asm-$2/arch #删除arm-arm/arch的旧的链接
if [ -z \ ln -s ${LNPREFIX}arch-$3 asm-$2/arch else ln -s ${LNPREFIX}arch-$6 asm-$2/arch #执行该句命令 fi
if [ \ rm -f asm-$2/proc ln -s ${LNPREFIX}proc-armv asm-$2/proc fi 因为$6=mx51,不会空,所以会执行创建arch-mx51新的链接文件asm-arm/arch,因为$2=arm,所以,删除asm-arm/proc链接,重新建立asm-arm/proc?proc-armv。这里LNPREFIX的值为空。
2、创建config.mk文件 路径:顶层目录/include/config.mk # Create include file for Make #
echo \ = $2\ config.mk # ARCH = arm 写入config.mk文件 echo \ = $3\ # CPU = arm_cortexa8写入config.mk文件 echo \ = $4\ # BOARD = mx51_bbg写入config.mk文件
#下面这句,把VENDOR=freescale写入config.mk文件
[ \
#下面这句,把SOC=mx51写入到config.mk文件
[ \ = $6\ 用Source Insight打开TOPPEVLE/include/config.mk,内容如下:
ARCH = arm
CPU = arm_cortexa8 BOARD = mx51_bbg VENDOR = freescale SOC = mx51
3、创建config.h文件 路径:TOPLEVEL/include/config.h
#
# Create board specific header file #
if [ \# Append to existing config file then echo >> config.h else > config.h # Create new config file fi
echo \echo \echo \
exit 0 当APPEND的值为yes时,会在原来旧的./include/config.h的后面,进行追加操作。如果APPEND的值为no时,将重新创建一个新的config.h文件。 后面连续3个echo命令,是往创建的config.h文件中添加内容,我们把编译时产生的config.h文件打开,内容如下:
/* Automatically generated - do not edit */ #include
最后的exit 0 命令,表示正常退出。
总结
针对一个特定的目标板(我们这里是I.MX51_BBG),mkcongfig脚本主要完成三项工作: 1、创建必要的链接 asm-?asm-arm asm-arm/arch-? arch-mx51 asm-arm/proc?proc-armv
2、创建./include/config.mk文件,定义5个变量 ARCH = arm
CPU = arm_cortexa8 BOARD = mx51_bbg VENDOR = freescale SOC = mx51
3、创建./include/config.h
/* Automatically generated - do not edit */ #include
上海风合电子科技有限公司
I.MX Design Group
wigros 2010年5月