Linux Kconfig

最後更新: 2022-07-06 20:06:54 +0800 +0800
tags: Kconfig | Kernel | Linux
原文以英文撰寫。您正在閱讀AI翻譯版本。

Kconfig 描述建置 Linux 核心設定時所做的選擇。核心開發者編輯 Kconfig 檔案來定義符號與其關係;使用者透過 make menuconfig、make nconfig、make xconfig 等前端,或 olddefconfig 等非互動目標選取值。

產生的 .config 是 Kbuild 的輸入,而不是完整的建置指令碼。設定同步會產生由 Make 與 C 消費的檔案,包括 include/config/auto.conf 與 include/generated/autoconf.h。

從根檔案到單一設定 #

解析從頂層 Kconfig 開始。它的 source 陳述式會包含子系統檔案,而架構選擇會引入 arch/$(SRCARCH)/Kconfig。其他包含形式為:

  • rsource,其路徑相對於包含檔案;
  • osource,忽略遺失的檔案;
  • orsource,結合相對與選用行為。

mainmenu 設定前端標題。menu/endmenu、if/endif、choice/endchoice、comment、config 與 menuconfig 建立項目結構。

同一符號可以在多個包含檔案中定義。Kconfig 會組合符號的屬性,不會建立架構本機變數。定義必須使用一致型別,依賴子句會累積,而預設值順序仍然重要。因此,共用檔案可以宣告不可見功能,而架構定義會選取它。

kconfig
# lib/Kconfig
config HAVE_FAST_CHECKSUM
    bool

config FAST_CHECKSUM
    bool "Use the generic fast checksum implementation"
    depends on HAVE_FAST_CHECKSUM

# arch/example/Kconfig
config EXAMPLE
    bool
    select HAVE_FAST_CHECKSUM

HAVE_* 符號表達實作能力。接著,使用者可見功能依賴該能力,避免使用 select 繞過功能的實際相依性。

巨集與前處理器層 #

Kconfig 會在選單項目語言處理一行之前執行文字展開。其變數語法類似 Make:

makefile
immediate := $(ARCH)
deferred = $(ARCH)
message = architecture $(1), compiler $(2)

$(info,configuring $(immediate))
label := $(message,$(ARCH),$(CC))
  • := 會立即展開右側。
  • = 儲存遞迴展開的值。
  • += 依變數現有的展開風格附加內容。
  • $(name) 展開變數。
  • $(name,arg1,arg2) 展開參數化變數,其中 $(1)、$(2) 等是位置引數。

與 Make 不同,參數化 Kconfig 變數會直接呼叫;沒有 $(call ...)。逗號分隔函式引數。內建函式包括 shell、info、warning-if、error-if、filename 與 lineno。核心透過 Kconfig 函式機制加入編譯器選項探測等函式。

巨集展開是文字性的,因此引號與空白對接收結果的語言仍然重要。使用前處理來處理小型重複運算式與功能探測,而不是產生大型、難以稽核的選單片段。

符號、型別與提示 #

config NAME 定義名為 NAME 的符號;.config 與 C 將它暴露為 CONFIG_NAME。menuconfig 定義相同種類的符號,但會告訴相容前端該項目預期包含子選單。

可用的符號型別有五種:

型別.config 中的範例產生的 C 形式
boolCONFIG_FOO=y 或 # CONFIG_FOO is not set#define CONFIG_FOO 1 或不存在
tristateCONFIG_FOO=y、CONFIG_FOO=m 或未設定CONFIG_FOO、CONFIG_FOO_MODULE 或兩者皆無
stringCONFIG_FOO="value"加引號的字串巨集
intCONFIG_FOO=42整數巨集
hexCONFIG_FOO=0x2a十六進位整數巨集

bool "Enable foo" 與 tristate "Build foo" 將型別與 prompt 結合。沒有可見提示的符號無法在設定前端編輯,但預設值、select 或其他運算式仍可為它提供值。

