Python Kconfiglib初次學習

2023-01-05 06:00:32

1 參考

kconfiglib庫官方介紹kconfiglib · PyPI

Kconfiglib原始碼:GitHub - ulfalizer/Kconfiglib: A flexible Python 2/3 Kconfig implementation and library

Kconfig語法:Kconfig Language — The Linux Kernel documentation

其它參考:

【華為雲技術分享】STM32L476移植華為LiteOS系列教學---Kconfig 6 - zhy_learn - 部落格園 (cnblogs.com)

menuconfig 和、Kconfig 介紹及例子解析! (qq.com)

驅動模組(6)_Kconfig語法 - Hello-World3 - 部落格園 (cnblogs.com)

Kconfig語法簡介 - schips - 部落格園 (cnblogs.com)

2 Python Kconfiglib

簡介:Kconfiglib is a Python 2/3 library for scripting and extracting information from Kconfig (https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt) configuration systems.(Kconfiglib是一個從Kconfig設定系統中編寫指令碼提取資訊的庫,Kconfig設定系統是Linux核心提出的一個設定資料庫,關於Kconfig的語法可參考核心檔案)。

幾個概念:

  • menuconfig:設定選單,支援設定的圖形化介面。
  • Kconfig:生成menuconfig介面的一種語言,對選單項進行了描述。
  • .config:通過設定選單生成的組態檔,一般在Makefile中使用。

本文除了介紹python Kconfiglib庫之外,還要重點學習Kconfig的語法規則,瞭解了語法就知道如何用menuconfig進行設定項的選擇。以下章節來自官方的介紹說明。

2.1 Getting started

  1. Install the library and the utilities.(安裝庫和相關的工具)

  2. Write Kconfig files that describe the available configuration options. See Kconfig Language — The Linux Kernel documentation for some general Kconfig advice.(編寫Kconfig檔案,用來描述設定選項,可以參考核心的Kconfig語言來學習)

  3. Generate an initial configuration with e.g. menuconfig/guiconfig or alldefconfig. The configuration is saved as .config by default.(使用menuconfig/guiconfig或者alldefconfig生成一個最初的設定,預設儲存為.config檔案)

    For more advanced projects, the defconfig utility can be used to generate the initial configuration from an existing configuration file. Usually, this existing configuration file would be a minimal configuration file, as generated by e.g. savedefconfig.(對於更高階的用法,defconfig可以從一個已存在的組態檔中生成一個初始化設定,通常已存在的組態檔作為一個最小的組態檔,使用savedefconfig生成組態檔)

  4. Run genconfig to generate a header file. By default, it is saved as config.h.(genconfig 用於生成一個標頭檔案,預設儲存為config.h)

    Normally, genconfig would be run automatically as part of the build.(通常,genconfig 作為build的一部分自動執行)

    Before writing a header file or other configuration output, Kconfiglib compares the old contents of the file against the new contents. If there's no change, the write is skipped. This avoids updating file metadata like the modification time, and might save work depending on your build setup.(在輸出一個標頭檔案或其它組態檔之前,會先比較舊的輸出檔案,如果沒有改變,直接跳過不輸出)

    Adding new configuration output formats should be relatively straightforward. See the implementation of write_config() in kconfiglib.py. The documentation for the Symbol.config_string property has some tips as well.(新增新的設定輸出格式時應該相對簡單,可以檢視write_config的用法,Symbol.config_string屬性也有一些提示)

  5. To update an old .config file after the Kconfig files have changed (e.g. to add new options), run oldconfig (prompts for values for new options) or olddefconfig (gives new options their default value). Entering the menuconfig or guiconfig interface and saving the configuration will also update it (the configuration interfaces always prompt for saving on exit if it would modify the contents of the .config file).(當執行oldconfig 或者olddefconfig時,如果Kconfig檔案改變時,會更新.config。執行menuconfig 或者guiconfig時,也會更新.config

    Due to Kconfig semantics, simply loading an old .config file performs an implicit olddefconfig, so building will normally not be affected by having an outdated configuration.

2.2 .config

.config files use Make syntax and can be included directly in Makefiles to read configuration values from there. This is why n-valued bool/tristate values are written out as # CONFIG_FOO is not set (a Make comment) in .config, allowing them to be tested with ifdef in Make.(輸出的.config檔案使用的是Make語法,可以直接在Makefile中包含這個檔案讀取設定值。bool/tristate型別的n輸出為# CONFIG_FOO is not set,Makefile中使用 ifdef方式使用)

.config檔案一般格式為:

# LOSCFG_DEBUG_KERNEL is not set
LOSCFG_SHELL=y

Makefile中一般的使用方式:

ifeq ($(LOSCFG_SHELL), y)
    LITEOS_SHELL_INCLUDE  += -I $(LITEOSTOPDIR)/shell/include
endif

If you make use of this, you might want to pass --config-out <filename> to genconfig and include the configuration file it generates instead of including .config directly. This has the advantage that the generated configuration file will always be a "full" configuration file, even if .config is outdated. Otherwise, it might be necessary to run old(def)config or menuconfig/guiconfig before rebuilding with an outdated .config.

If you use --sync-deps to generate incremental build information, you can include deps/auto.conf instead, which is also a full configuration file.

2.3 Library features

Kconfiglib can do the following, among other things:(Kconfiglib庫可以完成以下事情)

  • Programmatically get and set symbol values(以程式設計方式獲取和設定符合值)

    See allnoconfig.py and allyesconfig.py, which are automatically verified to produce identical output to the standard make allnoconfig and make allyesconfig.

  • Read and write .config and defconfig files(讀寫.config和deconfig檔案)

    The generated .config and defconfig (minimal configuration) files are character-for-character identical to what the C implementation would generate (except for the header comment). The test suite relies on this, as it compares the generated files.(通過庫生成的.configdeconfig檔案和C語言生成的是一樣的,除了標頭檔案註釋)

  • Write C headers(寫C標頭檔案)

    The generated headers use the same format as include/generated/autoconf.h from the Linux kernel. Output for symbols appears in the order that they're defined, unlike in the C tools (where the order depends on the hash table implementation).(生成的標頭檔案格式和核心的include/generated/autoconf.h檔案一樣,輸出的符號按它們的定義順序顯示)

  • Implement incremental builds(實現增量構建)

    This uses the same scheme as the include/config directory in the kernel: Symbols are translated into files that are touched when the symbol's value changes between builds, which can be used to avoid having to do a full rebuild whenever the configuration is changed.

    See the sync_deps() function for more information.

  • Inspect symbols

    Printing a symbol or other item (which calls __str__()) returns its definition in Kconfig format. This also works for symbols defined in multiple locations.

    A helpful __repr__() is on all objects too.

    All __str__() and __repr__() methods are deliberately implemented with just public APIs, so all symbol information can be fetched separately as well.

  • Inspect expressions

    Expressions use a simple tuple-based format that can be processed manually if needed. Expression printing and evaluation functions are provided, implemented with public APIs.

  • Inspect the menu tree

    The underlying menu tree is exposed, including submenus created implicitly from symbols depending on preceding symbols. This can be used e.g. to implement menuconfig-like functionality.

    See menuconfig.py/guiconfig.py and the minimalistic menuconfig_example.py example.

2.4 Menuconfig interfaces

Three configuration interfaces are currently available:(有三種設定介面,可以看作是三種不同的設定介面)

  • menuconfig.py is a terminal-based configuration interface implemented using the standard Python curses module. xconfig features like showing invisible symbols and showing symbol names are included, and it's possible to jump directly to a symbol in the menu tree (even if it's currently invisible).(menuconfig.py是一個基於終端設定介面)

    See the docstring at the top of menuconfig.py for more information about the terminal menuconfig implementation.(更多資訊可以檢視menuconfig.py檔案的頂部的說明)

  • guiconfig.py is a graphical configuration interface written in Tkinter. Like menuconfig.py, it supports showing all symbols (with invisible symbols in red) and jumping directly to symbols. Symbol values can also be changed directly from the jump-to dialog.

  • pymenuconfig, built by RomaVis, is an older portable Python 2/3 TkInter menuconfig implementation.

3 Kconfig語法

官網參考:

linux/kconfig-language.rst at master · torvalds/linux · GitHub

Kconfig Language — The Linux Kernel documentation

注:以下出現entry 的地方,可以理解為一個選單項或者一個設定項。

3.1 Introduction

