linux源码Makefile和脚本分析

本文详细解析了基于slinx全志A33开发板的Linux内核编译过程,从解压源码到配置内核,再到编译指令,深入探讨了配置文件、脚本及其执行流程,特别是如何通过makefile和相关脚本生成vmlinux的过程。

基于平台: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 ……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值