요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
================
Kconfig Language
================
Introduction
------------
The configuration database is a collection of configuration options
organized in a tree structure::
+- Code maturity level options
| +- Prompt for development and/or incomplete code/drivers
+- General setup
| +- Networking support
| +- System V IPC
| +- BSD Process Accounting
| +- Sysctl support
+- Loadable module support
| +- Enable loadable module support
| +- Set version information on all module symbols
| +- Kernel module loader
+- ...
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.
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.
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::
bool "Networking support"
and::
bool
prompt "Networking support"
- 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 a prompt is not present, the config option is a non-visible
symbol, meaning its value cannot be directly changed by the user (such as
altering the value in ``.config``) and the option will not appear in any
config menus. Its value can only be set via "default" and "select" (see
below).
- 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.
Note:
Things that merit "default y/m" include:
a) A new Kconfig option for something that used to always be built
should be "default y".
b) 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.
c) Sub-driver behavior or similar options for a driver that is
"default n". This allows you to provide sane defaults.
d) 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::
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.
If "select" <symbol> is followed by "if" <expr>, <symbol> will be
selected by the logical AND of the value of the current menu symbol
and <expr>. This means, the lower limit can be downgraded due to the
presence of "if" <expr>. This behavior may seem weird, but we rely on
it. (The future of this behavior is undecided.)
- 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.
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 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
Note: If "imply" <symbol> is followed by "if" <expr>, the default of <symbol>
will be the logical AND of the value of the current menu symbol and <expr>.
(The future of this behavior is undecided.)
- 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.
- 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.
- 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.
- transitional attribute: "transitional"
This declares the symbol as transitional, meaning it should be processed
during configuration but omitted from newly written .config files.
Transitional symbols are useful for backward compatibility during config
option migrations - they allow olddefconfig to process existing .config
files while ensuring the old option doesn't appear in new configurations.
A transitional symbol:
- Has no prompt (is not visible to users in menus)
- Is processed normally during configuration (values are read and used)
- Can be referenced in default expressions of other symbols
- Is not written to new .config files
- Cannot have any other properties (it is a pass-through option)
Example migration from OLD_NAME to NEW_NAME::
config NEW_NAME
bool "New option name"
default OLD_NAME
help
This replaces the old CONFIG_OLD_NAME option.
config OLD_NAME
bool
transitional
help
Transitional config for OLD_NAME to NEW_NAME migration.
With this setup, existing .config files with "CONFIG_OLD_NAME=y" will
result in "CONFIG_NEW_NAME=y" being set, while CONFIG_OLD_NAME will be
omitted from newly written .config files.
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'.
(2) If the values of both symbols are equal, it returns 'y',
otherwise 'n'.
(3) If the values of both symbols are equal, it returns 'n',
otherwise 'y'.
(4) If value of <symbol1> is respectively lower, greater, lower-or-equal,
or greater-or-equal than value of <symbol2>, it returns 'y',
otherwise 'n'.
(5) Returns the value of the expression. Used to override precedence.
(6) Returns the result of (2-/expr/).
(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'.
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 '\'.
Menu structure
--------------
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.
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'
- 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'.
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.
config::
"config" <symbol>
<config options>
This defines a config symbol <symbol> and accepts any of above
attributes as options.
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 <config options> list must depend on the menuconfig symbol.
In practice, this is achieved by using one of the next two constructs::
(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::
(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 options>
<choice block>
"endchoice"
This defines a choice group and accepts "prompt", "default", "depends on", and
"help" attributes as options.
A choice only allows a single config entry to be selected.
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.
if::
"if" <expr>
<if block>
"endif"
This defines an if block. The dependency expression <expr> is appended
to all enclosed menu entries.
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.
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.
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.
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::
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::
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.::
config FOO
depends on BAR && m
limits FOO to module (=m) or disabled (=n).
Compile-testing
~~~~~~~~~~~~~~~
If a config symbol has a dependency, but the code controlled by the config
symbol can still be compiled if the dependency is not met, it is encouraged to
increase build coverage by adding an "|| COMPILE_TEST" clause to the
dependency. This is especially useful for drivers for more exotic hardware, as
it allows continuous-integration systems to compile-test the code on a more
common system, and detect bugs that way.
Note that compile-tested code should avoid crashing when run on a system where
the dependency is not met.
Architecture and platform dependencies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Due to the presence of stubs, most drivers can now be compiled on most
architectures. However, this does not mean it makes sense to have all drivers
available everywhere, as the actual hardware may only exist on specific
architectures and platforms. This is especially true for on-SoC IP cores,
which may be limited to a specific vendor or SoC family.
To prevent asking the user about drivers that cannot be used on the system(s)
the user is compiling a kernel for, and if it makes sense, config symbols
controlling the compilation of a driver should contain proper dependencies,
limiting the visibility of the symbol to (a superset of) the platform(s) the
driver can be used on. The dependency can be an architecture (e.g. ARM) or
platform (e.g. ARCH_OMAP4) dependency. This makes life simpler not only for
distro config owners, but also for every single developer or user who
configures a kernel.
Such a dependency can be relaxed by combining it with the compile-testing rule
above, leading to:
config FOO
bool "Support for foo hardware"
depends on ARCH_FOO_VENDOR || COMPILE_TEST
Optional dependencies
~~~~~~~~~~~~~~~~~~~~~
Some drivers are able to optionally use a feature from another module
or build cleanly with that module disabled, but cause a link failure
when trying to use that loadable module from a built-in driver.
The most common way to express this optional dependency in Kconfig logic
uses the slightly counterintuitive::
config FOO
tristate "Support for foo hardware"
depends on BAR || !BAR
This means that there is either a dependency on BAR that disallows
the combination of FOO=y with BAR=m, or BAR is completely disabled. The BAR
module must provide all the stubs for !BAR case.
For a more formalized approach if there are multiple drivers that have
the same dependency, a helper symbol can be used, like::
config FOO
tristate "Support for foo hardware"
depends on BAR_OPTIONAL
config BAR_OPTIONAL
def_tristate BAR || !BAR
Much less favorable way to express optional dependency is IS_REACHABLE() within
the module code, useful for example when the module BAR does not provide
!BAR stubs::
foo_init()
{
if (IS_REACHABLE(CONFIG_BAR))
bar_register(&foo);
...
}
IS_REACHABLE() is generally discouraged, because the code will be silently
discarded, when CONFIG_BAR=m and this code is built-in. This is not what users
usually expect when enabling BAR as module.
Kconfig recursive dependency limitations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you've hit the Kconfig error: "recursive dependency detected" you've run
into a recursive dependency issue with Kconfig, a recursive dependency can be
summarized as a circular dependency. The kconfig tools need to ensure that
Kconfig files comply with specified configuration requirements. In order to do
that kconfig must determine the values that are possible for all Kconfig
symbols, this is currently not possible if there is a circular relation
between two or more Kconfig symbols. For more details refer to the "Simple
Kconfig recursive issue" subsection below. Kconfig does not do recursive
dependency resolution; this has a few implications for Kconfig file writers.
We'll first explain why this issues exists and then provide an example
technical limitation which this brings upon Kconfig developers. Eager
developers wishing to try to address this limitation should read the next
subsections.
Simple Kconfig recursive issue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Read: Documentation/kbuild/Kconfig.recursion-issue-01
Test with::
make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-01 allnoconfig
Cumulative Kconfig recursive issue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Read: Documentation/kbuild/Kconfig.recursion-issue-02
Test with::
make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-02 allnoconfig
Practical solutions to kconfig recursive issue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Developers who run into the recursive Kconfig issue have two options
at their disposal. We document them below and also provide a list of
historical issues resolved through these different solutions.
a) Remove any superfluous "select FOO" or "depends on FOO"
b) Match dependency semantics:
b1) Swap all "select FOO" to "depends on FOO" or,
b2) Swap all "depends on FOO" to "select FOO"
The resolution to a) can be tested with the sample Kconfig file
Documentation/kbuild/Kconfig.recursion-issue-01 through the removal
of the "select CORE" from CORE_BELL_A_ADVANCED as that is implicit already
since CORE_BELL_A depends on CORE. At times it may not be possible to remove
some dependency criteria, for such cases you can work with solution b).
The two different resolutions for b) can be tested in the sample Kconfig file
Documentation/kbuild/Kconfig.recursion-issue-02.
Below is a list of examples of prior fixes for these types of recursive issues;
all errors appear to involve one or more "select" statements and one or more
"depends on".
============ ===================================
commit fix
============ ===================================
06b718c01208 select A -> depends on A
c22eacfe82f9 depends on A -> depends on B
6a91e854442c select A -> depends on A
118c565a8f2e select A -> select B
f004e5594705 select A -> depends on A
c7861f37b4c6 depends on A -> (null)
80c69915e5fb select A -> (null) (1)
c2218e26c0d0 select A -> depends on A (1)
d6ae99d04e1c select A -> depends on A
95ca19cf8cbf select A -> depends on A
8f057d7bca54 depends on A -> (null)
8f057d7bca54 depends on A -> select A
a0701f04846e select A -> depends on A
0c8b92f7f259 depends on A -> (null)
e4e9e0540928 select A -> depends on A (2)
7453ea886e87 depends on A > (null) (1)
7b1fff7e4fdf select A -> depends on A
86c747d2a4f0 select A -> depends on A
d9f9ab51e55e select A -> depends on A
0c51a4d8abd6 depends on A -> select A (3)
e98062ed6dc4 select A -> depends on A (3)
91e5d284a7f1 select A -> (null)
============ ===================================
(1) Partial (or no) quote of error.
(2) That seems to be the gist of that fix.
(3) Same error.
Future kconfig work
~~~~~~~~~~~~~~~~~~~
Work on kconfig is welcomed on both areas of clarifying semantics and on
evaluating the use of a full SAT solver for it. A full SAT solver can be
desirable to enable more complex dependency mappings and / or queries,
for instance one possible use case for a SAT solver could be that of handling
the current known recursive dependency issues. It is not known if this would
address such issues but such evaluation is desirable. If support for a full SAT
solver proves too complex or that it cannot address recursive dependency issues
Kconfig should have at least clear and well defined semantics which also
addresses and documents limitations or requirements such as the ones dealing
with recursive dependencies.
Further work on both of these areas is welcomed on Kconfig. We elaborate
on both of these in the next two subsections.
Semantics of Kconfig
~~~~~~~~~~~~~~~~~~~~
The use of Kconfig is broad, Linux is now only one of Kconfig's users:
one study has completed a broad analysis of Kconfig use in 12 projects [0]_.
Despite its widespread use, and although this document does a reasonable job
in documenting basic Kconfig syntax a more precise definition of Kconfig
semantics is welcomed. One project deduced Kconfig semantics through
the use of the xconfig configurator [1]_. Work should be done to confirm if
the deduced semantics matches our intended Kconfig design goals.
Another project formalized a denotational semantics of a core subset of
the Kconfig language [10]_.
Having well defined semantics can be useful for tools for practical
evaluation of dependencies, for instance one such case was work to
express in boolean abstraction of the inferred semantics of Kconfig to
translate Kconfig logic into boolean formulas and run a SAT solver on this to
find dead code / features (always inactive), 114 dead features were found in
Linux using this methodology [1]_ (Section 8: Threats to validity).
The kismet tool, based on the semantics in [10]_, finds abuses of reverse
dependencies and has led to dozens of committed fixes to Linux Kconfig files [11]_.
Confirming this could prove useful as Kconfig stands as one of the leading
industrial variability modeling languages [1]_ [2]_. Its study would help
evaluate practical uses of such languages, their use was only theoretical
and real world requirements were not well understood. As it stands though
only reverse engineering techniques have been used to deduce semantics from
variability modeling languages such as Kconfig [3]_.
.. [0] https://www.eng.uwaterloo.ca/~shshe/kconfig_semantics.pdf
.. [1] https://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
.. [2] https://gsd.uwaterloo.ca/sites/default/files/ase241-berger_0.pdf
.. [3] https://gsd.uwaterloo.ca/sites/default/files/icse2011.pdf
Full SAT solver for Kconfig
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Although SAT solvers [4]_ haven't yet been used by Kconfig directly, as noted
in the previous subsection, work has been done however to express in boolean
abstraction the inferred semantics of Kconfig to translate Kconfig logic into
boolean formulas and run a SAT solver on it [5]_. Another known related project
is CADOS [6]_ (former VAMOS [7]_) and the tools, mainly undertaker [8]_, which
has been introduced first with [9]_. The basic concept of undertaker is to
extract variability models from Kconfig and put them together with a
propositional formula extracted from CPP #ifdefs and build-rules into a SAT
solver in order to find dead code, dead files, and dead symbols. If using a SAT
solver is desirable on Kconfig one approach would be to evaluate repurposing
such efforts somehow on Kconfig. There is enough interest from mentors of
existing projects to not only help advise how to integrate this work upstream
but also help maintain it long term. Interested developers should visit:
https://kernelnewbies.org/KernelProjects/kconfig-sat
.. [4] https://www.cs.cornell.edu/~sabhar/chapters/SATSolvers-KR-Handbook.pdf
.. [5] https://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
.. [6] https://cados.cs.fau.de
.. [7] https://vamos.cs.fau.de
.. [8] https://undertaker.cs.fau.de
.. [9] https://www4.cs.fau.de/Publications/2011/tartler_11_eurosys.pdf
.. [10] https://paulgazzillo.com/papers/esecfse21.pdf
.. [11] https://github.com/paulgazz/kmax
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Configuration tree와 기본 menu attribute
1-120Configuration database는 option을 tree 구조로 정리한 집합입니다. 예제 tree의 최상위에는 code maturity, general setup, loadable module support가 있고, general setup 아래에는 networking·System V IPC·BSD process accounting·sysctl이, module support 아래에는 symbol version과 module loader가 있습니다.
Child entry는 parent가 visible할 때만 보입니다.
각 entry에는 dependency가 있고 이는 visibility를 결정합니다. Child entry는 parent entry도 visible해야 visible합니다. 대부분 entry는 config option을 정의하고 나머지는 이를 구조화합니다.
`config MODVERSIONS` 예제는 `bool` prompt, `depends on MODULES`, indent된 help를 가집니다. 각 줄은 keyword로 시작하고 여러 argument가 뒤따를 수 있습니다. `config`는 새 entry를 시작하며 뒤의 줄이 type, prompt, dependency, help, default를 정의합니다.
같은 이름의 config option을 여러 번 정의할 수 있지만 각 definition에는 input prompt가 하나만 있을 수 있고 type은 서로 충돌하면 안 됩니다.
한 symbol definition에 붙을 수 있는 기본 속성입니다.
모든 config option에는 type이 필요합니다. 기본 type은 tristate와 string 두 가지이고 나머지는 이를 기반으로 합니다. Type 선언은 prompt를 함께 받을 수 있어 `bool "Networking support"`와 `bool` 뒤 `prompt "Networking support"`는 같습니다.
각 menu entry에는 prompt가 최대 하나 있습니다. `prompt <text> if <expr>`로 그 prompt에만 dependency를 붙일 수 있습니다. Prompt가 없으면 menu에 나타나지 않는 non-visible symbol이며 `.config`를 직접 바꾸는 방식으로도 사용자가 값을 바꿀 수 없습니다. 값은 `default`와 `select`로만 설정됩니다.
`default <expr> if <expr>`는 여러 번 정의할 수 있지만 visible한 default가 여러 개면 먼저 정의된 것만 활성화됩니다. Default는 entry와 다른 곳에서 정의할 수 있고 더 앞선 definition이 override할 수 있습니다. 사용자가 visible prompt에서 값을 정하지 않았을 때만 symbol에 배정되며 prompt가 보이면 사용자가 default를 바꿀 수 있습니다.
기본값은 build 비대화를 막기 위해 의도적으로 `n`입니다. `make oldconfig`가 release 사이 기존 config에 가능한 적게 추가하도록 새 option은 드문 예외를 빼고 이를 바꾸지 않아야 합니다.
새 option이 기존 동작과 발견 가능성을 유지해야 할 때의 예외입니다.
`def_bool`과 `def_tristate`는 type 정의와 default value를 합친 축약형이며 default에만 적용할 `if` dependency를 선택적으로 받을 수 있습니다.
================
Kconfig Language
================
Introduction
------------
The configuration database is a collection of configuration options
organized in a tree structure::
+- Code maturity level options
| +- Prompt for development and/or incomplete code/drivers
+- General setup
| +- Networking support
| +- System V IPC
| +- BSD Process Accounting
| +- Sysctl support
+- Loadable module support
| +- Enable loadable module support
| +- Set version information on all module symbols
| +- Kernel module loader
+- ...
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.
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.
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::
bool "Networking support"
and::
bool
prompt "Networking support"
- 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 a prompt is not present, the config option is a non-visible
symbol, meaning its value cannot be directly changed by the user (such as
altering the value in ``.config``) and the option will not appear in any
config menus. Its value can only be set via "default" and "select" (see
below).
- 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.
Note:
Things that merit "default y/m" include:
a) A new Kconfig option for something that used to always be built
should be "default y".
b) 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.
c) Sub-driver behavior or similar options for a driver that is
"default n". This allows you to provide sane defaults.
d) 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".
`depends on`, `select`, `imply`와 기타 속성
121-266`depends on <expr>`는 menu entry dependency를 정의합니다. 여러 dependency는 `&&`로 연결되고 `if` expression을 받을 수 있는 type·default·prompt 등 entry의 모든 option에 적용됩니다. 따라서 각 attribute에 `if BAR`를 붙이는 것과 entry에 `depends on BAR`를 한 번 쓰는 것은 같습니다.
일반 dependency는 symbol 값의 상한을 낮추지만 reverse dependency인 `select <symbol> if <expr>`는 다른 symbol의 하한을 강제합니다. 현재 menu symbol 값이 대상의 최소값이 되고 여러 곳에서 select하면 가장 큰 값이 하한이 됩니다. Boolean과 tristate에만 사용할 수 있습니다.
`select`는 대상 dependency를 검사하지 않고 값을 강제하므로 주의해야 합니다. BAR가 설정되지 않았는데 `depends on BAR`인 FOO를 select할 수도 있습니다. 일반적으로 prompt가 어디에도 없는 non-visible symbol이며 자체 dependency가 없는 symbol에만 사용해야 illegal configuration을 피할 수 있습니다.
`select` 뒤의 `if`가 있으면 현재 symbol과 expression의 logical AND가 대상 하한입니다. 따라서 조건 때문에 하한이 내려갈 수 있으며 이상해 보이지만 현재 의존하는 동작이고 미래는 결정되지 않았습니다.
Weak reverse dependency인 `imply`도 대상의 하한을 제안하지만 대상 symbol은 direct dependency나 visible prompt를 통해 여전히 `n`으로 설정될 수 있습니다.
FOO가 BAZ를 imply하고 BAZ가 BAR에 depends할 때의 원문 조합입니다.
이는 여러 driver가 secondary subsystem 연동 가능성을 표시하면서도 사용자가 driver를 끄지 않고 subsystem을 제외할 수 있게 할 때 유용합니다. BAZ가 FOO에 매우 중요하면 FOO는 BAZ뿐 아니라 dependency BAR도 imply해야 합니다. `imply <symbol> if <expr>`의 default는 현재 symbol과 expression의 logical AND이며 이 동작의 미래도 결정되지 않았습니다.
상한, 강제 하한, 제안 하한의 차이입니다.
`visible if <expr>`는 menu block에만 적용됩니다. False이면 block을 사용자에게 보이지 않지만 내부 symbol을 다른 symbol이 select할 수는 있습니다. 개별 entry의 conditional prompt와 비슷하며 기본 visible 값은 true입니다.
`range <symbol> <symbol> if <expr>`는 int와 hex 입력값을 첫 symbol 이상, 둘째 symbol 이하로 제한합니다.
`help` text는 첫 help line보다 indentation이 작은 줄에서 끝납니다.
`modules` attribute는 모든 config symbol의 세 번째 modular state를 활성화하는 MODULES symbol을 선언합니다. 이 option을 가진 symbol은 최대 하나입니다.
`transitional`은 configuration 중 읽고 처리하지만 새 `.config`에는 쓰지 않는 migration용 symbol입니다. Prompt가 없고 menu에 보이지 않으며 다른 symbol의 default expression에서 참조할 수 있지만 다른 property를 가질 수 없는 pass-through option입니다.
OLD_NAME에서 NEW_NAME으로 옮기는 예제는 NEW_NAME의 default를 OLD_NAME으로 두고 OLD_NAME을 prompt 없는 bool transitional symbol로 정의합니다. 기존 `CONFIG_OLD_NAME=y`는 `CONFIG_NEW_NAME=y`를 만들지만 새 `.config`에는 OLD_NAME이 기록되지 않습니다.
기존 config 값은 읽되 새 이름만 출력합니다.
- 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::
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.
If "select" <symbol> is followed by "if" <expr>, <symbol> will be
selected by the logical AND of the value of the current menu symbol
and <expr>. This means, the lower limit can be downgraded due to the
presence of "if" <expr>. This behavior may seem weird, but we rely on
it. (The future of this behavior is undecided.)
- 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.
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 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
Note: If "imply" <symbol> is followed by "if" <expr>, the default of <symbol>
will be the logical AND of the value of the current menu symbol and <expr>.
(The future of this behavior is undecided.)
- 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.
- 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.
- 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.
- transitional attribute: "transitional"
This declares the symbol as transitional, meaning it should be processed
during configuration but omitted from newly written .config files.
Transitional symbols are useful for backward compatibility during config
option migrations - they allow olddefconfig to process existing .config
files while ensuring the old option doesn't appear in new configurations.
A transitional symbol:
- Has no prompt (is not visible to users in menus)
- Is processed normally during configuration (values are read and used)
- Can be referenced in default expressions of other symbols
- Is not written to new .config files
- Cannot have any other properties (it is a pass-through option)
Example migration from OLD_NAME to NEW_NAME::
config NEW_NAME
bool "New option name"
default OLD_NAME
help
This replaces the old CONFIG_OLD_NAME option.
config OLD_NAME
bool
transitional
help
Transitional config for OLD_NAME to NEW_NAME migration.
With this setup, existing .config files with "CONFIG_OLD_NAME=y" will
result in "CONFIG_NEW_NAME=y" being set, while CONFIG_OLD_NAME will be
omitted from newly written .config files.
Kconfig statement 문법
359-491Configuration file은 menu entry의 연속이며 help text를 제외한 모든 줄이 keyword로 시작합니다. `config`, `menuconfig`, `choice/endchoice`, `comment`, `menu/endmenu`, `if/endif`, `source`는 이전 entry를 끝냅니다. 앞의 다섯 종류는 새 menu entry도 시작합니다.
각 keyword가 만드는 구조와 허용 option입니다.
`config`는 symbol과 config option을 정의합니다. `menuconfig`도 같지만 front end에 suboption을 별도 목록으로 표시하라는 hint입니다. 하위 option이 실제로 menuconfig 아래 보이려면 모두 menuconfig symbol에 depend해야 합니다.
권장 예제는 `menuconfig M` 뒤 `if M` block 안에 C1·C2를 두거나 C1·C2 각각에 `depends on M`을 둡니다. C0처럼 M에 depend하지 않는 entry가 사이에 오면 C1·C2가 M dependency를 가져도 더는 menuconfig M 아래 나타나지 않습니다.
연속성과 parent dependency를 모두 만족해야 합니다.
`choice ... endchoice`는 config entry 하나만 선택할 수 있는 group입니다. `comment`는 configuration 과정에서 사용자에게 보이고 output file에도 echo됩니다. `menu`는 block을 만들고, `if` expression은 enclosed entry 전체에 dependency로 추가됩니다.
`source`는 지정 configuration file을 읽으며 그 file은 항상 parse됩니다. `mainmenu`는 configurator가 사용한다면 title bar를 설정하고 다른 statement보다 먼저 configuration top에 둬야 합니다.
Source line에서 quote되지 않은 `#` 문자는 어디에 있든 source comment 시작을 뜻하며 그 줄의 나머지는 comment입니다.
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.
config::
"config" <symbol>
<config options>
This defines a config symbol <symbol> and accepts any of above
attributes as options.
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 <config options> list must depend on the menuconfig symbol.
In practice, this is achieved by using one of the next two constructs::
(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::
(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 options>
<choice block>
"endchoice"
This defines a choice group and accepts "prompt", "default", "depends on", and
"help" attributes as options.
A choice only allows a single config entry to be selected.
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.
if::
"if" <expr>
<if block>
"endif"
This defines an if block. The dependency expression <expr> is appended
to all enclosed menu entries.
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.
공통 기능, compiler, module과 optional dependency
492-640일부 architecture에만 관련된 공통 기능은 common Kconfig에 `HAVE_*` variable을 두고 해당 architecture가 select하는 방식이 권장됩니다. Generic IOMAP 예제는 `HAVE_GENERIC_IOMAP`을 내부 capability로 두고 사용자 option `GENERIC_IOMAP`이 `HAVE_GENERIC_IOMAP && FOO`에 depends하며 Makefile이 `CONFIG_GENERIC_IOMAP`으로 `iomap.o`를 build합니다.
Architecture는 기존 X86 option에서 `select HAVE_GENERIC_IOMAP`을 사용하며 HAVE를 select하려고 새 option을 만들지 않습니다. 내부 HAVE symbol은 dependency와 무관하게 `y`를 강제하는 select 한계를 피하기 위한 것으로, 실제 dependency는 사용자 option GENERIC_IOMAP에 둡니다.
Architecture capability 표시와 사용자 기능 dependency를 분리합니다.
Compiler 지원이 필요한 기능은 test macro를 붙인 `depends on`으로 표현합니다. Stack protector 예제는 `depends on $(cc-option,-fstack-protector)`를 사용합니다. Capability를 Makefile이나 C source에도 노출해야 하면 `CC_HAS_` prefix가 권장되며 `CC_HAS_FOO` 예제는 `$(success,...cc-check-foo.sh $(CC))` 결과를 `def_bool`로 사용합니다.
Module로만 build하려면 `depends on m`을 추가합니다. `depends on BAR && m`인 FOO는 `m` 또는 `n`만 가능합니다.
Dependency가 없어도 code 자체는 compile 가능하면 build coverage를 늘리기 위해 `|| COMPILE_TEST`를 권장합니다. 특히 드문 hardware driver를 일반 CI system에서 compile해 bug를 찾는 데 유용하지만 실제 dependency가 없는 system에서 실행해도 crash하지 않아야 합니다.
Stub 덕분에 많은 driver를 여러 architecture에서 compile할 수 있지만 hardware가 특정 architecture·platform에만 있다면 모든 곳에서 option을 보일 필요는 없습니다. Driver symbol은 실제 사용 platform의 superset으로 visibility를 제한하는 `ARM`이나 `ARCH_OMAP4` 같은 dependency를 가져야 distro config maintainer와 사용자에게 불필요한 질문을 줄일 수 있습니다.
Platform 제한은 `depends on ARCH_FOO_VENDOR || COMPILE_TEST`처럼 compile-test rule과 결합해 완화할 수 있습니다.
다른 module의 기능을 선택적으로 사용하며 module이 꺼져도 build되지만 built-in driver가 loadable module을 사용할 때 link 실패하는 경우 `depends on BAR || !BAR`를 씁니다. 이는 FOO=y, BAR=m 조합을 막거나 BAR를 완전히 끄도록 합니다. `!BAR` 경우에는 BAR module이 필요한 stub을 모두 제공해야 합니다.
`BAR || !BAR`는 built-in이 loadable module에 의존하는 조합을 제외합니다.
여러 driver가 같은 optional dependency를 가지면 `BAR_OPTIONAL` helper symbol에 `def_tristate BAR || !BAR`를 두고 각 driver가 depend할 수 있습니다.
BAR가 `!BAR` stub을 제공하지 않을 때 module code 안에서 `IS_REACHABLE(CONFIG_BAR)`를 쓰는 방법은 덜 권장됩니다. CONFIG_BAR=m이고 호출 code가 built-in이면 code가 조용히 버려져 사용자가 BAR를 module로 켰을 때 기대한 동작과 다르기 때문입니다.
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.
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.
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::
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::
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.::
config FOO
depends on BAR && m
limits FOO to module (=m) or disabled (=n).
Compile-testing
~~~~~~~~~~~~~~~
If a config symbol has a dependency, but the code controlled by the config
symbol can still be compiled if the dependency is not met, it is encouraged to
increase build coverage by adding an "|| COMPILE_TEST" clause to the
dependency. This is especially useful for drivers for more exotic hardware, as
it allows continuous-integration systems to compile-test the code on a more
common system, and detect bugs that way.
Note that compile-tested code should avoid crashing when run on a system where
the dependency is not met.
Architecture and platform dependencies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Due to the presence of stubs, most drivers can now be compiled on most
architectures. However, this does not mean it makes sense to have all drivers
available everywhere, as the actual hardware may only exist on specific
architectures and platforms. This is especially true for on-SoC IP cores,
which may be limited to a specific vendor or SoC family.
To prevent asking the user about drivers that cannot be used on the system(s)
the user is compiling a kernel for, and if it makes sense, config symbols
controlling the compilation of a driver should contain proper dependencies,
limiting the visibility of the symbol to (a superset of) the platform(s) the
driver can be used on. The dependency can be an architecture (e.g. ARM) or
platform (e.g. ARCH_OMAP4) dependency. This makes life simpler not only for
distro config owners, but also for every single developer or user who
configures a kernel.
Such a dependency can be relaxed by combining it with the compile-testing rule
above, leading to:
config FOO
bool "Support for foo hardware"
depends on ARCH_FOO_VENDOR || COMPILE_TEST
Optional dependencies
~~~~~~~~~~~~~~~~~~~~~
Some drivers are able to optionally use a feature from another module
or build cleanly with that module disabled, but cause a link failure
when trying to use that loadable module from a built-in driver.
The most common way to express this optional dependency in Kconfig logic
uses the slightly counterintuitive::
config FOO
tristate "Support for foo hardware"
depends on BAR || !BAR
This means that there is either a dependency on BAR that disallows
the combination of FOO=y with BAR=m, or BAR is completely disabled. The BAR
module must provide all the stubs for !BAR case.
For a more formalized approach if there are multiple drivers that have
the same dependency, a helper symbol can be used, like::
config FOO
tristate "Support for foo hardware"
depends on BAR_OPTIONAL
config BAR_OPTIONAL
def_tristate BAR || !BAR
Much less favorable way to express optional dependency is IS_REACHABLE() within
the module code, useful for example when the module BAR does not provide
!BAR stubs::
foo_init()
{
if (IS_REACHABLE(CONFIG_BAR))
bar_register(&foo);
...
}
IS_REACHABLE() is generally discouraged, because the code will be silently
discarded, when CONFIG_BAR=m and this code is built-in. This is not what users
usually expect when enabling BAR as module.
Recursive dependency 한계와 해결 사례
641-733`recursive dependency detected` error는 둘 이상의 Kconfig symbol 사이 circular dependency를 뜻합니다. Kconfig tool은 모든 symbol의 가능한 값을 알아야 configuration 요구를 확인할 수 있지만 현재 circular relation에서는 계산할 수 없습니다. Kconfig는 recursive dependency resolution을 하지 않습니다.
간단한 사례는 `Documentation/kbuild/Kconfig.recursion-issue-01`이며 `make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-01 allnoconfig`로 시험합니다. 누적 사례는 `Kconfig.recursion-issue-02`이고 같은 방식으로 해당 path를 `KBUILD_KCONFIG`에 줍니다.
불필요한 edge를 없애거나 한 방향의 dependency 의미로 통일합니다.
첫 sample에서는 CORE_BELL_A가 이미 CORE에 depends하므로 CORE_BELL_A_ADVANCED의 `select CORE`가 암시적이고 제거할 수 있습니다. Edge를 제거할 수 없다면 b 방식으로 dependency semantics를 맞춥니다. 둘째 sample에서 두 b 해결책을 시험할 수 있습니다.
원문 commit과 dependency 변경을 행 단위로 보존했습니다.
표의 (1)은 error 인용이 일부이거나 없음을, (2)는 수정의 요지로 보인다는 뜻이며 (3)은 같은 error를 뜻합니다. 과거 error는 모두 하나 이상의 `select`와 하나 이상의 `depends on`이 얽혀 있습니다.
Kconfig recursive dependency limitations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you've hit the Kconfig error: "recursive dependency detected" you've run
into a recursive dependency issue with Kconfig, a recursive dependency can be
summarized as a circular dependency. The kconfig tools need to ensure that
Kconfig files comply with specified configuration requirements. In order to do
that kconfig must determine the values that are possible for all Kconfig
symbols, this is currently not possible if there is a circular relation
between two or more Kconfig symbols. For more details refer to the "Simple
Kconfig recursive issue" subsection below. Kconfig does not do recursive
dependency resolution; this has a few implications for Kconfig file writers.
We'll first explain why this issues exists and then provide an example
technical limitation which this brings upon Kconfig developers. Eager
developers wishing to try to address this limitation should read the next
subsections.
Simple Kconfig recursive issue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Read: Documentation/kbuild/Kconfig.recursion-issue-01
Test with::
make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-01 allnoconfig
Cumulative Kconfig recursive issue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Read: Documentation/kbuild/Kconfig.recursion-issue-02
Test with::
make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-02 allnoconfig
Practical solutions to kconfig recursive issue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Developers who run into the recursive Kconfig issue have two options
at their disposal. We document them below and also provide a list of
historical issues resolved through these different solutions.
a) Remove any superfluous "select FOO" or "depends on FOO"
b) Match dependency semantics:
b1) Swap all "select FOO" to "depends on FOO" or,
b2) Swap all "depends on FOO" to "select FOO"
The resolution to a) can be tested with the sample Kconfig file
Documentation/kbuild/Kconfig.recursion-issue-01 through the removal
of the "select CORE" from CORE_BELL_A_ADVANCED as that is implicit already
since CORE_BELL_A depends on CORE. At times it may not be possible to remove
some dependency criteria, for such cases you can work with solution b).
The two different resolutions for b) can be tested in the sample Kconfig file
Documentation/kbuild/Kconfig.recursion-issue-02.
Below is a list of examples of prior fixes for these types of recursive issues;
all errors appear to involve one or more "select" statements and one or more
"depends on".
============ ===================================
commit fix
============ ===================================
06b718c01208 select A -> depends on A
c22eacfe82f9 depends on A -> depends on B
6a91e854442c select A -> depends on A
118c565a8f2e select A -> select B
f004e5594705 select A -> depends on A
c7861f37b4c6 depends on A -> (null)
80c69915e5fb select A -> (null) (1)
c2218e26c0d0 select A -> depends on A (1)
d6ae99d04e1c select A -> depends on A
95ca19cf8cbf select A -> depends on A
8f057d7bca54 depends on A -> (null)
8f057d7bca54 depends on A -> select A
a0701f04846e select A -> depends on A
0c8b92f7f259 depends on A -> (null)
e4e9e0540928 select A -> depends on A (2)
7453ea886e87 depends on A > (null) (1)
7b1fff7e4fdf select A -> depends on A
86c747d2a4f0 select A -> depends on A
d9f9ab51e55e select A -> depends on A
0c51a4d8abd6 depends on A -> select A (3)
e98062ed6dc4 select A -> depends on A (3)
91e5d284a7f1 select A -> (null)
============ ===================================
(1) Partial (or no) quote of error.
(2) That seems to be the gist of that fix.
(3) Same error.
Kconfig semantics와 SAT solver 연구
734-811Kconfig 작업은 semantics를 명확히 하는 분야와 full SAT solver 사용을 평가하는 분야 모두 환영합니다. SAT solver는 더 복잡한 dependency mapping이나 query, 현재 recursive dependency 문제 처리에 유용할 수 있지만 해결 가능 여부는 아직 모릅니다. 너무 복잡하거나 recursion을 해결하지 못하더라도 Kconfig는 제약과 요구를 포함한 명확한 semantics를 가져야 합니다.
Kconfig는 Linux 외 여러 project에서 널리 쓰이며 한 연구는 12개 project를 분석했습니다. 기본 syntax 문서는 있지만 더 정확한 semantics 정의가 필요합니다. 한 project는 xconfig configurator에서 semantics를 추론했고, 다른 project는 core subset의 denotational semantics를 formalize했습니다. 추론된 의미가 Kconfig 설계 목표와 맞는지 확인해야 합니다.
명확한 semantics는 dependency를 실제로 평가하는 tool에 유용합니다. Kconfig logic을 boolean formula로 번역해 SAT solver로 항상 inactive인 dead feature를 찾은 연구는 Linux에서 114개를 발견했습니다. Formal semantics 기반 `kismet` tool은 reverse dependency 남용을 찾아 수십 건의 Kconfig 수정을 이끌었습니다.
Kconfig는 대표적인 industrial variability modeling language이므로 semantics 확인은 실세계 요구를 이해하는 데 도움이 됩니다. 현재까지 Kconfig 같은 language의 semantics는 주로 reverse engineering으로 추론했습니다.
원문 [0]~[3], [10], [11]의 연구와 tool link입니다.
Kconfig 자체는 아직 SAT solver를 직접 쓰지 않지만 inferred semantics를 boolean abstraction으로 바꿔 solver에 넣는 연구가 있습니다. CADOS(이전 VAMOS)와 `undertaker`는 Kconfig variability model, CPP `#ifdef`, build rule에서 proposition을 추출해 SAT solver로 dead code·file·symbol을 찾습니다.
Kconfig에 SAT solver를 도입한다면 이런 기존 노력을 재사용할 수 있습니다. 기존 project mentor가 upstream 통합 자문과 장기 유지에 관심을 보이고 있으며 참여자는 `https://kernelnewbies.org/KernelProjects/kconfig-sat`를 참고합니다.
원문 [4]~[9]와 project page입니다.
서로 다른 source의 조건을 하나의 proposition model로 결합합니다.
Future kconfig work
~~~~~~~~~~~~~~~~~~~
Work on kconfig is welcomed on both areas of clarifying semantics and on
evaluating the use of a full SAT solver for it. A full SAT solver can be
desirable to enable more complex dependency mappings and / or queries,
for instance one possible use case for a SAT solver could be that of handling
the current known recursive dependency issues. It is not known if this would
address such issues but such evaluation is desirable. If support for a full SAT
solver proves too complex or that it cannot address recursive dependency issues
Kconfig should have at least clear and well defined semantics which also
addresses and documents limitations or requirements such as the ones dealing
with recursive dependencies.
Further work on both of these areas is welcomed on Kconfig. We elaborate
on both of these in the next two subsections.
Semantics of Kconfig
~~~~~~~~~~~~~~~~~~~~
The use of Kconfig is broad, Linux is now only one of Kconfig's users:
one study has completed a broad analysis of Kconfig use in 12 projects [0]_.
Despite its widespread use, and although this document does a reasonable job
in documenting basic Kconfig syntax a more precise definition of Kconfig
semantics is welcomed. One project deduced Kconfig semantics through
the use of the xconfig configurator [1]_. Work should be done to confirm if
the deduced semantics matches our intended Kconfig design goals.
Another project formalized a denotational semantics of a core subset of
the Kconfig language [10]_.
Having well defined semantics can be useful for tools for practical
evaluation of dependencies, for instance one such case was work to
express in boolean abstraction of the inferred semantics of Kconfig to
translate Kconfig logic into boolean formulas and run a SAT solver on this to
find dead code / features (always inactive), 114 dead features were found in
Linux using this methodology [1]_ (Section 8: Threats to validity).
The kismet tool, based on the semantics in [10]_, finds abuses of reverse
dependencies and has led to dozens of committed fixes to Linux Kconfig files [11]_.
Confirming this could prove useful as Kconfig stands as one of the leading
industrial variability modeling languages [1]_ [2]_. Its study would help
evaluate practical uses of such languages, their use was only theoretical
and real world requirements were not well understood. As it stands though
only reverse engineering techniques have been used to deduce semantics from
variability modeling languages such as Kconfig [3]_.
.. [0] https://www.eng.uwaterloo.ca/~shshe/kconfig_semantics.pdf
.. [1] https://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
.. [2] https://gsd.uwaterloo.ca/sites/default/files/ase241-berger_0.pdf
.. [3] https://gsd.uwaterloo.ca/sites/default/files/icse2011.pdf
Full SAT solver for Kconfig
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Although SAT solvers [4]_ haven't yet been used by Kconfig directly, as noted
in the previous subsection, work has been done however to express in boolean
abstraction the inferred semantics of Kconfig to translate Kconfig logic into
boolean formulas and run a SAT solver on it [5]_. Another known related project
is CADOS [6]_ (former VAMOS [7]_) and the tools, mainly undertaker [8]_, which
has been introduced first with [9]_. The basic concept of undertaker is to
extract variability models from Kconfig and put them together with a
propositional formula extracted from CPP #ifdefs and build-rules into a SAT
solver in order to find dead code, dead files, and dead symbols. If using a SAT
solver is desirable on Kconfig one approach would be to evaluate repurposing
such efforts somehow on Kconfig. There is enough interest from mentors of
existing projects to not only help advise how to integrate this work upstream
but also help maintain it long term. Interested developers should visit:
https://kernelnewbies.org/KernelProjects/kconfig-sat
.. [4] https://www.cs.cornell.edu/~sabhar/chapters/SATSolvers-KR-Handbook.pdf
.. [5] https://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
.. [6] https://cados.cs.fau.de
.. [7] https://vamos.cs.fau.de
.. [8] https://undertaker.cs.fau.de
.. [9] https://www4.cs.fau.de/Publications/2011/tartler_11_eurosys.pdf
.. [10] https://paulgazzillo.com/papers/esecfse21.pdf
.. [11] https://github.com/paulgazz/kmax
요약·해설
kconfig-language.rst:1-811Kconfig는 `n/m/y` tristate logic으로 symbol의 visibility와 허용 범위를 계산합니다. `depends on`은 상한, `select`는 dependency를 우회하는 강제 하한, `imply`는 사용자가 낮출 수 있는 약한 하한이므로 목적에 맞게 구분해야 합니다.
문서 전체에서 반복되는 안전한 작성 원칙입니다.
Tree와 expression이 함께 최종 표시 여부를 결정합니다.