簡介:The configuration database is a collection of configuration options organized in a tree structure:(Kconfig就是以樹形結構來組織設定選項的一個集合)

Every entry has its own dependencies. These dependencies are used to determine the visibility of an entry. Any child entry is only visible if its parent entry is also visible.(每一個設定都有自己的依賴,這些依賴關係確定了一個設定的可見性,任何子設定只有在父設定可見時才可見。)

3.2 Menu entries

Most entries define a config option; all other entries help to organize them. A single configuration option is defined like this:(大部分設定項都定義了一個設定選項,其它設定項可用來組織它們,一個簡單的設定選項如下)

config MODVERSIONS
      bool "Set version information on all module symbols"
      depends on MODULES
      help
        Usually, modules have to be recompiled whenever you switch to a new
        kernel.  ...

Every line starts with a key word and can be followed by multiple arguments. 「config」starts a new config entry. The following lines define attributes for this config option. Attributes can be the type of the config option, input prompt, dependencies, help text and default values. A config option can be defined multiple times with the same name, but every definition can have only a single input prompt and the type must not conflict.(每一行都以一個關鍵字開始,後面可以跟多個引數。config關鍵字表示一個設定項的開始,緊跟著的定義了一些設定項的屬性。可以有以下屬性:設定項型別、輸入提示、依賴關係、幫助資訊、預設值。一個設定項可以使用相同設定名被定義多次,但是每個定義只能有一個輸入提示,並且型別不不能衝突。)

3.3 Menu attributes

A menu entry can have a number of attributes. Not all of them are applicable everywhere (see syntax).(一個選單項可以有多個屬性,具體使用參考語法)

  • type definition: bool/tristate/string/hex/int(型別定義:布林值/三態/字串/十六進位制/整數)

    Every config option must have a type. There are only two basic types: tristate and string; the other types are based on these two. The type definition optionally accepts an input prompt, so these two examples are equivalent:(每一個設定項必須有一種型別。有兩種基礎型別:三態和字串。其他的型別都是基於這兩種型別。型別定義的輸入提示prompt是可選的,因此下面的兩種定義是等效的)

    bool "Networking support"
    

    and:

    bool
    prompt "Networking support"
    

    三態:3種狀態,對應Y、N、M三種選擇方式,就是這個設定項可以被三種選擇。如果=y則會被編入(built-in)核心,如果=m會被單獨連線成一個」.ko」模組。

  • input prompt: "prompt" <prompt> ["if" <expr>] (輸入提示)

    Every menu entry can have at most one prompt, which is used to display to the user. Optionally dependencies only for this prompt can be added with "if".(每一個選單項至少有一個輸入提示,用於顯示給使用者,可以通過新增if判斷來僅提示某一種提示)

  • default value: "default" <expr> ["if" <expr>](預設值)

    A config option can have any number of default values. If multiple default values are visible, only the first defined one is active. Default values are not limited to the menu entry where they are defined. This means the default can be defined somewhere else or be overridden by an earlier definition. The default value is only assigned to the config symbol if no other value was set by the user (via the input prompt above). If an input prompt is visible the default value is presented to the user and can be overridden by him. Optionally, dependencies only for this default value can be added with "if".(設定項可以有任意多個預設值,如果有多個預設值,僅保留第一個預設值。預設值不限於在定義它的選單項中定義,也可以在其他地方定義。預設值僅在使用者沒有分配設定值的時候使用,如果輸入可見,預設值就呈現給使用者。)

The default value deliberately defaults to 'n' in order to avoid bloating the build. With few exceptions, new config options should not change this. The intent is for 「make oldconfig」 to add as little as possible to the config from release to release.(為了避免編譯膨脹,預設值預設為'n'。)

  • Note:

    Things that merit 「default y/m」 include:A new Kconfig option for something that used to always be built should be 「default y」.A new gatekeeping Kconfig option that hides/shows other Kconfig options (but does not generate any code of its own), should be 「default y」 so people will see those other options.Sub-driver behavior or similar options for a driver that is 「default n」. This allows you to provide sane defaults.Hardware or infrastructure that everybody expects, such as CONFIG_NET or CONFIG_BLOCK. These are rare exceptions.

  • type definition + default value:(型別定義+預設值)

    "def_bool"/"def_tristate" <expr> ["if" <expr>]
    

    This is a shorthand notation for a type definition plus a value. Optionally dependencies for this default value can be added with "if".(這是型別定義+值的簡寫方式)

  • dependencies: "depends on" <expr>(依賴)

    This defines a dependency for this menu entry. If multiple dependencies are defined, they are connected with ‘&&’. Dependencies are applied to all other options within this menu entry (which also accept an 「if」 expression), so these two examples are equivalent:(定義選單項的依賴。如果要定義多個依賴,可以使用"&&"連線,依賴應用於當前選單項的所有選項,也可以使用if表示式,下面的兩種定義是等價的)

    bool "foo" if BAR
    default y if BAR
    

    and:

    depends on BAR
    bool "foo"
    default y
    
  • reverse dependencies: "select" <symbol> ["if" <expr>](反向依賴)

    While normal dependencies reduce the upper limit of a symbol (see below), reverse dependencies can be used to force a lower limit of another symbol. The value of the current menu symbol is used as the minimal value <symbol> can be set to. If <symbol> is selected multiple times, the limit is set to the largest selection. Reverse dependencies can only be used with boolean or tristate symbols.(正常的依賴是符號在設定項的上面,反向依賴可以讓符號在設定項的下面。當前選單符號的值被用作符號設定的最小值。如果符號被選擇多次,這個限制是符號被選擇的最大次數。反向依賴只能和布林符號或三態符號使用)

    • Note:

      select should be used with care. select will force a symbol to a value without visiting the dependencies. By abusing select you are able to select a symbol FOO even if FOO depends on BAR that is not set. In general use select only for non-visible symbols (no prompts anywhere) and for symbols with no dependencies. That will limit the usefulness but on the other hand avoid the illegal configurations all over.(反向依賴應該小心使用,反向依賴將強制設定符號沒有可見的依賴項。通常僅對不可見的符號使用反向依賴。)

  • weak reverse dependencies: "imply" <symbol> ["if" <expr>](弱反向依賴)

    This is similar to 「select」 as it enforces a lower limit on another symbol except that the "implied" symbol’s value may still be set to n from a direct dependency or with a visible prompt.(類似於反向依賴,強制另一個符號在它的下面,但是根據一個可見的提示項,符號仍然可能設定為'n')

    Given the following example:

    config FOO
        tristate "foo"
        imply BAZ
    
    config BAZ
        tristate "baz"
        depends on BAR
    

    The following values are possible:

    FOO BAR BAZ’s default choice for BAZ
    n y n N/m/y
    m y m M/y/n
    y y y Y/m/n
    n m n N/m
    m m m M/n
    y m m M/n
    y n N

    This is useful e.g. with multiple drivers that want to indicate their ability to hook into a secondary subsystem while allowing the user to configure that subsystem out without also having to unset these drivers.

    Note: If the combination of FOO=y and BAR=m causes a link error, you can guard the function call with IS_REACHABLE():

    foo_init()
    {
            if (IS_REACHABLE(CONFIG_BAZ))
                    baz_register(&foo);
            ...
    }
    

    Note: If the feature provided by BAZ is highly desirable for FOO, FOO should imply not only BAZ, but also its dependency BAR:

    config FOO
        tristate "foo"
        imply BAR
        imply BAZ
    
  • limiting menu display: "visible if" <expr>(限制選單顯示)

    This attribute is only applicable to menu blocks, if the condition is false, the menu block is not displayed to the user (the symbols contained there can still be selected by other symbols, though). It is similar to a conditional 「prompt」 attribute for individual menu entries. Default value of 「visible」 is true.(這個屬性僅作用於選單塊,如果條件為false,選單塊對使用者不顯示,類似於選單項的prompt屬性,預設為true)

  • numerical ranges: "range" <symbol> <symbol> ["if" <expr>](數值範圍)

    This allows to limit the range of possible input values for int and hex symbols. The user can only input a value which is larger than or equal to the first symbol and smaller than or equal to the second symbol.(對應int和hex型別,可以限制輸入值的範圍,使用者只能輸入範圍內的值)

  • help text: "help"(幫助資訊)

    This defines a help text. The end of the help text is determined by the indentation level, this means it ends at the first line which has a smaller indentation than the first line of the help text.(定義幫助資訊,幫助資訊由縮排表示一行的結束)

  • module attribute: "modules"(模組屬性)

    This declares the symbol to be used as the MODULES symbol, which enables the third modular state for all config symbols. At most one symbol may have the 「modules」 option set.

