Kconfig 宏語言¶
概念¶
基本思想受到 Make 的啟發。當我們檢視 Make 時,我們注意到一種語言中包含兩種語言。一種語言描述了由目標和先決條件組成的依賴關係圖。另一種是用於執行文字替換的宏語言。
兩種語言階段之間有明顯的區別。例如,您可以編寫如下的 makefile
APP := foo
SRC := foo.c
CC := gcc
$(APP): $(SRC)
$(CC) -o $(APP) $(SRC)
宏語言將變數引用替換為其展開形式,並將其視為原始檔輸入,如下所示
foo: foo.c
gcc -o foo foo.c
然後,Make 分析依賴關係圖並確定要更新的目標。
Kconfig 中的想法非常相似 - 可以像這樣描述 Kconfig 檔案
CC := gcc
config CC_HAS_FOO
def_bool $(shell, $(srctree)/scripts/gcc-check-foo.sh $(CC))
Kconfig 中的宏語言將原始檔處理為以下中間狀態
config CC_HAS_FOO
def_bool y
然後,Kconfig 進入評估階段,以解決符號間的依賴關係,如Kconfig 語言中所述。
變數¶
與 Make 中一樣,Kconfig 中的變數用作宏變數。宏變數“就地”展開以產生文字字串,然後可以進一步展開。要獲取變數的值,請將變數名括在 $( ) 中。即使對於單字母變數名,也需要括號;$X 是語法錯誤。也不支援花括號形式,如 ${CC}。
有兩種型別的變數:簡單展開的變數和遞迴展開的變數。
簡單展開的變數使用 := 賦值運算子定義。它的右側在從 Kconfig 檔案讀取該行時立即展開。
遞迴展開的變數使用 = 賦值運算子定義。它的右側僅儲存為變數的值,而不以任何方式展開它。相反,展開在變數使用時執行。
還有另一種型別的賦值運算子;+= 用於將文字附加到變數。如果左側最初定義為簡單變數,則 += 的右側立即展開。否則,其評估將被推遲。
變數引用可以採用引數,形式如下
$(name,arg1,arg2,arg3)
您可以將引數化引用視為函式。(更準確地說,是“使用者定義的函式”,與下面列出的“內建函式”相對)。
有用的函式必須在使用時展開,因為如果傳遞不同的引數,則相同的函式會以不同的方式展開。因此,使用者定義的函式使用 = 賦值運算子定義。引數在主體定義中用 $(1)、$(2) 等引用。
事實上,遞迴展開的變數和使用者定義的函式在內部是相同的。(換句話說,“變數”是“零引數的函式”。)當我們廣義地說“變數”時,它包括“使用者定義的函式”。
內建函式¶
與 Make 類似,Kconfig 提供了幾個內建函式。每個函式都接受特定數量的引數。
在 Make 中,每個內建函式至少接受一個引數。Kconfig 允許內建函式使用零引數,例如 $(filename)、$(lineno)。您可以將這些視為“內建變數”,但這只是我們如何稱呼它的問題。讓我們在這裡說“內建函式”來指代本機支援的功能。
Kconfig 當前支援以下內建函式。
$(shell,command)
“shell”函式接受一個引數,該引數被展開並傳遞給子 shell 以執行。然後讀取命令的標準輸出並將其作為函式的值返回。輸出中的每個換行符都替換為空格。任何尾隨換行符都會被刪除。不返回標準錯誤,也不返回任何程式退出狀態。
$(info,text)
“info”函式接受一個引數並將其列印到標準輸出。它評估為空字串。
$(warning-if,condition,text)
“warning-if”函式接受兩個引數。如果 condition 部分是“y”,則 text 部分將傳送到標準錯誤。文字以當前 Kconfig 檔案的名稱和當前行號為字首。
$(error-if,condition,text)
“error-if”函式類似於“warning-if”,但如果 condition 部分是“y”,則它會立即終止解析。
$(filename)
“filename”不帶引數,$(filename) 擴充套件為正在解析的檔名。
$(lineno)
“lineno”不帶引數,$(lineno) 擴充套件為正在解析的行號。
Make vs Kconfig¶
Kconfig 採用類似 Make 的宏語言,但函式呼叫語法略有不同。
Make 中的函式呼叫如下所示
$(func-name arg1,arg2,arg3)
函式名和第一個引數之間至少用一個空格分隔。然後,從第一個引數中刪除前導空格,而保留其他引數中的空格。您需要使用一種技巧才能使第一個引數以空格開頭。例如,如果您想讓“info”函式列印“ hello”,您可以這樣寫
empty :=
space := $(empty) $(empty)
$(info $(space)$(space)hello)
Kconfig 僅使用逗號作為分隔符,並保留函式呼叫中的所有空格。有些人喜歡在每個逗號分隔符後放置一個空格
$(func-name, arg1, arg2, arg3)
在這種情況下,“func-name”將接收“ arg1”、“ arg2”、“ arg3”。前導空格的存在可能會影響函式。同樣適用於 Make - 例如,$(subst .c, .o, $(sources)) 是一個典型的錯誤;它將“.c”替換為“ .o”。
在 Make 中,使用者定義的函式透過使用內建函式“call”來引用,如下所示
$(call my-func,arg1,arg2,arg3)
Kconfig 以相同的方式呼叫使用者定義的函式和內建函式。省略“call”使語法更短。
在 Make 中,某些函式將逗號視為字面量而不是引數分隔符。例如,$(shell echo hello, world) 執行命令“echo hello, world”。同樣,$(info hello, world) 將“hello, world”列印到標準輸出。你可以說這是一種_有用的_不一致。
在 Kconfig 中,為了更簡單的實現和語法一致性,出現在 $( ) 上下文中的逗號始終是分隔符。這意味著
$(shell, echo hello, world)
是一個錯誤,因為它傳遞了兩個引數,而“shell”函式僅接受一個引數。要在引數中傳遞逗號,您可以使用以下技巧
comma := ,
$(shell, echo hello$(comma) world)
注意事項¶
變數(或函式)不能跨標記展開。因此,您不能使用變數作為包含多個標記的表示式的簡寫。以下有效
RANGE_MIN := 1
RANGE_MAX := 3
config FOO
int "foo"
range $(RANGE_MIN) $(RANGE_MAX)
但是,以下不起作用
RANGES := 1 3
config FOO
int "foo"
range $(RANGES)
變數不能擴充套件為 Kconfig 中的任何關鍵字。以下不起作用
MY_TYPE := tristate
config FOO
$(MY_TYPE) "foo"
default y
顯然從設計來看,$(shell command) 在文字替換階段展開。您不能將符號傳遞給“shell”函式。
以下內容無法按預期工作
config ENDIAN_FLAG
string
default "-mbig-endian" if CPU_BIG_ENDIAN
default "-mlittle-endian" if CPU_LITTLE_ENDIAN
config CC_HAS_ENDIAN_FLAG
def_bool $(shell $(srctree)/scripts/gcc-check-flag ENDIAN_FLAG)
相反,您可以像下面這樣做,以便靜態展開任何函式呼叫
config CC_HAS_ENDIAN_FLAG
bool
default $(shell $(srctree)/scripts/gcc-check-flag -mbig-endian) if CPU_BIG_ENDIAN
default $(shell $(srctree)/scripts/gcc-check-flag -mlittle-endian) if CPU_LITTLE_ENDIAN