Linux 内核 Makefiles

本文档描述了 Linux 内核 Makefiles。

概述

Makefiles 分为五个部分

Makefile                    the top Makefile.
.config                     the kernel configuration file.
arch/$(SRCARCH)/Makefile    the arch Makefile.
scripts/Makefile.*          common rules etc. for all kbuild Makefiles.
kbuild Makefiles            exist in every subdirectory

顶层 Makefile 读取 .config 文件,该文件来自内核配置过程。

顶层 Makefile 负责构建两个主要产品:vmlinux(常驻内核映像)和模块(任何模块文件)。它通过递归下降到内核源代码树的子目录来构建这些目标。

访问的子目录列表取决于内核配置。顶层 Makefile 以文本形式包含一个名为 arch/$(SRCARCH)/Makefile 的架构 Makefile。架构 Makefile 向顶层 Makefile 提供特定于架构的信息。

每个子目录都有一个 kbuild Makefile,它执行从上面传递下来的命令。kbuild Makefile 使用 .config 文件中的信息来构建 kbuild 用于构建任何内置或模块化目标的各种文件列表。

scripts/Makefile.* 包含用于基于 kbuild makefiles 构建内核的所有定义/规则等。

谁做什么

人们与内核 Makefiles 有四种不同的关系。

用户 是构建内核的人。这些人键入诸如 make menuconfigmake 之类的命令。他们通常不读取或编辑任何内核 Makefiles(或任何其他源文件)。

普通开发人员 是从事设备驱动程序、文件系统和网络协议等功能的人。这些人需要维护他们正在开发的子系统的 kbuild Makefiles。为了有效地执行此操作,他们需要一些关于内核 Makefiles 的整体知识,以及关于 kbuild 公共接口的详细知识。

架构开发人员 是从事整个架构(如 sparc 或 x86)的人员。架构开发人员需要了解架构 Makefile 以及 kbuild Makefiles。

Kbuild 开发人员 是从事内核构建系统本身的人员。这些人需要了解内核 Makefiles 的所有方面。

本文档面向普通开发人员和架构开发人员。

kbuild 文件

内核中的大多数 Makefiles 都是使用 kbuild 基础设施的 kbuild Makefiles。本章介绍了 kbuild makefiles 中使用的语法。

kbuild 文件的首选名称是 Makefile,但可以使用 Kbuild,如果同时存在 MakefileKbuild 文件,则将使用 Kbuild 文件。

目标定义 是一篇快速入门;后续章节将提供更多详细信息,并提供实际示例。

目标定义

目标定义是 kbuild Makefile 的主要部分(核心)。这些行定义了要构建的文件、任何特殊的编译选项以及任何要递归进入的子目录。

最简单的 kbuild makefile 包含一行

示例

obj-y += foo.o

这告诉 kbuild 该目录中有一个名为 foo.o 的对象。foo.o 将从 foo.c 或 foo.S 构建。

如果 foo.o 应构建为模块,则使用变量 obj-m。因此,经常使用以下模式

示例

obj-$(CONFIG_FOO) += foo.o

$(CONFIG_FOO) 的计算结果为 y(对于内置)或 m(对于模块)。如果 CONFIG_FOO 既不是 y 也不是 m,则不会编译或链接该文件。

内置对象目标 - obj-y

kbuild Makefile 在 $(obj-y) 列表中指定 vmlinux 的目标文件。这些列表取决于内核配置。

Kbuild 编译所有 $(obj-y) 文件。然后调用 $(AR) rcSTP 将这些文件合并到一个 built-in.a 文件中。这是一个不带符号表的精简存档。它稍后将由 scripts/link-vmlinux.sh 链接到 vmlinux 中

$(obj-y) 中文件的顺序很重要。列表中允许重复项:第一个实例将链接到 built-in.a 中,后续实例将被忽略。

链接顺序很重要,因为某些函数(module_init() / __initcall)将在启动期间按照它们出现的顺序被调用。因此请记住,更改链接顺序可能会更改例如检测到 SCSI 控制器的顺序,从而重新编号您的磁盘。

示例

#drivers/isdn/i4l/Makefile
# Makefile for the kernel ISDN subsystem and device drivers.
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN_I4L)         += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

可加载模块目标 - obj-m

$(obj-m) 指定作为可加载内核模块构建的目标文件。

一个模块可以从一个源文件或多个源文件构建。对于一个源文件的情况,kbuild makefile 只需将该文件添加到 $(obj-m)。

示例

#drivers/isdn/i4l/Makefile
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

注意:在此示例中,$(CONFIG_ISDN_PPP_BSDCOMP) 的计算结果为 “m”

如果一个内核模块是从多个源文件构建的,您将以与上述相同的方式指定要构建模块;但是,kbuild 需要知道您要从哪些目标文件构建模块,因此您必须通过设置 $(<module_name>-y) 变量来告诉它。

示例

#drivers/isdn/i4l/Makefile
obj-$(CONFIG_ISDN_I4L) += isdn.o
isdn-y := isdn_net_lib.o isdn_v110.o isdn_common.o

在此示例中,模块名称将为 isdn.o。Kbuild 将编译 $(isdn-y) 中列出的对象,然后在这些文件列表上运行 $(LD) -r 以生成 isdn.o。

由于 kbuild 识别用于复合对象的 $(<module_name>-y),因此您可以使用 CONFIG_ 符号的值来选择性地将目标文件作为复合对象的一部分包含在内。

示例

#fs/ext2/Makefile
obj-$(CONFIG_EXT2_FS) += ext2.o
ext2-y := balloc.o dir.o file.o ialloc.o inode.o ioctl.o \
  namei.o super.o symlink.o
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o \
  xattr_trusted.o

在此示例中,仅当 $(CONFIG_EXT2_FS_XATTR) 的计算结果为 “y” 时,xattr.o、xattr_user.o 和 xattr_trusted.o 才是复合对象 ext2.o 的一部分。

注意:当然,当您将对象构建到内核中时,上面的语法也适用。因此,如果您有 CONFIG_EXT2_FS=y,kbuild 将为您构建一个 ext2.o 文件,该文件由各个部分组成,然后将其链接到 built-in.a 中,正如您所期望的那样。

库文件目标 - lib-y

