找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

巢课
电巢直播8月计划
查看: 54|回复: 1
打印 上一主题 下一主题

Arm linux 内核构建

[复制链接]

114

主题

136

帖子

1000

积分

四级会员(40)

Rank: 4Rank: 4Rank: 4Rank: 4

积分
1000
跳转到指定楼层
1#
发表于 2017-11-15 11:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您!

您需要 登录 才可以下载或查看,没有帐号?注册

x
一、概述
本文基于Linux Kernel 4.10版本讲解。
Linux内核采用类似于GNU Make的kbuild构建而成,关于内核的构建系统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)
其中,callmake的内置函数,用于调用用户自己定义的带有参数的函数,这里调用的是if_changed,参数是link-vmlinux
if_changedscripts/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_INITKBUILD_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.olib.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。
; b. C& F& z) V- ?! Y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 支持!支持! 反对!反对!

0

主题

116

帖子

165

积分

二级会员(20)

Rank: 2Rank: 2

积分
165
2#
发表于 2018-6-8 15:54 | 只看该作者
比较难懂,先看看,谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

巢课

技术风云榜

关于我们|手机版|EDA365 ( 粤ICP备18020198号 )

GMT+8, 2024-11-23 11:47 , Processed in 0.057080 second(s), 31 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表