【问题标题】:How does kbuild actually work?kbuild 实际上是如何工作的?
【发布时间】:2015-03-24 11:47:02
【问题描述】:

当我在开发一个 linux 驱动程序时,我通过这个document 了解了如何编写 linux kbuild makefile

我知道 kbuild 系统使用 makefile 变量,例如 obj-y obj-m 来确定要构建什么以及如何构建。

但我很困惑的是kbuild系统在哪里真正执行构建过程。总而言之,如果我有obj-m = a.o,那么kbuild系统在哪里解析obj-m并执行gcc a.c?

【问题讨论】:

  • 答案是 make 完成所有工作。主内核构建 makefile 可能具有在适当位置使用 obj-m 和 obj-y 变量的规则,以将这些文件与适当的构建规则挂钩。 (作为评论发布,因为我根本不知道 kbuild,所以这只是基于一般的 make 行为。)

标签: c linux makefile linux-kernel kbuild


【解决方案1】:

Kbuild 的 Makefile 不是最容易阅读的,但这里有一个高级解开(使用 4.0-rc3 内核):

  1. 顶层 Makefile 做

    include $(srctree)/scripts/Kbuild.include
    

    ,其中$(srctree) 是顶级内核目录。

  2. Kbuild.include 定义了各种常用的东西和助手。其中有build:

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

    build 与$(MAKE) $(build)=dir 之类的命令一起使用,以执行目录dir 的构建。它使用scripts/Makefile.build。

  3. 回到顶层Makefile,有以下内容:

    $(vmlinux-dirs): prepare scripts
            $(Q)$(MAKE) $(build)=$@
    

    vmlinux-dirs 包含要构建的子目录列表(init、usr、kernel 等)。 $(Q)$(MAKE) $(build)=<subdirectory> 将为每个子目录运行。

    上述规则为内核映像和模块编译目标文件。在顶层 Makefile 的更下方,还有一些特定于模块的额外内容:

    ifdef CONFIG_MODULES
    ...
    modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin
            # Do additional module-specific stuff using
            # scripts/Makefile.modpost among other things
            # (my comment).
            ...
    ...
    endif # CONFIG_MODULES
    
  4. 现在查看scripts/Makefile.build($(build) 使用的 Makefile),首先初始化 obj-* 列表和各种其他列表:

    # Init all relevant variables used in kbuild files so
    # 1) they have correct type
    # 2) they do not inherit any value from the environment
    obj-y :=
    obj-m :=
    lib-y :=
    lib-m :=
    

    再往下一点,它会加载到设置了obj-y、obj-m 等的Kbuild 文件中:

    include $(kbuild-file)
    

    再往下是默认规则,它具有$(obj-y) 和$(obj-m) 列表作为先决条件:

    __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
             $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
             $(subdir-ym) $(always)
            @:
    

    $(obj-y) 先决条件来自$(builtin-target),其定义如下:

    builtin-target := $(obj)/built-in.o
    ...
    $(builtin-target): $(obj-y) FORCE
            $(call if_changed,link_o_target)
    

    实际的构建似乎是按照以下规则执行的:

    # Built-in and composite module parts
    $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
            $(call cmd,force_checksrc)
            $(call if_changed_rule,cc_o_c)
    

    if_changed_rule 来自Kbuild.include。该规则最终在Makefile.build 中运行以下命令:

    define rule_cc_o_c
            $(call echo-cmd,checksrc) $(cmd_checksrc)                         \
            $(call echo-cmd,cc_o_c) $(cmd_cc_o_c);                            \
            ...
    endef
    

    $(cmd_cc_o_c) 似乎是实际的编译命令。通常的定义(Makefile.build,AFAICS 中有两种可能)似乎如下:

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

    除非明确设置使用例如make CC=clang、CC 默认为 gcc,可以在顶级 Makefile 中看到:

    ifneq ($(CC),)
    ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
    COMPILER := clang
    else
    COMPILER := gcc
    endif
    export COMPILER
    endif
    

我解决这个问题的方法是在内核构建期间执行 CTRL-C 并查看make 报告错误的位置。另一个方便的make 调试技术是使用$(warning $(variable)) 打印variable 的值。

【讨论】:

  • 这是很酷的调试方法。既然`$(obj-y)`只是XXX.o的一个列表,那么make怎么知道在哪里可以找到这个XXX.c呢? make究竟是如何获取路径信息的?
  • @demonguy:模式规则$(obj)/%.o: $(src)/%.c 负责处理它。 $(obj) 是编译后的目标文件所在的目录,$(src) 是源文件所在的目录。规则说$(obj)/&lt;name&gt;.o 形式的文件依赖于$(src)/&lt;name&gt;.c 形式的文件(其中&lt;name&gt; 在两种情况下都是相同的),并且您从.c 文件创建.o 文件通过运行规则的配方(它包含的命令)。
  • 但是有很多不同的路径,例如test1/1.c中的makefile包含obj-y += 1.o和test2/2.c中的makefile包含obj-y += 2.o,那么最后obj-y应该是@987654382 @。那么$(src)如何处理不同的路径呢?
  • @demonguy:我没有仔细研究过,但在每个Kbuild 文件中,我认为您通常只处理一个目录。 build 生成一个单独的 make 实例来为每个目录运行 Makefile.build。 (顺便说一下,从 makefile 中调用 make 称为 recursive make。)
猜你喜欢
  • 2021-01-21
  • 2011-09-27
  • 2021-12-16
  • 2013-03-14
  • 2021-03-23
  • 2011-02-11
  • 2017-07-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多