使用 obj-* 列出的对象用于模块,或组合在该特定目录的 built-in.a 中。还可以列出将包含在库 lib.a 中的对象。使用 lib-y 列出的所有对象都组合在该目录的单个库中。在 obj-y 中列出且另外在 lib-y 中列出的对象将不包含在库中,因为它们无论如何都可访问。为了保持一致性,lib-m 中列出的对象将包含在 lib.a 中。

请注意,同一 kbuild makefile 可能会列出要内置的文件以及要作为库一部分的文件。因此,同一目录可能同时包含 built-in.a 文件和 lib.a 文件。

示例

#arch/x86/lib/Makefile
lib-y    := delay.o

这将基于 delay.o 创建一个库 lib.a。为了让 kbuild 实际识别正在构建 lib.a,该目录应在 libs-y 中列出。

另请参阅 列出下降时要访问的目录

lib-y 的使用通常仅限于 lib/arch/*/lib

下降到目录中

Makefile 仅负责构建其自身目录中的对象。子目录中的文件应由这些子目录中的 Makefiles 处理。只要您让它知道它们,构建系统将自动递归调用子目录中的 make。

为此,使用 obj-y 和 obj-m。ext2 位于单独的目录中,fs/ 中的 Makefile 使用以下赋值告诉 kbuild 下降。

示例

#fs/Makefile
obj-$(CONFIG_EXT2_FS) += ext2/

如果 CONFIG_EXT2_FS 设置为 “y”(内置)或 “m”(模块化),则将设置相应的 obj- 变量,并且 kbuild 将下降到 ext2 目录中。

Kbuild 使用此信息不仅决定需要访问该目录,还决定是否将该目录中的对象链接到 vmlinux 中。

当 Kbuild 下降到 “y” 目录时,该目录中的所有内置对象都会合并到 built-in.a 中,最终将链接到 vmlinux 中。

相反,当 Kbuild 进入带有 “m” 的目录时,该目录中的任何内容都不会链接到 vmlinux 中。如果该目录中的 Makefile 指定了 obj-y,则这些对象将被遗弃。这很可能是 Makefile 或 Kconfig 中依赖项的错误。

Kbuild 还支持用于进入子目录的专用语法,subdir-y 和 subdir-m。 当您知道它们根本不包含内核空间对象时,它非常适合。 一个典型的用法是让 Kbuild 进入子目录以构建工具。

示例

# scripts/Makefile
subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
subdir-$(CONFIG_MODVERSIONS) += genksyms
subdir-$(CONFIG_SECURITY_SELINUX) += selinux

与 obj-y/m 不同,subdir-y/m 不需要尾部的斜杠,因为此语法始终用于目录。

在分配目录名称时,使用 CONFIG_ 变量是一种好习惯。 这允许 kbuild 在相应的 CONFIG_ 选项既不是 “y” 也不是 “m” 时完全跳过该目录。

非内置 vmlinux 目标 - extra-y

extra-y 指定构建 vmlinux 所需的目标,但不会组合到 built-in.a 中。

示例包括

  1. vmlinux 链接器脚本

    vmlinux 的链接器脚本位于 arch/$(SRCARCH)/kernel/vmlinux.lds

示例

# arch/x86/kernel/Makefile
extra-y       += vmlinux.lds

$(extra-y) 应该只包含 vmlinux 所需的目标。

当 vmlinux 显然不是最终目标时,Kbuild 会跳过 extra-y。(例如,make modules 或构建外部模块)

如果您打算无条件地构建目标,则 always-y(在下一节中解释)是正确的语法。

始终构建的目标 - always-y

always-y 指定当 Kbuild 访问 Makefile 时始终构建的目标。

示例

# ./Kbuild
offsets-file := include/generated/asm-offsets.h
always-y += $(offsets-file)

编译标志

ccflags-y、asflags-y 和 ldflags-y

这三个标志仅适用于分配它们的 kbuild makefile。 它们用于递归构建期间发生的所有普通 cc、as 和 ld 调用。 注意:具有相同行为的标志以前被命名为:EXTRA_CFLAGS、EXTRA_AFLAGS 和 EXTRA_LDFLAGS。 它们仍然受支持,但其使用已被弃用。

ccflags-y 指定使用 $(CC) 编译的选项。

示例

# drivers/acpi/acpica/Makefile
ccflags-y                           := -Os -D_LINUX -DBUILDING_ACPICA
ccflags-$(CONFIG_ACPI_DEBUG)        += -DACPI_DEBUG_OUTPUT

此变量是必需的,因为顶层 Makefile 拥有变量 $(KBUILD_CFLAGS) 并将其用于整个树的编译标志。

asflags-y 指定汇编器选项。

示例

#arch/sparc/kernel/Makefile
asflags-y := -ansi

ldflags-y 指定与 $(LD) 链接的选项。

示例

#arch/cris/boot/compressed/Makefile
ldflags-y += -T $(src)/decompress_$(arch-y).lds
subdir-ccflags-y、subdir-asflags-y

上面列出的两个标志类似于 ccflags-y 和 asflags-y。 不同之处在于,subdir- 变体对它们所在的 kbuild 文件和所有子目录都有效。 使用 subdir-* 指定的选项会添加到命令行中,在 使用非 subdir 变体指定的选项之前。

示例

subdir-ccflags-y := -Werror
ccflags-remove-y、asflags-remove-y

这些标志用于删除编译器、汇编器调用的特定标志。

示例

ccflags-remove-$(CONFIG_MCOUNT) += -pg
CFLAGS_$@, AFLAGS_$@

CFLAGS_$@ 和 AFLAGS_$@ 仅适用于当前 kbuild makefile 中的命令。

$(CFLAGS_$@) 指定 $(CC) 的每个文件选项。 $@ 部分具有一个文字值,用于指定它所针对的文件。

CFLAGS_$@ 的优先级高于 ccflags-remove-y; CFLAGS_$@ 可以重新添加被 ccflags-remove-y 删除的编译器标志。

示例

# drivers/scsi/Makefile
CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF

此行指定 aha152x.o 的编译标志。

$(AFLAGS_$@) 是汇编语言源文件的类似功能。

AFLAGS_$@ 的优先级高于 asflags-remove-y; AFLAGS_$@ 可以重新添加被 asflags-remove-y 删除的汇编器标志。

示例

# arch/arm/kernel/Makefile
AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
AFLAGS_iwmmxt.o      := -Wa,-mcpu=iwmmxt

依赖项跟踪

Kbuild 会跟踪以下依赖项

  1. 所有先决条件文件(*.c*.h

  2. 所有先决条件文件中使用的 CONFIG_ 选项

  3. 用于编译目标的命令行

因此,如果您更改 $(CC) 的选项,则所有受影响的文件都将被重新编译。

自定义规则

当 kbuild 基础设施不提供所需的支持时,将使用自定义规则。一个典型的例子是在构建过程中生成的头文件。另一个例子是特定于架构的 Makefile,它们需要自定义规则来准备启动映像等。

自定义规则编写为普通的 Make 规则。Kbuild 不在 Makefile 所在的目录中执行,因此所有自定义规则都应使用相对于先决条件文件和目标文件的相对路径。

定义自定义规则时使用两个变量

$(src)

$(src) 是 Makefile 所在的目录。 当引用位于 src 树中的文件时,始终使用 $(src)。

$(obj)

$(obj) 是保存目标的目录。 当引用生成的文件时,始终使用 $(obj)。 对于需要同时适用于生成文件和真实源文件的模式规则,请使用 $(obj)(VPATH 将有助于不仅在对象树中,而且在源树中查找先决条件)。

示例

#drivers/scsi/Makefile
$(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl
$(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl

这是一个自定义规则,遵循 make 所需的普通语法。

目标文件依赖于两个先决条件文件。 对目标文件的引用以 $(obj) 为前缀,对先决条件的引用以 $(src) 引用(因为它们不是生成的文件)。

$(srcroot)

$(srcroot) 指的是您正在构建的源的根目录,它可以是内核源或外部模块源,具体取决于是否设置了 KBUILD_EXTMOD。 这可以是相对路径或绝对路径,但如果设置了 KBUILD_ABS_SRCTREE=1,则它始终是绝对路径。

$(srctree)

$(srctree) 指的是内核源树的根目录。 构建内核时,这与 $(srcroot) 相同。

$(objtree)

$(objtree) 指的是内核对象树的根目录。 构建内核时它是 .,但在构建外部模块时它不同。

$(kecho)

在规则中向用户回显信息通常是一种好习惯,但是当执行 make -s 时,人们不希望看到除警告/错误之外的任何输出。 为了支持这一点,kbuild 定义了 $(kecho),它会将 $(kecho) 后面的文本回显到 stdout,除非使用 make -s

示例

# arch/arm/Makefile
$(BOOT_TARGETS): vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
        @$(kecho) '  Kernel: $(boot)/$@ is ready'

当 kbuild 在 KBUILD_VERBOSE 未设置的情况下执行时,通常只显示命令的简写形式。 为了对自定义命令启用此行为,kbuild 需要设置两个变量

quiet_cmd_<command> - what shall be echoed
      cmd_<command> - the command to execute

示例

# lib/Makefile
quiet_cmd_crc32 = GEN     $@
      cmd_crc32 = $< > $@

$(obj)/crc32table.h: $(obj)/gen_crc32table
        $(call cmd,crc32)

当更新 $(obj)/crc32table.h 目标时,该行

GEN     lib/crc32table.h

将使用 make KBUILD_VERBOSE= 显示。

命令更改检测

当评估规则时,会比较目标及其先决条件文件之间的时间戳。 当任何先决条件比目标更新时,GNU Make 会更新目标。

当命令行自上次调用以来发生更改时,也应重建目标。 Make 本身不支持此功能,因此 Kbuild 通过一种元编程来实现此目的。

if_changed 是用于此目的的宏,形式如下

quiet_cmd_<command> = ...
      cmd_<command> = ...

<target>: <source(s)> FORCE
        $(call if_changed,<command>)

任何利用 if_changed 的目标都必须在 $(targets) 中列出,否则命令行检查将失败,并且将始终构建目标。

如果目标已在可识别的语法(例如 obj-y/m、lib-y/m、extra-y/m、always-y/m、hostprogs、userprogs)中列出,则 Kbuild 会自动将其添加到 $(targets)。 否则,必须将目标显式添加到 $(targets)。

$(targets) 的赋值不带 $(obj)/ 前缀。 if_changed 可以与 自定义规则中定义的自定义规则结合使用。

注意:忘记 FORCE 先决条件是一个典型的错误。 另一个常见的陷阱是空格有时很重要;例如,以下操作将失败(请注意逗号后的额外空格)

target: source(s) FORCE

错误! $(call if_changed, objcopy)

注意

每个目标不应使用 if_changed 多次。 它将执行的命令存储在相应的 .cmd 文件中,当目标是最新的并且只有对已更改命令的测试触发命令执行时,多次调用将导致覆盖和不希望的结果。

$(CC) 支持函数

可以使用多个不同版本的 $(CC) 来构建内核,每个版本都支持一组独特的功能和选项。 kbuild 提供基本支持来检查 $(CC) 的有效选项。 $(CC) 通常是 gcc 编译器,但也有其他替代方案。

as-option

as-option 用于检查 $(CC)(当用于编译汇编器(*.S)文件时)是否支持给定的选项。 如果不支持第一个选项,则可以指定可选的第二个选项。

示例

#arch/sh/Makefile
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)

在上面的示例中,如果 $(CC) 支持 -Wa$(comma)-isa=$(isa-y) 选项,则会将该选项分配给 cflags-y。 第二个参数是可选的,如果提供,则在不支持第一个参数时使用。

as-instr

as-instr 检查汇编器是否报告特定指令,然后输出 option1 或 option2。C 转义在测试指令中受支持。注意:as-instr-option 将 KBUILD_AFLAGS 用于汇编器选项

cc-option

cc-option 用于检查 $(CC) 是否支持给定的选项,如果不支持,则使用可选的第二个选项。

示例

#arch/x86/Makefile
cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586)

在上面的示例中,如果 $(CC) 支持 -march=pentium-mmx,则会将该选项分配给 cflags-y,否则将分配 -march=i586。 cc-option 的第二个参数是可选的,如果省略,则在不支持第一个选项时,不会为 cflags-y 分配任何值。 注意:cc-option 将 KBUILD_CFLAGS 用于 $(CC) 选项

cc-option-yn

cc-option-yn 用于检查 $(CC) 是否支持给定的选项,如果支持则返回 “y”,否则返回 “n”。

示例

#arch/ppc/Makefile
biarch := $(call cc-option-yn, -m32)
aflags-$(biarch) += -a32
cflags-$(biarch) += -m32

在上面的示例中,如果 $(CC) 支持 -m32 选项,则将 $(biarch) 设置为 y。 当 $(biarch) 等于 “y” 时,展开的变量 $(aflags-y) 和 $(cflags-y) 将分别被分配值 -a32 和 -m32。

注意:cc-option-yn 将 KBUILD_CFLAGS 用于 $(CC) 选项

cc-disable-warning

cc-disable-warning 检查 $(CC) 是否支持给定的警告,并返回禁用它的命令行开关。 需要此特殊功能,因为 gcc 4.4 及更高版本接受任何未知的 -Wno-* 选项,并且仅当源文件中存在另一个警告时才会发出警告。

示例

KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)

在上面的示例中,只有当 $(CC) 真正接受时,才会将 -Wno-unused-but-set-variable 添加到 KBUILD_CFLAGS。

gcc-min-version

gcc-min-version 测试 $(CONFIG_GCC_VERSION) 的值是否大于或等于提供的值,如果是,则评估为 y。

示例

cflags-$(call gcc-min-version, 70100) := -foo

在此示例中,如果 $(CC) 是 gcc 并且 $(CONFIG_GCC_VERSION) >= 7.1,则会将值 -foo 分配给 cflags-y。

clang-min-version

clang-min-version 测试 $(CONFIG_CLANG_VERSION) 的值是否大于或等于提供的值,如果是,则评估为 y。

示例

cflags-$(call clang-min-version, 110000) := -foo

在此示例中,如果 $(CC) 是 clang 并且 $(CONFIG_CLANG_VERSION) >= 11.0.0,则 cflags-y 将被赋值为 -foo。

cc-cross-prefix

cc-cross-prefix 用于检查路径中是否存在具有所列前缀之一的 $(CC)。返回在 PATH 中存在 prefix$(CC) 的第一个前缀,如果没有找到 prefix$(CC),则不返回任何内容。

在调用 cc-cross-prefix 时,附加前缀用单个空格分隔。

此功能对于尝试将 CROSS_COMPILE 设置为众所周知的值,但可能需要在多个值之间进行选择的体系结构 Makefile 非常有用。

建议仅在交叉编译(主机架构与目标架构不同)时尝试设置 CROSS_COMPILE。如果已设置 CROSS_COMPILE,则保留旧值。

示例

#arch/m68k/Makefile
ifneq ($(SUBARCH),$(ARCH))
        ifeq ($(CROSS_COMPILE),)
                CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu-)
        endif
endif

$(LD) 支持函数

ld-option

ld-option 用于检查 $(LD) 是否支持提供的选项。ld-option 接受两个选项作为参数。

第二个参数是一个可选选项,如果 $(LD) 不支持第一个选项,则可以使用该选项。

示例

#Makefile
LDFLAGS_vmlinux += $(call ld-option, -X)

脚本调用

Make 规则可能会调用脚本来构建内核。这些规则应始终提供适当的解释器来执行脚本。它们不应依赖于设置的执行位,也不应直接调用脚本。为了方便手动调用脚本,例如调用 ./scripts/checkpatch.pl,建议无论如何都要在脚本上设置执行位。

Kbuild 提供变量 $(CONFIG_SHELL)、$(AWK)、$(PERL) 和 $(PYTHON3) 来引用相应脚本的解释器。

示例

#Makefile
cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \
        $(KERNELRELEASE)

主机程序支持

Kbuild 支持在编译阶段在主机上构建可执行文件以供使用。

要使用主机可执行文件,需要两个步骤。

第一步是告诉 kbuild 存在一个主机程序。这是通过使用变量 hostprogs 来完成的。

第二步是向可执行文件添加显式依赖项。这可以通过两种方式完成。可以在规则中添加依赖项,或者使用变量 always-y。以下描述了这两种可能性。

简单主机程序

在某些情况下,需要在运行构建的计算机上编译和运行程序。

以下行告诉 kbuild,程序 bin2hex 应在构建主机上构建。

示例

hostprogs := bin2hex

在以上示例中,Kbuild 假定 bin2hex 是由一个名为 bin2hex.c 的单个 c 源文件生成的,该文件与 Makefile 位于同一目录中。

复合主机程序

主机程序可以基于复合对象组成。用于定义主机程序复合对象的语法类似于用于内核对象的语法。$(<executable>-objs) 列出了用于链接最终可执行文件的所有对象。

示例

#scripts/lxdialog/Makefile
hostprogs     := lxdialog
lxdialog-objs := checklist.o lxdialog.o

扩展名为 .o 的对象是从相应的 .c 文件编译的。在以上示例中,checklist.c 被编译为 checklist.o,lxdialog.c 被编译为 lxdialog.o。

最后,两个 .o 文件被链接到可执行文件 lxdialog。注意:主机程序不允许使用语法 <executable>-y。

为主机程序使用 C++

kbuild 为用 C++ 编写的主机程序提供支持。引入此功能仅是为了支持 kconfig,不建议用于一般用途。

示例

#scripts/kconfig/Makefile
hostprogs     := qconf
qconf-cxxobjs := qconf.o

在上面的示例中,可执行文件由 C++ 文件 qconf.cc 组成 - 由 $(qconf-cxxobjs) 标识。

如果 qconf 由 .c 和 .cc 文件的混合组成,则可以使用额外的行来标识这一点。

示例

#scripts/kconfig/Makefile
hostprogs     := qconf
qconf-cxxobjs := qconf.o
qconf-objs    := check.o

为主机程序使用 Rust

Kbuild 为用 Rust 编写的主机程序提供支持。但是,由于 Rust 工具链对于内核编译不是强制性的,因此它只能在需要 Rust 可用的情况下使用(例如,启用 CONFIG_RUST 时)。

示例

hostprogs     := target
target-rust   := y

Kbuild 将使用 target.rs 作为 crate 根来编译 target,该文件与 Makefile 位于同一目录中。crate 可能由多个源文件组成(请参阅 samples/rust/hostprogs)。

控制主机程序的编译器选项

编译主机程序时,可以设置特定的标志。这些程序将始终使用传递给 $(KBUILD_HOSTCFLAGS) 中指定选项的 $(HOSTCC) 进行编译。

要设置对该 Makefile 中创建的所有主机程序生效的标志,请使用变量 HOST_EXTRACFLAGS。

示例

#scripts/lxdialog/Makefile
HOST_EXTRACFLAGS += -I/usr/include/ncurses

要为单个文件设置特定标志,请使用以下构造

示例

#arch/ppc64/boot/Makefile
HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE)

还可以为链接器指定其他选项。

示例

#scripts/kconfig/Makefile
HOSTLDLIBS_qconf := -L$(QTDIR)/lib

链接 qconf 时,它将传递额外的选项 -L$(QTDIR)/lib

实际构建主机程序的时间

仅当主机程序被引用为先决条件时,Kbuild 才会构建它们。

这可以通过两种方式实现

  1. 在自定义规则中显式列出先决条件。

    示例

    #drivers/pci/Makefile
    hostprogs := gen-devlist
    $(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist
    ( cd $(obj); ./gen-devlist ) < $<
    

    在更新 $(obj)/gen-devlist 之前,不会构建目标 $(obj)/devlist.h。请注意,在自定义规则中对主机程序的引用必须以 $(obj) 为前缀。

  2. 使用 always-y

    当没有合适的自定义规则,并且在进入 makefile 时应构建主机程序时,应使用 always-y 变量。

    示例

    #scripts/lxdialog/Makefile
    hostprogs     := lxdialog
    always-y      := $(hostprogs)
    

    Kbuild 为此提供了以下简写形式

    hostprogs-always-y := lxdialog
    

    这将告诉 kbuild 构建 lxdialog,即使它没有在任何规则中引用。

用户空间程序支持

与主机程序一样,Kbuild 还支持为目标架构(即您正在为其构建内核的同一架构)构建用户空间可执行文件。

语法非常相似。区别在于使用 userprogs 而不是 hostprogs

简单用户空间程序

以下行告诉 kbuild,程序 bpf-direct 应为目标架构构建。

示例

userprogs := bpf-direct

在以上示例中,Kbuild 假定 bpf-direct 是由一个名为 bpf-direct.c 的单个 C 源文件生成的,该文件与 Makefile 位于同一目录中。

复合用户空间程序

用户空间程序可以基于复合对象组成。用于定义用户空间程序复合对象的语法类似于用于内核对象的语法。$(<executable>-objs) 列出了用于链接最终可执行文件的所有对象。

示例

#samples/seccomp/Makefile
userprogs      := bpf-fancy
bpf-fancy-objs := bpf-fancy.o bpf-helper.o

扩展名为 .o 的对象是从相应的 .c 文件编译的。在以上示例中,bpf-fancy.c 被编译为 bpf-fancy.o,bpf-helper.c 被编译为 bpf-helper.o。

最后,两个 .o 文件被链接到可执行文件 bpf-fancy。注意:用户空间程序不允许使用语法 <executable>-y。

控制用户空间程序的编译器选项

编译用户空间程序时,可以设置特定的标志。这些程序将始终使用传递给 $(KBUILD_USERCFLAGS) 中指定选项的 $(CC) 进行编译。

要设置对该 Makefile 中创建的所有用户空间程序生效的标志,请使用变量 userccflags。

示例

# samples/seccomp/Makefile
userccflags += -I usr/include

要为单个文件设置特定标志,请使用以下构造

示例

bpf-helper-userccflags += -I user/include

还可以为链接器指定其他选项。

示例

# net/bpfilter/Makefile
bpfilter_umh-userldflags += -static

要指定链接到用户空间程序的库,可以使用 <executable>-userldlibsuserldlibs 语法指定链接到当前 Makefile 中创建的所有用户空间程序的库。

链接 bpfilter_umh 时,将传递额外的选项 -static。

从命令行中,还会使用 USERCFLAGS 和 USERLDFLAGS

实际构建用户空间程序的时间

Kbuild 仅在被告知时才构建用户空间程序。有两种方法可以实现此目的。

  1. 将其添加为另一个文件的先决条件

    示例

    #net/bpfilter/Makefile
    userprogs := bpfilter_umh
    $(obj)/bpfilter_umh_blob.o: $(obj)/bpfilter_umh
    

    在构建 $(obj)/bpfilter_umh_blob.o 之前,会构建 $(obj)/bpfilter_umh

  2. 使用 always-y

    示例

    userprogs := binderfs_example
    always-y := $(userprogs)
    

    Kbuild 为此提供了以下简写形式

    userprogs-always-y := binderfs_example
    

    这将告诉 Kbuild 在访问此 Makefile 时构建 binderfs_example。

Kbuild 清理基础设施

make clean 删除 obj 树中大多数生成的文件,内核在其中编译。这包括生成的文件,例如主机程序。Kbuild 知道 $(hostprogs)、$(always-y)、$(always-m)、$(always-)、$(extra-y)、$(extra-) 和 $(targets) 中列出的目标。在 make clean 期间会删除所有这些目标。当执行 make clean 时,内核源代码树中会删除与模式 *.[oas]*.ko 和 kbuild 生成的一些其他文件匹配的文件。

可以通过使用 $(clean-files) 在 kbuild makefile 中指定其他文件或目录。

示例

#lib/Makefile
clean-files := crc32table.h

执行 make clean 时,将删除文件 crc32table.h。Kbuild 将假定文件与 Makefile 位于同一相对目录中。

要从 make clean 中排除某些文件或目录,请使用 $(no-clean-files) 变量。

通常,kbuild 会由于 obj-* := dir/ 而下降到子目录中,但是在体系结构 makefile 中,kbuild 基础设施不足以满足需求,有时需要显式指定。

示例

#arch/x86/boot/Makefile
subdir- := compressed

以上赋值指示 kbuild 在执行 make clean 时下降到 compressed/ 目录中。

注意 1:arch/$(SRCARCH)/Makefile 不能使用 subdir-,因为该文件包含在顶层 makefile 中。相反,arch/$(SRCARCH)/Kbuild 可以使用 subdir-

注意 2:在 make clean 期间会访问 core-y、libs-y、drivers-y 和 net-y 中列出的所有目录。

体系结构 Makefile

顶层 Makefile 设置环境并进行准备,然后再开始下降到各个目录中。

顶层 makefile 包含通用部分,而 arch/$(SRCARCH)/Makefile 包含为该架构设置 kbuild 所需的内容。

为此,arch/$(SRCARCH)/Makefile 设置了许多变量并定义了一些目标。

当 kbuild 执行时,将遵循以下步骤(大致)

  1. 内核配置 => 生成 .config

  2. 将内核版本存储在 include/linux/version.h 中

  3. 更新目标 prepare 的所有其他先决条件

    • 其他先决条件在 arch/$(SRCARCH)/Makefile 中指定。

  4. 递归地进入 init-* core* drivers-* net-* libs-* 中列出的所有目录,并构建所有目标。

    • 上述变量的值在 arch/$(SRCARCH)/Makefile 中展开。

  5. 然后将所有目标文件链接起来,生成的文件 vmlinux 位于 obj 树的根目录。链接的最先对象列在 scripts/head-object-list.txt 中。

  6. 最后,体系结构特定的部分执行任何所需的后处理并构建最终的引导映像。

    • 这包括构建引导记录

    • 准备 initrd 映像等

设置变量以调整构建以适应体系结构

KBUILD_LDFLAGS

通用 $(LD) 选项

用于所有链接器调用的标志。通常指定仿真就足够了。

示例

#arch/s390/Makefile
KBUILD_LDFLAGS         := -m elf_s390

注意:可以使用 ldflags-y 来进一步自定义使用的标志。请参阅非内置 vmlinux 目标 - extra-y

LDFLAGS_vmlinux

链接 vmlinux 时 $(LD) 的选项

LDFLAGS_vmlinux 用于指定在链接最终 vmlinux 映像时传递给链接器的其他标志。

LDFLAGS_vmlinux 使用 LDFLAGS_$@ 支持。

示例

#arch/x86/Makefile
LDFLAGS_vmlinux := -e stext
OBJCOPYFLAGS

objcopy 标志

当 $(call if_changed,objcopy) 用于转换 .o 文件时,将使用 OBJCOPYFLAGS 中指定的标志。

$(call if_changed,objcopy) 通常用于在 vmlinux 上生成原始二进制文件。

示例

#arch/s390/Makefile
OBJCOPYFLAGS := -O binary

#arch/s390/boot/Makefile
$(obj)/image: vmlinux FORCE
        $(call if_changed,objcopy)

在此示例中,二进制文件 $(obj)/image 是 vmlinux 的二进制版本。$(call if_changed,xxx) 的用法将在后面描述。

KBUILD_AFLAGS

汇编器标志

默认值 - 请参阅顶级 Makefile。

根据需要按体系结构追加或修改。

示例

#arch/sparc64/Makefile
KBUILD_AFLAGS += -m64 -mcpu=ultrasparc
KBUILD_CFLAGS

$(CC) 编译器标志

默认值 - 请参阅顶级 Makefile。

根据需要按体系结构追加或修改。

通常,KBUILD_CFLAGS 变量取决于配置。

示例

#arch/x86/boot/compressed/Makefile
cflags-$(CONFIG_X86_32) := -march=i386
cflags-$(CONFIG_X86_64) := -mcmodel=small
KBUILD_CFLAGS += $(cflags-y)

许多 arch Makefiles 动态运行目标 C 编译器以探测支持的选项

#arch/x86/Makefile

...
cflags-$(CONFIG_MPENTIUMII)     += $(call cc-option,\
                                            -march=pentium2,-march=i686)
...
# Disable unit-at-a-time mode ...
KBUILD_CFLAGS += $(call cc-option,-fno-unit-at-a-time)
...

第一个示例利用了配置选项在选择时扩展为“y”的技巧。

KBUILD_RUSTFLAGS

$(RUSTC) 编译器标志

默认值 - 请参阅顶级 Makefile。

根据需要按体系结构追加或修改。

通常,KBUILD_RUSTFLAGS 变量取决于配置。

请注意,目标规范文件生成(对于 --target)在 scripts/generate_rust_target.rs 中处理。

KBUILD_AFLAGS_KERNEL

特定于内置的汇编器选项

$(KBUILD_AFLAGS_KERNEL) 包含用于编译驻留内核代码的额外 C 编译器标志。

KBUILD_AFLAGS_MODULE

特定于模块的汇编器选项

$(KBUILD_AFLAGS_MODULE) 用于添加用于汇编程序的体系结构特定选项。

从命令行应使用 AFLAGS_MODULE(请参阅Kbuild)。

KBUILD_CFLAGS_KERNEL

特定于内置的 $(CC) 选项

$(KBUILD_CFLAGS_KERNEL) 包含用于编译驻留内核代码的额外 C 编译器标志。

KBUILD_CFLAGS_MODULE

构建模块时 $(CC) 的选项

$(KBUILD_CFLAGS_MODULE) 用于添加用于 $(CC) 的体系结构特定选项。

从命令行应使用 CFLAGS_MODULE(请参阅Kbuild)。

KBUILD_RUSTFLAGS_KERNEL

特定于内置的 $(RUSTC) 选项

$(KBUILD_RUSTFLAGS_KERNEL) 包含用于编译驻留内核代码的额外 Rust 编译器标志。

KBUILD_RUSTFLAGS_MODULE

构建模块时 $(RUSTC) 的选项

$(KBUILD_RUSTFLAGS_MODULE) 用于添加用于 $(RUSTC) 的体系结构特定选项。

从命令行应使用 RUSTFLAGS_MODULE(请参阅Kbuild)。

KBUILD_LDFLAGS_MODULE

链接模块时 $(LD) 的选项

$(KBUILD_LDFLAGS_MODULE) 用于添加链接模块时使用的体系结构特定选项。这通常是链接器脚本。

从命令行应使用 LDFLAGS_MODULE(请参阅Kbuild)。

KBUILD_LDS

具有完整路径的链接器脚本。由顶层 Makefile 分配。

KBUILD_VMLINUX_OBJS

vmlinux 的所有目标文件。它们以 KBUILD_VMLINUX_OBJS 中列出的相同顺序链接到 vmlinux。

scripts/head-object-list.txt 中列出的对象是例外;它们放在其他对象之前。

KBUILD_VMLINUX_LIBS

vmlinux 的所有 .a lib 文件。KBUILD_VMLINUX_OBJS 和 KBUILD_VMLINUX_LIBS 一起指定用于链接 vmlinux 的所有目标文件。

将先决条件添加到 archheaders

archheaders: 规则用于生成可以通过 make header_install 安装到用户空间的头文件。

当在体系结构本身上运行时,它在 make archprepare 之前运行。

将先决条件添加到 archprepare

archprepare: 规则用于列出在开始进入子目录之前需要构建的先决条件。

这通常用于包含汇编器常量的头文件。

示例

#arch/arm/Makefile
archprepare: maketools

在此示例中,文件目标 maketools 将在进入子目录之前处理。

另请参阅描述 kbuild 如何支持生成偏移头文件的 XXX-TODO 章。

列出进入时要访问的目录

arch Makefile 与顶级 Makefile 协同工作,以定义变量来指定如何构建 vmlinux 文件。请注意,模块没有对应的体系结构特定部分;模块构建机制都是独立于体系结构的。

core-y、libs-y、drivers-y

$(libs-y) 列出可以找到 lib.a 存档的目录。

其余列出可以找到 built-in.a 目标文件的目录。

然后其余的按此顺序排列

$(core-y)、$(libs-y)、$(drivers-y)

顶级 Makefile 定义所有通用目录的值,而 arch/$(SRCARCH)/Makefile 仅添加特定于体系结构的目录。

示例

# arch/sparc/Makefile
core-y                 += arch/sparc/

libs-y                 += arch/sparc/prom/
libs-y                 += arch/sparc/lib/

drivers-$(CONFIG_PM) += arch/sparc/power/

特定于体系结构的引导映像

arch Makefile 指定获取 vmlinux 文件、对其进行压缩、将其包装在引导代码中并将生成的文件复制到某处的“目标”。这包括各种安装命令。实际目标在各个体系结构之间没有标准化。

通常将任何其他处理放置在 arch/$(SRCARCH)/ 下的 boot/ 目录中。

Kbuild 不提供任何智能方式来支持构建 boot/ 中指定的目标。因此,arch/$(SRCARCH)/Makefile 应手动调用 make 以构建 boot/ 中的目标。

建议的方法是在 arch/$(SRCARCH)/Makefile 中包含快捷方式,并在调用到 arch/$(SRCARCH)/boot/Makefile 中时使用完整路径。

示例

#arch/x86/Makefile
boot := arch/x86/boot
bzImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@

$(Q)$(MAKE) $(build)=<dir> 是在子目录中调用 make 的推荐方法。

没有用于命名特定于体系结构的目标的规则,但是执行 make help 将列出所有相关目标。为了支持这一点,必须定义 $(archhelp)。

示例

#arch/x86/Makefile
define archhelp
  echo  '* bzImage      - Compressed kernel image (arch/x86/boot/bzImage)'
endif

当执行 make 时不带参数,将构建遇到的第一个目标。在顶层 Makefile 中,存在的第一个目标是 all:。

每个体系结构应始终默认构建可引导映像。在 make help 中,默认目标用 * 突出显示。

向 all: 添加新的先决条件,以选择与 vmlinux 不同的默认目标。

示例

#arch/x86/Makefile
all: bzImage

当执行 make 时不带参数,将构建 bzImage。

可用于构建引导映像的命令

Kbuild 提供了一些在构建引导映像时有用的宏。

ld

链接目标。通常,LDFLAGS_$@ 用于为 ld 设置特定选项。

示例

#arch/x86/boot/Makefile
LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
LDFLAGS_setup    := -Ttext 0x0 -s --oformat binary -e begtext

targets += setup setup.o bootsect bootsect.o
$(obj)/setup $(obj)/bootsect: %: %.o FORCE
        $(call if_changed,ld)

在此示例中,存在两个可能的目标,需要链接器的不同选项。链接器选项使用 LDFLAGS_$@ 语法指定 - 每个潜在目标一个。

$(targets) 被分配所有潜在目标,kbuild 通过它知道目标并将

  1. 检查命令行更改

  2. 在 make clean 期间删除目标

先决条件的 : %: %.o 部分是一种简写,使我们无需列出 setup.o 和 bootsect.o 文件。

注意:忘记 targets := 分配是一个常见的错误,导致目标文件被重新编译而没有明显原因。

objcopy

复制二进制文件。使用通常在 arch/$(SRCARCH)/Makefile 中指定的 OBJCOPYFLAGS。

OBJCOPYFLAGS_$@ 可用于设置其他选项。

gzip

压缩目标。使用最大压缩率压缩目标。

示例

#arch/x86/boot/compressed/Makefile
$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,gzip)
dtc

创建适合链接到 vmlinux 的扁平设备树 blob 对象。链接到 vmlinux 的设备树 blob 放置在映像的 init 部分中。平台代码必须在调用 unflatten_device_tree() 之前将 blob 复制到非 init 内存中。

要使用此命令,只需将 *.dtb 添加到 obj-y 或 targets 中,或者使某些其他目标依赖于 %.dtb

存在一个中心规则,用于从 $(src)/%.dts 创建 $(obj)/%.dtb;体系结构 Makefile 不需要显式写出该规则。

示例

targets += $(dtb-y)
DTC_FLAGS ?= -p 1024

预处理链接器脚本

构建 vmlinux 映像时,将使用链接器脚本 arch/$(SRCARCH)/kernel/vmlinux.lds。

该脚本是位于同一目录中的文件 vmlinux.lds.S 的预处理变体。

kbuild 知道 .lds 文件并包含一个规则 *lds.S -> *lds

示例

#arch/x86/kernel/Makefile
extra-y := vmlinux.lds

对 extra-y 的赋值用于告诉 kbuild 构建目标 vmlinux.lds。

对 $(CPPFLAGS_vmlinux.lds) 的赋值告诉 kbuild 在构建目标 vmlinux.lds 时使用指定的选项。

在构建 *.lds 目标时,kbuild 使用变量

KBUILD_CPPFLAGS      : Set in top-level Makefile
cppflags-y           : May be set in the kbuild makefile
CPPFLAGS_$(@F)       : Target-specific flags.
                       Note that the full filename is used in this
                       assignment.

*lds 文件的 kbuild 基础设施在多个特定于体系结构的文件中使用。

通用头文件

目录 include/asm-generic 包含可在各个体系结构之间共享的头文件。

推荐的使用通用头文件的方法是在 Kbuild 文件中列出该文件。

有关语法等的更多信息,请参阅generic-y

链接后处理

如果文件 arch/xxx/Makefile.postlink 存在,则会为架构调用此 makefile,以便对链接后的对象(vmlinux 和 modules.ko)执行链接后处理。还必须处理 clean 目标。

此处理在 kallsyms 生成之后运行。如果架构需要修改符号位置,而不是操作 kallsyms,则可以更容易地为 .tmp_vmlinux? 目标添加另一个链接后目标,以便从 link-vmlinux.sh 中调用。

例如,powerpc 使用它来检查链接的 vmlinux 文件的重定位完整性。

导出的头文件的 Kbuild 语法

内核包含一组导出到用户空间的头文件。许多头文件可以按原样导出,但其他头文件在准备好供用户空间使用之前需要进行最少的预处理。

预处理会

  • 删除内核特定的注释

  • 删除 compiler.h 的包含

  • 删除所有内核内部的段(由 ifdef __KERNEL__ 保护)

include/uapi/、include/generated/uapi/、arch/<arch>/include/uapi/ 和 arch/<arch>/include/generated/uapi/ 下的所有头文件都会被导出。

可以在 arch/<arch>/include/uapi/asm/ 和 arch/<arch>/include/asm/ 下定义 Kbuild 文件,以列出来自 asm-generic 的 asm 文件。

有关 Kbuild 文件的语法,请参见后续章节。

no-export-headers

no-export-headers 主要由 include/uapi/linux/Kbuild 使用,以避免在不支持特定头文件(例如 kvm.h)的架构上导出它们。应尽可能避免使用它。

generic-y

如果某个架构使用来自 include/asm-generic 的头文件的逐字副本,则此信息会像这样列在文件 arch/$(SRCARCH)/include/asm/Kbuild 中

示例

#arch/x86/include/asm/Kbuild
generic-y += termios.h
generic-y += rtc.h

在构建的 prepare 阶段,将在目录中生成一个包装器包含文件

arch/$(SRCARCH)/include/generated/asm

当导出架构使用通用头文件的头文件时,会生成类似的包装器,作为目录中导出的头文件集的一部分

usr/include/asm

在这两种情况下,生成的包装器都将如下所示

示例:termios.h

#include <asm-generic/termios.h>

generated-y

如果某个架构除了生成 generic-y 包装器之外还生成其他头文件,则 generated-y 会指定它们。

这可以防止它们被视为过时的 asm-generic 包装器而被删除。

示例

#arch/x86/include/asm/Kbuild
generated-y += syscalls_32.h

mandatory-y

mandatory-y 主要由 include/(uapi/)asm-generic/Kbuild 使用,以定义所有架构都必须具有的最小 ASM 头文件集。

这与可选的 generic-y 类似。如果 arch/$(SRCARCH)/include/(uapi/)/asm 中缺少强制头文件,Kbuild 将自动生成 asm-generic 文件的包装器。

Kbuild 变量

顶层 Makefile 导出以下变量

VERSION、PATCHLEVEL、SUBLEVEL、EXTRAVERSION

这些变量定义当前内核版本。一些 arch Makefile 实际上直接使用这些值;它们应该使用 $(KERNELRELEASE) 代替。

$(VERSION)、$(PATCHLEVEL) 和 $(SUBLEVEL) 定义基本的三部分版本号,例如 “2”、“4” 和 “0”。这三个值始终是数字。

$(EXTRAVERSION) 为预补丁或附加补丁定义一个更小的子级别。它通常是一些非数字字符串,例如“-pre4”,并且通常为空。

KERNELRELEASE

$(KERNELRELEASE) 是一个单一的字符串,例如 “2.4.0-pre4”,适合于构造安装目录名称或在版本字符串中显示。一些 arch Makefile 将其用于此目的。

ARCH

此变量定义目标架构,例如 “i386”、“arm” 或 “sparc”。一些 kbuild Makefile 测试 $(ARCH) 以确定要编译的文件。

默认情况下,顶层 Makefile 将 $(ARCH) 设置为与主机系统架构相同。对于交叉构建,用户可以在命令行上覆盖 $(ARCH) 的值

make ARCH=m68k ...
SRCARCH

此变量指定要构建的 arch/ 中的目录。

ARCH 和 SRCARCH 不一定匹配。一些 arch 目录是双架构的,也就是说,单个 arch/*/ 目录同时支持 32 位和 64 位。