3.4 Menu dependencies

Dependencies define the visibility of a menu entry and can also reduce the input range of tristate symbols. The tristate logic used in the expressions uses one more state than normal boolean logic to express the module state. Dependency expressions have the following syntax:(依賴項定義了選單項的可見性,也可以減少三態的輸入範圍。三態的邏輯表示式比布林表示式多了一種模組狀態,依賴的表示式語法如下)

<expr> ::= <symbol>                           (1)
         <symbol> '=' <symbol>                (2)
         <symbol> '!=' <symbol>               (3)
         <symbol1> '<' <symbol2>              (4)
         <symbol1> '>' <symbol2>              (4)
         <symbol1> '<=' <symbol2>             (4)
         <symbol1> '>=' <symbol2>             (4)
         '(' <expr> ')'                       (5)
         '!' <expr>                           (6)
         <expr> '&&' <expr>                   (7)
         <expr> '||' <expr>                   (8)

Expressions are listed in decreasing order of precedence.

  1. Convert the symbol into an expression. Boolean and tristate symbols are simply converted into the respective expression values. All other symbol types result in 'n'.(將符號轉換為表示式。布林值和三態轉換為對應的表示式,其他型別符號轉換為'n')
  2. If the values of both symbols are equal, it returns ‘y’, otherwise ‘n’.(如果兩個符號相等,返回'y',否則為'n')
  3. If the values of both symbols are equal, it returns ‘n’, otherwise ‘y’.(如果兩個符號不相等,返回'y',否則為'n')
  4. If value of <symbol1> is respectively lower, greater, lower-or-equal, or greater-or-equal than value of , it returns ‘y’, otherwise ‘n’.(如果符號<symbol1>小於等於<symbol2>,返回'y',否則為'n')
  5. Returns the value of the expression. Used to override precedence.
  6. Returns the result of (2-/expr/).(返回2-表示式的值)
  7. Returns the result of min(/expr/, /expr/).(返回最小值)
  8. Returns the result of max(/expr/, /expr/).(返回最大值)

An expression can have a value of ‘n’, ‘m’ or ‘y’ (or 0, 1, 2 respectively for calculations). A menu entry becomes visible when its expression evaluates to ‘m’ or ‘y’.(一個表示式的值可以為'n'/'m'/'y',或者0/1/2用於計算,當表示式的結果為'm'/'y',選單項才可見)

There are two types of symbols: constant and non-constant symbols. Non-constant symbols are the most common ones and are defined with the ‘config’ statement. Non-constant symbols consist entirely of alphanumeric characters or underscores. Constant symbols are only part of expressions. Constant symbols are always surrounded by single or double quotes. Within the quote, any other character is allowed and the quotes can be escaped using ''.(有兩種型別符號:常數和非常數符號,非常數符號比較常見,非常數符號完全由字母和下劃線組成,常數符號只是表示式的一部分,常數符號通常使用雙引號或單引號括起來。)

3.5 Menu structure

menu條目用於生成選單。

The position of a menu entry in the tree is determined in two ways. First it can be specified explicitly:(選單項的位置有兩種方式,第一種可以顯示的指定。)

menu "Network device support"
      depends on NET

config NETDEVICES
      ...

endmenu

All entries within the 「menu」 … 「endmenu」 block become a submenu of 「Network device support」. All subentries inherit the dependencies from the menu entry, e.g. this means the dependency 「NET」 is added to the dependency list of the config option NETDEVICES.(所有在"menu" … "endmenu"結構中的選單項,都成為"Network device support"的一個子選單,所有的子選單都繼承自選單項,比如"NET"也是子選單項"NETDEVICES"的依賴項)

The other way to generate the menu structure is done by analyzing the dependencies. If a menu entry somehow depends on the previous entry, it can be made a submenu of it. First, the previous (parent) symbol must be part of the dependency list and then one of these two conditions must be true:(生成選單結構的另一種方式是解析依賴,如果一個選單項依賴前一個選單項,那麼它就成為了子選單,之前的選單(父選單)必須成為依賴的一部分)

  • the child entry must become invisible, if the parent is set to 'n'(如果父選單項設定為'n',子選單就不可見)

  • the child entry must only be visible, if the parent is visible:(如果父選單可見,則子選單必須可見)

    config MODULES
        bool "Enable loadable module support"
    
    config MODVERSIONS
        bool "Set version information on all module symbols"
        depends on MODULES
    
    comment "module support disabled"
        depends on !MODULES
    

MODVERSIONS directly depends on MODULES, this means it’s only visible if MODULES is different from 'n'. The comment on the other hand is only visible when MODULES is set to 'n'.()

3.6 Kconfig syntax

The configuration file describes a series of menu entries, where every line starts with a keyword (except help texts). The following keywords end a menu entry:(組態檔描述了一系列設定項,每一個設定項都以一個關鍵字開頭,幫助資訊除外,以關鍵字結束)

  • config
  • menuconfig
  • choice/endchoice
  • comment
  • menu/endmenu
  • if/endif
  • source

The first five also start the definition of a menu entry.(前5條用於開始定義選單項)

  • config:
"config" <symbol>
<config options>

This defines a config symbol <symbol> and accepts any of above attributes as options.(定義一個config符號)

  • menuconfig:
"menuconfig" <symbol>
<config options>

This is similar to the simple config entry above, but it also gives a hint to front ends, that all suboptions should be displayed as a separate list of options. To make sure all the suboptions will really show up under the menuconfig entry and not outside of it, every item from the list must depend on the menuconfig symbol. In practice, this is achieved by using one of the next two constructs:(和上面的config類似,但menuconfig給出了一個提示端,它所有的子選項都顯示為一個單獨的選項顯示在選單設定項下)

(1):
menuconfig M
if M
    config C1
    config C2
endif

(2):
menuconfig M
config C1
    depends on M
config C2
    depends on M

In the following examples (3) and (4), C1 and C2 still have the M dependency, but will not appear under menuconfig M anymore, because of C0, which doesn’t depend on M:(以下範例中,C1和C2依賴於M,但不會出現在選單M下面,因為C0不依賴M)

(3):
menuconfig M
    config C0
if M
    config C1
    config C2
endif

(4):
menuconfig M
config C0
config C1
    depends on M
config C2
    depends on M

  • choices

choice條目將多個類似的設定選項組合在一起,供使用者單選或者多選。

"choice" [symbol]
<choice options>
<choice block>
"endchoice"

This defines a choice group and accepts any of the above attributes as options. A choice can only be of type bool or tristate. If no type is specified for a choice, its type will be determined by the type of the first choice element in the group or remain unknown if none of the choice elements have a type specified, as well.(定義一個選項組,使用上述的任何屬性作為輸入。一個選項只能是布林型或三態型,如果沒有定義型別,它的型別由組內第一個元素指定)

While a boolean choice only allows a single config entry to be selected, a tristate choice also allows any number of config entries to be set to 'm'. This can be used if multiple drivers for a single hardware exists and only a single driver can be compiled/loaded into the kernel, but all drivers can be compiled as modules.(一個布林選項僅允許一個設定項選擇,一個三態選項可以允許選擇任意多個設定項設定為'm',適用於一個硬體有多個驅動程式的情況並且僅一個驅動可以被編譯進核心,但是所有的驅動可以被編譯為模組)

A choice accepts another option "optional", which allows to set the choice to 'n' and no entry needs to be selected. If no [symbol] is associated with a choice, then you can not have multiple definitions of that choice. If a [symbol] is associated to the choice, then you may define the same choice (i.e. with the same entries) in another place.(一個選擇項接受另一個可選項"optional",這種情況允許設定為'n'並且沒有設定項需要被選擇,如果沒有[symbol]與另一個選擇項關聯,則不能有對這個選擇項有多種定義。如果一個[symbol]關聯一個選擇項,那你可以在另一個地方定義相同的選擇項。)

  • comment:

comment條目定義了一些幫助資訊,它在設定過程中出現在介面的第一行,並且這些幫助資訊會出現在組態檔中。

"comment" <prompt>
<comment options>

This defines a comment which is displayed to the user during the configuration process and is also echoed to the output files. The only possible options are dependencies.(定義了一個註釋項,它在設定過程中顯示給使用者,同時也顯示在輸出檔案中,唯一的可選項是依賴)

  • menu:
