以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
参考博客
前言
板级支持包(Board Support Package),是由引导程序(bootloader)、内核( kernel)、根文件系统(rootfs)、工具链(toolchain)等软件组成的资源包,一般由芯片厂家或板卡厂家提供。
ARM+linux形式的BSP,其内容和结构都是相似的,因此以X210开发板的BSP为例进行说明。
X210开发板的BSP见下载地址,它包括以下文件或文件夹。
文件或文件夹 | 描述 |
tslib_x210_qtopia.tgz | 用来支持QT的触摸屏操作的应用层库 |
xboot和uboot文件夹 | X210支持的2个bootloader源代码 |
kernel文件夹 | 内核源代码 |
buildroot文件夹 | 用来构建根文件系统的文件夹 |
tools文件夹 | 一些有用工具 |
mk文件 | 用来管理和编译整个bsp |
一、分析mk文件
1、mk文件内容
#!/bin/sh
#
# Description : Build Qt Script.
# Authors : jianjun jiang - jerryjianjun@gmail.com
# Version : 0.01
# Notes : None
#
CPU_NUM=$(cat /proc/cpuinfo |grep processor|wc -l)
CPU_NUM=$((CPU_NUM+1))
SOURCE_DIR=$(cd `dirname $0` ; pwd)
RELEASE_DIR=${SOURCE_DIR}/release/
BOOTLOADER_XBOOT_CONFIG=arm32-x210ii
QT_KERNEL_CONFIG=x210ii_qt_defconfig
INITRD_KERNEL_CONFIG=x210ii_initrd_defconfig
BUILDROOT_CONFIG=x210_defconfig
setup_environment()
{
cd ${SOURCE_DIR};
mkdir -p ${RELEASE_DIR} || return 1;
}
build_bootloader_xboot()
{
if [ ! -f ${RELEASE_DIR}/zImage-initrd ]; then
echo "not found kernel zImage-initrd, please build kernel first" >&2
return 1
fi
if [ ! -f ${RELEASE_DIR}/zImage-qt ]; then
echo "not found kernel zImage-qt, please build kernel first" >&2
return 1
fi
# copy zImage-initrd and zImage-qt to xboot's romdisk directory
cp -v ${RELEASE_DIR}/zImage-initrd ${SOURCE_DIR}/xboot/src/arch/arm32/mach-x210ii/romdisk/boot || return 1;
cp -v ${RELEASE_DIR}/zImage-qt ${SOURCE_DIR}/xboot/src/arch/arm32/mach-x210ii/romdisk/boot || return 1;
# compiler xboot
cd ${SOURCE_DIR}/xboot || return 1
make TARGET=${BOOTLOADER_XBOOT_CONFIG} CROSS=/usr/local/arm/arm-2012.09/bin/arm-none-eabi- clean || return 1;
make TARGET=${BOOTLOADER_XBOOT_CONFIG} CROSS=/usr/local/arm/arm-2012.09/bin/arm-none-eabi- || return 1;
# rm zImage-initrd and zImage-qt
rm -fr ${SOURCE_DIR}/xboot/src/arch/arm32/mach-x210ii/romdisk/boot/zImage-initrd
rm -fr ${SOURCE_DIR}/xboot/src/arch/arm32/mach-x210ii/romdisk/boot/zImage-qt
# copy xboot.bin to release directory
cp -v ${SOURCE_DIR}/xboot/output/xboot.bin ${RELEASE_DIR}
echo "" >&2
echo "^_^ xboot path: ${RELEASE_DIR}/xboot.bin" >&2
return 0
}
build_bootloader_uboot_nand()
{
cd ${SOURCE_DIR}/uboot || return 1
make distclean
make x210_nand_config
make -j${CPU_NUM}
mv u-boot.bin uboot_nand.bin
if [ -f uboot_nand.bin ]; then
cp uboot_nand.bin ${RELEASE_DIR}/uboot.bin
cd ${RELEASE_DIR}
${SOURCE_DIR}/tools/mkheader uboot.bin
echo "^_^ uboot_nand.bin is finished successful!"
exit
else
echo "make error,cann't compile u-boot.bin!"
exit
fi
}
build_bootloader_uboot_inand()
{
cd ${SOURCE_DIR}/uboot || return 1
make distclean
make x210_sd_config
make -j${CPU_NUM}
mv u-boot.bin uboot_inand.bin
if [ -f uboot_inand.bin ]; then
cp uboot_inand.bin ${RELEASE_DIR}/uboot.bin
cd ${RELEASE_DIR}
${SOURCE_DIR}/tools/mkheader uboot.bin
echo "^_^ uboot_inand.bin is finished successful!"
exit
else
echo "make error,cann't compile u-boot.bin!"
exit
fi
}
build_kernel()
{
cd ${SOURCE_DIR}/kernel || return 1
# make ${INITRD_KERNEL_CONFIG} || return 1
# make -j${threads} || return 1
# dd if=${SOURCE_DIR}/kernel/arch/arm/boot/zImage of=${RELEASE_DIR}/zImage-initrd bs=2048 count=8192 conv=sync;
make ${QT_KERNEL_CONFIG} || return 1
make -j${threads} || return 1
dd if=${SOURCE_DIR}/kernel/arch/arm/boot/zImage of=${RELEASE_DIR}/zImage-qt bs=2048 count=8192 conv=sync;
echo "" >&2
# echo "^_^ initrd kernel path: ${RELEASE_DIR}/zImage-initrd" >&2
echo "^_^ qt kernel path: ${RELEASE_DIR}/zImage-qt" >&2
return 0
}
build_rootfs()
{
cd ${SOURCE_DIR}/buildroot || return 1
make ${BUILDROOT_CONFIG} || return 1
make || return 1
# copy rootfs.tar to release directory
cp -v ${SOURCE_DIR}/buildroot/output/images/rootfs.tar ${RELEASE_DIR} || { return 1; }
}
# must root user
gen_qt_rootfs_ext3()
{
if [ ! -f ${RELEASE_DIR}/rootfs.tar ]; then
echo "not found rootfs.tar, please build rootfs" >&2
return 1
fi
echo "making ext3 qt4.8 rootfs now,wait a moment..."
cd ${RELEASE_DIR}
rm -rf rootfs
mkdir -p rootfs
tar xf rootfs.tar -C rootfs
rm rootfs_qt4.ext3
rm -rf rootfs_img
mkdir -p rootfs_img
dd if=/dev/zero of=rootfs_qt4.ext3 bs=1024 count=262144
mkfs.ext3 rootfs_qt4.ext3
mount -o loop rootfs_qt4.ext3 ./rootfs_img
cp ./rootfs/* ./rootfs_img -ar
umount ./rootfs_img
echo "^_^ make rootfs_qt4.ext3 successful!"
}
# must root user
gen_qt_rootfs_jffs2()
{
if [ ! -f ${RELEASE_DIR}/rootfs.tar ]; then
echo "not found rootfs.tar, please build rootfs" >&2
return 1
fi
echo "making jffs2 qt4.8 rootfs now,wait a moment..."
cd ${RELEASE_DIR}
rm -rf rootfs
mkdir -p rootfs
tar xf rootfs.tar -C rootfs
[ -e "rootfs" ] ||{ echo "error!can't find rootfs dir"; exit;}
mkfs.jffs2 -r rootfs -o rootfs_qt4.jffs2 -e 0x20000 -s 0x800 --pad=0x5000000 -n
echo "^_^ make rootfs_qt4.jffs2 successful!"
}
gen_qt_update_bin()
{
# check image files
if [ ! -f ${RELEASE_DIR}/xboot.bin ]; then
echo "not found bootloader xboot.bin, please build bootloader" >&2
return 1
fi
if [ ! -f ${RELEASE_DIR}/zImage-initrd ]; then
echo "not found kernel zImage-initrd, please build kernel first" >&2
return 1
fi
if [ ! -f ${RELEASE_DIR}/zImage-qt ]; then
echo "not found kernel zImage-qt, please build kernel first" >&2
return 1
fi
if [ ! -f ${RELEASE_DIR}/rootfs.tar ]; then
echo "not found rootfs.tar, please build rootfs" >&2
return 1
fi
rm -fr ${RELEASE_DIR}/tmp || return 1;
rm -fr ${RELEASE_DIR}/qt-update.bin || return 1;
mkdir -p ${RELEASE_DIR}/tmp || return 1;
# copy image files
cp ${RELEASE_DIR}/xboot.bin ${RELEASE_DIR}/tmp/;
cp ${RELEASE_DIR}/zImage-initrd ${RELEASE_DIR}/tmp/;
cp ${RELEASE_DIR}/zImage-qt ${RELEASE_DIR}/tmp/;
cp ${RELEASE_DIR}/rootfs.tar ${RELEASE_DIR}/tmp/;
# create md5sum.txt
cd ${RELEASE_DIR}/tmp/;
find . -type f -print | while read line; do
if [ $line != 0 ]; then
md5sum ${line} >> md5sum.txt
fi
done
# mkisofs
mkisofs -l -r -o ${RELEASE_DIR}/qt-update.bin ${RELEASE_DIR}/tmp/ || return 1;
cd ${SOURCE_DIR} || return 1
rm -fr ${RELEASE_DIR}/tmp || return 1;
return 0;
}
threads=4;
xboot=no;
uboot_inand=no;
uboot_nand=no;
kernel=no;
rootfs=no;
rootfs_ext3=no;
rootfs_jffs2=no;
update=no;
if [ -z $1 ]; then
xboot=yes
uboot_inand=no;
uboot_nand=no;
kernel=yes
rootfs=yes
rootfs_ext3=no;
rootfs_jffs2=no;
update=yes
fi
while [ "$1" ]; do
case "$1" in
-j=*)
x=$1
threads=${x#-j=}
;;
-x|--xboot)
xboot=yes
;;
-ui|--uboot_inand)
uboot_inand=yes
;;
-un|--uboot_nand)
uboot_nand=yes
;;
-k|--kernel)
kernel=yes
;;
-r|--rootfs)
rootfs=yes
;;
-re|--rootfs_ext3)
rootfs_ext3=yes
;;
-rj|--rootfs_jffs2)
rootfs_jffs2=yes
;;
-U|--update)
update=yes
;;
-a|--all)
xboot=yes
kernel=yes
rootfs=yes
update=yes
;;
-h|--help)
cat >&2 <<EOF
Usage: mk [OPTION]
Build script for compile the source of telechips project.
-j=n using n threads when building source project (example: -j=16)
-x, --xboot build bootloader xboot from source file
-ui,--uboot_inand build uboot for emmc
-un,--uboot_nand build uboot for nand flash
-k, --kernel build kernel from source file and using default config file
-r, --rootfs build root file system
-re,--rootfs_ext3 build rootfs for emmc,used with uboot
-rj,--rootfs_jffs2 build rootfs for nand,used with uboot
-U, --update gen update package update.bin,used with xboot
-a, --all build all, include anything
-h, --help display this help and exit
EOF
exit 0
;;
*)
echo "build.sh: Unrecognised option $1" >&2
exit 1
;;
esac
shift
done
setup_environment || exit 1
if [ "${kernel}" = yes ]; then
build_kernel || exit 1
fi
if [ "${xboot}" = yes ]; then
build_bootloader_xboot || exit 1
fi
if [ "${uboot_inand}" = yes ]; then
build_bootloader_uboot_inand || exit 1
fi
if [ "${uboot_nand}" = yes ]; then
build_bootloader_uboot_nand || exit 1
fi
if [ "${rootfs}" = yes ]; then
build_rootfs || exit 1
fi
if [ "${rootfs_ext3}" = yes ]; then
gen_qt_rootfs_ext3 || exit 1
fi
if [ "${rootfs_jffs2}" = yes ]; then
gen_qt_rootfs_jffs2 || exit 1
fi
if [ "${update}" = yes ]; then
gen_qt_update_bin || exit 1
fi
exit 0
2、mk文件作用
利用mk脚本可以选择性地编译,即可以通过参数来指定想要编译的内容。
命令 | 描述 |
./mk -a | 编译所有的bsp源代码 |
./mk -x | 只编译xboot |
./mk -ui | 只编译uboot针对inand版本开发板的源代码 |
./mk -r | 只编译buildroot,得到文件夹形式的rootfs |
./mk -re | 编译buildroot并且制作得到ext3格式的rootfs镜像 |
./mk -rj | 编译buildroot并且制作得到jffs2格式的rootfs镜像 |
./mk -h | 查看mk的帮助信息 |
这是如何实现的?
- mk脚本内部用一个函数来完成某块内容的编译(见mk脚本代码),比如编译内核用build_kernel函数,编译inand版本的uboot用build_bootloader_uboot_inand。
- 然后用一些变量来控制这个函数是否被编译,比如变量uboot_inand=yes则表示要编译inand版本的uboot,=no则表示不编译。
- 编译时通过“./mk -xxx”来传参时,这些传参会影响这些变量的值(yes或no)。
- 如果直接./mk并不传参,则$1为空,这时候按照一套默认的配置来编译。
二、分析buildroot文件夹
1、buildroot的作用
buildroot是一个集成包,主要集成了制作交叉编译工具链、构建rootfs等功能。
- 之前的交叉编译工具链arm-linux-gcc,我们都是从soc官方那里得到的,但官方的工具链从何而来?实际上交叉编译工具链都是由gcc配置编译生成的。
- 在构建根文件系统中介绍了从零开始构建根文件系统,但是步骤麻烦。使用buildroot可以很简便的得到一个做好的文件夹形式的根文件系统。buildroot移植了kernel的make xxx_defconfig、make menuconfig的2步配置法。在buildroot的配置界面下完成配置,然后直接make,最终可以得到文件夹形式的rootfs。
2、buildroot的目录
├── arch: 存放CPU架构相关的配置脚本,如arm/mips/x86,这些CPU相关的配置,在制作工具链时,编译uboot和kernel时很关键.
├── board 存放了一些默认开发板的配置补丁之类的
├── boot
├── CHANGES
├── Config.in
├── Config.in.legacy
├── configs: 放置开发板的一些配置参数.
├── COPYING
├── DEVELOPERS
├── dl: 存放下载的源代码及应用软件的压缩包.
├── docs: 存放相关的参考文档.
├── fs: 放各种文件系统的源代码.
├── linux: 存放着Linux kernel的自动构建脚本.
├── Makefile
├── Makefile.legacy
├── output: 是编译出来的输出文件夹.
│ ├── build: 存放解压后的各种软件包编译完成后的现场.
│ ├── host: 存放着制作好的编译工具链,如gcc、arm-linux-gcc等工具.
│ ├── images: 存放着编译好的uboot.bin, zImage, rootfs等镜像文件,可烧写到板子里, 让linux系统跑起来.
│ ├── staging
│ └── target: 用来制作rootfs文件系统,里面放着Linux系统基本的目录结构,以及编译好的应用库和bin可执行文件. (buildroot根据用户配置把.ko .so .bin文件安装到对应的目录下去,根据用户的配置安装指定位置)
├── package:下面放着应用软件的配置文件,每个应用软件的配置文件有Config.in和soft_name.mk,其中soft_name.mk(这种其实就Makefile脚本的自动构建脚本)文件可以去下载应用软件的包。
├── README
├── support
├── system
└── toolchain
3、配置与编译过程
(1)先执行“make x210_defconfig”。
root@ubuntu:/home/xjh/iot/embedded_basic/bsp/buildroot/configs# ls
x210_defconfig #由这里可以知道是make x210_defconfig
root@ubuntu:/home/xjh/iot/embedded_basic/bsp/buildroot# ls
arch CHANGES configs docs Makefile package system
board Config.in COPYING fs Makefile.legacy S99qttest toolchain
boot Config.in.legacy dl linux output support
root@ubuntu:/home/xjh/iot/embedded_basic/bsp/buildroot# make x210_defconfig
//省略部分内容
#
# configuration written to /home/xjh/iot/embedded_basic/bsp/buildroot/.config
#
root@ubuntu:/home/xjh/iot/embedded_basic/bsp/buildroot#
(2)接着执行“make menuconfig”。因为九鼎移植的时候已经配置好了,这个步骤可以省略。
(3)最后执行“make”。
直接执行make会遇到很多错误,这些错误原因都是因为ubuntu中缺乏一些必要软件包造成的。我们需要从网上下载这些软件包,因此整个编译过程需要在联网状态下进行。
You must install 'bison' on your build machine
#sudo apt-get install bison
You must install 'flex' on your build machine
#sudo apt-get install flex
You must install 'makeinfo' on your build machine
makeinfo is usually part of the texinfo package in your distribution
#sudo apt-get install makeinfo
#sudo apt-get install texinfo
You must install 'git' on your build machine
#sudo apt-get install git
You must install 'hg' on your build machine
#sudo apt-get install hg
E: 无法定位软件包 hg
#sudo apt-get install hgsubversion 这个是由在命令行输入“apt-cache search hg”查询得知的
You need the 'mkpasswd' utility to set the root password
(in Debian/ubuntu, 'mkpasswd' provided by the whois package)
#sudo apt-get install whois
(4)编译生成的文件夹格式的rootfs,位于buildroot/output/images/rootfs.tar。
root@ubuntu:/home/xjh/iot/embedded_basic/BSP/buildroot/output# ls
build host images staging stamps target toolchain
root@ubuntu:/home/xjh/iot/embedded_basic/BSP/buildroot/output# cd images/
root@ubuntu:/home/xjh/iot/embedded_basic/BSP/buildroot/output/images# ls
rootfs.tar
root@ubuntu:/home/xjh/iot/embedded_basic/BSP/buildroot/output/images#