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_ 變數。如果相應的 CONFIG_ 選項既不是 “y” 也不是 “m”,則這允許 kbuild 完全跳過該目錄。

非內建 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 現在已棄用,因為這等效於

always-$(KBUILD_BUILTIN) += 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 呼叫。

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 基礎設施不提供所需的支援時,使用自定義規則。一個典型的例子是在構建過程中生成的標頭檔案。另一個例子是架構特定的 Makefiles,它需要自定義規則來準備引導映象等。

自定義規則編寫為普通的 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),除非使用 make -s,否則它會將 $(kecho) 後面的文本回顯到 stdout。

示例

# 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 分配選項 -Wa$(comma)-isa=$(isa-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) 支援,則將為 cflags-y 分配選項 -march=pentium-mmx,否則為 -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, 110100) := -foo

在此示例中,如果 $(CC) 是 gcc 並且 $(CONFIG_GCC_VERSION) >= 11.1,則 cflags-y 將被賦值為 -foo。

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)。返回路徑中存在 prefix$(CC) 的第一個字首 - 如果未找到 prefix$(CC),則不返回任何內容。

其他字首在 cc-cross-prefix 的呼叫中用單個空格分隔。

此功能對於嘗試將 CROSS_COMPILE 設定為眾所周知的值但可能需要在多個值之間進行選擇的架構 Makefiles 很有用。

建議僅在交叉構建(主機架構與目標架構不同)時才嘗試設定 CROSS_COMPILE。如果 CROSS_COMPILE 已經設定,則將其保留為舊值。

示例

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

$(RUSTC) 支援函式

rustc-min-version

rustc-min-version 測試 $(CONFIG_RUSTC_VERSION) 的值是否大於或等於提供的值,如果是,則評估為 y。

示例

rustflags-$(call rustc-min-version, 108500) := -Cfoo

在此示例中,如果 $(CONFIG_RUSTC_VERSION) >= 1.85.0,則 rustflags-y 將被賦值為 -Cfoo。

$(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)。

控制主機程式的編譯器選項

編譯主機程式時,可以設定特定的標誌。 這些程式將始終使用 $(HOSTCC) 編譯,並傳遞 $(KBUILD_HOSTCFLAGS) 中指定的選項。

要設定將對在該 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 不允許用於使用者空間程式。

控制使用者空間程式的編譯器選項

編譯使用者空間程式時,可以設定特定的標誌。 這些程式將始終使用 $(CC) 編譯,並傳遞 $(KBUILD_USERCFLAGS) 中指定的選項。

要設定將對在該 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) 變數。

通常,由於 obj-* := dir/,kbuild 會下降到子目錄中,但在架構 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 Makefile 動態執行目標 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 將在下降到子目錄中之前處理。

另請參閱 XXX-TODO 章,該章描述了 kbuild 如何支援生成偏移標頭檔案。

列出下降時要訪問的目錄

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

複製二進位制檔案。 使用 OBJCOPYFLAGS,通常在 arch/$(SRCARCH)/Makefile 中指定。

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,則新增另一個 postlink 目標以從 link-vmlinux.sh 呼叫的 .tmp_vmlinux? 目標可能更容易。

例如,powerpc 使用它來檢查連結的 vmlinux 檔案的重定位健全性。

匯出的標頭檔案的 Kbuild 語法

核心包含一組匯出到使用者空間的標頭檔案。 許多標頭檔案可以按原樣匯出,但其他標頭檔案在準備好供使用者空間使用之前需要最少的預處理。

預處理執行

  • 刪除核心特定註釋

  • 刪除 include of 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

如果架構在通用-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

這些變數定義了當前的核心版本。一些架構的 Makefile 實際上直接使用了這些值;它們應該使用 $(KERNELRELEASE) 代替。

$(VERSION)、$(PATCHLEVEL) 和 $(SUBLEVEL) 定義了基本的三部分版本號,例如“2”、“4”和“0”。這三個值始終是數字。

$(EXTRAVERSION) 為預補丁或附加補丁定義了一個更小的子級別。它通常是一些非數字字串,例如“-pre4”,並且通常為空。

KERNELRELEASE

$(KERNELRELEASE) 是一個單獨的字串,例如“2.4.0-pre4”,適合用於構建安裝目錄名或在版本字串中顯示。一些架構 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

此變數定義了一個位置,供架構 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 章中新增更多變數?