"menu" <prompt>
<menu options>
<menu block>
"endmenu"

This defines a menu block, see 「Menu structure」 above for more information. The only possible options are dependencies and 「visible」 attributes.(定義一個選單塊,可以參考「Menu structure」,可選擇項可能是依賴或者visible屬性)

  • if:
"if" <expr>
<if block>
"endif"

This defines an if block. The dependency expression <expr> is appended to all enclosed menu entries.(定義一個if塊,依賴表示式<expr>附加到所有附帶選單項)

  • source:
"source" <prompt>

This reads the specified configuration file. This file is always parsed.(讀取指定的組態檔,讀取的檔案也會被解析)

  • mainmenu:
"mainmenu" <prompt>

This sets the config program's title bar if the config program chooses to use it. It should be placed at the top of the configuration, before any other statement.(設定設定選單的標籤欄,這個應該放在組態檔的開頭)

  • '#' Kconfig source file comment:

An unquoted # character anywhere in a source file line indicates the beginning of a source file comment. The remainder of that line is a comment.(在原始檔開頭,不帶引號的'#'表示註釋)

3.7 Kconfig hints

This is a collection of Kconfig tips, most of which aren't obvious at first glance and most of which have become idioms in several Kconfig files.(Kconfig提示,大部分提示已經在kconfig檔案中)

  • Adding common features and make the usage configurable(新增常用特性並讓用法可設定)

It is a common idiom to implement a feature/functionality that are relevant for some architectures but not all. The recommended way to do so is to use a config variable named HAVE_* that is defined in a common Kconfig file and selected by the relevant architectures. An example is the generic IOMAP functionality.(實現一個跟某架構不緊密關聯的特定/功能,推薦的方式是使用以HAVE_*開頭的設定變數,並在kconfig檔案中來選擇架構,以IOMAP為例說明)

We would in lib/Kconfig see:

# Generic IOMAP is used to ...
config HAVE_GENERIC_IOMAP

config GENERIC_IOMAP
      depends on HAVE_GENERIC_IOMAP && FOO

And in lib/Makefile we would see:

obj-$(CONFIG_GENERIC_IOMAP) += iomap.o

For each architecture using the generic IOMAP functionality we would see:

config X86
      select ...
      select HAVE_GENERIC_IOMAP
      select ...

Note: we use the existing config option and avoid creating a new config variable to select HAVE_GENERIC_IOMAP.

Note: the use of the internal config variable HAVE_GENERIC_IOMAP, it is introduced to overcome the limitation of select which will force a config option to 'y' no matter the dependencies. The dependencies are moved to the symbol GENERIC_IOMAP and we avoid the situation where select forces a symbol equals to 'y'.

  • Adding features that need compiler support(新增需要編譯器支援的特性)

There are several features that need compiler support. The recommended way to describe the dependency on the compiler feature is to use "depends on" followed by a test macro:(有幾個特性需要編譯器支援,推薦在對編譯器的依賴時使用"depends on"+測試宏的方式)

config STACKPROTECTOR
      bool "Stack Protector buffer overflow detection"
      depends on $(cc-option,-fstack-protector)
      ...

If you need to expose a compiler capability to makefiles and/or C source files, CC_HAS_ is the recommended prefix for the config option:(如果需要將編譯器相關功能提供給Makefile/C檔案使用,建議使用CC_HAS_字首)

config CC_HAS_FOO
      def_bool $(success,$(srctree)/scripts/cc-check-foo.sh $(CC))
  • Build as module only(作為模組編譯)

To restrict a component build to module-only, qualify its config symbol with "depends on m". E.g.:(將元件限制為僅編譯為模組,可以使用設定符號"depends on m")

config FOO
      depends on BAR && m

limits FOO to module (=m) or disabled (=n).(將FOO限制為模組(=m),或者不使用(=n))

4 編碼測試

4.1 環境資訊

Linux下測試,版本:Centos7(如果是在Windows下測試,除了安裝kconfiglib外,還需要安裝windows_curses庫。)

使用的Python版本:3.8 https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tgz

使用的Kconfiglib庫版本:14.1.0

4.1 檔案組織

需要用到以下檔案:

  • config.in:Kconfig組態檔
  • Makefile:Makefile檔案
  • menu_main.py:呼叫Kconfiglib庫的指令碼

輸出檔案:

  • .config:輸出的.config設定,一般在Makefile中使用
  • autoconfig.h:輸出的C標頭檔案

config.in:Kconfig組態檔在後續測試過程中會一直更改,這裡就不進行說明。

Makefile檔案中的內容(根據不同的設定項執行指令碼輸入不同的引數):

.PHONY: menuconfig savemenuconfig defconfig allyesconfig allnoconfig

# 進入設定選單
menuconfig:
	python menu_main.py

# 儲存設定選單,如果之前通過設定選單更改了設定值,將儲存修改後的值
savemenuconfig:
	python menu_main.py savemenuconfig

# 根據組態檔中的結構,輸出預設設定,同時會覆蓋menuconfig設定介面中之前的設定資訊
defconfig:
	python menu_main.py defconfig

# 將盡可能多的設定項設定為'y’
allyesconfig:
	python menu_main.py allyesconfig

# 將盡可能多的設定項設定為'n’
allnoconfig:
	python menu_main.py allnoconfig

menu_main.py檔案中的內容,

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os, sys
from kconfiglib import Kconfig
from menuconfig import menuconfig

# 設定Kconfig環境變數
def mconf_set_env():
    os.environ["MENUCONFIG_STYLE"]      = "default selection=fg:white,bg:red" # 設定menuconfig的顏色主題
    os.environ["KCONFIG_CONFIG"]        = os.path.join(".config")                # 輸出的組態檔名
    os.environ["KCONFIG_CONFIG_HEADER"] = "# Generated by Kconfig Tool\n"        # 設定生成的組態檔開頭的字串,會在生成的組態檔開頭的第一行進行顯示。
    os.environ["KCONFIG_AUTOHEADER"]    = os.path.join("autoconfig.h")           # 指定輸出符號到C標頭檔案的檔名
    # os.environ["CONFIG_"]               = "MYTEST"

def mconfig(argv):
    mconf_set_env()
    kconfig = os.path.join("config.in") # menuconfig組態檔
    kconf = Kconfig(filename=kconfig)

    if len(argv) == 2 and argv[1] == 'savemenuconfig':
        kconf.load_config()         # 載入設定
        print(kconf.write_config()) # 儲存設定到組態檔
    elif len(argv) == 2 and argv[1] == 'defconfig':
        kconf.load_allconfig("alldef.config") # 載入預設設定
        print(kconf.write_config())
    elif len(argv) == 2 and argv[1] == 'allyesconfig':
        kconf.warn = False
        for sym in kconf.unique_defined_syms:
            sym.set_value(1 if sym.choice else 2)
        for choice in kconf.unique_choices:
            choice.set_value(2)
        kconf.warn = True
        kconf.load_allconfig("allyes.config") # 儘可能設定多的設定為'y'
        print(kconf.write_config())
    elif len(argv) == 2 and argv[1] == 'allnoconfig':
        kconf.warn = False
        for sym in kconf.unique_defined_syms:
            sym.set_value(2 if sym.is_allnoconfig_y else 0)
        kconf.warn = True
        kconf.load_allconfig("allno.config") # 儘可能設定多的設定為'n'
        print(kconf.write_config())
    else:
        print("python menuconfig ... \n")
        menuconfig(kconf)

    # 儲存autoconfig.h
    kconf.write_autoconf()


if __name__ == "__main__":
    print("start ... \n")
    mconfig(sys.argv)

4.2 部分函數說明

  • Kconfig類

參考:https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py

功能:建立一個Kconfig設定系統,預設的組態檔名為kconfig,使用者可以通過filename更改組態檔名。

class Kconfig(object):
    def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True, encoding="utf-8", suppress_traceback=False):

引數filename:載入的Kconfig檔名。

引數warn:為True(預設)表示解析組態檔過程中產生可能的警告。可以參考 Kconfig.warn_*變數,用於在使能警告時啟用或禁止某些警告。所有生成的警告都會新增到Kconfig.warnings列表中。

引數warn_to_stderr:解析組態檔過程中,產生的警告是否列印到標準輸出stderr(預設為True)。

  • load_config函數

