基于平台:slinx的全志A33开发板
开发板编译系统指令如下:
tar -xvf sinlinx-a33-linux-xxx.tar.gz
git reset –hard工具链:
tar -jxvf /root/work/sinlinx/a33/tools/toolchain/arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 -C /opt/
export PATH=$PATH:/opt/arm-2014.05/bin编译指令:
cd lichee
./build.sh config
./build.sh
./build.sh pack
首先我们需要先配置内核,装载哪些东西不装载哪些东西,这个配置文件就是deconfig,我平台的deconfig如下:
sinlinx-a33-linux-20160409\lichee\linux-3.4\arch\arm\configs\sun8iw5p1smp_defconfig
这个defconfig最后会编译进根目录下的.config
make menuconfig 会根据上面 defconfig 的基础上生成一个配置页面,实际上也是去读取 .config 的内容,我们可以在上面修改配置项
我的平台并不是直接的进行 make sun8iw5p1smp_defconfig,而是通过一系列的脚本间接的进行 make,这样做的目的是为了兼容其它不同的平台
先是执行了脚本+config选项,所以这里分析下 ./build.sh config
build.sh 打开并运行 mkcommon.sh 这个脚本:
buildroot/scripts/mkcommon.sh $@
mkcommon.sh 根据 config 选项运行 mksetup.sh :
if [ "x$1" = "xconfig" ] ; then
. ${BR_SCRIPTS_DIR}/mksetup.sh
mksetup.sh 执行 mkcmd.sh 脚本然后执行 mksetup 函数:
. buildroot/scripts/mkcmd.sh
mksetup
mkcmd.sh 定义了一些变量,主要是定义内核目录、工具目录、输出目录等,然后定义了一些功能函数:
# define importance variable
LICHEE_TOP_DIR=`pwd`
LICHEE_BR_DIR=${LICHEE_TOP_DIR}/buildroot
LICHEE_KERN_DIR=${LICHEE_TOP_DIR}/linux-3.4
LICHEE_TOOLS_DIR=${LICHEE_TOP_DIR}/tools
LICHEE_OUT_DIR=${LICHEE_TOP_DIR}/out
function init_defconf(){}
function init_chips(){}
function select_board(){}
.....
接着回到 mksetup.sh 这个脚本继续执行 mksetup 函数:
function mksetup()
{
rm -f .buildconfig
printf "\n"
printf "Welcome to mkscript setup progress\n"
select_board
init_defconf
}
先执行 select_board 函数,经过分析后先后执行了以下函数来进行系统相关的配置:
select_chip
select_platform
select_qt
select_kern_ver
select_board
脚本先后实现芯片、平台、QT、kernel、boards的选择,然后执行函数 init_defconf,函数关键内容如下 :
pattern="${LICHEE_CHIP}_${LICHEE_PLATFORM}_${LICHEE_BOARD}"
defconf=`awk '$1=="'$pattern'" {print $2,$3}' buildroot/scripts/mkrule`
根据前面定义的配置,这里实际去 mkrule 文件里面匹配到 LICHEE_KERN_DEFCONF = sun8iw5p1smp_defconfig 这个配置文件
然后执行 ./build.sh,由于参数个数是0,所以配置完成后会执行 mklichee 这个函数
elif [ $# -eq 0 ] ; then
init_defconf
mklichee
exit $?
mklichee 函数执行如下:
mkbr && mkkernel && mkrootfs
mkkernel 去运行了”根目录”下的 scripts/build.sh 脚本:
(cd ${LICHEE_KERN_DIR} && [ -x ${build_script} ] && ./${build_script})
linux-3.4/scripts/build.sh 执行如下函数:
build_kernel
build_modules
build_ramfs
gen_output
build_kernel 执行如下内容:
cp arch/arm/configs/${LICHEE_KERN_DEFCONF} .config
make ARCH=arm CROSS_COMPILE=${CROSS_COMPILE} -j${LICHEE_JLEVEL} uImage modules
复制配置文件 sun8iw5p1smp_defconfig 到根目录下的 .config
然后执行 make uImage
下面是内核 Makfile 分析:
make uImage :uImage这个选项在顶层Makefile里面找不到
但是顶层 Makefile 肯定会包含架构下的 Makefile,可以在顶层 Makefile 找到如下内容:
include $(srctree)/arch/$(SRCARCH)/Makefile
这个 Makefile 就有包含 uImage 这个选项,内容如下:
zImage Image xipImage bootpImage uImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
它依赖于 vmlinux
uImage :是一个头部+真正的内核(vmlinux)
vmlinux 在顶层 Makefile 定义,它的依赖如下:
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
vmlinux-init := $(head-y) $(init-y)
head-y(这个在arch/arm里面的Makefile定义的):= arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o ------>表明最初始的代码就是head$(MMUEXT).o和init_task.o
init-y := init/ ---->表示init目录下面的所有'涉及'的文件会被编译为built-in.o
init-y := $(patsubst %/, %/built-in.o, $(init-y)) = init/built-in.o
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
core-y := usr/
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
core-y := $(patsubst %/, %/built-in.o, $(core-y))
core-y 最终就 = usr/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/ block/built-in.o
libs-y := lib/lib.a lib/built-in.o
drivers-y := drivers/built-in.o sound/built-in.o firmware/built-in.o
net-y := net/built-in.o
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(SRCARCH)/kernel/vmlinux.lds
以上这些文件怎么组合链接在一起形成 vmlinux 的呢?查看 vmlinux 是如何被编译的即可,在顶层 Makefile 中的代码如下:
# vmlinux image - including updated kernel symbols
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
$(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
$(Q)$(MAKE) $(build)=Documentation
endif
$(call vmlinux-modpost)
$(call if_changed_rule,vmlinux__)
$(Q)rm -f .old_version
以上涉及的脚本非常多,我们想知道它如何编译生成 vmlinux 的话可以分析 makefile,或者直接编译内核,先删除 vmlinux,然后编译
rm vmlinux
make uImage V=1 --->V=1表示内容更加详细的显示出来
如果是sinlinx的开发板,在 linux-3.4/scripts/build.sh 的 build_kernel 这个函数的 make 后面加 V=1 即可
我们可以得到如下的一段链接过程,可以得知vmlinux链接的时候是如何排布的
arm-linux-gnueabi-ld -EL -p --no-undefined -X --build-id -o .tmp_vmlinux1 -T arch/arm/kernel/vmlinux.lds
arch/arm/kernel/head.o arch/arm/kernel/init_task.o
init/built-in.o
--start-group usr/built-in.o arch/arm/vfp/built-in.o arch/arm/kernel/built-in.o
arch/arm/mm/built-in.o arch/arm/common/built-in.o arch/arm/net/built-in.o
arch/arm/mach-sunxi/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o
ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o
arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o
drivers/built-in.o sound/built-in.o firmware/built-in.o net/built-in.o --end-group
这段显示的链接过程就跟上面分析的一一对应起来了
分析makefile可以得知:
第一个文件:arch/arm/kernel/head.S
链接脚本:arch/arm/kernel/vmlinux.lds.S
链接脚本里面的代码段排放顺序就是上面 make uImge 后显示的文件顺序,先是head.o,然后init_task.o ……
本文详细解析了基于slinx全志A33开发板的Linux内核编译过程,从解压源码到配置内核,再到编译指令,深入探讨了配置文件、脚本及其执行流程,特别是如何通过makefile和相关脚本生成vmlinux的过程。


被折叠的 条评论
为什么被折叠?



