在《Lichee(三) Android4.0的目标产品目录与Lichee的纽带---extract-bsp》中我们分析了extract-bsp的作用和意义,到这里,我们可以开始编译Android了
执行 make -j8
………………
漫长的等待之后,Android的目标文件都到了out目录,假设我们的目标产品名叫crane-mt7332
out/target/product/crane-mt7332/
├── android-info.txt
├── boot.img
├── clean_steps.mk
├── data
├── installed-files.txt
├── kernel
├── obj
├── previous_build_config.mk
├── ramdisk.img
├── ramdisk-recovery.img
├── recovery
├── recovery.fstab
├── recovery.img
├── root
├── symbols
├── system
├── system.img
└── userdata.img
很高兴,我们看到了很多的.img文件,这些文件就是为了给我们打包做准备
接下来,我们开始详细地分析Lichee的打包过程
打包有2种方式,在lichee,Android中都可以完成pack
在lichee中执行
$ ./build.sh pack就可以实现打包
在 buildroot/scripts/common.sh中有:
if [ "$1" = "pack" ]; then
${BR_DIR}/scripts/build_pack.sh
exit 0
fi
这里环境变量BR_DIR=buildroot,其实去执行buildroot/script/build_pack.sh
变量赋值部分:
LICHEE_ROOT=$PWD
PACK_ROOT=tools/pack
TARGET_CHIP="sun4i"
TARGET_PLATFORM="linux"
TARGET_BOARD="evb"
count=0
选择chip
目录结构
#tree -L 1 tools/pack/chips/
#tools/pack/chips/
#└── sun4i
printf "Start packing for Lichee system\n\n"
select_chips
我们分析这个函数
select_chips()
{
count=0
printf "All valid chips:\n"
# $PACK_ROOT/chips/ 就是 lichee/tools/pack/chips
#find -mindepth 1 -maxdepth 1 -type d |sort 意思是查找 lichee/tools/pack/chips中的所有目录,深度为1,也就是只查找到chips这一级,不再往下查找子目录了
#我们来tree一下 tools/pack/chips/ 这个目录,发现就只有sun4i一个子目录
for chip in $(cd $PACK_ROOT/chips/; find -mindepth 1 -maxdepth 1 -type d |sort); do
chips[$count]=`basename $PACK_ROOT/chips/$chip`
printf "$count. ${chips[$count]}\n"
let count=$count+1
done
# 在这里读取我们的选择,并对输入的数据做验证
while true; do
read -p "Please select a chip:"
RES=`expr match $REPLY "[0-9][0-9]*$"`
if [ "$RES" -le 0 ]; then
echo "please use index number"
continue
fi
if [ "$REPLY" -ge $count ]; then
echo "too big"
continue
fi
if [ "$REPLY" -lt "0" ]; then
echo "too small"
continue
fi
break
done
TARGET_CHIP=${chips[$REPLY]}
}
我们来看看实际执行结果
Start packing for Lichee system
All valid chips:
0. sun4i
Please select a chip:0
果然不出所料 只有一个sun4i 说明我们前面的分析完全正确,这里我们输入 '0'
选择平台
执行命令
select_platform $TARGET_CHIP
目录结构
tools/pack/chips/sun4i/configs/
├── crane
├── dragonboard
├── linux
└── test
select_platform()
{
count=0
chip=$1
printf "All valid platforms:\n"
# 由于之前select_chips已经$TARGET_CHIP=sun4i 所以$chip=sun4i
# 类似于select_chips,这里会find tools/pack/chips/sun4i/configs/的结果,以序号. 目录名的方式输出到终端,让用户选择
for platform in $(cd $PACK_ROOT/chips/$chip/configs/; find -mindepth 1 -maxdepth 1 -type d |sort); do
platforms[$count]=`basename $PACK_ROOT/chips/$chip/configs/$platform`
printf "$count. ${platforms[$count]}\n"
let count=$count+1
done
……
TARGET_PLATFORM=${platforms[$REPLY]}
}
执行结果
All valid platforms:
0. crane
1. dragonboard
2. linux
3. test
Please select a platform:0
这么我们要打包的平台是Android 所以我们选择crane,输入 '0'
选择目标板
select_boards $TARGET_CHIP $TARGET_PLATFORM
目录结构
tree -L 1 tools/pack/chips/sun4i/configs/crane/
tools/pack/chips/sun4i/configs/crane/
├── 3g
├── aino
├── aino-aurora
├── bk7011
├── default
├── evb
├── evb_mmc
├── evb-v12r
├── evb-v13
├── m1003h6
├── m802h6
├── mid7042
├── MID9742-sc3052
├── t780
└── tvdevb
select_boards()
{
count=0
# 把我们选定的chip 和 platform 参数传进来
chip=$1
platform=$2
printf "All valid boards:\n"
# 根据传进来的参数 $PACK_ROOT/chips/$chip/configs/$platform/ 即 tools/pack/chips/sun4i/configs/crane 查找1级子目录 ,并排序
for board in $(cd $PACK_ROOT/chips/$chip/configs/$platform/; find -mindepth 1 -maxdepth 1 -type d |grep -v default|sort); do
boards[$count]=`basename $PACK_ROOT/chips/$chip/configs/$platform/$board`
printf "$count. ${boards[$count]}\n"
let count=$count+1
done
……
}
到这里我们发现了我们打包缺少了一个非常重要的步骤,记得《Lichee(三) Android4.0的目标产品目录与Lichee的纽带---extract-bsp》我们lunch之后,会有自己的目标产品,通过上面的分析我们可以看出,我们必须在打包的时候在tools/pack/chips/sun4i/configs/crane目录下创建一个自己产品的目录,我们暂时把evb-v13目录复制过来,改名为mt7332,关于mt7332目下的具体内容,后面会作为重点对象单独提出来分析
执行pack
cd $PACK_ROOT
./pack -c $TARGET_CHIP -p $TARGET_PLATFORM -b $TARGET_BOARD
cd -
当编译完成后我们会执行一个pack命令,pack也是一个脚本,路径:lichee/tools/pack/pack,这是一个可执行的脚本文件(softwinner同样也提供了windows的打包工具),然后我们来看看pack究竟干了些什么
do_pack_crane()
{
printf "!!!Packing for crane!!!\n"
if [ -z "$LICHEE_OUT" ]; then
LICHEE_OUT=`cd ../../out; pwd`
fi
if [ -z "$CRANE_IMAGE_OUT" ]; then
echo "please specify CRANE_IMAGE_OUT env"
exit 1
fi
#拷贝所有的fex cfg文件到out目录
cp -v chips/$PACK_CHIP/configs/$PACK_PLATFORM/default/* out/
cp -v chips/$PACK_CHIP/configs/$PACK_PLATFORM/$PACK_BOARD/*.fex out/ 2>/dev/null
cp -v chips/$PACK_CHIP/configs/$PACK_PLATFORM/$PACK_BOARD/*.cfg out/ 2>/dev/null
#cp -v (verbose)选项,cp命令将告诉用户正在做什么。
#2>/dev/null 就是当出错的时候,重定向到/dev/null,也就是不向中断输出出错时候的信息
# modify the debug opt
if [ $PACK_CHIP = sun4i ]; then
#由于A10有2个可以复用的UART0 如果执行命令是 ./pack -c sun4i -p crane -b mt7332 -d card0,就表示将串口内容输出到card0
#因为我们使用默认的PB22 PB23,所以我们的执行命令时./pack -c sun4i -p crane -b mt7332 -d uart0
if [ $PACK_DEBUG = card0 ]; then
cp $TOOLS_DIR/awk_debug_card0 out/awk_debug_card0
TX=`awk '$0~"a10"{print $2}' pctools/linux/card_debug_pin`
RX=`awk '$0~"a10"{print $3}' pctools/linux/card_debug_pin`
sed -i s'/uart_debug_tx =/uart_debug_tx = '$TX'/g' out/awk_debug_card0
sed -i s'/uart_debug_rx =/uart_debug_rx = '$RX'/g' out/awk_debug_card0
sed -i s'/uart_tx =/uart_tx = '$TX'/g' out/awk_debug_card0
sed -i s'/uart_rx =/uart_rx = '$RX'/g' out/awk_debug_card0
awk -f out/awk_debug_card0 out/sys_config1.fex > out/a.fex
rm out/sys_config1.fex
mv out/a.fex out/sys_config1.fex
echo "uart -> card0 !!!"
fi
fi
#将boot0.bin boot1.bin bootfs.ini diskfs.fex拷贝到fex目录下
cp -rf eFex/split_xxxx.fex eFex/card/mbr.fex \
eGon/storage_media/nand/boot0.bin eGon/storage_media/nand/boot1.bin \
wboot/bootfs wboot/bootfs.ini wboot/diskfs.fex \
out/
cp -rf eGon/storage_media/sdcard/boot0.bin out/card_boot0.fex
cp -rf eGon/storage_media/sdcard/boot1.bin out/card_boot1.fex
cp -v chips/$PACK_CHIP/configs/$PACK_PLATFORM/$PACK_BOARD/drv_de.drv out/bootfs/ 2>/dev/null
cd out/
# 拷贝uboot 执行cp -v $LICHEE_OUT/u-boot.bin bootfs/linux/u-boot.bin
do_copy_u_boot
sed -i 's/\\bootfs/\/bootfs/g' bootfs.ini
sed -i 's/\\\\/\//g' image.cfg
sed -i 's/imagename/;imagename/g' image.cfg
if [ $PACK_DEBUG = card0 ]; then
IMG_NAME="${PACK_CHIP}_${PACK_PLATFORM}_${PACK_BOARD}_$PACK_DEBUG.img"
else
IMG_NAME="${PACK_CHIP}_${PACK_PLATFORM}_${PACK_BOARD}.img"
fi
echo "imagename = $IMG_NAME" >> image.cfg
echo "" >> image.cfg
# sys_config.fex和sys_config1.fex文件其实就是 tools/pack/chips/sun4i/configs/crane/mt7332目录下面的配置,sys_config1.fex主要配置CPU频率、外设、GPIO等, sys_config.fex主要用来配置分区
# unix2dos 将unix转为dos的文件方式,最主要的就是换行不同
busybox unix2dos sys_config.fex
busybox unix2dos sys_config1.fex
script sys_config.fex
script sys_config1.fex
update_23 sys_config1.bin boot0.bin boot1.bin
update_23 sys_config1.bin card_boot0.fex card_boot1.fex SDMMC_CARD
cp sys_config1.bin bootfs/script0.bin
cp sys_config1.bin bootfs/script.bin
update_mbr sys_config.bin mbr.fex 4 16777216
fsbuild bootfs.ini split_xxxx.fex
# get bootloader.fex
mv bootfs.fex bootloader.fex
# get env.fex
u_boot_env_gen env_mmc.cfg env_mmc.fex
u_boot_env_gen env_nand.cfg env_nand.fex
cat env_mmc.fex >> env_nand.fex
cp env_nand.fex env.fex
# get other images from android build
ln -s $CRANE_IMAGE_OUT/boot.img boot.fex
ln -s $CRANE_IMAGE_OUT/system.img system.fex
ln -s $CRANE_IMAGE_OUT/recovery.img recovery.fex
# checksum for all fex
FileAddSum bootloader.fex vbootloader.fex
FileAddSum env.fex venv.fex
FileAddSum boot.fex vboot.fex
FileAddSum system.fex vsystem.fex
FileAddSum recovery.fex vrecovery.fex
#根据 image.cfg 用dragon来打包,生成最后的img文件
dragon image.cfg
if [ -e ${IMG_NAME} ]; then
mv ${IMG_NAME} ../${IMG_NAME}
echo '---------image is at-------------'
echo -e '\033[0;31;1m'
echo ${ROOT_DIR}/${IMG_NAME}
echo -e '\033[0m'
fi
cd - 1>/dev/null
}
./pack -c sun4i -p crane -b mt7332 -d uart0
./pack -c sun4i -p crane -b mt7332 -d card0
小贴士:
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。
awk的处理文本和数据的方式:它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。
awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Peter Weinberger、Brian Kernighan。
gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的,在linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍。
本文主要是对于pack的过程进行了分析,对于do_pack_crane的分析比较浅显,因为这个脚本的关键内容,诸如update_23, update_mbr, dragon 等,我们无法看到源代码,打包固件的过程本来就是比较复杂的,但是我们对Lichee的主要架构已经非常清晰了,通过对脚本的分析,我们知道了在tools/pack/chips/sun4i/configs/crane目录下必须创建我们自己产品的目录,否则就无法打包