功能:從.config格式檔案中載入符號值。等同於呼叫Symbol.set_value()函數設定每個值。在.config檔案中 "# CONFIG_FOO is not set"將設定符號'FOO'的值為'n'。呼叫這個函數同時會更新Kconfig.missing_syms屬性,其中包括組態檔中未定義符號的所有賦值。如果replace為真,Kconfig.missing_syms被清除,否則被追加。請參考Kconfig.missing_syms設定檔案。

def load_config(self, filename=None, replace=True, verbose=None):

引數filename:指定載入組態檔名。如果filename為空(預設),組態檔將自動載入,載入方式如下:

  1. 如果KCONFIG_CONFIG環境變數設定了,它指定了載入組態檔的路徑。否則,.config被當作預設檔名。
  2. 如果第1.中指定的檔案不存在,將載入kconf.defconfig_filename指定的檔案,這是由'option defconfig_list'符號派生的。
  3. 如果1.和2.都沒有發現組態檔,那麼將不會載入組態檔,並且返回一個錯誤值。
  • write_config函數

功能:向.config格式的組態檔中輸出符號值。符號生成順序和kconfig檔案中出現一樣。對於在多個地方定義的符號,將在符號第一個地方定義的地方輸出符號。

def write_config(self, filename=None, header=None, save_old=True, verbose=None):

引數filename:指定輸出組態檔名。如果為空(預設),檔名將由環境變數KCONFIG_CONFIG指定,否則預設為.config

引數header:在組態檔中的開頭插入的字串,應該使用"#"開頭的註釋,並以換行符結束。如果為空(預設),可通過環境變數KCONFIG_CONFIG_HEADER指定,否則為空。

引數save_old:如果當前指定的組態檔名已經存在,在寫入新的組態檔前,是否在當前目錄重新拷貝一份並命名為<filename>.old。預設為"TRUE"。如果<filename>.old不能寫,將返回錯誤。

返回值:返回一個字串,說明檔案已經儲存或者檔案沒有改變。可以直接使用print(kconf.write_config()).方式呼叫。

  • load_allconfig函數

功能:針對所有all*config,載入(合併)由KCONFIG_ALLCONFIG指定的組態檔,可參考Linux核心Documentation/kbuild/kconfig.txt

def load_allconfig(self, filename):

引數filename:特定的組態檔名,比如:"allyes.config"、"allno.config"

(1)設定設定項的值為預設值

kconf.load_allconfig("alldef.config")

(2)將盡可能多的設定項值設為'y'

Kconfiglib/allyesconfig.py at master · ulfalizer/Kconfiglib · GitHub中的範例:

def main():
    kconf = kconfiglib.standard_kconfig(__doc__)

    # Avoid warnings that would otherwise get printed by Kconfiglib for the
    # following: (避免Kconfiglib列印以下警告)
    #
    # 1. Assigning a value to a symbol without a prompt, which never has any
    #    effect (在沒有提示符的情況下對符號賦值,該符號從沒有提示符)
    #
    # 2. Assigning values invalid for the type (only bool/tristate symbols
    #    accept 0/1/2, for n/m/y). The assignments will be ignored for other
    #    symbol types, which is what we want. (對某型別賦無效值,只有布林和三態型別可以賦值為0/1/2,表示n/m/y。對於其它型別符號,賦的值會被忽略。)
    kconf.warn = False

    # Try to set all symbols to 'y'. Dependencies might truncate the value down
    # later, but this will at least give the highest possible value.(試著對所有符號賦值為'y'。依賴關係可能在後面會被截斷,但這至少會給出最多的值。)
    #
    # Assigning 0/1/2 to non-bool/tristate symbols has no effect (int/hex
    # symbols still take a string, because they preserve formatting).(對於非布林/三態型別的符號賦值為0/1/2沒有作用,因為它們保留了格式)
    for sym in kconf.unique_defined_syms:
        # Set choice symbols to 'm'. This value will be ignored for choices in
        # 'y' mode (the "normal" mode), which will instead just get their
        # default selection, but will set all symbols in m-mode choices to 'm',
        # which is as high as they can go.(設定choice符號依賴為'm'。對於'y'模式(正常模式)下的choices,這個值會被忽略,
        # 它只會得到它們預設的選擇,但會將'm'模式中的所有符號設定為'm',這是它們可以設定的最大值。)
        # Here's a convoluted example of how you might get an m-mode choice
        # even during allyesconfig:(下面是一個範例,說明設定為allyesconfig,如何獲得'm'模式的choice)
        #
        #   choice OPT_BOOL_CHOICE
        #   	tristate "weird choice"
        #   	depends on m
        #   
        #   config OPT_BOOL_CHOICE_SYM_1
        #   	tristate "Optional bool choice sym 1"
        #   
        #   config OPT_BOOL_CHOICE_SYM_2
        #   	tristate "Optional bool choice sym 2"
        #   
        #   endchoice
        #   
        #   輸出為:
        #        OPT_BOOL_CHOICE_SYM_1=m
        #        OPT_BOOL_CHOICE_SYM_2=m
        sym.set_value(1 if sym.choice else 2)

    # Set all choices to the highest possible mode(設定所有選項值為最高模式,也就是最大值'y')
    for choice in kconf.unique_choices:
        choice.set_value(2)

    kconf.warn = True

    kconf.load_allconfig("allyes.config")

    print(kconf.write_config())

(3)設定儘可能多的設定項值設為'n':

Kconfiglib/allnoconfig.py at master · ulfalizer/Kconfiglib · GitHub的範例:

def main():
    kconf = kconfiglib.standard_kconfig(__doc__)

    # Avoid warnings that would otherwise get printed by Kconfiglib for the
    # following: (避免Kconfiglib列印以下警告)
    #
    # 1. Assigning a value to a symbol without a prompt, which never has any
    #    effect (在沒有提示符的情況下對符號賦值,該符號從沒有提示符)
    #
    # 2. Assigning values invalid for the type (only bool/tristate symbols
    #    accept 0/1/2, for n/m/y). The assignments will be ignored for other
    #    symbol types, which is what we want. (對某型別賦無效值,只有布林和三態型別可以賦值為0/1/2,表示n/m/y。對於其它型別符號,賦的值會被忽略。)
    kconf.warn = False
    for sym in kconf.unique_defined_syms:
        sym.set_value(2 if sym.is_allnoconfig_y else 0)
    kconf.warn = True

    kconf.load_allconfig("allno.config")

    print(kconf.write_config())
  • menuconfig.py

參考:Kconfiglib/menuconfig.py at master · ulfalizer/Kconfiglib · GitHub

說明:menuconfig.py既可以作為獨立的可執行檔案執行,也可以呼叫menuconfig()函數時傳入Kconfig範例來執行。第二個選項有點不靈活,因為它仍然會載入和儲存.config等。

當以獨立模式執行時,要載入的kconfig組態檔可以通過引數傳遞,如果沒有引數,則預設的"Kconfig"檔案。環境變數KCONFIG_CONFIG指定了載入和儲存的.config檔名,如果沒有設定,預設為.config檔名。當覆蓋一個組態檔時,舊的檔案可以指定<filename>.old儲存檔名。

def menuconfig(kconf):

函數說明:啟動使用者設定介面,使用者退出後返回。

引數kconf:設定的Kconfig類的範例。

設定系統中的使用到的一些按鍵及其作用:

J/K     : Down/Up
L       : Enter menu/Toggle item
H       : Leave menu
Ctrl-D/U: Page Down/Page Up
G/End   : Jump to end of list
g/Home  : Jump to beginning of list
[Space] toggles values if possible, and enters menus otherwise. 
[Enter] works the other way around.
  • write_autoconf函數
def write_autoconf(self, filename=None, header=None):

函數說明:輸出符號值作為C標頭檔案,與核心的include/generated/autoconf.h檔案的格式匹配。#define的順序和write_config()生成的一致。如果檔名'filename'存在,並且它的內容和要寫入的內容一致,則將保持不變。

引數filename:寫入標頭檔案路徑,如果為空(預設),則檔名由環境變數KCONFIG_AUTOHEADER指定,否則為include/generated/autoconf.h

引數header:在檔案的開頭插入的文字,通常是一些格式為/* ... */的註釋,並且以換行符結束。如果為空(預設),它的值可以由環境變數KCONFIG_AUTOHEADER_HEADER指定,否則不新增檔案頭註釋。

返回值:返回一個字串,說明標頭檔案已經儲存或者標頭檔案沒有改變。可以直接使用print(kconf.write_autoconf()).方式呼叫。

