全志A33编译脚本分析
0x00 环境说明:
分析所使用的SDK为锐尔威视的开发板的资料中的Linux-SDK
0x01 脚本分析:
顶层目录下的build.sh:
buildroot/scripts/mkcommon.sh $@
本质上是调用的 buildroot/scripts/mkcommon.sh 并直接把所有的参数传过去
mkcommon.sh前几行:
BR_SCRIPTS_DIR=`dirname $0`
# source shflags
. ${BR_SCRIPTS_DIR}/shflags/shflags. ${BR_SCRIPTS_DIR}/mkcmd.sh
设置目录,导入相关命令
然后是:
[ -f .buildconfig ] && . .buildconfig
.buildconfig 文件存在时source该文件
往后是:
if [ "x$1" = "xconfig" ] ; then
. ${BR_SCRIPTS_DIR}/mksetup.sh
exit $?
elif [ "x$1" = "xpack" ] ; then
init_defconf
mkpack
exit $?
elif [ "x$1" = "xpack_debug" ] ; then
init_defconf
mkpack -d card0
exit $?
elif [ "x$1" = "xpack_dump" ] ; then
init_defconf
mkpack -m dump
exit $?
elif [ "x$1" = "xpack_prvt" ] ; then
init_defconf
mkpack -f prvt
exit $?
elif [ $# -eq 0 ] ; then
init_defconf
mklichee
exit $?
fi
根据传入的参数进行相关的操作,从上到下判断的参数依次是:
1、config
2、pack
3、pack_debug
4、pack_dump
5、pack_prvt
6、参数为空
step1:“./build.sh config”
按照编译时的操作顺序,首先执行时传入的参数为 config,调用的是 该目录下的 mksetup.sh:
. buildroot/scripts/mkcmd.sh
function mksetup()
{
rm -f .buildconfig
printf "\n"
printf "Welcome to mkscript setup progress\n"select_board
init_defconf
}mksetup
可以知道具体流程如下:
1、导入 buildroot/scripts/mkcmd.sh 中符号(函数)
2、删除配置文件 .buildconfig(顶层目录)
3、打印提示信息
4、执行 mkcmd.sh 中的 select_board
5、执行 mkcmd.sh 中的 init_defconf
在 select_board 中需要用户设置 chip、platform、kernel、board 等配置
在 init_defconf 则主要设置一些编译时所需要的路径信息
最终会在顶层目录的 .buildconfig 文件中生成如下信息(不同的选择会有所差异):
export LICHEE_CHIP=sun8iw5p1
export LICHEE_PLATFORM=dragonboard
export LICHEE_KERN_VER=linux-3.4
export LICHEE_BOARD=vstar
step2:“cp a33_vstar_defconfig .config”
在 Linux 内核的顶层目录下生成编译配置文件 .config
后续可以通过命令修改配置:
make menuconfig
当然也可以直接进行编辑
step3:“./build.sh ”
编译时直接调用 build.sh,不传入任何参数,在 mkcommon.sh 中执行的是第六条分支:
elif [ $# -eq 0 ] ; then
init_defconf
mklichee
exit $?
fi
其中 init_defconf 确保环境的初始化
编译时主要执行的命令是 mklichee
在 mkcmd.sh 文件中查看 mklichee 的实现:
function mklichee()
{mk_info "----------------------------------------"
mk_info "build lichee ..."
mk_info "chip: $LICHEE_CHIP"
mk_info "platform: $LICHEE_PLATFORM"
mk_info "kernel: $LICHEE_KERN_VER"
mk_info "board: $LICHEE_BOARD"
mk_info "output: out/${LICHEE_CHIP}/${LICHEE_PLATFORM}/${LICHEE_BOARD}"
mk_info "----------------------------------------"
check_envmkbr && mkkernel && mkrootfs
[ $? -ne 0 ] && return 1
mk_info "----------------------------------------"
mk_info "build lichee OK."
mk_info "----------------------------------------"
}
其中 mk_info 设置打印字符串的格式:
function mk_info()
{
echo -e "\033[47;30mINFO: $*\033[0m"
}
mklichee 大致流程为:
1、打印相关配置信息
2、调用 check_env 检查环境
3、依次调用 mkbr、mkkernel、mkrootfs
4、检查执行结果
mkbr:
function mkbr()
{
mk_info "build buildroot ..."local build_script="scripts/build.sh"
(cd ${LICHEE_BR_DIR} && [ -x ${build_script} ] && ./${build_script})
[ $? -ne 0 ] && mk_error "build buildroot Failed" && return 1mk_info "build buildroot OK."
}
该命令实现:进入顶层目录下的 buildroot 文件夹,并执行该文件夹下的 scripts/build.sh
buildroot/scripts/build.sh 先进行编译环境的配置,然后执行:
case "$1" in
clean)
rm -rf ${LICHEE_BR_OUT}
;;
*)
if [ "x${LICHEE_PLATFORM}" = "xlinux" ] ; then
build_buildroot
export PATH=${LICHEE_BR_OUT}/external-toolchain/bin:$PATH
build_external
else
build_toolchain
fi
;;
esac
调用时未传入任何参数,直接跳过第一种参数为 “clean” 时的情况,后续为:
1、当 platform 配置为 linux 时,调用build_buildroot、导出路径、调用build_external
2、当 platform 配置其他情况(android/dragonboard)时,直接调用 build_toolchain
其中 build_buildroot 与 build_external :
build_buildroot()
{
if [ ! -f ${LICHEE_BR_OUT}/.config ] ; then
printf "\nUsing default config ...\n\n"
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} ${LICHEE_BR_DEFCONF}
fimake O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} LICHEE_GEN_ROOTFS=n \
BR2_JLEVEL=${LICHEE_JLEVEL}
}build_external()
{
for dir in ${EXTERNAL_DIR}/* ; do
if [ -f ${dir}/Makefile ]; then
BUILD_COMMAND="make -C ${dir} ${BUILD_OPTIONS} all"
eval $BUILD_COMMAND
BUILD_COMMAND="make -C ${dir} ${BUILD_OPTIONS} install"
eval $BUILD_COMMAND
fi
done
}
build_buildroot 编译生成 交叉工具链(arm-linux-gnueabi),其中:
LICHEE_PLAT_OUT="${LICHEE_OUT_DIR}/${LICHEE_CHIP}/${LICHEE_PLATFORM}/${out_dir}"
LICHEE_BR_OUT="${LICHEE_PLAT_OUT}/buildroot"
build_external 编译扩展的软件工具包,其中:
EXTERNAL_DIR=${LICHEE_BR_DIR}/external-packages
build_toolchain:
build_toolchain()
{
local tooldir="${LICHEE_BR_OUT}/external-toolchain"
mkdir -p ${tooldir}
if [ -f ${tooldir}/.installed ] ; then
printf "external toolchain has been installed\n"
else
printf "installing external toolchain\n"
printf "please wait for a few minutes ...\n"
tar --strip-components=1 \
-jxf ${LICHEE_BR_DIR}/dl/gcc-linaro.tar.bz2 \
-C ${tooldir}
[ $? -eq 0 ] && touch ${tooldir}/.installed
fiexport PATH=${tooldir}/bin:${PATH}
}
作用是直接安装交叉工具链(gcc-linaro),路径为:${LICHEE_BR_DIR}/dl/gcc-linaro.tar.bz2
mkbr到这里就分析完了,下面看mkkernel:
function mkkernel()
{
mk_info "build kernel ..."local build_script="scripts/build.sh"
prepare_toolchain
# mark kernel .config belong to which platform
local config_mark="${LICHEE_KERN_DIR}/.config.mark"
if [ -f ${config_mark} ] ; then
if ! grep -q "${LICHEE_PLATFORM}" ${config_mark} ; then
mk_info "clean last time build for different platform"
(cd ${LICHEE_KERN_DIR} && [ -x ${build_script} ] && ./${build_script} "clean")
echo "${LICHEE_PLATFORM}" > ${config_mark}
fi
else
echo "${LICHEE_PLATFORM}" > ${config_mark}
fi(cd ${LICHEE_KERN_DIR} && [ -x ${build_script} ] && ./${build_script})
[ $? -ne 0 ] && mk_error "build kernel Failed" && return 1mk_info "build kernel OK."
}
流程为处理配置文件之后调用 linux3.4/scripts/build.sh 编译Linux内核:
case "$1" in
kernel)
build_kernel
;;
modules)
build_modules
;;
clean)
clean_kernel
clean_modules
;;
*)
build_kernel
build_modules
build_ramfs
gen_output
;;
esac
下面分析 mkrootfs:
function mkrootfs()
{
mk_info "build rootfs ..."
if [ ${LICHEE_PLATFORM} = "linux" ] ; then
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} target-generic-getty-busybox
[ $? -ne 0 ] && mk_error "build rootfs Failed" && return 1
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} target-finalize
[ $? -ne 0 ] && mk_error "build rootfs Failed" && return 1
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} LICHEE_GEN_ROOTFS=y rootfs-ext4
[ $? -ne 0 ] && mk_error "build rootfs Failed" && return 1
cp ${LICHEE_BR_OUT}/images/rootfs.ext4 ${LICHEE_PLAT_OUT}
elif [ ${LICHEE_PLATFORM} = "dragonboard" ] ; then
echo "Regenerating dragonboard Rootfs..."
(
cd ${LICHEE_BR_DIR}/target/dragonboard; \
if [ ! -d "./rootfs" ]; then \
echo "extract dragonboard rootfs.tar.gz"; \
tar zxf rootfs.tar.gz; \
fi
)
mkdir -p ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules
rm -rf ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules/*
cp -rf ${LICHEE_KERN_DIR}/output/lib/modules/* ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules/
(cd ${LICHEE_BR_DIR}/target/dragonboard; ./build.sh)
cp ${LICHEE_BR_DIR}/target/dragonboard/rootfs.ext4 ${LICHEE_PLAT_OUT}
else
mk_info "skip make rootfs for ${LICHEE_PLATFORM}"
fimk_info "build rootfs OK."
}
作用是生成根文件系统,按照配置的平台的不同分为以下情况:
1、linux:从头开始编译根文件系统
2、dragonboard:直接解压打包好的根文件系统(rootfs.tar.gz),然后加入相关的驱动模块
3、android:直接跳过,android的根文件系统不在这里生成
如果需要进行根文件系统的定制修改,需要分析 mkrootfs 的一些细节
0x02 简单汇总:
最后贴上笔者分析过程中的简单笔记,分析的时候可以凑合着看
build.sh-> buildroot/scripts/mkcommon.sh $@
. ./mkcmd.sh(导入相关编译命令)
[ -f .buildconfig ] && . .buildconfig$1==config:
mksetup.sh
rm -f .buildconfig(build.sh目录下)
select_board
init_defconf(配置输出路径)
LICHEE_PLAT_OUT:/root/a33_linux/dragonboard/out/sun8iw5p1/linux/common
LICHEE_BR_OUT:/root/a33_linux/dragonboard/out/sun8iw5p1/linux/common/buildroot$1==pack:
init_defconf
mkpack
check_env
(cd ${LICHEE_TOOLS_DIR}/pack && \
./pack -c ${LICHEE_CHIP} -p ${LICHEE_PLATFORM} -b ${LICHEE_BOARD} $@)
./pack -c sun8iw5p1 -p linux -b vstar
$1为空:
init_defconf
mklichee
mk_info(打印一些配置信息)
check_env(检查配置,即检查之前有没有运行"./build.sh config"命令)
mkbr && mkkernel && mkrootfs
mkbr:(编译buildroot)
执行scripts/build.sh
mkkernel:(编译内核)
prepare_toolchain(检查工具链)
使用${LICHEE_KERN_DIR}/.config.mark文件中的平台设置
执行scripts/build.sh
mkrootfs:(编译rootfs)
linux:
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} target-generic-getty-busybox
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} target-finalize
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} LICHEE_GEN_ROOTFS=y rootfs-ext4
cp ${LICHEE_BR_OUT}/images/rootfs.ext4 ${LICHEE_PLAT_OUT}
dragonboard:
cd ${LICHEE_BR_DIR}/target/dragonboard
tar zxf rootfs.tar.gz
mkdir -p ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules
rm -rf ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules/*
cp -rf ${LICHEE_KERN_DIR}/output/lib/modules/* ${LICHEE_BR_DIR}/target/dragonboard/rootfs/lib/modules/
(cd ${LICHEE_BR_DIR}/target/dragonboard; ./build.sh)
cp ${LICHEE_BR_DIR}/target/dragonboard/rootfs.ext4 ${LICHEE_PLAT_OUT}
Android:(Android不在这里编译根文件系统)
#make O=/root/a33_linux/dragonboard/out/sun8iw5p1/linux/common/buildroot
scripts/build.sh:
$1==clean:
rm -rf ${LICHEE_BR_OUT}
默认:
${LICHEE_PLATFORM}==linux:
build_buildroot
export PATH=${LICHEE_BR_OUT}/external-toolchain/bin:$PATH
build_external
默认:
build_toolchain