kconfig
config FOO
    tristate "Foo transport"
    depends on NET
    default m if MODULES
    help
      Build support for the Foo transport.

def_bool EXPR 與 def_tristate EXPR 是型別加上 default EXPR 的縮寫。當選用條件為真時,range MIN MAX 會限制 int 或 hex 符號。

Tristate 運算式 #

邏輯 Kconfig 運算式使用有序值 n = 0、m = 1 與 y = 2。因此:

  • A && B 是兩個值的最小值;
  • A || B 是最大值;
  • !A 是 2 - A。

比較會產生 tristate 結果。括號控制分組,而加引號的常值表示字串值。bool 不能保留 m;模組相關運算式會依符號型別與是否啟用模組而折疊。

直接相依性會施加上限:

kconfig
config USB_WIDGET
    tristate "USB widget"
    depends on USB && HAS_IOMEM

若 USB=m,USB_WIDGET 不能成為 y。提示上的選用條件會影響提示是否可見,而符號的直接相依性無論前端如何呈現都會限制其值。

預設值、反向相依性與可見性 #

屬性解決不同問題:

  • default VALUE if CONDITION 只在使用者尚未設定時提供值。若多個預設值可見,第一個可見預設值勝出。預設值不會覆寫現有 .config 中保留的值。
  • depends on EXPR 限制符號最大值與提示可見性。
  • select TARGET if CONDITION 建立反向相依性,並將 TARGET 提升到至少選取運算式的值。它不會遵守 TARGET 自己的直接相依性,因此只應選取前置條件已確定滿足的簡單不可見符號。
  • imply TARGET if CONDITION 是弱反向相依性。它提供仍可被可見使用者選擇降低的下限,而目標的直接相依性仍會限制結果。
  • visible if EXPR 限制 menu 區塊的可見性,但不改變其中符號的值。

例如:

kconfig
config DRIVER_FOO
    tristate "Foo device"
    depends on PCI
    select CRC32
    imply FW_LOADER

CRC32 應該是沒有未滿足相依性的內部輔助工具。FW_LOADER 只是受到鼓勵,因為驅動程式沒有它也能運作。加入 select 來修復相依性循環是不正確的,因為 Kconfig 會拒絕遞迴相依性,且不使用 SAT solver 推導偏好解。

選單位置不是相依性圖 #

來源順序與明確容器決定大部分顯示位置:

kconfig
menu "Network drivers"
    visible if NET

config NET_VENDOR_EXAMPLE
    bool "Example devices"

if NET_VENDOR_EXAMPLE
source "drivers/net/ethernet/example/Kconfig"
endif

endmenu

當後續項目強烈依賴前一項,使子項目只有在父項目可見時才能可見,前端也會推導隱含子選單。語言文件描述精確的提示相依規則。

除此之外,相依性不會重新定位項目。符號可以依賴顯示於不同區段的另一個符號,而 select 不會使目標出現在選取器下方。因此,選單配置傳達導覽,而相依性運算式傳達有效值。將前者視為後者的渲染結果,會產生令人困惑的 Kconfig 檔案。

產生的設定構件 #

前端寫入 .config 後,Kbuild 會同步產生的輸入。重要表示如下:

text
.config
include/config/auto.conf
include/generated/autoconf.h

.config 是持久且面向使用者的指派檔案。auto.conf 將指派呈現給 Make,讓規則可以使用以下運算式:

makefile
obj-$(CONFIG_USB_WIDGET) += usb-widget.o

autoconf.h 將啟用的符號呈現給 C 前處理。核心 C 程式碼應包含一般核心標頭,而不是直接包含 autoconf.h。IS_ENABLED(CONFIG_FOO) 等輔助工具能處理內建與模組形式,而不必自行撰寫每種前處理組合。

設定更新可以加入較新樹引入的符號。make oldconfig 會詢問新的選擇,而 make olddefconfig 接受它們的預設值。make savedefconfig 會相對於預設值寫入最小 defconfig;它不能與封存完整 .config 互換。

參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)