4.2 部分環境變數說明

  • MENUCONFIG_STYLE:設定menuconfig的顏色主題,使用方式可以檢視庫原始檔menuconfig.py中的描述。比如:
os.environ["MENUCONFIG_STYLE"] = "default selection=fg:white,bg:blue"

default:表示主題型別,支援三種:

- default       classic Kconfiglib theme with a yellow accent
- monochrome    colorless theme (uses only bold and standout) attributes, this style is used if the terminal doesn't support colors
- aquatic       blue-tinted style loosely resembling the lxdialog theme

selection=fg:white,bg:blue:設定選項的樣式

fg:white表示設定前景色和背景色為白色。

bg:blue表示設定背景色為藍色。

其它使用舉例:

MENUCONFIG_STYLE="aquatic selection=fg:white,bg:red"
MENUCONFIG_STYLE="default selection=fg:white,bg:red"
  • KCONFIG_CONFIG_HEADER:設定生成的組態檔開頭的字串,會在生成的組態檔開頭的第一行進行顯示。
  • KCONFIG_CONFIG:輸出的組態檔名,如果不設定,預設輸出.config
  • KCONFIG_AUTOHEADER:指定輸出符號到C標頭檔案的檔名,否則預設輸出到include/generated/autoconf.h
  • CONFIG_:指定輸出組態檔中字串的字首,比如設定為os.environ["CONFIG_"] = "MYTEST",則輸出字串的格式為MYTEST_XXXX,不設定預設格式為CONFIG_XXXX

4.3 測試

4.1 kmenuconfig

組態檔config.in如下,這裡直接使用的是庫中的範例(Kconfiglib/Kmenuconfig at master · ulfalizer/Kconfiglib · GitHub):

mainmenu "Example Kconfig configuration"

config MODULES
	bool "Enable loadable module support"
	option modules
	default y

menu "Bool and tristate symbols"

config BOOL
	bool "Bool symbol"
	default y

config BOOL_DEP
	bool "Dependent bool symbol"
	depends on BOOL

# Mix it up a bit with an 'if' instead of a 'depends on'
if BOOL

config TRI_DEP
	tristate "Dependent tristate symbol"
	select SELECTED_BY_TRI_DEP
	imply IMPLIED_BY_TRI_DEP

endif

config TWO_MENU_NODES
	bool "First prompt"
	depends on BOOL

config TRI
	tristate "Tristate symbol"

config TWO_MENU_NODES
	bool "Second prompt"

comment "These are selected by TRI_DEP"

config SELECTED_BY_TRI_DEP
	tristate "Tristate selected by TRI_DEP"

config IMPLIED_BY_TRI_DEP
	tristate "Tristate implied by TRI_DEP"

endmenu


menu "String, int, and hex symbols"

config STRING
	string "String symbol"
	default "foo"

config INT
	int "Int symbol"
	default 747

config HEX
	hex "Hex symbol"
	default 0xABC

endmenu


menu "Various choices"

choice BOOL_CHOICE
	bool "Bool choice"

config BOOL_CHOICE_SYM_1
	bool "Bool choice sym 1"

config BOOL_CHOICE_SYM_2
	bool "Bool choice sym 2"

endchoice

choice TRI_CHOICE
	tristate "Tristate choice"

config TRI_CHOICE_SYM_1
	tristate "Tristate choice sym 1"

config TRI_CHOICE_SYM_2
	tristate "Tristate choice sym 2"

endchoice

choice OPT_BOOL_CHOICE
	bool "Optional bool choice"
	optional

config OPT_BOOL_CHOICE_SYM_1
	bool "Optional bool choice sym 1"

config OPT_BOOL_CHOICE_SYM_2
	bool "Optional bool choice sym 2"

endchoice

endmenu

執行命令make defconfig輸出預設設定。

$ more autoconfig.h 
#define CONFIG_MODULES 1
#define CONFIG_BOOL 1
#define CONFIG_STRING "foo"
#define CONFIG_INT 747
#define CONFIG_HEX 0xABC
#define CONFIG_BOOL_CHOICE_SYM_1 1

$ more .config 
# Generated by Kconfig Tool
CONFIG_MODULES=y

#
# Bool and tristate symbols
#
CONFIG_BOOL=y
# CONFIG_BOOL_DEP is not set
# CONFIG_TRI_DEP is not set
# CONFIG_TWO_MENU_NODES is not set
# CONFIG_TRI is not set

#
# These are selected by TRI_DEP
#
# CONFIG_SELECTED_BY_TRI_DEP is not set
# CONFIG_IMPLIED_BY_TRI_DEP is not set
# end of Bool and tristate symbols

#
# String, int, and hex symbols
#
CONFIG_STRING="foo"
CONFIG_INT=747
CONFIG_HEX=0xABC
# end of String, int, and hex symbols

#
# Various choices
#
CONFIG_BOOL_CHOICE_SYM_1=y
# CONFIG_BOOL_CHOICE_SYM_2 is not set
# CONFIG_TRI_CHOICE_SYM_1 is not set
# CONFIG_TRI_CHOICE_SYM_2 is not set
# end of Various choices

下面分開進行學習。

設定項為布林型別,預設為'y'。

mainmenu "Example Kconfig configuration"

config MODULES
	bool "Enable loadable module support" # 布林型別
	option modules # 宣告將符號編譯為MODULES符號
	default y # 預設為'y'

Bool and tristate

輸入的kconfig檔案型別值:

mainmenu "Example Kconfig configuration"

menu "Bool and tristate symbols"

config BOOL
	bool "Bool symbol"
	default y

config BOOL_DEP
	bool "Dependent bool symbol"
	depends on BOOL

# Mix it up a bit with an 'if' instead of a 'depends on'
if BOOL

config TRI_DEP
	tristate "Dependent tristate symbol"
	select SELECTED_BY_TRI_DEP # 反向依賴
	imply IMPLIED_BY_TRI_DEP   # 弱反向依賴

endif

config TWO_MENU_NODES
	bool "First prompt"
	depends on BOOL

config TRI
	tristate "Tristate symbol"

config TWO_MENU_NODES
	bool "Second prompt"

comment "These are selected by TRI_DEP"

config SELECTED_BY_TRI_DEP
	tristate "Tristate selected by TRI_DEP"

config IMPLIED_BY_TRI_DEP
	tristate "Tristate implied by TRI_DEP"

endmenu

  • MODULES為'y'時,BO_1被當作三態型別,可以定義為'm'/'y'/'n';
  • MODULES為'n'時,BO_1被當作布林型別,可以定義為'y'/'n';

int hex and string

輸入的kconfig檔案中的設定項:

mainmenu "Example Kconfig configuration"

menu "String, int, and hex symbols"

config STRING
	string "String symbol"
	default "foo"

config INT
	int "Int symbol"
	default 747

config HEX
	hex "Hex symbol"
	default 0xABC

endmenu

輸出的預設值:

$ make defconfig
python menu_main.py defconfig
start ... 

Configuration saved to '.config'

$ more .config
# Generated by Kconfig Tool

#
# String, int, and hex symbols
#
CONFIG_STRING="foo"
CONFIG_INT=747
CONFIG_HEX=0xABC
# end of String, int, and hex symbols

$ more autoconfig.h 
#define CONFIG_STRING "foo"
#define CONFIG_INT 747
#define CONFIG_HEX 0xABC

更改設定值,更改字串為"test",int型別為1000,hex型別為0x789:

$ more .config
# Generated by Huawei LiteOS Kconfig Tool
#
# String, int, and hex symbols
#
STRING="test"
INT=1000
HEX=0x789
# end of String, int, and hex symbols

$ more autoconfig.h
/*
 Generated by Huawei LiteOS Kconfig Tool
*/
#define STRING "test"
#define INT 1000
#define HEX 0x789

choice

輸入的kconfig組態檔:

mainmenu "Example Kconfig configuration"

menu "Various choices"

config MODULES
	bool "Enable loadable module support"
	option modules
	default y

choice BOOL_CHOICE
	bool "Bool choice"

config BOOL_CHOICE_SYM_1
	bool "Bool choice sym 1"

config BOOL_CHOICE_SYM_2
	bool "Bool choice sym 2"

endchoice

choice TRI_CHOICE
	tristate "Tristate choice"

config TRI_CHOICE_SYM_1
	tristate "Tristate choice sym 1"

config TRI_CHOICE_SYM_2
	tristate "Tristate choice sym 2"

endchoice

choice OPT_BOOL_CHOICE
	bool "Optional bool choice"
	optional

