美文网首页嵌牛IT观察
Arm Linux 内核构建

Arm Linux 内核构建

作者: 风雨无阻59 | 来源:发表于2017-11-27 02:21 被阅读0次

    姓名:殷晨阳

    转载自中国电子网技术论坛,有改动。

    【嵌牛导读】:本文讲述了Linux的内核是如何进行构建的,其中,详细介绍了构建VmLinux,并给出了部分的源代码。

    【嵌牛鼻子】:Linux内核,VmLinux

    【嵌牛提问】:源码是如何选择性地参与内核的构建的?

    哪些源码参与了内核的构建?而Vmlinux是如何控制的?

    【嵌牛正文】:

    一、概述

    本文基于Linux Kernel 4.10版本讲解。Linux内核采用类似于GNU Make的kbuild构建而成。

    Kbuild结构简介

    arm linux内核的构建分为三次编译链接,一次组合。三次链接的中间结果分别是:

    1.arch/arm/boot/compressed/vmlinux

    2.arch/arm/boot/vmlinux.bin

    3.arch/arm/boot/setup.bin

    最后的组合就是将vmlinux.bin和setup.bin组合成arch/arm/boot/zImage:

    二、vmlinux的构建

    vmlinux的构建在顶层的Makefile中:

    cmd_link-vmlinux =                                         \

    $(CONFIG_SHELL) $<$(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) ;      \

    $(if $(ARCH_POSTLINK), $(MAKE) -f$(ARCH_POSTLINK) $@, true)

    vmlinux: scripts/link-vmlinux.sh vmlinux_prereq$(vmlinux-deps) FORCE

    +$(callif_changed,link-vmlinux)

    其中,call是make的内置函数,用于调用用户自己定义的带有参数的函数,这里调用的是if_changed,参数是link-vmlinux。

    if_changed是scripts/Kbuild.include里定义的一个函数,定义如下:

    if_changed = $(if $(strip $(any-prereq) $(arg-check)),   \

    @set -e;                                                                                  \

    $(echo-cmd) $(cmd_$(1));                                                 \

    echo 'cmd_$@ :=$(make-cmd)' > $(dot-target).cmd)

    any-prereq检查是否有依赖比目标新,或者依赖还没有创建;arg-check检查编译目标的命令相对上次是否发生变化。set–e命令表示make出错时直接退出,加个@符号表示不显示该set命令。cmd_$(1)中的1表示传给if_changed的第一个参数。嵌入式物联网智能硬件企鹅意义气呜呜吧久零就易,在这里传给if_changed的实参是link-vmlinux,所以cmd_$(1)展开后为cmd_link-vmlinux。

    注意cmd_link-vmlinux中的$<表示规则中的第一个依赖,即scripts/link-vmlinux.sh。这个脚本用于vmlinux的链接,内容如下:

    # Link of vmlinux

    # ${1} - optionalextra .o files

    # ${2} - output file

    vmlinux_link()

    {

    locallds="${objtree}/${KBUILD_LDS}"

    local objects

    if [ "${SRCARCH}" !="um" ]; then

    if [ -n"${CONFIG_THIN_ARCHIVES}" ]; then

    objects="--whole-archivebuilt-in.o ${1}"

    else

    objects="${KBUILD_VMLINUX_INIT}   \

    --start-group                                           \

    ${KBUILD_VMLINUX_MAIN}             \

    --end-group                                           \

    ${1}"

    fi

    ${LD} ${LDFLAGS}${LDFLAGS_vmlinux} -o ${2}      \

    -T ${lds} ${objects}

    else

    ... ...

    fi

    }

    如果平台不是“um”,就将变量KBUILD_VMLINUX_INIT和KBUILD_VMLINUX_MAIN中的目标文件链接为vmlinux;否则就直接编译为vmlinux,也就是式中的${2}。

    接下来以core-y来分析变量KBUILD_VMLINUX_MAIN:

    Linux-4.10/Makefile:

    exportKBUILD_VMLINUX_INIT := $(head-y) $(init-y)

    exportKBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y) $(virt-y)

    exportKBUILD_LDS          :=arch/$(SRCARCH)/kernel/vmlinux.lds

    … …

    core-y                := usr/

    … …

    core-y                += kernel/ certs/ mm/ fs/ ipc/security/ crypto/ block/

    … …

    core-y                := $(patsubst %/, %/built-in.o,$(core-y))

    make的内置函数patsubst用于查找模式匹配的字符串,并进行替换。在上面这句语句里,就是将所有‘/’替换成‘/built-in.o’。因此core-y最终变为:

    core-y :=user/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.osecurity/ built-in.o crypto/ built-in.o block/ built-in.o

    再看其他几个类似的赋值语句:

    init-y                   := $(patsubst %/,%/built-in.o, $(init-y))

    drivers-y           :=$(patsubst %/, %/built-in.o, $(drivers-y))

    net-y                  := $(patsubst %/,%/built-in.o, $(net-y))

    libs-y1                := $(patsubst %/, %/lib.a,$(libs-y))

    libs-y2                := $(patsubst %/, %/built-in.o,$(libs-y))

    libs-y                  := $(libs-y1) $(libs-y2)

    virt-y                  := $(patsubst %/,%/built-in.o, $(virt-y))

    不难看出,vmlinux就是由这些目录下的built-in.o和lib.a链接而成。

    vmlinux的另一个依赖是vmlinux-deps,其构建规则也在顶层Makefile中定义:

    Linux-4.10/Makefile:

    vmlinux-dirs     := $(patsubst %/,%,$(filter %/, $(init-y)$(init-m) \

    $(core-y) $(core-m) $(drivers-y)$(drivers-m) \

    $(net-y) $(net-m) $(libs-y) $(libs-m)$(virt-y)))

    vmlinux-deps :=$(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)

    … …

    # The actual objectsare generated when descending,

    # make sure noimplicit rule kicks in

    $(sort$(vmlinux-deps)): $(vmlinux-dirs) ;

    … …

    $(vmlinux-dirs):prepare scripts

    $(Q)$(MAKE) $(build)=$@

    目标vmlinux-deps的构建规则下没有命令可执行,只依赖于另外一个目标vmlinux-dirs,该变量的赋值语句里的filter表示过滤掉不以‘/’结尾的字符串。而filter的这些输入变量,如core-y,其子目录都是以‘/’结尾。因此vmlinux-dirs是一个多目标规则,相当于:

    init: prepare scripts

    $(Q) $(MAKE) $(build) =$@

    kernel: preparescripts

    $(Q) $(MAKE) $(build) =$@

    … …

    规则中的命令展开为:

    Make–f script/Makefile.buildobj=$@

    Make的自动变量$@表示规则的目标,这里就是要构建的子目录init,kernel等。

    总结一下,kbuild依次构建Makefile中指定的子目录,生成built-in.o、lib.a等文件,然后链接为vmlinux。

    相关文章

      网友评论

        本文标题:Arm Linux 内核构建

        本文链接:https://www.haomeiwen.com/subject/dpqrbxtx.html