例如,您可以传入 ARCH=i386、ARCH=x86_64 或 ARCH=x86。对于所有这些,SRCARCH=x86,因为 arch/x86/ 同时支持 i386 和 x86_64。

INSTALL_PATH

此变量定义 arch Makefile 安装常驻内核映像和 System.map 文件的位置。将其用于架构特定的安装目标。

INSTALL_MOD_PATH、MODLIB

$(INSTALL_MOD_PATH) 指定模块安装的 $(MODLIB) 的前缀。此变量未在 Makefile 中定义,但如果需要,用户可以传入。

$(MODLIB) 指定模块安装的目录。顶层 Makefile 将 $(MODLIB) 定义为 $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)。如果需要,用户可以在命令行上覆盖此值。

INSTALL_MOD_STRIP

如果指定了此变量,它将导致模块在安装后被剥离。如果 INSTALL_MOD_STRIP 为 “1”,则将使用默认选项 --strip-debug。否则,INSTALL_MOD_STRIP 值将用作 strip 命令的选项。

INSTALL_DTBS_PATH

此变量指定构建根所需的重定位的前缀。它定义了安装设备树 blob 的位置。与 INSTALL_MOD_PATH 类似,它未在 Makefile 中定义,但可以由用户传入(如果需要)。否则,它将默认为内核安装路径。

Makefile 语言

内核 Makefile 设计为使用 GNU Make 运行。Makefile 仅使用 GNU Make 的文档记录的功能,但它们确实使用了许多 GNU 扩展。

GNU Make 支持基本的列表处理函数。内核 Makefile 使用一种新颖的列表构建和操作风格,几乎没有 if 语句。

GNU Make 有两个赋值运算符,:==:= 执行右侧的立即求值,并将实际字符串存储到左侧。= 就像一个公式定义;它以未求值的形式存储右侧,然后在每次使用左侧时都对该形式进行求值。

在某些情况下,= 是合适的。但是,通常,:= 是正确的选择。

贡献者

待办事项

  • 生成偏移量头文件。

  • 在第 7 章或第 9 章中添加更多变量?