config OPT_BOOL_CHOICE_SYM_1
	bool "Optional bool choice sym 1"

config OPT_BOOL_CHOICE_SYM_2
	bool "Optional bool choice sym 2"

endchoice

endmenu

預設的設定項的值:

$ make defconfig
python usr_config.py defconfig
Configuration saved to '.config'
Kconfig header saved to 'autoconfig.h'

$ more .config
# Generated by Huawei LiteOS Kconfig Tool
#
# Various choices
#
BOOL_CHOICE_SYM_1=y
# BOOL_CHOICE_SYM_2 is not set
TRI_CHOICE_SYM_1=y
# TRI_CHOICE_SYM_2 is not set
# end of Various choices

$ more autoconfig.h
/*
 Generated by Huawei LiteOS Kconfig Tool
*/
#define BOOL_CHOICE_SYM_1 1
#define TRI_CHOICE_SYM_1 1

更改設定項的值:

(1)預設'optional'設定項OPT_BOOL_CHOICE不會被選擇,因為optional屬性。

(2)BOOL_CHOICE設定項選擇第二個設定。

(3)(4)當'MODULES'設定項選擇為y,表示可以設定為'm','TRI_CHOICE'設定項這時可以同時設定多個設定項為'm'或者'n'。

(5)當'MODULES'設定項選擇為n,'TRI_CHOICE'被當作bool型別,僅能從多個設定項中選擇一個,預設選擇第一個。

(6)選擇OPT_BOOL_CHOICE設定項,預設會選擇其子項的第一個設定項;

(5)OPT_BOOL_CHOICE設定項選擇第二個設定。

$ more .config
# Generated by Huawei LiteOS Kconfig Tool
#
# Various choices
#
# BOOL_CHOICE_SYM_1 is not set
BOOL_CHOICE_SYM_2=y
# TRI_CHOICE_SYM_1 is not set
TRI_CHOICE_SYM_2=y
# OPT_BOOL_CHOICE_SYM_1 is not set
OPT_BOOL_CHOICE_SYM_2=y
# end of Various choices

$ more autoconfig.h
/*
 Generated by Huawei LiteOS Kconfig Tool
*/
#define BOOL_CHOICE_SYM_2 1
#define TRI_CHOICE_SYM_2 1
#define OPT_BOOL_CHOICE_SYM_2 1

總結:

  • choice 開始,endchoice 結束。
  • choice 中間可以加入其他設定,以及 choice 巢狀
  • choice設定之間只能有一個被設定為'y',表示進行選擇。
  • MODULES設定項設定為'y',表示支援設定為'm',這時tristate型別設定項可以同時多個設定為'm'或者'n'。
  • OPT_BOOL_CHOICE設定項預設不會選擇,選擇之後預設會選擇第一個設定項;

4.2 列印kconfig設定樹

Kconfiglib庫中給的範例,用於列印Kconfig檔案的樹形關係:Kconfiglib/print_tree.py at master · ulfalizer/Kconfiglib · GitHub

原始碼實現:

# Prints the menu tree of the configuration. Dependencies between symbols can
# sometimes implicitly alter the menu structure (see kconfig-language.txt), and
# that's implemented too.
#
# Note: See the Kconfig.node_iter() function as well, which provides a simpler
# interface for walking the menu tree.

import sys

from kconfiglib import Kconfig, Symbol, Choice, MENU, COMMENT

def indent_print(s, indent):
    print(indent*" " + s)

def print_items(node, indent):
    while node:
        if isinstance(node.item, Symbol):
            indent_print("config " + node.item.name, indent)

        elif isinstance(node.item, Choice):
            indent_print("choice", indent)

        elif node.item == MENU:
            indent_print('menu "{}"'.format(node.prompt[0]), indent)

        elif node.item == COMMENT:
            indent_print('comment "{}"'.format(node.prompt[0]), indent)


        if node.list:
            print_items(node.list, indent + 2)

        node = node.next

if __name__ == "__main__":
    kconf = Kconfig(sys.argv[1])
    print_items(kconf.top_node, 0)

測試的Kconfig組態檔:

mainmenu "Example Kconfig configuration"

menu "Various choices"

choice BOOL_CHOICE
	bool "Bool choice"

config BOOL_CHOICE_SYM_1
	bool "Bool choice sym 1"

config BOOL_CHOICE_SYM_2
	bool "Bool choice sym 2"

endchoice

choice TRI_CHOICE
	tristate "Tristate choice"

config TRI_CHOICE_SYM_1
	tristate "Tristate choice sym 1"

config TRI_CHOICE_SYM_2
	tristate "Tristate choice sym 2"

endchoice

choice OPT_BOOL_CHOICE
	bool "Optional bool choice"
	optional

config OPT_BOOL_CHOICE_SYM_1
	bool "Optional bool choice sym 1"

config OPT_BOOL_CHOICE_SYM_2
	bool "Optional bool choice sym 2"

endchoice

endmenu

執行,測試:

$ python print_tree.py kconfig
menu "Example Kconfig configuration"
  menu "Various choices"
    choice
      config BOOL_CHOICE_SYM_1
      config BOOL_CHOICE_SYM_2
    choice
      config TRI_CHOICE_SYM_1
      config TRI_CHOICE_SYM_2
    choice
      config OPT_BOOL_CHOICE_SYM_1
      config OPT_BOOL_CHOICE_SYM_2

4.3 choice詳細分析

使用Kconfiglib/Kchoice at master · ulfalizer/Kconfiglib · GitHub中的kconfig檔案來進行測試:

  • bool型別的choice設定,只能二選一,預設選第一個B_1設定項。
choice BOOL
    bool "bool"
config B_1
    tristate "B_1"
config B_2
    tristate "B_2"
endchoice
  • bool型別的choice設定,只能二選一,帶optional屬性,預設一個都不選擇。
choice BOOL_OPT
    bool "bool optional"
    optional
config BO_1
    tristate "BO_1"
config BO_2
    tristate "BO_2"
endchoice
  • tristate型別的choice設定,只能二選一,預設選第一個T_1設定項。
choice TRISTATE
    tristate "tristate"
config T_1
    tristate "T_1"
config T_2
    tristate "T_2"
endchoice
  • tristate型別的choice設定,只能二選一,帶optional屬性,預設一個都不選擇。
choice TRISTATE_OPT
    tristate "tristate optional"
    optional
config TO_1
    tristate "TO_1"
config TO_2
    tristate "TO_2"
endchoice
  • bool型別的choice設定,並且只有在MODULES為'y'的時候才能選擇,預設不能選擇,選擇時只能二選一。
config MODULES
    bool "modules"
	
choice BOOL_M
    bool "bool m" if m
config BM_1
    tristate "BM_1"
config BM_2
    tristate "BM_2"
endchoice

  • tristate型別的choice設定,並且只有在MODULES為'y'的時候才能選擇,預設不能選擇,可以同時設定多個選項為'm'或者'n'。
config MODULES
    bool "modules"
	
choice BOOL_M
    bool "bool m" if m
config BM_1
    tristate "BM_1"
config BM_2
    tristate "BM_2"
endchoice
  • 預設OPT_4設定為'y',其餘都為'n',如果TRISTATE_SYM被設定為'y',則預設為OPT_2
    config TRISTATE_SYM
        tristate "tristate"

    choice DEFAULTS
        bool "defaults"
        default OPT_1 if n
        default OPT_2 if TRISTATE_SYM
        default OPT_4
    config OPT_1
        tristate "OPT_1"
    config OPT_2
        tristate "OPT_2"
    config OPT_3
        tristate "OPT_3"
    config OPT_4
        tristate "OPT_4"
    endchoice

  • 預設OPT_8設定為'y',其餘都為'n',OPT_7不可見
choice DEFAULTS_NOT_VISIBLE
    bool "defaults not visible"
    # Skipped due to condition
    default OPT_6 if n
    # Skipped because OPT_7 is not visible
    default OPT_7
    # This one should apply
    default OPT_8
config OPT_5
    tristate "OPT_5"
config OPT_6
    tristate "OPT_6"
config OPT_7
    tristate "OPT_7" if n
config OPT_8
    tristate "OPT_8"
config OPT_9
    tristate "OPT_9"
endchoice
  • 沒有指定型別的選項choice,預設為第一個設定項的型別
# Choices without an explicitly specified type should get the type of the first symbol with a type

choice NO_TYPE_BOOL
    prompt "no type bool"
config NTB_1
    bool "NTB_1"
