• Linux4.4内核构建脚本分析(一)- vmlinux的构建


    Vmlinux

    Vmlinux的目标定义在顶层Makefile文件中

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

        +$(call if_changed,link-vmlinux)

    If_changed是定义在scripts/Kbuild.include中的函数

    # Execute command if command has changed or prerequisite(s) are updated.

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

      @set -e;                                                             \

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

      printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)

    核心的代码是 $(cmd_$(1)) , 展开之后$(cmd_link-vmlinux), 也就是调用cmd_link-vmlinux函数。cmd_link-vmlinux函数的定义在顶层Makefile

    # Final link of vmlinux with optional arch pass after final link

    cmd_link-vmlinux =                                                 \

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

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

    第一行代码中$<代表第一个依赖项, 这行代码展开之后是

    sh  scripts/link-vmlinux.sh $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)

    其实就是调用scripts/link-vmlinux.sh这个脚本来完成vmlinux的构建工作, 这个脚本的分析就不在这里展开。 vmlinux生成时需要链接内核各个目录下built-in.o文件,所以各个目录built-in.o文件需要提前编译出来,而这些.o文件是通过一个叫$(vmlinux-dirs)定义的伪目标来驱动产生的 。

    $(vmlinux-dirs)

    $(vmlinux-dirs)伪目标定义在顶层Makefile中

    $(vmlinux-dirs): prepare scripts

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

    $(vmlinux-dirs)的值展开后就是内核源文件的各个子目录

    例如

    init usr arch/arm/vfp arch/arm/kvm arch/arm/vdso arch/arm/kernel arch/arm/mm arch/arm/common arch/arm/probes arch/arm/net arch/arm/crypto arch/arm/firmware arch/arm/mach-sunxi kernel certs mm fs ipc security crypto block drivers sound firmware net arch/arm/lib lib virt

    而构建命令$(Q)$(MAKE) $(build)=$@,其中的$(build)定义在scripts/Kbuild.include文件中。

    ###

    # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=

    # Usage:

    # $(Q)$(MAKE) $(build)=dir

    build := -f $(srctree)/scripts/Makefile.build obj

    $@代表当前的目标项, 以init目录为例, 展开后就是

    make -f ./scripts/Makefile.build obj=init

    所以这里通过使用./scripts/Makefile.build编译脚本, 传递需要编译的目录作为参数, 来分别构建需要构建的目录下的built-in.o

    Makefile.build

    这个脚本的默认目标是__build

    # We keep a list of all modules in $(MODVERDIR)

    __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \

     $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \

     $(subdir-ym) $(always)

        @:

    其中依赖项$(builtin-target)的定义是

    ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)

    builtin-target := $(obj)/built-in.o

    endif

    所以只要这些$(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target))变量的值不为空的话,$(obj)/built-in.o就会成为一个需要构建的依赖项。

    $(builtin-target): $(obj-y) FORCE

        $(call if_changed,link_o_target)

    $(call if_changed,link_o_target)展开之后就是调用命令

    # If the list of objects to link is empty, just create an empty built-in.o

    cmd_link_o_target = $(if $(strip $(obj-y)),\

          $(cmd_make_builtin) $@ $(filter $(obj-y), $^) \

          $(cmd_secanalysis),\

          $(cmd_make_empty_builtin) $@)

    核心代码是$(cmd_make_builtin) $@ $(filter $(obj-y), $^) ,以init目录的编译为例, 展开后是

     rm -f init/built-in.o; arm-linux-ar rcSTPD init/built-in.o init/main.o init/version.o init/mounts.o init/initramfs.o init/calibrate.o init/init_task.o

    $@代表目标init/built-in.o, $(filter $(obj-y), $^)其实就是$(obj-y), Makefile.build会包含要编译目录下的Makefile文件

    # The filename Kbuild has precedence over Makefile

    kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))

    kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)

    include $(kbuild-file)

    obj-y就是在init目录下的Makefile文件里面定义的

    obj-y                          := main.o version.o mounts.o

    ifneq ($(CONFIG_BLK_DEV_INITRD),y)

    obj-y                          += noinitramfs.o

    else

    obj-$(CONFIG_BLK_DEV_INITRD)   += initramfs.o

    endif

    obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o

    ifneq ($(CONFIG_ARCH_INIT_TASK),y)

    obj-y                          += init_task.o

    endif

    而各个.o文件的编译规则定义在

    # Built-in and composite module parts

    $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE

        $(call cmd,force_checksrc)

        $(call if_changed_rule,cc_o_c)

    $(call if_changed_rule,cc_o_c)展开后调用rule_cc_o_c

    define rule_cc_o_c

      $(call echo-cmd,checksrc) $(cmd_checksrc)   \

      $(call cmd_and_fixdep,cc_o_c)   \

      $(call echo-cmd,objtool) $(cmd_objtool)   \

      $(cmd_modversions_c)   \

      $(call echo-cmd,record_mcount) $(cmd_record_mcount)

    endef

    核心代码$(call cmd_and_fixdep,cc_o_c), 其中cmd_and_fixdep定义是

    cmd_and_fixdep =                                                             \

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

      scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\

      rm -f $(depfile);                                                    \

      mv -f $(dot-target).tmp $(dot-target).cmd;

    最后展开后还是调用 cmd_cc_o_c

    cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<

    $(c_flags)的定义在scripts/Makefile.lib文件中

    c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \

       $(__c_flags) $(modkern_cflags)                           \

       $(basename_flags) $(modname_flags)

    __c_flags的相关定义在

    __c_flags = $(if $(obj),$(call addtree,-I$(src)) -I$(obj)) \

      $(call flags,_c_flags)

    orig_c_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \

                     $(ccflags-y) $(CFLAGS_$(basetarget).o)

    _c_flags       = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))

    在编译的目录下面Makefile文件也可以修改$(ccflags-y) 调整编译参数

    ccflags-y := -fno-function-sections -fno-data-sections

  • 相关阅读:
    Spark中对大表子查询加limit为什么会报Broadcast超时错误
    Day2:面试必考题目
    JVM进阶(2)
    独立站外链的数量和质量哪个更重要?
    生成模型(1)无监督生成模型
    springbooy求职招聘网站毕业设计-附源码301914
    H3C S7000/S7500E/10500系列交换机Console密码忘记处理方法
    二叉排序树的创建与添加操作(思路分析)
    KaFormer个人笔记整理
    依赖注入跟::调用方法,哪种好,有什么区别?
  • 原文地址:https://blog.csdn.net/zf_prm/article/details/126347132