config NTB_2
    tristate "NTB_2"
endchoice

choice NO_TYPE_TRISTATE
    prompt "no type tristate"
config NTT_1
config NTT_2
    tristate "NTB_2"
config NTT_3
    bool "NTT_3"
endchoice

  • 沒有顯示指定型別的choice選項,應該預設為choice的型別,MISSING_MEMBER_TYPES_2因為沒有指定型別和提示符,不可見
# Choice items without an explicitly specified type should get the type of the choice

choice MISSING_MEMBER_TYPES_1
    bool "missing member types"
config MMT_1
config MMT_2
config MMT_3
    tristate "mmt1/2/3"
endchoice

choice MISSING_MEMBER_TYPES_2
config MMT_4
config MMT_5
    bool "mmt4/5"
endchoice
  • 預設選擇第一個設定項,但由於其依賴於另一個符號DEP,因此選項中第一個符號不可見,預設就會選擇第二個設定項B。
# Choice where the default selection (the first symbol) depends on another symbol.
# If that symbol becomes 'n', the default selection should change to the first visible symbol in the choice.

choice DEFAULT_WITH_DEP
    bool "default with dep"

config A
    bool "A"
    depends on DEP

config B
    bool "B"

endchoice

config DEP
    bool "dep"

  • 由於choice依賴於前面的符號,它不應該被當做choice選項。這可能是一個bug,但有時會用到它。預設選擇WS1。只有WS1被選擇之後,WS2和WS5才能選擇。WS1、WS6、WS9這三個只能選擇一個。WS7因為沒有定義提示符,所以不可見。
# Choice with symbols that shouldn't be considered choice symbols because they depend on the preceding symbol.
# This might be a kconfig bug, but some things use it, so we need to emulate it.

choice WEIRD_SYMS
    bool "weird symbols that aren't considered part of the choice"

# Only WS1 is part of the choice
config WS1
    bool "WS1"

config WS2
    bool "WS2"
    depends on WS1

config WS3
    bool
    depends on WS2

config WS4
    bool
    depends on WS1

config WS5
    bool "WS5" if WS1

# 'if' has the same effect, so only WS6 is part of the choice
config WS6
    bool "WS6"

if WS6

config WS7
    bool

config WS8
    bool "WS8"

endif

# Should also be part of the choice
config WS9
    bool "WS9"

endchoice

4.4 guiconfig

4.1 簡介

參考:Kconfiglib/guiconfig.py at master · ulfalizer/Kconfiglib (github.com)

guiconfig.py介紹(檔案開頭的介紹):一個基於tkinter的選單設定實現,基於樹檢視控制元件和幫助顯示。顯示可以在顯示完整的樹和僅顯示單個選單(如menuconfig.py)之間進行切換。

  • 只有單選單模式才能區分用'config'定義的符號和用'menuconfig'定義的符號。
  • show-all模式下所有符號都可見,不可見的專案使用紅色標記出。
  • 同時支援滑鼠和鍵盤操作,支援的快捷鍵如下:

Ctrl-S : Save configuration

Ctrl-O : Open configuration

Ctrl-A : Toggle show-all mode

Ctrl-N : Toggle show-name mode

Ctrl-M : Toggle single-menu mode

Ctrl-F, /: Open jump-to dialog

ESC : Close

  • guiconfig.py可以作為獨立的檔案執行,也可以通過使用現有的Kconfig範例呼叫menuconfig()函數來執行,第二種方式不是很靈活。
  • 當以獨立模式執行時,要載入的Kconfig檔案可以作為命令列引數傳遞。如果沒有引數,它預設為Kconfig。
  • KCONFIG_CONFIG環境變數可以指定載入和儲存的.config檔名,如果沒有指定,預設為.config。
  • 覆蓋一個組態檔時,舊版的檔案被儲存為<filename>.old。

4.2 範例

以載入庫中預設的Kmenuconfig組態檔為例進行舉例說明:

kconfig組態檔:Kconfiglib/Kmenuconfig at master · ulfalizer/Kconfiglib (github.com)

執行,可以直接使用滑鼠操作,也可以使用鍵盤快捷鍵操作,可以看出在Windows下用這種方式設定還是比較人性話:

python .\guiconfig.py .\examples\Kmenuconfig

使用menuconfig方式載入這個kconfig檔案:

可以看出,使用guiconfig.py的方式設定,樹形結構更加直觀。

4.5 all*config

4.5.1 輸出kconfig預設設定值

官方實現:Kconfiglib/alldefconfig.py at master · ulfalizer/Kconfiglib (github.com)

import kconfiglib

def main():
    kconf = kconfiglib.standard_kconfig(__doc__)
    kconf.load_allconfig("alldef.config")
    print(kconf.write_config())

if __name__ == "__main__":
    main()

使用方式:

python .\alldefconfig.py .\examples\Kmenuconfig

4.5.2 輸出儘可能多的'm'

官方:Kconfiglib/allmodconfig.py at master · ulfalizer/Kconfiglib (github.com)

說明:寫入一個組態檔,將盡可能多的符號被設定為"m"。

import kconfiglib

def main():
    kconf = kconfiglib.standard_kconfig(__doc__)

    # See allnoconfig.py
    kconf.warn = False

    for sym in kconf.unique_defined_syms:
        if sym.orig_type == kconfiglib.BOOL:
            # 'bool' choice symbols get their default value, as determined by
            # e.g. 'default's on the choice
            if not sym.choice:
                # All other bool symbols get set to 'y', like for allyesconfig
                sym.set_value(2)
        elif sym.orig_type == kconfiglib.TRISTATE:
            sym.set_value(1)

    for choice in kconf.unique_choices:
        choice.set_value(2 if choice.orig_type == kconfiglib.BOOL else 1)

    kconf.warn = True

    kconf.load_allconfig("allmod.config")

    print(kconf.write_config())

if __name__ == "__main__":
    main()

使用方式:

python .\alldefconfig.py .\examples\Kmenuconfig

4.5.2 輸出儘可能多的'n'

官方:Kconfiglib/allnoconfig.py at master · ulfalizer/Kconfiglib (github.com)

說明:寫入一個組態檔,將盡可能多的符號被設定為"n"。

import kconfiglib

def main():
    kconf = kconfiglib.standard_kconfig(__doc__)

    # Avoid warnings that would otherwise get printed by Kconfiglib for the
    # following:
    #
    # 1. Assigning a value to a symbol without a prompt, which never has any
    #    effect
    #
    # 2. Assigning values invalid for the type (only bool/tristate symbols
    #    accept 0/1/2, for n/m/y). The assignments will be ignored for other
    #    symbol types, which is what we want.
    kconf.warn = False
    for sym in kconf.unique_defined_syms:
        sym.set_value(2 if sym.is_allnoconfig_y else 0)
    kconf.warn = True

    kconf.load_allconfig("allno.config")

    print(kconf.write_config())

if __name__ == "__main__":
    main()

使用方式:

python .\alldefconfig.py .\examples\Kmenuconfig

4.5.2 輸出儘可能多的'y'

官方:Kconfiglib/allyesconfig.py at master · ulfalizer/Kconfiglib (github.com)

說明:寫入一個組態檔,將盡可能多的符號被設定為"y"。

import kconfiglib

def main():
    kconf = kconfiglib.standard_kconfig(__doc__)

    # See allnoconfig.py
    kconf.warn = False

    # Try to set all symbols to 'y'. Dependencies might truncate the value down
    # later, but this will at least give the highest possible value.
    #
    # Assigning 0/1/2 to non-bool/tristate symbols has no effect (int/hex
    # symbols still take a string, because they preserve formatting).
    for sym in kconf.unique_defined_syms:
        # Set choice symbols to 'm'. This value will be ignored for choices in
        # 'y' mode (the "normal" mode), which will instead just get their
        # default selection, but will set all symbols in m-mode choices to 'm',
        # which is as high as they can go.
        #
        # Here's a convoluted example of how you might get an m-mode choice
        # even during allyesconfig:
        #
        #   choice
        #           tristate "weird choice"
        #           depends on m
        sym.set_value(1 if sym.choice else 2)

    # Set all choices to the highest possible mode
    for choice in kconf.unique_choices:
        choice.set_value(2)

    kconf.warn = True

    kconf.load_allconfig("allyes.config")

    print(kconf.write_config())

if __name__ == "__main__":
    main()

使用方式:

python .\alldefconfig.py .\examples\Kmenuconfig