mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen: Update Kconfig to Linux v5.4
This patch updates Kconfig to a more recent version of Kconfig, found
in Linux v5.4.0, 219d54332a09 ("Linux 5.4").
With the updated version of Kconfig, other changes are necessary to
avoid breaking the build.
Kconfig files:
- fix Kconfig files that where using option env=*:
Since Linux commit 104daea149c4 ("kconfig: reference environment
variables directly and remove 'option env='"), we can access the
environment directly via $() and "option env=" as been removed.
- CONFIG_EXPERT='y' will now appear in .config file if
XEN_CONFIG_EXPERT=y in the environment. The alternative is to change
"EXPERT" to "$(XEN_CONFIG_EXPERT)" in all Kconfig files.
Makefile:
- silentoldconfig target as been removed from Kconfig. To update
include/generated/autoconf.h, we need to use syncconfig target
instead.
Makefile.kconfig:
- Import newer needed code from Linux's Makefile.lib and
Kbuild.include and Makefile.build.
- Set Q to empty, Xen build system doesn't silence commands. Having Q
empty mean we can import stuff from Linux without having to remove the
leading $(Q) from build commands. And quiet='' means commands will be
echoed.
- Add $(PHONY) to .PHONY. Like it is intended by Kbuild.
Makefile.host is also updated and copied from Linux.
Dependency change:
- Now depends on flex/bison, maybe we could _shipped those files like
before. Linux doesn't do that anymore.
The .gitignore in kconfig/ has more entries, compared to upstream, for
file generated by Makefile.host.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
1 parent
9b71d6a759
commit
f80fe2b34f
112 files changed
+5605
-8034
No files matched your search
@@ -0,0 +1,701 @@
|
||||
================
|
||||
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".
|
||||
|
||||
- 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.
|
||||
|
||||
- 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
|
||||
imply BAZ
|
||||
|
||||
config BAZ
|
||||
tristate
|
||||
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/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.
|
||||
|
||||
- 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" or "---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.
|
||||
"---help---" and "help" do not differ in behaviour, "---help---" is
|
||||
used to help visually separate configuration logic from help within
|
||||
the file as an aid to developers.
|
||||
|
||||
- misc options: "option" <symbol>[=<value>]
|
||||
|
||||
Various less common options can be defined via this option syntax,
|
||||
which can modify the behaviour of the menu entry and its config
|
||||
symbol. These options are currently possible:
|
||||
|
||||
- "defconfig_list"
|
||||
This declares a list of default entries which can be used when
|
||||
looking for the default configuration (which is used when the main
|
||||
.config doesn't exists yet.)
|
||||
|
||||
- "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.
|
||||
|
||||
- "allnoconfig_y"
|
||||
This declares the symbol as one that should have the value y when
|
||||
using "allnoconfig". Used for symbols that hide other symbols.
|
||||
|
||||
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" [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.
|
||||
|
||||
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.
|
||||
|
||||
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_STACKPROTECTOR_NONE
|
||||
def_bool $(cc-option,-fno-stack-protector)
|
||||
|
||||
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).
|
||||
|
||||
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's 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 on 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.
|
||||
|
||||
Having well defined semantics can be useful for tools for practical
|
||||
evaluation of depenencies, for instance one such use known 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).
|
||||
|
||||
Confirming this could prove useful as Kconfig stands as one of the 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] http://www.eng.uwaterloo.ca/~shshe/kconfig_semantics.pdf
|
||||
.. [1] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
|
||||
.. [2] http://gsd.uwaterloo.ca/sites/default/files/ase241-berger_0.pdf
|
||||
.. [3] http://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
|
||||
exract 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:
|
||||
|
||||
http://kernelnewbies.org/KernelProjects/kconfig-sat
|
||||
|
||||
.. [4] http://www.cs.cornell.edu/~sabhar/chapters/SATSolvers-KR-Handbook.pdf
|
||||
.. [5] http://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
|
||||
@@ -1,395 +0,0 @@
|
||||
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".
|
||||
|
||||
- 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".
|
||||
|
||||
- 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.
|
||||
|
||||
- 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" or "---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.
|
||||
"---help---" and "help" do not differ in behaviour, "---help---" is
|
||||
used to help visually separate configuration logic from help within
|
||||
the file as an aid to developers.
|
||||
|
||||
- misc options: "option" <symbol>[=<value>]
|
||||
Various less common options can be defined via this option syntax,
|
||||
which can modify the behaviour of the menu entry and its config
|
||||
symbol. These options are currently possible:
|
||||
|
||||
- "defconfig_list"
|
||||
This declares a list of default entries which can be used when
|
||||
looking for the default configuration (which is used when the main
|
||||
.config doesn't exists yet.)
|
||||
|
||||
- "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.
|
||||
|
||||
- "env"=<value>
|
||||
This imports the environment variable into Kconfig. It behaves like
|
||||
a default, except that the value comes from the environment, this
|
||||
also means that the behaviour when mixing it with normal defaults is
|
||||
undefined at this point. The symbol is currently not exported back
|
||||
to the build environment (if this is desired, it can be done via
|
||||
another symbol).
|
||||
|
||||
- "allnoconfig_y"
|
||||
This declares the symbol as one that should have the value y when
|
||||
using "allnoconfig". Used for symbols that hide other symbols.
|
||||
|
||||
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)
|
||||
'(' <expr> ')' (4)
|
||||
'!' <expr> (5)
|
||||
<expr> '&&' <expr> (6)
|
||||
<expr> '||' <expr> (7)
|
||||
|
||||
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) Returns the value of the expression. Used to override precedence.
|
||||
(5) Returns the result of (2-/expr/).
|
||||
(6) Returns the result of min(/expr/, /expr/).
|
||||
(7) 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 always
|
||||
visible when MODULES is visible (the (empty) dependency of MODULES is
|
||||
also part of the comment dependencies).
|
||||
|
||||
|
||||
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.
|
||||
|
||||
choices:
|
||||
|
||||
"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, 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.
|
||||
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 (ie. with the same entries) in another
|
||||
place.
|
||||
|
||||
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 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'.
|
||||
|
||||
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).
|
||||
@@ -0,0 +1,247 @@
|
||||
======================
|
||||
Kconfig macro language
|
||||
======================
|
||||
|
||||
Concept
|
||||
-------
|
||||
|
||||
The basic idea was inspired by Make. When we look at Make, we notice sort of
|
||||
two languages in one. One language describes dependency graphs consisting of
|
||||
targets and prerequisites. The other is a macro language for performing textual
|
||||
substitution.
|
||||
|
||||
There is clear distinction between the two language stages. For example, you
|
||||
can write a makefile like follows::
|
||||
|
||||
APP := foo
|
||||
SRC := foo.c
|
||||
CC := gcc
|
||||
|
||||
$(APP): $(SRC)
|
||||
$(CC) -o $(APP) $(SRC)
|
||||
|
||||
The macro language replaces the variable references with their expanded form,
|
||||
and handles as if the source file were input like follows::
|
||||
|
||||
foo: foo.c
|
||||
gcc -o foo foo.c
|
||||
|
||||
Then, Make analyzes the dependency graph and determines the targets to be
|
||||
updated.
|
||||
|
||||
The idea is quite similar in Kconfig - it is possible to describe a Kconfig
|
||||
file like this::
|
||||
|
||||
CC := gcc
|
||||
|
||||
config CC_HAS_FOO
|
||||
def_bool $(shell, $(srctree)/scripts/gcc-check-foo.sh $(CC))
|
||||
|
||||
The macro language in Kconfig processes the source file into the following
|
||||
intermediate::
|
||||
|
||||
config CC_HAS_FOO
|
||||
def_bool y
|
||||
|
||||
Then, Kconfig moves onto the evaluation stage to resolve inter-symbol
|
||||
dependency as explained in kconfig-language.txt.
|
||||
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Like in Make, a variable in Kconfig works as a macro variable. A macro
|
||||
variable is expanded "in place" to yield a text string that may then be
|
||||
expanded further. To get the value of a variable, enclose the variable name in
|
||||
$( ). The parentheses are required even for single-letter variable names; $X is
|
||||
a syntax error. The curly brace form as in ${CC} is not supported either.
|
||||
|
||||
There are two types of variables: simply expanded variables and recursively
|
||||
expanded variables.
|
||||
|
||||
A simply expanded variable is defined using the := assignment operator. Its
|
||||
righthand side is expanded immediately upon reading the line from the Kconfig
|
||||
file.
|
||||
|
||||
A recursively expanded variable is defined using the = assignment operator.
|
||||
Its righthand side is simply stored as the value of the variable without
|
||||
expanding it in any way. Instead, the expansion is performed when the variable
|
||||
is used.
|
||||
|
||||
There is another type of assignment operator; += is used to append text to a
|
||||
variable. The righthand side of += is expanded immediately if the lefthand
|
||||
side was originally defined as a simple variable. Otherwise, its evaluation is
|
||||
deferred.
|
||||
|
||||
The variable reference can take parameters, in the following form::
|
||||
|
||||
$(name,arg1,arg2,arg3)
|
||||
|
||||
You can consider the parameterized reference as a function. (more precisely,
|
||||
"user-defined function" in contrast to "built-in function" listed below).
|
||||
|
||||
Useful functions must be expanded when they are used since the same function is
|
||||
expanded differently if different parameters are passed. Hence, a user-defined
|
||||
function is defined using the = assignment operator. The parameters are
|
||||
referenced within the body definition with $(1), $(2), etc.
|
||||
|
||||
In fact, recursively expanded variables and user-defined functions are the same
|
||||
internally. (In other words, "variable" is "function with zero argument".)
|
||||
When we say "variable" in a broad sense, it includes "user-defined function".
|
||||
|
||||
|
||||
Built-in functions
|
||||
------------------
|
||||
|
||||
Like Make, Kconfig provides several built-in functions. Every function takes a
|
||||
particular number of arguments.
|
||||
|
||||
In Make, every built-in function takes at least one argument. Kconfig allows
|
||||
zero argument for built-in functions, such as $(fileno), $(lineno). You could
|
||||
consider those as "built-in variable", but it is just a matter of how we call
|
||||
it after all. Let's say "built-in function" here to refer to natively supported
|
||||
functionality.
|
||||
|
||||
Kconfig currently supports the following built-in functions.
|
||||
|
||||
- $(shell,command)
|
||||
|
||||
The "shell" function accepts a single argument that is expanded and passed
|
||||
to a subshell for execution. The standard output of the command is then read
|
||||
and returned as the value of the function. Every newline in the output is
|
||||
replaced with a space. Any trailing newlines are deleted. The standard error
|
||||
is not returned, nor is any program exit status.
|
||||
|
||||
- $(info,text)
|
||||
|
||||
The "info" function takes a single argument and prints it to stdout.
|
||||
It evaluates to an empty string.
|
||||
|
||||
- $(warning-if,condition,text)
|
||||
|
||||
The "warning-if" function takes two arguments. If the condition part is "y",
|
||||
the text part is sent to stderr. The text is prefixed with the name of the
|
||||
current Kconfig file and the current line number.
|
||||
|
||||
- $(error-if,condition,text)
|
||||
|
||||
The "error-if" function is similar to "warning-if", but it terminates the
|
||||
parsing immediately if the condition part is "y".
|
||||
|
||||
- $(filename)
|
||||
|
||||
The 'filename' takes no argument, and $(filename) is expanded to the file
|
||||
name being parsed.
|
||||
|
||||
- $(lineno)
|
||||
|
||||
The 'lineno' takes no argument, and $(lineno) is expanded to the line number
|
||||
being parsed.
|
||||
|
||||
|
||||
Make vs Kconfig
|
||||
---------------
|
||||
|
||||
Kconfig adopts Make-like macro language, but the function call syntax is
|
||||
slightly different.
|
||||
|
||||
A function call in Make looks like this::
|
||||
|
||||
$(func-name arg1,arg2,arg3)
|
||||
|
||||
The function name and the first argument are separated by at least one
|
||||
whitespace. Then, leading whitespaces are trimmed from the first argument,
|
||||
while whitespaces in the other arguments are kept. You need to use a kind of
|
||||
trick to start the first parameter with spaces. For example, if you want
|
||||
to make "info" function print " hello", you can write like follows::
|
||||
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
$(info $(space)$(space)hello)
|
||||
|
||||
Kconfig uses only commas for delimiters, and keeps all whitespaces in the
|
||||
function call. Some people prefer putting a space after each comma delimiter::
|
||||
|
||||
$(func-name, arg1, arg2, arg3)
|
||||
|
||||
In this case, "func-name" will receive " arg1", " arg2", " arg3". The presence
|
||||
of leading spaces may matter depending on the function. The same applies to
|
||||
Make - for example, $(subst .c, .o, $(sources)) is a typical mistake; it
|
||||
replaces ".c" with " .o".
|
||||
|
||||
In Make, a user-defined function is referenced by using a built-in function,
|
||||
'call', like this::
|
||||
|
||||
$(call my-func,arg1,arg2,arg3)
|
||||
|
||||
Kconfig invokes user-defined functions and built-in functions in the same way.
|
||||
The omission of 'call' makes the syntax shorter.
|
||||
|
||||
In Make, some functions treat commas verbatim instead of argument separators.
|
||||
For example, $(shell echo hello, world) runs the command "echo hello, world".
|
||||
Likewise, $(info hello, world) prints "hello, world" to stdout. You could say
|
||||
this is _useful_ inconsistency.
|
||||
|
||||
In Kconfig, for simpler implementation and grammatical consistency, commas that
|
||||
appear in the $( ) context are always delimiters. It means::
|
||||
|
||||
$(shell, echo hello, world)
|
||||
|
||||
is an error because it is passing two parameters where the 'shell' function
|
||||
accepts only one. To pass commas in arguments, you can use the following trick::
|
||||
|
||||
comma := ,
|
||||
$(shell, echo hello$(comma) world)
|
||||
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
A variable (or function) cannot be expanded across tokens. So, you cannot use
|
||||
a variable as a shorthand for an expression that consists of multiple tokens.
|
||||
The following works::
|
||||
|
||||
RANGE_MIN := 1
|
||||
RANGE_MAX := 3
|
||||
|
||||
config FOO
|
||||
int "foo"
|
||||
range $(RANGE_MIN) $(RANGE_MAX)
|
||||
|
||||
But, the following does not work::
|
||||
|
||||
RANGES := 1 3
|
||||
|
||||
config FOO
|
||||
int "foo"
|
||||
range $(RANGES)
|
||||
|
||||
A variable cannot be expanded to any keyword in Kconfig. The following does
|
||||
not work::
|
||||
|
||||
MY_TYPE := tristate
|
||||
|
||||
config FOO
|
||||
$(MY_TYPE) "foo"
|
||||
default y
|
||||
|
||||
Obviously from the design, $(shell command) is expanded in the textual
|
||||
substitution phase. You cannot pass symbols to the 'shell' function.
|
||||
|
||||
The following does not work as expected::
|
||||
|
||||
config ENDIAN_FLAG
|
||||
string
|
||||
default "-mbig-endian" if CPU_BIG_ENDIAN
|
||||
default "-mlittle-endian" if CPU_LITTLE_ENDIAN
|
||||
|
||||
config CC_HAS_ENDIAN_FLAG
|
||||
def_bool $(shell $(srctree)/scripts/gcc-check-flag ENDIAN_FLAG)
|
||||
|
||||
Instead, you can do like follows so that any function call is statically
|
||||
expanded::
|
||||
|
||||
config CC_HAS_ENDIAN_FLAG
|
||||
bool
|
||||
default $(shell $(srctree)/scripts/gcc-check-flag -mbig-endian) if CPU_BIG_ENDIAN
|
||||
default $(shell $(srctree)/scripts/gcc-check-flag -mlittle-endian) if CPU_LITTLE_ENDIAN
|
||||
@@ -1,14 +1,17 @@
|
||||
This file contains some assistance for using "make *config".
|
||||
===================
|
||||
Kconfig make config
|
||||
===================
|
||||
|
||||
This file contains some assistance for using `make *config`.
|
||||
|
||||
Use "make help" to list all of the possible configuration targets.
|
||||
|
||||
The xconfig ('qconf') and menuconfig ('mconf') programs also
|
||||
have embedded help text. Be sure to check it for navigation,
|
||||
search, and other general help text.
|
||||
The xconfig ('qconf'), menuconfig ('mconf'), and nconfig ('nconf')
|
||||
programs also have embedded help text. Be sure to check that for
|
||||
navigation, search, and other general help text.
|
||||
|
||||
======================================================================
|
||||
General
|
||||
--------------------------------------------------
|
||||
-------
|
||||
|
||||
New kernel releases often introduce new config symbols. Often more
|
||||
important, new kernel releases may rename config symbols. When
|
||||
@@ -17,48 +20,55 @@ this happens, using a previously working .config file and running
|
||||
for you, so you may find that you need to see what NEW kernel
|
||||
symbols have been introduced.
|
||||
|
||||
To see a list of new config symbols when using "make oldconfig", use
|
||||
To see a list of new config symbols, use::
|
||||
|
||||
cp user/some/old.config .config
|
||||
make listnewconfig
|
||||
|
||||
and the config program will list any new symbols, one per line.
|
||||
|
||||
Alternatively, you can use the brute force method::
|
||||
|
||||
make oldconfig
|
||||
scripts/diffconfig .config.old .config | less
|
||||
|
||||
______________________________________________________________________
|
||||
Environment variables for '*config'
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Environment variables for `*config`
|
||||
|
||||
KCONFIG_CONFIG
|
||||
--------------------------------------------------
|
||||
--------------
|
||||
This environment variable can be used to specify a default kernel config
|
||||
file name to override the default name of ".config".
|
||||
|
||||
KCONFIG_OVERWRITECONFIG
|
||||
--------------------------------------------------
|
||||
-----------------------
|
||||
If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
|
||||
break symlinks when .config is a symlink to somewhere else.
|
||||
|
||||
CONFIG_
|
||||
--------------------------------------------------
|
||||
If you set CONFIG_ in the environment, Kconfig will prefix all symbols
|
||||
`CONFIG_`
|
||||
---------
|
||||
If you set `CONFIG_` in the environment, Kconfig will prefix all symbols
|
||||
with its value when saving the configuration, instead of using the default,
|
||||
"CONFIG_".
|
||||
`CONFIG_`.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
______________________________________________________________________
|
||||
Environment variables for '{allyes/allmod/allno/rand}config'
|
||||
|
||||
KCONFIG_ALLCONFIG
|
||||
--------------------------------------------------
|
||||
-----------------
|
||||
(partially based on lkml email from/by Rob Landley, re: miniconfig)
|
||||
|
||||
--------------------------------------------------
|
||||
|
||||
The allyesconfig/allmodconfig/allnoconfig/randconfig variants can also
|
||||
use the environment variable KCONFIG_ALLCONFIG as a flag or a filename
|
||||
that contains config symbols that the user requires to be set to a
|
||||
specific value. If KCONFIG_ALLCONFIG is used without a filename where
|
||||
KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", "make *config"
|
||||
KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", `make *config`
|
||||
checks for a file named "all{yes/mod/no/def/random}.config"
|
||||
(corresponding to the *config command that was used) for symbol values
|
||||
(corresponding to the `*config` command that was used) for symbol values
|
||||
that are to be forced. If this file is not found, it checks for a
|
||||
file named "all.config" to contain forced values.
|
||||
|
||||
@@ -71,43 +81,55 @@ This 'KCONFIG_ALLCONFIG' file is a config file which contains
|
||||
(usually a subset of all) preset config symbols. These variable
|
||||
settings are still subject to normal dependency checks.
|
||||
|
||||
Examples:
|
||||
Examples::
|
||||
|
||||
KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig
|
||||
or
|
||||
|
||||
or::
|
||||
|
||||
KCONFIG_ALLCONFIG=mini.config make allnoconfig
|
||||
or
|
||||
|
||||
or::
|
||||
|
||||
make KCONFIG_ALLCONFIG=mini.config allnoconfig
|
||||
|
||||
These examples will disable most options (allnoconfig) but enable or
|
||||
disable the options that are explicitly listed in the specified
|
||||
mini-config files.
|
||||
|
||||
______________________________________________________________________
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Environment variables for 'randconfig'
|
||||
|
||||
KCONFIG_SEED
|
||||
--------------------------------------------------
|
||||
------------
|
||||
You can set this to the integer value used to seed the RNG, if you want
|
||||
to somehow debug the behaviour of the kconfig parser/frontends.
|
||||
If not set, the current time will be used.
|
||||
|
||||
KCONFIG_PROBABILITY
|
||||
--------------------------------------------------
|
||||
-------------------
|
||||
This variable can be used to skew the probabilities. This variable can
|
||||
be unset or empty, or set to three different formats:
|
||||
|
||||
======================= ================== =====================
|
||||
KCONFIG_PROBABILITY y:n split y:m:n split
|
||||
-----------------------------------------------------------------
|
||||
======================= ================== =====================
|
||||
unset or empty 50 : 50 33 : 33 : 34
|
||||
N N : 100-N N/2 : N/2 : 100-N
|
||||
[1] N:M N+M : 100-(N+M) N : M : 100-(N+M)
|
||||
[2] N:M:L N : 100-N M : L : 100-(M+L)
|
||||
======================= ================== =====================
|
||||
|
||||
where N, M and L are integers (in base 10) in the range [0,100], and so
|
||||
that:
|
||||
|
||||
[1] N+M is in the range [0,100]
|
||||
|
||||
[2] M+L is in the range [0,100]
|
||||
|
||||
Examples:
|
||||
Examples::
|
||||
|
||||
KCONFIG_PROBABILITY=10
|
||||
10% of booleans will be set to 'y', 90% to 'n'
|
||||
5% of tristates will be set to 'y', 5% to 'm', 90% to 'n'
|
||||
@@ -118,34 +140,36 @@ Examples:
|
||||
10% of booleans will be set to 'y', 90% to 'n'
|
||||
15% of tristates will be set to 'y', 15% to 'm', 70% to 'n'
|
||||
|
||||
______________________________________________________________________
|
||||
Environment variables for 'silentoldconfig'
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Environment variables for 'syncconfig'
|
||||
|
||||
KCONFIG_NOSILENTUPDATE
|
||||
--------------------------------------------------
|
||||
----------------------
|
||||
If this variable has a non-blank value, it prevents silent kernel
|
||||
config updates (requires explicit updates).
|
||||
|
||||
KCONFIG_AUTOCONFIG
|
||||
--------------------------------------------------
|
||||
------------------
|
||||
This environment variable can be set to specify the path & name of the
|
||||
"auto.conf" file. Its default value is "include/config/auto.conf".
|
||||
|
||||
KCONFIG_TRISTATE
|
||||
--------------------------------------------------
|
||||
----------------
|
||||
This environment variable can be set to specify the path & name of the
|
||||
"tristate.conf" file. Its default value is "include/config/tristate.conf".
|
||||
|
||||
KCONFIG_AUTOHEADER
|
||||
--------------------------------------------------
|
||||
------------------
|
||||
This environment variable can be set to specify the path & name of the
|
||||
"autoconf.h" (header) file.
|
||||
Its default value is "include/generated/autoconf.h".
|
||||
|
||||
|
||||
======================================================================
|
||||
----------------------------------------------------------------------
|
||||
|
||||
menuconfig
|
||||
--------------------------------------------------
|
||||
----------
|
||||
|
||||
SEARCHING for CONFIG symbols
|
||||
|
||||
@@ -155,56 +179,98 @@ Searching in menuconfig:
|
||||
names, so you have to know something close to what you are
|
||||
looking for.
|
||||
|
||||
Example:
|
||||
Example::
|
||||
|
||||
/hotplug
|
||||
This lists all config symbols that contain "hotplug",
|
||||
e.g., HOTPLUG_CPU, MEMORY_HOTPLUG.
|
||||
|
||||
For search help, enter / followed TAB-TAB-TAB (to highlight
|
||||
For search help, enter / followed by TAB-TAB (to highlight
|
||||
<Help>) and Enter. This will tell you that you can also use
|
||||
regular expressions (regexes) in the search string, so if you
|
||||
are not interested in MEMORY_HOTPLUG, you could try
|
||||
are not interested in MEMORY_HOTPLUG, you could try::
|
||||
|
||||
/^hotplug
|
||||
|
||||
When searching, symbols are sorted thus:
|
||||
|
||||
- first, exact matches, sorted alphabetically (an exact match
|
||||
is when the search matches the complete symbol name);
|
||||
- then, other matches, sorted alphabetically.
|
||||
|
||||
For example: ^ATH.K matches:
|
||||
|
||||
ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
|
||||
[...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
|
||||
|
||||
of which only ATH5K and ATH9K match exactly and so are sorted
|
||||
first (and in alphabetical order), then come all other symbols,
|
||||
sorted in alphabetical order.
|
||||
|
||||
______________________________________________________________________
|
||||
----------------------------------------------------------------------
|
||||
|
||||
User interface options for 'menuconfig'
|
||||
|
||||
MENUCONFIG_COLOR
|
||||
--------------------------------------------------
|
||||
----------------
|
||||
It is possible to select different color themes using the variable
|
||||
MENUCONFIG_COLOR. To select a theme use:
|
||||
MENUCONFIG_COLOR. To select a theme use::
|
||||
|
||||
make MENUCONFIG_COLOR=<theme> menuconfig
|
||||
|
||||
Available themes are:
|
||||
mono => selects colors suitable for monochrome displays
|
||||
blackbg => selects a color scheme with black background
|
||||
classic => theme with blue background. The classic look
|
||||
bluetitle => a LCD friendly version of classic. (default)
|
||||
Available themes are::
|
||||
|
||||
- mono => selects colors suitable for monochrome displays
|
||||
- blackbg => selects a color scheme with black background
|
||||
- classic => theme with blue background. The classic look
|
||||
- bluetitle => a LCD friendly version of classic. (default)
|
||||
|
||||
MENUCONFIG_MODE
|
||||
--------------------------------------------------
|
||||
---------------
|
||||
This mode shows all sub-menus in one large tree.
|
||||
|
||||
Example:
|
||||
Example::
|
||||
|
||||
make MENUCONFIG_MODE=single_menu menuconfig
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
nconfig
|
||||
-------
|
||||
|
||||
nconfig is an alternate text-based configurator. It lists function
|
||||
keys across the bottom of the terminal (window) that execute commands.
|
||||
You can also just use the corresponding numeric key to execute the
|
||||
commands unless you are in a data entry window. E.g., instead of F6
|
||||
for Save, you can just press 6.
|
||||
|
||||
Use F1 for Global help or F3 for the Short help menu.
|
||||
|
||||
Searching in nconfig:
|
||||
|
||||
You can search either in the menu entry "prompt" strings
|
||||
or in the configuration symbols.
|
||||
|
||||
Use / to begin a search through the menu entries. This does
|
||||
not support regular expressions. Use <Down> or <Up> for
|
||||
Next hit and Previous hit, respectively. Use <Esc> to
|
||||
terminate the search mode.
|
||||
|
||||
F8 (SymSearch) searches the configuration symbols for the
|
||||
given string or regular expression (regex).
|
||||
|
||||
NCONFIG_MODE
|
||||
------------
|
||||
This mode shows all sub-menus in one large tree.
|
||||
|
||||
Example::
|
||||
|
||||
make NCONFIG_MODE=single_menu nconfig
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
======================================================================
|
||||
xconfig
|
||||
--------------------------------------------------
|
||||
-------
|
||||
|
||||
Searching in xconfig:
|
||||
|
||||
@@ -212,9 +278,12 @@ Searching in xconfig:
|
||||
names, so you have to know something close to what you are
|
||||
looking for.
|
||||
|
||||
Example:
|
||||
Example::
|
||||
|
||||
Ctrl-F hotplug
|
||||
or
|
||||
|
||||
or::
|
||||
|
||||
Menu: File, Search, hotplug
|
||||
|
||||
lists all config symbol entries that contain "hotplug" in
|
||||
@@ -224,14 +293,12 @@ Searching in xconfig:
|
||||
to return to the main menu.
|
||||
|
||||
|
||||
======================================================================
|
||||
----------------------------------------------------------------------
|
||||
|
||||
gconfig
|
||||
--------------------------------------------------
|
||||
-------
|
||||
|
||||
Searching in gconfig:
|
||||
|
||||
None (gconfig isn't maintained as well as xconfig or menuconfig);
|
||||
however, gconfig does have a few more viewing choices than
|
||||
xconfig does.
|
||||
|
||||
###
|
||||
There is no search command in gconfig. However, gconfig does
|
||||
have several different viewing choices, modes, and options.
|
||||
+3
-15
@@ -2,24 +2,12 @@
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see docs/misc/kconfig-language.txt
|
||||
#
|
||||
mainmenu "Xen/$SRCARCH $XEN_FULLVERSION Configuration"
|
||||
|
||||
config SRCARCH
|
||||
string
|
||||
option env="SRCARCH"
|
||||
|
||||
config ARCH
|
||||
string
|
||||
option env="ARCH"
|
||||
mainmenu "Xen/$(SRCARCH) $(XEN_FULLVERSION) Configuration"
|
||||
|
||||
config BROKEN
|
||||
bool
|
||||
|
||||
source "arch/$SRCARCH/Kconfig"
|
||||
|
||||
config XEN_FULLVERSION
|
||||
string
|
||||
option env="XEN_FULLVERSION"
|
||||
source "arch/$(SRCARCH)/Kconfig"
|
||||
|
||||
config DEFCONFIG_LIST
|
||||
string
|
||||
@@ -28,7 +16,7 @@ config DEFCONFIG_LIST
|
||||
|
||||
config EXPERT
|
||||
string
|
||||
option env="XEN_CONFIG_EXPERT"
|
||||
default y if "$(XEN_CONFIG_EXPERT)" = "y"
|
||||
|
||||
config LTO
|
||||
bool "Link Time Optimisation"
|
||||
|
||||
+2
-2
@@ -267,7 +267,7 @@ $(foreach base,arch/x86/mm/guest_walk_% \
|
||||
arch/x86/mm/shadow/guest_%, \
|
||||
$(foreach ext,o i s,$(call build-intermediate,$(base).$(ext))))
|
||||
|
||||
kconfig := silentoldconfig oldconfig config menuconfig defconfig \
|
||||
kconfig := oldconfig config menuconfig defconfig \
|
||||
nconfig xconfig gconfig savedefconfig listnewconfig olddefconfig \
|
||||
randconfig $(notdir $(wildcard arch/$(SRCARCH)/configs/*_defconfig))
|
||||
.PHONY: $(kconfig)
|
||||
@@ -275,7 +275,7 @@ $(kconfig):
|
||||
$(MAKE) -f $(BASEDIR)/tools/kconfig/Makefile.kconfig ARCH=$(ARCH) SRCARCH=$(SRCARCH) HOSTCC="$(HOSTCC)" HOSTCXX="$(HOSTCXX)" $@
|
||||
|
||||
include/config/%.conf: include/config/auto.conf.cmd $(KCONFIG_CONFIG)
|
||||
$(MAKE) -f $(BASEDIR)/tools/kconfig/Makefile.kconfig ARCH=$(ARCH) SRCARCH=$(SRCARCH) HOSTCC="$(HOSTCC)" HOSTCXX="$(HOSTCXX)" silentoldconfig
|
||||
$(MAKE) -f $(BASEDIR)/tools/kconfig/Makefile.kconfig ARCH=$(ARCH) SRCARCH=$(SRCARCH) HOSTCC="$(HOSTCC)" HOSTCXX="$(HOSTCXX)" syncconfig
|
||||
|
||||
# Allow people to just run `make` as before and not force them to configure
|
||||
$(KCONFIG_CONFIG):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
config 64BIT
|
||||
bool
|
||||
default ARCH != "arm32"
|
||||
default "$(ARCH)" != "arm32"
|
||||
help
|
||||
Say yes to build a 64-bit Xen
|
||||
Say no to build a 32-bit Xen
|
||||
|
||||
+2
-10
@@ -69,14 +69,6 @@ config NEEDS_LIBELF
|
||||
config NEEDS_LIST_SORT
|
||||
bool
|
||||
|
||||
config HAS_BUILD_ID
|
||||
string
|
||||
option env="XEN_HAS_BUILD_ID"
|
||||
|
||||
config HAS_CHECKPOLICY
|
||||
string
|
||||
option env="XEN_HAS_CHECKPOLICY"
|
||||
|
||||
menu "Speculative hardening"
|
||||
|
||||
config SPECULATIVE_HARDEN_ARRAY
|
||||
@@ -195,7 +187,7 @@ config XSM_FLASK_AVC_STATS
|
||||
|
||||
config XSM_FLASK_POLICY
|
||||
bool "Compile Xen with a built-in FLASK security policy"
|
||||
default y if HAS_CHECKPOLICY = "y"
|
||||
default y if "$(XEN_HAS_CHECKPOLICY)" = "y"
|
||||
depends on XSM_FLASK
|
||||
---help---
|
||||
This includes a default XSM policy in the hypervisor so that the
|
||||
@@ -283,7 +275,7 @@ config CRYPTO
|
||||
config LIVEPATCH
|
||||
bool "Live patching support"
|
||||
default X86
|
||||
depends on HAS_BUILD_ID = "y"
|
||||
depends on "$(XEN_HAS_BUILD_ID)" = "y"
|
||||
---help---
|
||||
Allows a running Xen hypervisor to be dynamically patched using
|
||||
binary patches without rebooting. This is primarily used to binarily
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#
|
||||
# Generated files
|
||||
#
|
||||
config*
|
||||
*.lex.c
|
||||
*.tab.c
|
||||
*.tab.h
|
||||
zconf.hash.c
|
||||
*.moc
|
||||
*conf-cfg
|
||||
|
||||
#
|
||||
# configuration programs
|
||||
|
||||
+97
-171
@@ -1,9 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# ===========================================================================
|
||||
# Kernel configuration targets
|
||||
# These targets are used from top-level makefile
|
||||
|
||||
PHONY += xconfig gconfig menuconfig config silentoldconfig \
|
||||
localmodconfig localyesconfig
|
||||
PHONY += xconfig gconfig menuconfig config localmodconfig localyesconfig \
|
||||
build_menuconfig build_nconfig build_gconfig build_xconfig
|
||||
|
||||
ifdef KBUILD_KCONFIG
|
||||
Kconfig := $(KBUILD_KCONFIG)
|
||||
@@ -11,6 +12,10 @@ else
|
||||
Kconfig := Kconfig
|
||||
endif
|
||||
|
||||
ifndef KBUILD_DEFCONFIG
|
||||
KBUILD_DEFCONFIG := defconfig
|
||||
endif
|
||||
|
||||
ifeq ($(quiet),silent_)
|
||||
silent := -s
|
||||
endif
|
||||
@@ -33,49 +38,52 @@ config: $(obj)/conf
|
||||
nconfig: $(obj)/nconf
|
||||
$< $(silent) $(Kconfig)
|
||||
|
||||
silentoldconfig: $(obj)/conf
|
||||
$(Q)mkdir -p include/config include/generated
|
||||
$< $(silent) --$@ $(Kconfig)
|
||||
build_menuconfig: $(obj)/mconf
|
||||
|
||||
localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
|
||||
$(Q)mkdir -p include/config include/generated
|
||||
$(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config
|
||||
build_nconfig: $(obj)/nconf
|
||||
|
||||
build_gconfig: $(obj)/gconf
|
||||
|
||||
build_xconfig: $(obj)/qconf
|
||||
|
||||
localyesconfig localmodconfig: $(obj)/conf
|
||||
$(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config
|
||||
$(Q)if [ -f .config ]; then \
|
||||
cmp -s .tmp.config .config || \
|
||||
(mv -f .config .config.old.1; \
|
||||
mv -f .tmp.config .config; \
|
||||
$(obj)/conf $(silent) --silentoldconfig $(Kconfig); \
|
||||
$< $(silent) --oldconfig $(Kconfig); \
|
||||
mv -f .config.old.1 .config.old) \
|
||||
else \
|
||||
mv -f .tmp.config .config; \
|
||||
$(obj)/conf $(silent) --silentoldconfig $(Kconfig); \
|
||||
$< $(silent) --oldconfig $(Kconfig); \
|
||||
fi
|
||||
$(Q)rm -f .tmp.config
|
||||
|
||||
# These targets map 1:1 to the commandline options of 'conf'
|
||||
#
|
||||
# Note:
|
||||
# syncconfig has become an internal implementation detail and is now
|
||||
# deprecated for external use
|
||||
simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \
|
||||
alldefconfig randconfig listnewconfig olddefconfig
|
||||
alldefconfig randconfig listnewconfig olddefconfig syncconfig
|
||||
PHONY += $(simple-targets)
|
||||
|
||||
$(simple-targets): $(obj)/conf
|
||||
$< $(silent) --$@ $(Kconfig)
|
||||
|
||||
PHONY += oldnoconfig savedefconfig defconfig
|
||||
|
||||
# oldnoconfig is an alias of olddefconfig, because people already are dependent
|
||||
# on its behavior (sets new symbols to their default value but not 'n') with the
|
||||
# counter-intuitive name.
|
||||
oldnoconfig: olddefconfig
|
||||
PHONY += savedefconfig defconfig
|
||||
|
||||
savedefconfig: $(obj)/conf
|
||||
$< $(silent) --$@=defconfig $(Kconfig)
|
||||
|
||||
defconfig: $(obj)/conf
|
||||
ifeq ($(KBUILD_DEFCONFIG),)
|
||||
$< $(silent) --defconfig $(Kconfig)
|
||||
else
|
||||
ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
|
||||
@$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
|
||||
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
|
||||
else
|
||||
@$(kecho) "*** Default configuration is based on target '$(KBUILD_DEFCONFIG)'"
|
||||
$(Q)$(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG)
|
||||
endif
|
||||
|
||||
%_defconfig: $(obj)/conf
|
||||
@@ -86,7 +94,7 @@ configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/c
|
||||
%.config: $(obj)/conf
|
||||
$(if $(call configfiles),, $(error No configuration exists for this target on this architecture))
|
||||
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles)
|
||||
+$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig
|
||||
$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
|
||||
|
||||
PHONY += kvmconfig
|
||||
kvmconfig: kvm_guest.config
|
||||
@@ -100,18 +108,24 @@ PHONY += tinyconfig
|
||||
tinyconfig:
|
||||
$(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
|
||||
|
||||
# CHECK: -o cache_dir=<path> working?
|
||||
PHONY += testconfig
|
||||
testconfig: $(obj)/conf
|
||||
$(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
|
||||
-o cache_dir=$(abspath $(obj)/tests/.cache) \
|
||||
$(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no)
|
||||
clean-files += tests/.cache
|
||||
|
||||
# Help text used by make help
|
||||
help:
|
||||
@echo ' config - Update current config utilising a line-oriented program'
|
||||
@echo ' nconfig - Update current config utilising a ncurses menu based'
|
||||
@echo ' program'
|
||||
@echo ' nconfig - Update current config utilising a ncurses menu based program'
|
||||
@echo ' menuconfig - Update current config utilising a menu based program'
|
||||
@echo ' xconfig - Update current config utilising a Qt based front-end'
|
||||
@echo ' gconfig - Update current config utilising a GTK+ based front-end'
|
||||
@echo ' oldconfig - Update current config utilising a provided .config as base'
|
||||
@echo ' localmodconfig - Update current config disabling modules not loaded'
|
||||
@echo ' localyesconfig - Update current config converting local mods to core'
|
||||
@echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
|
||||
@echo ' defconfig - New config with default from ARCH supplied defconfig'
|
||||
@echo ' savedefconfig - Save current config as ./defconfig (minimal config)'
|
||||
@echo ' allnoconfig - New config where all options are answered with no'
|
||||
@@ -120,165 +134,77 @@ help:
|
||||
@echo ' alldefconfig - New config with all symbols set to default'
|
||||
@echo ' randconfig - New config with random answer to all options'
|
||||
@echo ' listnewconfig - List new options'
|
||||
@echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their'
|
||||
@echo ' default value'
|
||||
@echo ' olddefconfig - Same as oldconfig but sets new symbols to their'
|
||||
@echo ' default value without prompting'
|
||||
@echo ' kvmconfig - Enable additional options for kvm guest kernel support'
|
||||
@echo ' xenconfig - Enable additional options for xen dom0 and guest kernel support'
|
||||
@echo ' tinyconfig - Configure the tiniest possible kernel'
|
||||
|
||||
# lxdialog stuff
|
||||
check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
|
||||
|
||||
# Use recursively expanded variables so we do not call gcc unless
|
||||
# we really need to do so. (Do not call gcc as part of make mrproper)
|
||||
HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
|
||||
-DLOCALE
|
||||
@echo ' testconfig - Run Kconfig unit tests (requires python3 and pytest)'
|
||||
|
||||
# ===========================================================================
|
||||
# Shared Makefile for the various kconfig executables:
|
||||
# conf: Used for defconfig, oldconfig and related targets
|
||||
# nconf: Used for the nconfig target.
|
||||
# Utilizes ncurses
|
||||
# mconf: Used for the menuconfig target
|
||||
# Utilizes the lxdialog package
|
||||
# qconf: Used for the xconfig target
|
||||
# Based on Qt which needs to be installed to compile it
|
||||
# gconf: Used for the gconfig target
|
||||
# Based on GTK+ which needs to be installed to compile it
|
||||
# object files used by all kconfig flavours
|
||||
common-objs := confdata.o expr.o lexer.lex.o parser.tab.o preprocess.o \
|
||||
symbol.o
|
||||
|
||||
lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
|
||||
lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
|
||||
$(obj)/lexer.lex.o: $(obj)/parser.tab.h
|
||||
HOSTCFLAGS_lexer.lex.o := -I $(srctree)/$(src)
|
||||
HOSTCFLAGS_parser.tab.o := -I $(srctree)/$(src)
|
||||
|
||||
conf-objs := conf.o zconf.tab.o
|
||||
mconf-objs := mconf.o zconf.tab.o $(lxdialog)
|
||||
nconf-objs := nconf.o zconf.tab.o nconf.gui.o
|
||||
# conf: Used for defconfig, oldconfig and related targets
|
||||
hostprogs-y += conf
|
||||
conf-objs := conf.o $(common-objs)
|
||||
|
||||
# nconf: Used for the nconfig target based on ncurses
|
||||
hostprogs-y += nconf
|
||||
nconf-objs := nconf.o nconf.gui.o $(common-objs)
|
||||
|
||||
HOSTLDLIBS_nconf = $(shell . $(obj)/nconf-cfg && echo $$libs)
|
||||
HOSTCFLAGS_nconf.o = $(shell . $(obj)/nconf-cfg && echo $$cflags)
|
||||
HOSTCFLAGS_nconf.gui.o = $(shell . $(obj)/nconf-cfg && echo $$cflags)
|
||||
|
||||
$(obj)/nconf.o $(obj)/nconf.gui.o: $(obj)/nconf-cfg
|
||||
|
||||
# mconf: Used for the menuconfig target based on lxdialog
|
||||
hostprogs-y += mconf
|
||||
lxdialog := $(addprefix lxdialog/, \
|
||||
checklist.o inputbox.o menubox.o textbox.o util.o yesno.o)
|
||||
mconf-objs := mconf.o $(lxdialog) $(common-objs)
|
||||
|
||||
HOSTLDLIBS_mconf = $(shell . $(obj)/mconf-cfg && echo $$libs)
|
||||
$(foreach f, mconf.o $(lxdialog), \
|
||||
$(eval HOSTCFLAGS_$f = $$(shell . $(obj)/mconf-cfg && echo $$$$cflags)))
|
||||
|
||||
$(addprefix $(obj)/, mconf.o $(lxdialog)): $(obj)/mconf-cfg
|
||||
|
||||
# qconf: Used for the xconfig target based on Qt
|
||||
hostprogs-y += qconf
|
||||
qconf-cxxobjs := qconf.o
|
||||
qconf-objs := zconf.tab.o
|
||||
gconf-objs := gconf.o zconf.tab.o
|
||||
qconf-objs := images.o $(common-objs)
|
||||
|
||||
hostprogs-y := conf nconf mconf qconf gconf
|
||||
HOSTLDLIBS_qconf = $(shell . $(obj)/qconf-cfg && echo $$libs)
|
||||
HOSTCXXFLAGS_qconf.o = $(shell . $(obj)/qconf-cfg && echo $$cflags)
|
||||
|
||||
clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck
|
||||
clean-files += zconf.tab.c zconf.lex.c zconf.hash.c
|
||||
|
||||
# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
|
||||
PHONY += $(obj)/dochecklxdialog
|
||||
$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
|
||||
$(obj)/dochecklxdialog:
|
||||
$(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf)
|
||||
|
||||
always := dochecklxdialog
|
||||
|
||||
# generated files seem to need this to find local include files
|
||||
HOSTCFLAGS_zconf.lex.o := -I$(src)
|
||||
HOSTCFLAGS_zconf.tab.o := -I$(src)
|
||||
|
||||
LEX_PREFIX_zconf := zconf
|
||||
YACC_PREFIX_zconf := zconf
|
||||
|
||||
HOSTLOADLIBES_qconf = $(KC_QT_LIBS)
|
||||
HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS)
|
||||
|
||||
HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
|
||||
HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
|
||||
-Wno-missing-prototypes
|
||||
|
||||
HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
|
||||
|
||||
HOSTLOADLIBES_nconf = $(shell \
|
||||
pkg-config --libs menuw panelw ncursesw 2>/dev/null \
|
||||
|| pkg-config --libs menu panel ncurses 2>/dev/null \
|
||||
|| echo "-lmenu -lpanel -lncurses" )
|
||||
$(obj)/qconf.o: $(obj)/.tmp_qtcheck
|
||||
|
||||
ifeq ($(MAKECMDGOALS),xconfig)
|
||||
$(obj)/.tmp_qtcheck: $(src)/Makefile
|
||||
-include $(obj)/.tmp_qtcheck
|
||||
|
||||
# Qt needs some extra effort...
|
||||
$(obj)/.tmp_qtcheck:
|
||||
@set -e; $(kecho) " CHECK qt"; dir=""; pkg=""; \
|
||||
if ! pkg-config --exists QtCore 2> /dev/null; then \
|
||||
echo "* Unable to find the Qt4 tool qmake. Trying to use Qt3"; \
|
||||
pkg-config --exists qt 2> /dev/null && pkg=qt; \
|
||||
pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
|
||||
if [ -n "$$pkg" ]; then \
|
||||
cflags="\$$(shell pkg-config $$pkg --cflags)"; \
|
||||
libs="\$$(shell pkg-config $$pkg --libs)"; \
|
||||
moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
|
||||
dir="$$(pkg-config $$pkg --variable=prefix)"; \
|
||||
else \
|
||||
for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
|
||||
if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
|
||||
done; \
|
||||
if [ -z "$$dir" ]; then \
|
||||
echo >&2 "*"; \
|
||||
echo >&2 "* Unable to find any Qt installation. Please make sure that"; \
|
||||
echo >&2 "* the Qt4 or Qt3 development package is correctly installed and"; \
|
||||
echo >&2 "* either qmake can be found or install pkg-config or set"; \
|
||||
echo >&2 "* the QTDIR environment variable to the correct location."; \
|
||||
echo >&2 "*"; \
|
||||
false; \
|
||||
fi; \
|
||||
libpath=$$dir/lib; lib=qt; osdir=""; \
|
||||
$(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
|
||||
osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
|
||||
test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
|
||||
test -f $$libpath/libqt-mt.so && lib=qt-mt; \
|
||||
cflags="-I$$dir/include"; \
|
||||
libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
|
||||
moc="$$dir/bin/moc"; \
|
||||
fi; \
|
||||
if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
|
||||
echo "*"; \
|
||||
echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
|
||||
echo "*"; \
|
||||
moc="/usr/bin/moc"; \
|
||||
fi; \
|
||||
else \
|
||||
cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
|
||||
libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
|
||||
moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \
|
||||
[ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \
|
||||
fi; \
|
||||
echo "KC_QT_CFLAGS=$$cflags" > $@; \
|
||||
echo "KC_QT_LIBS=$$libs" >> $@; \
|
||||
echo "KC_QT_MOC=$$moc" >> $@
|
||||
endif
|
||||
|
||||
$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
|
||||
|
||||
ifeq ($(MAKECMDGOALS),gconfig)
|
||||
-include $(obj)/.tmp_gtkcheck
|
||||
|
||||
# GTK+ needs some extra effort, too...
|
||||
$(obj)/.tmp_gtkcheck:
|
||||
@if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \
|
||||
if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \
|
||||
touch $@; \
|
||||
else \
|
||||
echo >&2 "*"; \
|
||||
echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \
|
||||
echo >&2 "*"; \
|
||||
false; \
|
||||
fi \
|
||||
else \
|
||||
echo >&2 "*"; \
|
||||
echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \
|
||||
echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \
|
||||
echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \
|
||||
echo >&2 "*"; \
|
||||
false; \
|
||||
fi
|
||||
endif
|
||||
|
||||
$(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c
|
||||
|
||||
$(obj)/qconf.o: $(obj)/qconf.moc
|
||||
$(obj)/qconf.o: $(obj)/qconf-cfg $(obj)/qconf.moc
|
||||
|
||||
quiet_cmd_moc = MOC $@
|
||||
cmd_moc = $(KC_QT_MOC) -i $< -o $@
|
||||
cmd_moc = $(shell . $(obj)/qconf-cfg && echo $$moc) -i $< -o $@
|
||||
|
||||
$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck
|
||||
$(obj)/%.moc: $(src)/%.h $(obj)/qconf-cfg
|
||||
$(call cmd,moc)
|
||||
|
||||
# gconf: Used for the gconfig target based on GTK+
|
||||
hostprogs-y += gconf
|
||||
gconf-objs := gconf.o images.o $(common-objs)
|
||||
|
||||
HOSTLDLIBS_gconf = $(shell . $(obj)/gconf-cfg && echo $$libs)
|
||||
HOSTCFLAGS_gconf.o = $(shell . $(obj)/gconf-cfg && echo $$cflags)
|
||||
|
||||
$(obj)/gconf.o: $(obj)/gconf-cfg
|
||||
|
||||
# check if necessary packages are available, and configure build flags
|
||||
filechk_conf_cfg = $(CONFIG_SHELL) $<
|
||||
|
||||
$(obj)/%conf-cfg: $(src)/%conf-cfg.sh FORCE
|
||||
$(call filechk,conf_cfg)
|
||||
|
||||
clean-files += *conf-cfg
|
||||
@@ -1,3 +1,21 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# LEX
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_flex = LEX $@
|
||||
cmd_flex = $(LEX) -o$@ -L $<
|
||||
|
||||
$(obj)/%.lex.c: $(src)/%.l FORCE
|
||||
$(call if_changed,flex)
|
||||
|
||||
# YACC
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_bison = YACC $(basename $@).[ch]
|
||||
cmd_bison = $(YACC) -o $(basename $@).c --defines=$(basename $@).h -t -l $<
|
||||
|
||||
$(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE
|
||||
$(call if_changed,bison)
|
||||
|
||||
# ==========================================================================
|
||||
# Building binaries on the host system
|
||||
# Binaries are used during the compilation of the kernel, for example
|
||||
@@ -5,7 +23,7 @@
|
||||
#
|
||||
# Both C and C++ are supported, but preferred language is C for such utilities.
|
||||
#
|
||||
# Sample syntax (see Documentation/kbuild/makefiles.txt for reference)
|
||||
# Sample syntax (see Documentation/kbuild/makefiles.rst for reference)
|
||||
# hostprogs-y := bin2hex
|
||||
# Will compile bin2hex.c and create an executable named bin2hex
|
||||
#
|
||||
@@ -21,6 +39,8 @@
|
||||
# They are linked as C++ code to the executable qconf
|
||||
|
||||
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
|
||||
host-cshlib := $(sort $(hostlibs-y) $(hostlibs-m))
|
||||
host-cxxshlib := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m))
|
||||
|
||||
# C code
|
||||
# Executables compiled from a single .c file
|
||||
@@ -42,42 +62,38 @@ host-cxxmulti := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
|
||||
# C++ Object (.o) files compiled from .cc files
|
||||
host-cxxobjs := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
|
||||
|
||||
# output directory for programs/.o files
|
||||
# hostprogs-y := tools/build may have been specified.
|
||||
# Retrieve also directory of .o files from prog-objs or prog-cxxobjs notation
|
||||
host-objdirs := $(dir $(__hostprogs) $(host-cobjs) $(host-cxxobjs))
|
||||
# Object (.o) files used by the shared libaries
|
||||
host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
|
||||
host-cxxshobjs := $(sort $(foreach m,$(host-cxxshlib),$($(m:.so=-objs))))
|
||||
|
||||
host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
|
||||
|
||||
|
||||
__hostprogs := $(addprefix $(obj)/,$(__hostprogs))
|
||||
host-csingle := $(addprefix $(obj)/,$(host-csingle))
|
||||
host-cmulti := $(addprefix $(obj)/,$(host-cmulti))
|
||||
host-cobjs := $(addprefix $(obj)/,$(host-cobjs))
|
||||
host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti))
|
||||
host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs))
|
||||
host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
|
||||
|
||||
obj-dirs += $(host-objdirs)
|
||||
host-cshlib := $(addprefix $(obj)/,$(host-cshlib))
|
||||
host-cxxshlib := $(addprefix $(obj)/,$(host-cxxshlib))
|
||||
host-cshobjs := $(addprefix $(obj)/,$(host-cshobjs))
|
||||
host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs))
|
||||
|
||||
#####
|
||||
# Handle options to gcc. Support building with separate output directory
|
||||
|
||||
_hostc_flags = $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
|
||||
$(HOSTCFLAGS_$(basetarget).o)
|
||||
_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
|
||||
$(HOSTCXXFLAGS_$(basetarget).o)
|
||||
_hostc_flags = $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
|
||||
$(HOSTCFLAGS_$(target-stem).o)
|
||||
_hostcxx_flags = $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
|
||||
$(HOSTCXXFLAGS_$(target-stem).o)
|
||||
|
||||
ifeq ($(KBUILD_SRC),)
|
||||
__hostc_flags = $(_hostc_flags)
|
||||
__hostcxx_flags = $(_hostcxx_flags)
|
||||
else
|
||||
__hostc_flags = -I$(obj) $(call flags,_hostc_flags)
|
||||
__hostcxx_flags = -I$(obj) $(call flags,_hostcxx_flags)
|
||||
# $(objtree)/$(obj) for including generated headers from checkin source files
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
ifdef building_out_of_srctree
|
||||
_hostc_flags += -I $(objtree)/$(obj)
|
||||
_hostcxx_flags += -I $(objtree)/$(obj)
|
||||
endif
|
||||
endif
|
||||
|
||||
hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags)
|
||||
hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags)
|
||||
hostc_flags = -Wp,-MD,$(depfile) $(_hostc_flags)
|
||||
hostcxx_flags = -Wp,-MD,$(depfile) $(_hostcxx_flags)
|
||||
|
||||
#####
|
||||
# Compile programs on the host
|
||||
@@ -85,17 +101,17 @@ hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags)
|
||||
# Create executable from a single .c file
|
||||
# host-csingle -> Executable
|
||||
quiet_cmd_host-csingle = HOSTCC $@
|
||||
cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
|
||||
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
|
||||
cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(KBUILD_HOSTLDFLAGS) -o $@ $< \
|
||||
$(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem))
|
||||
$(host-csingle): $(obj)/%: $(src)/%.c FORCE
|
||||
$(call if_changed_dep,host-csingle)
|
||||
|
||||
# Link an executable based on list of .o files, all plain c
|
||||
# host-cmulti -> executable
|
||||
quiet_cmd_host-cmulti = HOSTLD $@
|
||||
cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
|
||||
$(addprefix $(obj)/,$($(@F)-objs)) \
|
||||
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
|
||||
cmd_host-cmulti = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -o $@ \
|
||||
$(addprefix $(obj)/, $($(target-stem)-objs)) \
|
||||
$(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem))
|
||||
$(host-cmulti): FORCE
|
||||
$(call if_changed,host-cmulti)
|
||||
$(call multi_depend, $(host-cmulti), , -objs)
|
||||
@@ -110,10 +126,10 @@ $(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE
|
||||
# Link an executable based on list of .o files, a mixture of .c and .cc
|
||||
# host-cxxmulti -> executable
|
||||
quiet_cmd_host-cxxmulti = HOSTLD $@
|
||||
cmd_host-cxxmulti = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \
|
||||
cmd_host-cxxmulti = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -o $@ \
|
||||
$(foreach o,objs cxxobjs,\
|
||||
$(addprefix $(obj)/,$($(@F)-$(o)))) \
|
||||
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
|
||||
$(addprefix $(obj)/, $($(target-stem)-$(o)))) \
|
||||
$(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem))
|
||||
$(host-cxxmulti): FORCE
|
||||
$(call if_changed,host-cxxmulti)
|
||||
$(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs)
|
||||
@@ -124,5 +140,42 @@ quiet_cmd_host-cxxobjs = HOSTCXX $@
|
||||
$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
|
||||
$(call if_changed_dep,host-cxxobjs)
|
||||
|
||||
# Compile .c file, create position independent .o file
|
||||
# host-cshobjs -> .o
|
||||
quiet_cmd_host-cshobjs = HOSTCC -fPIC $@
|
||||
cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
|
||||
$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
|
||||
$(call if_changed_dep,host-cshobjs)
|
||||
|
||||
# Compile .c file, create position independent .o file
|
||||
# Note that plugin capable gcc versions can be either C or C++ based
|
||||
# therefore plugin source files have to be compilable in both C and C++ mode.
|
||||
# This is why a C++ compiler is invoked on a .c file.
|
||||
# host-cxxshobjs -> .o
|
||||
quiet_cmd_host-cxxshobjs = HOSTCXX -fPIC $@
|
||||
cmd_host-cxxshobjs = $(HOSTCXX) $(hostcxx_flags) -fPIC -c -o $@ $<
|
||||
$(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE
|
||||
$(call if_changed_dep,host-cxxshobjs)
|
||||
|
||||
# Link a shared library, based on position independent .o files
|
||||
# *.o -> .so shared library (host-cshlib)
|
||||
quiet_cmd_host-cshlib = HOSTLLD -shared $@
|
||||
cmd_host-cshlib = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -shared -o $@ \
|
||||
$(addprefix $(obj)/, $($(target-stem)-objs)) \
|
||||
$(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem).so)
|
||||
$(host-cshlib): FORCE
|
||||
$(call if_changed,host-cshlib)
|
||||
$(call multi_depend, $(host-cshlib), .so, -objs)
|
||||
|
||||
# Link a shared library, based on position independent .o files
|
||||
# *.o -> .so shared library (host-cxxshlib)
|
||||
quiet_cmd_host-cxxshlib = HOSTLLD -shared $@
|
||||
cmd_host-cxxshlib = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -shared -o $@ \
|
||||
$(addprefix $(obj)/, $($(target-stem)-objs)) \
|
||||
$(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem).so)
|
||||
$(host-cxxshlib): FORCE
|
||||
$(call if_changed,host-cxxshlib)
|
||||
$(call multi_depend, $(host-cxxshlib), .so, -objs)
|
||||
|
||||
targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\
|
||||
$(host-cxxmulti) $(host-cxxobjs)
|
||||
$(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) $(host-cxxshlib) $(host-cxxshobjs)
|
||||
@@ -4,8 +4,8 @@
|
||||
all:
|
||||
|
||||
# Xen doesn't have a silent build flag
|
||||
quiet := silent_
|
||||
Q := @
|
||||
quiet :=
|
||||
Q :=
|
||||
kecho := :
|
||||
|
||||
# eventually you'll want to do out of tree builds
|
||||
@@ -13,16 +13,44 @@ srctree := $(XEN_ROOT)/xen
|
||||
objtree := $(srctree)
|
||||
src := tools/kconfig
|
||||
obj := $(src)
|
||||
KBUILD_SRC :=
|
||||
|
||||
# handle functions (most of these lifted from different Linux makefiles
|
||||
dot-target = $(dir $@).$(notdir $@)
|
||||
depfile = $(subst $(comma),,$(dot-target).d)
|
||||
basetarget = $(basename $(notdir $@))
|
||||
# target with $(obj)/ and its suffix stripped
|
||||
target-stem = $(basename $(patsubst $(obj)/%,%,$@))
|
||||
cmd = $(cmd_$(1))
|
||||
if_changed = $(cmd_$(1))
|
||||
if_changed_dep = $(cmd_$(1))
|
||||
|
||||
###
|
||||
# filechk is used to check if the content of a generated file is updated.
|
||||
# Sample usage:
|
||||
#
|
||||
# filechk_sample = echo $(KERNELRELEASE)
|
||||
# version.h: FORCE
|
||||
# $(call filechk,sample)
|
||||
#
|
||||
# The rule defined shall write to stdout the content of the new file.
|
||||
# The existing file will be compared with the new one.
|
||||
# - If no file exist it is created
|
||||
# - If the content differ the new file is used
|
||||
# - If they are equal no change, and no timestamp update
|
||||
# - stdin is piped in from the first prerequisite ($<) so one has
|
||||
# to specify a valid file as first prerequisite (often the kbuild file)
|
||||
define filechk
|
||||
$(Q)set -e; \
|
||||
mkdir -p $(dir $@); \
|
||||
{ $(filechk_$(1)); } > $@.tmp; \
|
||||
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
|
||||
rm -f $@.tmp; \
|
||||
else \
|
||||
$(kecho) ' UPD $@'; \
|
||||
mv -f $@.tmp $@; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define multi_depend
|
||||
$(foreach m, $(notdir $1), \
|
||||
$(eval $(obj)/$m: \
|
||||
@@ -38,6 +66,8 @@ CONFIG_SHELL := $(SHELL)
|
||||
# provide the host compiler
|
||||
HOSTCC ?= gcc
|
||||
HOSTCXX ?= g++
|
||||
YACC = $(if $(BISON),$(BISON),bison)
|
||||
LEX = $(if $(FLEX),$(FLEX),flex)
|
||||
|
||||
# force target
|
||||
PHONY += FORCE
|
||||
@@ -48,6 +78,18 @@ FORCE:
|
||||
include $(src)/Makefile
|
||||
include $(src)/Makefile.host
|
||||
|
||||
# Add intermediate targets:
|
||||
# When building objects with specific suffix patterns, add intermediate
|
||||
# targets that the final targets are derived from.
|
||||
intermediate_targets = $(foreach sfx, $(2), \
|
||||
$(patsubst %$(strip $(1)),%$(sfx), \
|
||||
$(filter %$(strip $(1)), $(targets))))
|
||||
|
||||
# %.lex.o <- %.lex.c <- %.l
|
||||
# %.tab.o <- %.tab.[ch] <- %.y
|
||||
targets += $(call intermediate_targets, .lex.o, .lex.c) \
|
||||
$(call intermediate_targets, .tab.o, .tab.c .tab.h)
|
||||
|
||||
# clean up rule
|
||||
clean-deps = $(foreach f,$(host-cobjs) $(host-cxxobjs),$(dir $f).$(notdir $f).d)
|
||||
clean-shipped = $(patsubst %_shipped,%,$(wildcard $(obj)/*_shipped))
|
||||
@@ -59,4 +101,6 @@ clean:
|
||||
rm -rf $(clean-shipped)
|
||||
|
||||
$(obj)/zconf%: $(src)/zconf%_shipped
|
||||
@cp -f $< $@
|
||||
cp -f $< $@
|
||||
|
||||
.PHONY: $(PHONY)
|
||||
+84
-101
@@ -1,9 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -18,11 +19,10 @@
|
||||
|
||||
static void conf(struct menu *menu);
|
||||
static void check_conf(struct menu *menu);
|
||||
static void xfgets(char *str, int size, FILE *in);
|
||||
|
||||
enum input_mode {
|
||||
oldaskconfig,
|
||||
silentoldconfig,
|
||||
syncconfig,
|
||||
oldconfig,
|
||||
allnoconfig,
|
||||
allyesconfig,
|
||||
@@ -33,14 +33,14 @@ enum input_mode {
|
||||
savedefconfig,
|
||||
listnewconfig,
|
||||
olddefconfig,
|
||||
} input_mode = oldaskconfig;
|
||||
};
|
||||
static enum input_mode input_mode = oldaskconfig;
|
||||
|
||||
static int indent = 1;
|
||||
static int tty_stdio;
|
||||
static int valid_stdin = 1;
|
||||
static int sync_kconfig;
|
||||
static int conf_cnt;
|
||||
static char line[128];
|
||||
static char line[PATH_MAX];
|
||||
static struct menu *rootEntry;
|
||||
|
||||
static void print_help(struct menu *menu)
|
||||
@@ -70,14 +70,14 @@ static void strip(char *str)
|
||||
*p-- = 0;
|
||||
}
|
||||
|
||||
static void check_stdin(void)
|
||||
/* Helper function to facilitate fgets() by Jean Sacren. */
|
||||
static void xfgets(char *str, int size, FILE *in)
|
||||
{
|
||||
if (!valid_stdin) {
|
||||
printf("aborted!\n\n");
|
||||
printf("Console input/output is redirected. ");
|
||||
printf("Run 'make oldconfig' to update configuration.\n\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!fgets(str, size, in))
|
||||
fprintf(stderr, "\nError in reading or end of file.\n");
|
||||
|
||||
if (!tty_stdio)
|
||||
printf("%s", str);
|
||||
}
|
||||
|
||||
static int conf_askvalue(struct symbol *sym, const char *def)
|
||||
@@ -90,7 +90,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
|
||||
line[0] = '\n';
|
||||
line[1] = 0;
|
||||
|
||||
if (!sym_is_changable(sym)) {
|
||||
if (!sym_is_changeable(sym)) {
|
||||
printf("%s\n", def);
|
||||
line[0] = '\n';
|
||||
line[1] = 0;
|
||||
@@ -99,18 +99,15 @@ static int conf_askvalue(struct symbol *sym, const char *def)
|
||||
|
||||
switch (input_mode) {
|
||||
case oldconfig:
|
||||
case silentoldconfig:
|
||||
case syncconfig:
|
||||
if (sym_has_value(sym)) {
|
||||
printf("%s\n", def);
|
||||
return 0;
|
||||
}
|
||||
check_stdin();
|
||||
/* fall through */
|
||||
case oldaskconfig:
|
||||
fflush(stdout);
|
||||
xfgets(line, 128, stdin);
|
||||
if (!tty_stdio)
|
||||
printf("\n");
|
||||
xfgets(line, sizeof(line), stdin);
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
@@ -190,9 +187,7 @@ static int conf_sym(struct menu *menu)
|
||||
printf("/m");
|
||||
if (oldval != yes && sym_tristate_within_range(sym, yes))
|
||||
printf("/y");
|
||||
if (menu_has_help(menu))
|
||||
printf("/?");
|
||||
printf("] ");
|
||||
printf("/?] ");
|
||||
if (!conf_askvalue(sym, sym_get_string_value(sym)))
|
||||
return 0;
|
||||
strip(line);
|
||||
@@ -239,7 +234,7 @@ static int conf_choice(struct menu *menu)
|
||||
|
||||
sym = menu->sym;
|
||||
is_new = !sym_has_value(sym);
|
||||
if (sym_is_changable(sym)) {
|
||||
if (sym_is_changeable(sym)) {
|
||||
conf_sym(menu);
|
||||
sym_calc_value(sym);
|
||||
switch (sym_get_tristate_value(sym)) {
|
||||
@@ -294,23 +289,19 @@ static int conf_choice(struct menu *menu)
|
||||
printf("[1]: 1\n");
|
||||
goto conf_childs;
|
||||
}
|
||||
printf("[1-%d", cnt);
|
||||
if (menu_has_help(menu))
|
||||
printf("?");
|
||||
printf("]: ");
|
||||
printf("[1-%d?]: ", cnt);
|
||||
switch (input_mode) {
|
||||
case oldconfig:
|
||||
case silentoldconfig:
|
||||
case syncconfig:
|
||||
if (!is_new) {
|
||||
cnt = def;
|
||||
printf("%d\n", cnt);
|
||||
break;
|
||||
}
|
||||
check_stdin();
|
||||
/* fall through */
|
||||
case oldaskconfig:
|
||||
fflush(stdout);
|
||||
xfgets(line, 128, stdin);
|
||||
xfgets(line, sizeof(line), stdin);
|
||||
strip(line);
|
||||
if (line[0] == '?') {
|
||||
print_help(menu);
|
||||
@@ -366,10 +357,11 @@ static void conf(struct menu *menu)
|
||||
|
||||
switch (prop->type) {
|
||||
case P_MENU:
|
||||
if ((input_mode == silentoldconfig ||
|
||||
input_mode == listnewconfig ||
|
||||
input_mode == olddefconfig) &&
|
||||
rootEntry != menu) {
|
||||
/*
|
||||
* Except in oldaskconfig mode, we show only menus that
|
||||
* contain new symbols.
|
||||
*/
|
||||
if (input_mode != oldaskconfig && rootEntry != menu) {
|
||||
check_conf(menu);
|
||||
return;
|
||||
}
|
||||
@@ -426,13 +418,23 @@ static void check_conf(struct menu *menu)
|
||||
|
||||
sym = menu->sym;
|
||||
if (sym && !sym_has_value(sym)) {
|
||||
if (sym_is_changable(sym) ||
|
||||
if (sym_is_changeable(sym) ||
|
||||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
|
||||
if (input_mode == listnewconfig) {
|
||||
if (sym->name && !sym_is_choice_value(sym)) {
|
||||
printf("%s%s\n", CONFIG_, sym->name);
|
||||
if (sym->name) {
|
||||
const char *str;
|
||||
|
||||
if (sym->type == S_STRING) {
|
||||
str = sym_get_string_value(sym);
|
||||
str = sym_escape_string_value(str);
|
||||
printf("%s%s=%s\n", CONFIG_, sym->name, str);
|
||||
free((void *)str);
|
||||
} else {
|
||||
str = sym_get_string_value(sym);
|
||||
printf("%s%s=%s\n", CONFIG_, sym->name, str);
|
||||
}
|
||||
} else if (input_mode != olddefconfig) {
|
||||
}
|
||||
} else {
|
||||
if (!conf_cnt++)
|
||||
printf("*\n* Restart config...\n*\n");
|
||||
rootEntry = menu_get_parent_menu(menu);
|
||||
@@ -448,8 +450,8 @@ static void check_conf(struct menu *menu)
|
||||
static struct option long_opts[] = {
|
||||
{"oldaskconfig", no_argument, NULL, oldaskconfig},
|
||||
{"oldconfig", no_argument, NULL, oldconfig},
|
||||
{"silentoldconfig", no_argument, NULL, silentoldconfig},
|
||||
{"defconfig", optional_argument, NULL, defconfig},
|
||||
{"syncconfig", no_argument, NULL, syncconfig},
|
||||
{"defconfig", required_argument, NULL, defconfig},
|
||||
{"savedefconfig", required_argument, NULL, savedefconfig},
|
||||
{"allnoconfig", no_argument, NULL, allnoconfig},
|
||||
{"allyesconfig", no_argument, NULL, allyesconfig},
|
||||
@@ -458,12 +460,6 @@ static struct option long_opts[] = {
|
||||
{"randconfig", no_argument, NULL, randconfig},
|
||||
{"listnewconfig", no_argument, NULL, listnewconfig},
|
||||
{"olddefconfig", no_argument, NULL, olddefconfig},
|
||||
/*
|
||||
* oldnoconfig is an alias of olddefconfig, because people already
|
||||
* are dependent on its behavior(sets new symbols to their default
|
||||
* value but not 'n') with the counter-intuitive name.
|
||||
*/
|
||||
{"oldnoconfig", no_argument, NULL, olddefconfig},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
@@ -475,9 +471,9 @@ static void conf_usage(const char *progname)
|
||||
printf(" --listnewconfig List new options\n");
|
||||
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
|
||||
printf(" --oldconfig Update a configuration using a provided .config as base\n");
|
||||
printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n");
|
||||
printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n");
|
||||
printf(" --oldnoconfig An alias of olddefconfig\n");
|
||||
printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
|
||||
" include/{generated/,config/}\n");
|
||||
printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
|
||||
printf(" --defconfig <file> New config with default defined in <file>\n");
|
||||
printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
|
||||
printf(" --allnoconfig New config where all options are answered with no\n");
|
||||
@@ -492,9 +488,9 @@ int main(int ac, char **av)
|
||||
const char *progname = av[0];
|
||||
int opt;
|
||||
const char *name, *defconfig_file = NULL /* gcc uninit */;
|
||||
struct stat tmpstat;
|
||||
int no_conf_write = 0;
|
||||
|
||||
tty_stdio = isatty(0) && isatty(1) && isatty(2);
|
||||
tty_stdio = isatty(0) && isatty(1);
|
||||
|
||||
while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
|
||||
if (opt == 's') {
|
||||
@@ -503,7 +499,12 @@ int main(int ac, char **av)
|
||||
}
|
||||
input_mode = (enum input_mode)opt;
|
||||
switch (opt) {
|
||||
case silentoldconfig:
|
||||
case syncconfig:
|
||||
/*
|
||||
* syncconfig is invoked during the build stage.
|
||||
* Suppress distracting "configuration written to ..."
|
||||
*/
|
||||
conf_set_message_callback(NULL);
|
||||
sync_kconfig = 1;
|
||||
break;
|
||||
case defconfig:
|
||||
@@ -551,39 +552,27 @@ int main(int ac, char **av)
|
||||
}
|
||||
}
|
||||
if (ac == optind) {
|
||||
printf("%s: Kconfig file missing\n", av[0]);
|
||||
fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
|
||||
conf_usage(progname);
|
||||
exit(1);
|
||||
}
|
||||
name = av[optind];
|
||||
conf_parse(name);
|
||||
//zconfdump(stdout);
|
||||
if (sync_kconfig) {
|
||||
name = conf_get_configname();
|
||||
if (stat(name, &tmpstat)) {
|
||||
fprintf(stderr, "***\n"
|
||||
"*** Configuration file \"%s\" not found!\n"
|
||||
"***\n"
|
||||
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
|
||||
"*** \"make menuconfig\" or \"make xconfig\").\n"
|
||||
"***\n", name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
switch (input_mode) {
|
||||
case defconfig:
|
||||
if (!defconfig_file)
|
||||
defconfig_file = conf_get_default_confname();
|
||||
if (conf_read(defconfig_file)) {
|
||||
printf("***\n"
|
||||
fprintf(stderr,
|
||||
"***\n"
|
||||
"*** Can't find default configuration \"%s\"!\n"
|
||||
"***\n", defconfig_file);
|
||||
"***\n",
|
||||
defconfig_file);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case savedefconfig:
|
||||
case silentoldconfig:
|
||||
case syncconfig:
|
||||
case oldaskconfig:
|
||||
case oldconfig:
|
||||
case listnewconfig:
|
||||
@@ -628,15 +617,15 @@ int main(int ac, char **av)
|
||||
}
|
||||
|
||||
if (sync_kconfig) {
|
||||
if (conf_get_changed()) {
|
||||
name = getenv("KCONFIG_NOSILENTUPDATE");
|
||||
if (name && *name) {
|
||||
if (conf_get_changed()) {
|
||||
fprintf(stderr,
|
||||
"\n*** The configuration requires explicit update.\n\n");
|
||||
return 1;
|
||||
}
|
||||
no_conf_write = 1;
|
||||
}
|
||||
valid_stdin = tty_stdio;
|
||||
}
|
||||
|
||||
switch (input_mode) {
|
||||
@@ -664,54 +653,48 @@ int main(int ac, char **av)
|
||||
case oldaskconfig:
|
||||
rootEntry = &rootmenu;
|
||||
conf(&rootmenu);
|
||||
input_mode = silentoldconfig;
|
||||
input_mode = oldconfig;
|
||||
/* fall through */
|
||||
case oldconfig:
|
||||
case listnewconfig:
|
||||
case olddefconfig:
|
||||
case silentoldconfig:
|
||||
case syncconfig:
|
||||
/* Update until a loop caused no more changes */
|
||||
do {
|
||||
conf_cnt = 0;
|
||||
check_conf(&rootmenu);
|
||||
} while (conf_cnt &&
|
||||
(input_mode != listnewconfig &&
|
||||
input_mode != olddefconfig));
|
||||
} while (conf_cnt);
|
||||
break;
|
||||
case olddefconfig:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (sync_kconfig) {
|
||||
/* silentoldconfig is used during the build so we shall update autoconf.
|
||||
* All other commands are only used to generate a config.
|
||||
*/
|
||||
if (conf_get_changed() && conf_write(NULL)) {
|
||||
fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
|
||||
exit(1);
|
||||
}
|
||||
if (conf_write_autoconf()) {
|
||||
fprintf(stderr, "\n*** Error during update of the configuration.\n\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (input_mode == savedefconfig) {
|
||||
if (input_mode == savedefconfig) {
|
||||
if (conf_write_defconfig(defconfig_file)) {
|
||||
fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
|
||||
defconfig_file);
|
||||
return 1;
|
||||
}
|
||||
} else if (input_mode != listnewconfig) {
|
||||
if (conf_write(NULL)) {
|
||||
if (!no_conf_write && conf_write(NULL)) {
|
||||
fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create auto.conf if it does not exist.
|
||||
* This prevents GNU Make 4.1 or older from emitting
|
||||
* "include/config/auto.conf: No such file or directory"
|
||||
* in the top-level Makefile
|
||||
*
|
||||
* syncconfig always creates or updates auto.conf because it is
|
||||
* used during the build.
|
||||
*/
|
||||
if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
|
||||
fprintf(stderr,
|
||||
"\n*** Error during sync of the configuration.\n\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to facilitate fgets() by Jean Sacren.
|
||||
*/
|
||||
void xfgets(char *str, int size, FILE *in)
|
||||
{
|
||||
if (fgets(str, size, in) == NULL)
|
||||
fprintf(stderr, "\nError in reading or end of file.\n");
|
||||
}
|
||||
+302
-183
@@ -1,12 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -16,6 +18,151 @@
|
||||
|
||||
#include "lkc.h"
|
||||
|
||||
/* return true if 'path' exists, false otherwise */
|
||||
static bool is_present(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
return !stat(path, &st);
|
||||
}
|
||||
|
||||
/* return true if 'path' exists and it is a directory, false otherwise */
|
||||
static bool is_dir(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st))
|
||||
return 0;
|
||||
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
/* return true if the given two files are the same, false otherwise */
|
||||
static bool is_same(const char *file1, const char *file2)
|
||||
{
|
||||
int fd1, fd2;
|
||||
struct stat st1, st2;
|
||||
void *map1, *map2;
|
||||
bool ret = false;
|
||||
|
||||
fd1 = open(file1, O_RDONLY);
|
||||
if (fd1 < 0)
|
||||
return ret;
|
||||
|
||||
fd2 = open(file2, O_RDONLY);
|
||||
if (fd2 < 0)
|
||||
goto close1;
|
||||
|
||||
ret = fstat(fd1, &st1);
|
||||
if (ret)
|
||||
goto close2;
|
||||
ret = fstat(fd2, &st2);
|
||||
if (ret)
|
||||
goto close2;
|
||||
|
||||
if (st1.st_size != st2.st_size)
|
||||
goto close2;
|
||||
|
||||
map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
|
||||
if (map1 == MAP_FAILED)
|
||||
goto close2;
|
||||
|
||||
map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
|
||||
if (map2 == MAP_FAILED)
|
||||
goto close2;
|
||||
|
||||
if (bcmp(map1, map2, st1.st_size))
|
||||
goto close2;
|
||||
|
||||
ret = true;
|
||||
close2:
|
||||
close(fd2);
|
||||
close1:
|
||||
close(fd1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the parent directory of the given path.
|
||||
*
|
||||
* For example, if 'include/config/auto.conf' is given, create 'include/config'.
|
||||
*/
|
||||
static int make_parent_dir(const char *path)
|
||||
{
|
||||
char tmp[PATH_MAX + 1];
|
||||
char *p;
|
||||
|
||||
strncpy(tmp, path, sizeof(tmp));
|
||||
tmp[sizeof(tmp) - 1] = 0;
|
||||
|
||||
/* Remove the base name. Just return if nothing is left */
|
||||
p = strrchr(tmp, '/');
|
||||
if (!p)
|
||||
return 0;
|
||||
*(p + 1) = 0;
|
||||
|
||||
/* Just in case it is an absolute path */
|
||||
p = tmp;
|
||||
while (*p == '/')
|
||||
p++;
|
||||
|
||||
while ((p = strchr(p, '/'))) {
|
||||
*p = 0;
|
||||
|
||||
/* skip if the directory exists */
|
||||
if (!is_dir(tmp) && mkdir(tmp, 0755))
|
||||
return -1;
|
||||
|
||||
*p = '/';
|
||||
while (*p == '/')
|
||||
p++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char depfile_path[PATH_MAX];
|
||||
static size_t depfile_prefix_len;
|
||||
|
||||
/* touch depfile for symbol 'name' */
|
||||
static int conf_touch_dep(const char *name)
|
||||
{
|
||||
int fd, ret;
|
||||
const char *s;
|
||||
char *d, c;
|
||||
|
||||
/* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
|
||||
if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
|
||||
return -1;
|
||||
|
||||
d = depfile_path + depfile_prefix_len;
|
||||
s = name;
|
||||
|
||||
while ((c = *s++))
|
||||
*d++ = (c == '_') ? '/' : tolower(c);
|
||||
strcpy(d, ".h");
|
||||
|
||||
/* Assume directory path already exists. */
|
||||
fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
if (errno != ENOENT)
|
||||
return -1;
|
||||
|
||||
ret = make_parent_dir(depfile_path);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Try it again. */
|
||||
fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct conf_printer {
|
||||
void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
|
||||
void (*print_comment)(FILE *, const char *, void *);
|
||||
@@ -28,9 +175,7 @@ static void conf_message(const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
static const char *conf_filename;
|
||||
static int conf_lineno, conf_warnings, conf_unsaved;
|
||||
|
||||
const char conf_defname[] = "arch/$ARCH/defconfig";
|
||||
static int conf_lineno, conf_warnings;
|
||||
|
||||
static void conf_warning(const char *fmt, ...)
|
||||
{
|
||||
@@ -43,16 +188,16 @@ static void conf_warning(const char *fmt, ...)
|
||||
conf_warnings++;
|
||||
}
|
||||
|
||||
static void conf_default_message_callback(const char *fmt, va_list ap)
|
||||
static void conf_default_message_callback(const char *s)
|
||||
{
|
||||
printf("#\n# ");
|
||||
vprintf(fmt, ap);
|
||||
printf("%s", s);
|
||||
printf("\n#\n");
|
||||
}
|
||||
|
||||
static void (*conf_message_callback) (const char *fmt, va_list ap) =
|
||||
static void (*conf_message_callback)(const char *s) =
|
||||
conf_default_message_callback;
|
||||
void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
|
||||
void conf_set_message_callback(void (*fn)(const char *s))
|
||||
{
|
||||
conf_message_callback = fn;
|
||||
}
|
||||
@@ -60,10 +205,15 @@ void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
|
||||
static void conf_message(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[4096];
|
||||
|
||||
if (!conf_message_callback)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (conf_message_callback)
|
||||
conf_message_callback(fmt, ap);
|
||||
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
conf_message_callback(buf);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@@ -74,55 +224,13 @@ const char *conf_get_configname(void)
|
||||
return name ? name : ".config";
|
||||
}
|
||||
|
||||
const char *conf_get_autoconfig_name(void)
|
||||
static const char *conf_get_autoconfig_name(void)
|
||||
{
|
||||
char *name = getenv("KCONFIG_AUTOCONFIG");
|
||||
|
||||
return name ? name : "include/config/auto.conf";
|
||||
}
|
||||
|
||||
static char *conf_expand_value(const char *in)
|
||||
{
|
||||
struct symbol *sym;
|
||||
const char *src;
|
||||
static char res_value[SYMBOL_MAXLENGTH];
|
||||
char *dst, name[SYMBOL_MAXLENGTH];
|
||||
|
||||
res_value[0] = 0;
|
||||
dst = name;
|
||||
while ((src = strchr(in, '$'))) {
|
||||
strncat(res_value, in, src - in);
|
||||
src++;
|
||||
dst = name;
|
||||
while (isalnum(*src) || *src == '_')
|
||||
*dst++ = *src++;
|
||||
*dst = 0;
|
||||
sym = sym_lookup(name, 0);
|
||||
sym_calc_value(sym);
|
||||
strcat(res_value, sym_get_string_value(sym));
|
||||
in = src;
|
||||
}
|
||||
strcat(res_value, in);
|
||||
|
||||
return res_value;
|
||||
}
|
||||
|
||||
char *conf_get_default_confname(void)
|
||||
{
|
||||
struct stat buf;
|
||||
static char fullname[PATH_MAX+1];
|
||||
char *env, *name;
|
||||
|
||||
name = conf_expand_value(conf_defname);
|
||||
env = getenv(SRCTREE);
|
||||
if (env) {
|
||||
sprintf(fullname, "%s/%s", env, name);
|
||||
if (!stat(fullname, &buf))
|
||||
return fullname;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
|
||||
{
|
||||
char *p2;
|
||||
@@ -150,14 +258,6 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
|
||||
conf_warning("symbol value '%s' invalid for %s",
|
||||
p, sym->name);
|
||||
return 1;
|
||||
case S_OTHER:
|
||||
if (*p != '"') {
|
||||
for (p2 = p; *p2 && !isspace(*p2); p2++)
|
||||
;
|
||||
sym->type = S_STRING;
|
||||
goto done;
|
||||
}
|
||||
/* fall through */
|
||||
case S_STRING:
|
||||
if (*p++ != '"')
|
||||
break;
|
||||
@@ -176,9 +276,8 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
|
||||
/* fall through */
|
||||
case S_INT:
|
||||
case S_HEX:
|
||||
done:
|
||||
if (sym_string_valid(sym, p)) {
|
||||
sym->def[def].val = strdup(p);
|
||||
sym->def[def].val = xstrdup(p);
|
||||
sym->flags |= def_flags;
|
||||
} else {
|
||||
if (def != S_DEF_AUTO)
|
||||
@@ -201,7 +300,7 @@ static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
|
||||
if (new_size > *n) {
|
||||
new_size += LINE_GROWTH - 1;
|
||||
new_size *= 2;
|
||||
nline = realloc(*lineptr, new_size);
|
||||
nline = xrealloc(*lineptr, new_size);
|
||||
if (!nline)
|
||||
return -1;
|
||||
|
||||
@@ -267,16 +366,15 @@ int conf_read_simple(const char *name, int def)
|
||||
if (in)
|
||||
goto load;
|
||||
sym_add_change_count(1);
|
||||
if (!sym_defconfig_list) {
|
||||
sym_calc_value(modules_sym);
|
||||
if (!sym_defconfig_list)
|
||||
return 1;
|
||||
}
|
||||
|
||||
for_all_defaults(sym_defconfig_list, prop) {
|
||||
if (expr_calc_value(prop->visible.expr) == no ||
|
||||
prop->expr->type != E_SYMBOL)
|
||||
continue;
|
||||
name = conf_expand_value(prop->expr->left.sym->name);
|
||||
sym_calc_value(prop->expr->left.sym);
|
||||
name = sym_get_string_value(prop->expr->left.sym);
|
||||
in = zconf_fopen(name);
|
||||
if (in) {
|
||||
conf_message("using defaults found in %s",
|
||||
@@ -292,7 +390,6 @@ load:
|
||||
conf_filename = name;
|
||||
conf_lineno = 0;
|
||||
conf_warnings = 0;
|
||||
conf_unsaved = 0;
|
||||
|
||||
def_flags = SYMBOL_DEF << def;
|
||||
for_all_symbols(i, sym) {
|
||||
@@ -329,7 +426,7 @@ load:
|
||||
sym = sym_find(line + 2 + strlen(CONFIG_));
|
||||
if (!sym) {
|
||||
sym_add_change_count(1);
|
||||
goto setsym;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
|
||||
@@ -359,17 +456,22 @@ load:
|
||||
if (*p2 == '\r')
|
||||
*p2 = 0;
|
||||
}
|
||||
if (def == S_DEF_USER) {
|
||||
|
||||
sym = sym_find(line + strlen(CONFIG_));
|
||||
if (!sym) {
|
||||
if (def == S_DEF_AUTO)
|
||||
/*
|
||||
* Reading from include/config/auto.conf
|
||||
* If CONFIG_FOO previously existed in
|
||||
* auto.conf but it is missing now,
|
||||
* include/config/foo.h must be touched.
|
||||
*/
|
||||
conf_touch_dep(line + strlen(CONFIG_));
|
||||
else
|
||||
sym_add_change_count(1);
|
||||
goto setsym;
|
||||
}
|
||||
} else {
|
||||
sym = sym_lookup(line + strlen(CONFIG_), 0);
|
||||
if (sym->type == S_UNKNOWN)
|
||||
sym->type = S_OTHER;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sym->flags & def_flags) {
|
||||
conf_warning("override: reassigning to symbol %s", sym->name);
|
||||
}
|
||||
@@ -377,10 +479,12 @@ load:
|
||||
continue;
|
||||
} else {
|
||||
if (line[0] != '\r' && line[0] != '\n')
|
||||
conf_warning("unexpected data");
|
||||
conf_warning("unexpected data: %.*s",
|
||||
(int)strcspn(line, "\r\n"), line);
|
||||
|
||||
continue;
|
||||
}
|
||||
setsym:
|
||||
|
||||
if (sym && sym_is_choice_value(sym)) {
|
||||
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
|
||||
switch (sym->def[def].tri) {
|
||||
@@ -403,34 +507,36 @@ setsym:
|
||||
}
|
||||
free(line);
|
||||
fclose(in);
|
||||
sym_calc_value(modules_sym);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_read(const char *name)
|
||||
{
|
||||
struct symbol *sym;
|
||||
int conf_unsaved = 0;
|
||||
int i;
|
||||
|
||||
sym_set_change_count(0);
|
||||
|
||||
if (conf_read_simple(name, S_DEF_USER))
|
||||
if (conf_read_simple(name, S_DEF_USER)) {
|
||||
sym_calc_value(modules_sym);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sym_calc_value(modules_sym);
|
||||
|
||||
for_all_symbols(i, sym) {
|
||||
sym_calc_value(sym);
|
||||
if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
|
||||
if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
|
||||
continue;
|
||||
if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
|
||||
/* check that calculated value agrees with saved value */
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
|
||||
break;
|
||||
if (!sym_is_choice(sym))
|
||||
if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
|
||||
continue;
|
||||
/* fall through */
|
||||
break;
|
||||
default:
|
||||
if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
|
||||
continue;
|
||||
@@ -629,7 +735,6 @@ static void conf_write_symbol(FILE *fp, struct symbol *sym,
|
||||
const char *str;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_OTHER:
|
||||
case S_UNKNOWN:
|
||||
break;
|
||||
case S_STRING:
|
||||
@@ -689,7 +794,7 @@ int conf_write_defconfig(const char *filename)
|
||||
goto next_menu;
|
||||
sym->flags &= ~SYMBOL_WRITE;
|
||||
/* If we cannot change the symbol - skip */
|
||||
if (!sym_is_changable(sym))
|
||||
if (!sym_is_changeable(sym))
|
||||
goto next_menu;
|
||||
/* If symbol equals to default value - skip */
|
||||
if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
|
||||
@@ -740,41 +845,36 @@ int conf_write(const char *name)
|
||||
FILE *out;
|
||||
struct symbol *sym;
|
||||
struct menu *menu;
|
||||
const char *basename;
|
||||
const char *str;
|
||||
char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
|
||||
char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
|
||||
char *env;
|
||||
int i;
|
||||
bool need_newline = false;
|
||||
|
||||
dirname[0] = 0;
|
||||
if (name && name[0]) {
|
||||
struct stat st;
|
||||
char *slash;
|
||||
if (!name)
|
||||
name = conf_get_configname();
|
||||
|
||||
if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
|
||||
strcpy(dirname, name);
|
||||
strcat(dirname, "/");
|
||||
basename = conf_get_configname();
|
||||
} else if ((slash = strrchr(name, '/'))) {
|
||||
int size = slash - name + 1;
|
||||
memcpy(dirname, name, size);
|
||||
dirname[size] = 0;
|
||||
if (slash[1])
|
||||
basename = slash + 1;
|
||||
else
|
||||
basename = conf_get_configname();
|
||||
} else
|
||||
basename = name;
|
||||
} else
|
||||
basename = conf_get_configname();
|
||||
if (!*name) {
|
||||
fprintf(stderr, "config name is empty\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_dir(name)) {
|
||||
fprintf(stderr, "%s: Is a directory\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (make_parent_dir(name))
|
||||
return -1;
|
||||
|
||||
sprintf(newname, "%s%s", dirname, basename);
|
||||
env = getenv("KCONFIG_OVERWRITECONFIG");
|
||||
if (!env || !*env) {
|
||||
sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
|
||||
out = fopen(tmpname, "w");
|
||||
} else {
|
||||
if (env && *env) {
|
||||
*tmpname = 0;
|
||||
out = fopen(newname, "w");
|
||||
out = fopen(name, "w");
|
||||
} else {
|
||||
snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
|
||||
name, (int)getpid());
|
||||
out = fopen(tmpname, "w");
|
||||
}
|
||||
if (!out)
|
||||
return 1;
|
||||
@@ -795,12 +895,17 @@ int conf_write(const char *name)
|
||||
"#\n"
|
||||
"# %s\n"
|
||||
"#\n", str);
|
||||
} else if (!(sym->flags & SYMBOL_CHOICE)) {
|
||||
need_newline = false;
|
||||
} else if (!(sym->flags & SYMBOL_CHOICE) &&
|
||||
!(sym->flags & SYMBOL_WRITTEN)) {
|
||||
sym_calc_value(sym);
|
||||
if (!(sym->flags & SYMBOL_WRITE))
|
||||
goto next;
|
||||
sym->flags &= ~SYMBOL_WRITE;
|
||||
|
||||
if (need_newline) {
|
||||
fprintf(out, "\n");
|
||||
need_newline = false;
|
||||
}
|
||||
sym->flags |= SYMBOL_WRITTEN;
|
||||
conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
|
||||
}
|
||||
|
||||
@@ -812,6 +917,12 @@ next:
|
||||
if (menu->next)
|
||||
menu = menu->next;
|
||||
else while ((menu = menu->parent)) {
|
||||
if (!menu->sym && menu_is_visible(menu) &&
|
||||
menu != &rootmenu) {
|
||||
str = menu_get_prompt(menu);
|
||||
fprintf(out, "# end of %s\n", str);
|
||||
need_newline = true;
|
||||
}
|
||||
if (menu->next) {
|
||||
menu = menu->next;
|
||||
break;
|
||||
@@ -820,40 +931,76 @@ next:
|
||||
}
|
||||
fclose(out);
|
||||
|
||||
for_all_symbols(i, sym)
|
||||
sym->flags &= ~SYMBOL_WRITTEN;
|
||||
|
||||
if (*tmpname) {
|
||||
strcat(dirname, basename);
|
||||
strcat(dirname, ".old");
|
||||
rename(newname, dirname);
|
||||
if (rename(tmpname, newname))
|
||||
if (is_same(name, tmpname)) {
|
||||
conf_message("No change to %s", name);
|
||||
unlink(tmpname);
|
||||
sym_set_change_count(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(oldname, sizeof(oldname), "%s.old", name);
|
||||
rename(name, oldname);
|
||||
if (rename(tmpname, name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
conf_message("configuration written to %s", newname);
|
||||
conf_message("configuration written to %s", name);
|
||||
|
||||
sym_set_change_count(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int conf_split_config(void)
|
||||
/* write a dependency file as used by kbuild to track dependencies */
|
||||
static int conf_write_dep(const char *name)
|
||||
{
|
||||
struct file *file;
|
||||
FILE *out;
|
||||
|
||||
out = fopen("..config.tmp", "w");
|
||||
if (!out)
|
||||
return 1;
|
||||
fprintf(out, "deps_config := \\\n");
|
||||
for (file = file_list; file; file = file->next) {
|
||||
if (file->next)
|
||||
fprintf(out, "\t%s \\\n", file->name);
|
||||
else
|
||||
fprintf(out, "\t%s\n", file->name);
|
||||
}
|
||||
fprintf(out, "\n%s: \\\n"
|
||||
"\t$(deps_config)\n\n", conf_get_autoconfig_name());
|
||||
|
||||
env_write_dep(out, conf_get_autoconfig_name());
|
||||
|
||||
fprintf(out, "\n$(deps_config): ;\n");
|
||||
fclose(out);
|
||||
|
||||
if (make_parent_dir(name))
|
||||
return 1;
|
||||
rename("..config.tmp", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int conf_touch_deps(void)
|
||||
{
|
||||
const char *name;
|
||||
char path[PATH_MAX+1];
|
||||
char *s, *d, c;
|
||||
struct symbol *sym;
|
||||
struct stat sb;
|
||||
int res, i, fd;
|
||||
int res, i;
|
||||
|
||||
strcpy(depfile_path, "include/config/");
|
||||
depfile_prefix_len = strlen(depfile_path);
|
||||
|
||||
name = conf_get_autoconfig_name();
|
||||
conf_read_simple(name, S_DEF_AUTO);
|
||||
sym_calc_value(modules_sym);
|
||||
|
||||
if (chdir("include/config"))
|
||||
return 1;
|
||||
|
||||
res = 0;
|
||||
for_all_symbols(i, sym) {
|
||||
sym_calc_value(sym);
|
||||
if ((sym->flags & SYMBOL_AUTO) || !sym->name)
|
||||
if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
|
||||
continue;
|
||||
if (sym->flags & SYMBOL_WRITE) {
|
||||
if (sym->flags & SYMBOL_DEF_AUTO) {
|
||||
@@ -902,63 +1049,28 @@ static int conf_split_config(void)
|
||||
* different from 'no').
|
||||
*/
|
||||
|
||||
/* Replace all '_' and append ".h" */
|
||||
s = sym->name;
|
||||
d = path;
|
||||
while ((c = *s++)) {
|
||||
c = tolower(c);
|
||||
*d++ = (c == '_') ? '/' : c;
|
||||
}
|
||||
strcpy(d, ".h");
|
||||
|
||||
/* Assume directory path already exists. */
|
||||
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
if (errno != ENOENT) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Create directory components,
|
||||
* unless they exist already.
|
||||
*/
|
||||
d = path;
|
||||
while ((d = strchr(d, '/'))) {
|
||||
*d = 0;
|
||||
if (stat(path, &sb) && mkdir(path, 0755)) {
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
*d++ = '/';
|
||||
}
|
||||
/* Try it again. */
|
||||
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
out:
|
||||
if (chdir("../.."))
|
||||
return 1;
|
||||
|
||||
res = conf_touch_dep(sym->name);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
int conf_write_autoconf(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_write_autoconf(int overwrite)
|
||||
{
|
||||
struct symbol *sym;
|
||||
const char *name;
|
||||
const char *autoconf_name = conf_get_autoconfig_name();
|
||||
FILE *out, *tristate, *out_h;
|
||||
int i;
|
||||
|
||||
sym_clear_all_valid();
|
||||
if (!overwrite && is_present(autoconf_name))
|
||||
return 0;
|
||||
|
||||
file_write_dep("include/config/auto.conf.cmd");
|
||||
conf_write_dep("include/config/auto.conf.cmd");
|
||||
|
||||
if (conf_split_config())
|
||||
if (conf_touch_deps())
|
||||
return 1;
|
||||
|
||||
out = fopen(".tmpconfig", "w");
|
||||
@@ -1003,19 +1115,26 @@ int conf_write_autoconf(void)
|
||||
name = getenv("KCONFIG_AUTOHEADER");
|
||||
if (!name)
|
||||
name = "include/generated/autoconf.h";
|
||||
if (make_parent_dir(name))
|
||||
return 1;
|
||||
if (rename(".tmpconfig.h", name))
|
||||
return 1;
|
||||
|
||||
name = getenv("KCONFIG_TRISTATE");
|
||||
if (!name)
|
||||
name = "include/config/tristate.conf";
|
||||
if (make_parent_dir(name))
|
||||
return 1;
|
||||
if (rename(".tmpconfig_tristate", name))
|
||||
return 1;
|
||||
name = conf_get_autoconfig_name();
|
||||
|
||||
if (make_parent_dir(autoconf_name))
|
||||
return 1;
|
||||
/*
|
||||
* This must be the last step, kbuild has a dependency on auto.conf
|
||||
* and this marks the successful completion of the previous steps.
|
||||
*/
|
||||
if (rename(".tmpconfig", name))
|
||||
if (rename(".tmpconfig", autoconf_name))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -1119,7 +1238,7 @@ void set_all_choice_values(struct symbol *csym)
|
||||
bool conf_set_all_new_symbols(enum conf_def_mode mode)
|
||||
{
|
||||
struct symbol *sym, *csym;
|
||||
int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y
|
||||
int i, cnt, pby, pty, ptm; /* pby: probability of bool = y
|
||||
* pty: probability of tristate = y
|
||||
* ptm: probability of tristate = m
|
||||
*/
|
||||
|
||||
+152
-61
@@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -94,7 +96,7 @@ struct expr *expr_copy(const struct expr *org)
|
||||
e->right.expr = expr_copy(org->right.expr);
|
||||
break;
|
||||
default:
|
||||
printf("can't copy type %d\n", e->type);
|
||||
fprintf(stderr, "can't copy type %d\n", e->type);
|
||||
free(e);
|
||||
e = NULL;
|
||||
break;
|
||||
@@ -113,7 +115,7 @@ void expr_free(struct expr *e)
|
||||
break;
|
||||
case E_NOT:
|
||||
expr_free(e->left.expr);
|
||||
return;
|
||||
break;
|
||||
case E_EQUAL:
|
||||
case E_GEQ:
|
||||
case E_GTH:
|
||||
@@ -127,7 +129,7 @@ void expr_free(struct expr *e)
|
||||
expr_free(e->right.expr);
|
||||
break;
|
||||
default:
|
||||
printf("how to free type %d?\n", e->type);
|
||||
fprintf(stderr, "how to free type %d?\n", e->type);
|
||||
break;
|
||||
}
|
||||
free(e);
|
||||
@@ -138,8 +140,18 @@ static int trans_count;
|
||||
#define e1 (*ep1)
|
||||
#define e2 (*ep2)
|
||||
|
||||
/*
|
||||
* expr_eliminate_eq() helper.
|
||||
*
|
||||
* Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does
|
||||
* not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
|
||||
* against all other leaves. Two equal leaves are both replaced with either 'y'
|
||||
* or 'n' as appropriate for 'type', to be eliminated later.
|
||||
*/
|
||||
static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
|
||||
{
|
||||
/* Recurse down to leaves */
|
||||
|
||||
if (e1->type == type) {
|
||||
__expr_eliminate_eq(type, &e1->left.expr, &e2);
|
||||
__expr_eliminate_eq(type, &e1->right.expr, &e2);
|
||||
@@ -150,12 +162,18 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
|
||||
__expr_eliminate_eq(type, &e1, &e2->right.expr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* e1 and e2 are leaves. Compare them. */
|
||||
|
||||
if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
|
||||
e1->left.sym == e2->left.sym &&
|
||||
(e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
|
||||
return;
|
||||
if (!expr_eq(e1, e2))
|
||||
return;
|
||||
|
||||
/* e1 and e2 are equal leaves. Prepare them for elimination. */
|
||||
|
||||
trans_count++;
|
||||
expr_free(e1); expr_free(e2);
|
||||
switch (type) {
|
||||
@@ -172,6 +190,35 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewrites the expressions 'ep1' and 'ep2' to remove operands common to both.
|
||||
* Example reductions:
|
||||
*
|
||||
* ep1: A && B -> ep1: y
|
||||
* ep2: A && B && C -> ep2: C
|
||||
*
|
||||
* ep1: A || B -> ep1: n
|
||||
* ep2: A || B || C -> ep2: C
|
||||
*
|
||||
* ep1: A && (B && FOO) -> ep1: FOO
|
||||
* ep2: (BAR && B) && A -> ep2: BAR
|
||||
*
|
||||
* ep1: A && (B || C) -> ep1: y
|
||||
* ep2: (C || B) && A -> ep2: y
|
||||
*
|
||||
* Comparisons are done between all operands at the same "level" of && or ||.
|
||||
* For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the
|
||||
* following operands will be compared:
|
||||
*
|
||||
* - 'e1', 'e2 || e3', and 'e4 || e5', against each other
|
||||
* - e2 against e3
|
||||
* - e4 against e5
|
||||
*
|
||||
* Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and
|
||||
* '(e1 && e2) && e3' are both a single level.
|
||||
*
|
||||
* See __expr_eliminate_eq() as well.
|
||||
*/
|
||||
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
|
||||
{
|
||||
if (!e1 || !e2)
|
||||
@@ -197,6 +244,12 @@ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
|
||||
#undef e1
|
||||
#undef e2
|
||||
|
||||
/*
|
||||
* Returns true if 'e1' and 'e2' are equal, after minor simplification. Two
|
||||
* &&/|| expressions are considered equal if every operand in one expression
|
||||
* equals some operand in the other (operands do not need to appear in the same
|
||||
* order), recursively.
|
||||
*/
|
||||
static int expr_eq(struct expr *e1, struct expr *e2)
|
||||
{
|
||||
int res, old_count;
|
||||
@@ -243,6 +296,17 @@ static int expr_eq(struct expr *e1, struct expr *e2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursively performs the following simplifications in-place (as well as the
|
||||
* corresponding simplifications with swapped operands):
|
||||
*
|
||||
* expr && n -> n
|
||||
* expr && y -> expr
|
||||
* expr || n -> expr
|
||||
* expr || y -> y
|
||||
*
|
||||
* Returns the optimized expression.
|
||||
*/
|
||||
static struct expr *expr_eliminate_yn(struct expr *e)
|
||||
{
|
||||
struct expr *tmp;
|
||||
@@ -516,12 +580,21 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* expr_eliminate_dups() helper.
|
||||
*
|
||||
* Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does
|
||||
* not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
|
||||
* against all other leaves to look for simplifications.
|
||||
*/
|
||||
static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
|
||||
{
|
||||
#define e1 (*ep1)
|
||||
#define e2 (*ep2)
|
||||
struct expr *tmp;
|
||||
|
||||
/* Recurse down to leaves */
|
||||
|
||||
if (e1->type == type) {
|
||||
expr_eliminate_dups1(type, &e1->left.expr, &e2);
|
||||
expr_eliminate_dups1(type, &e1->right.expr, &e2);
|
||||
@@ -532,6 +605,9 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct
|
||||
expr_eliminate_dups1(type, &e1, &e2->right.expr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* e1 and e2 are leaves. Compare and process them. */
|
||||
|
||||
if (e1 == e2)
|
||||
return;
|
||||
|
||||
@@ -568,6 +644,17 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct
|
||||
#undef e2
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewrites 'e' in-place to remove ("join") duplicate and other redundant
|
||||
* operands.
|
||||
*
|
||||
* Example simplifications:
|
||||
*
|
||||
* A || B || A -> A || B
|
||||
* A && B && A=y -> A=y && B
|
||||
*
|
||||
* Returns the deduplicated expression.
|
||||
*/
|
||||
struct expr *expr_eliminate_dups(struct expr *e)
|
||||
{
|
||||
int oldcount;
|
||||
@@ -584,6 +671,7 @@ struct expr *expr_eliminate_dups(struct expr *e)
|
||||
;
|
||||
}
|
||||
if (!trans_count)
|
||||
/* No simplifications done in this pass. We're done */
|
||||
break;
|
||||
e = expr_eliminate_yn(e);
|
||||
}
|
||||
@@ -591,6 +679,12 @@ struct expr *expr_eliminate_dups(struct expr *e)
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs various simplifications involving logical operators and
|
||||
* comparisons.
|
||||
*
|
||||
* Allocates and returns a new expression.
|
||||
*/
|
||||
struct expr *expr_transform(struct expr *e)
|
||||
{
|
||||
struct expr *tmp;
|
||||
@@ -805,6 +899,20 @@ bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserts explicit comparisons of type 'type' to symbol 'sym' into the
|
||||
* expression 'e'.
|
||||
*
|
||||
* Examples transformations for type == E_UNEQUAL, sym == &symbol_no:
|
||||
*
|
||||
* A -> A!=n
|
||||
* !A -> A=n
|
||||
* A && B -> !(A=n || B=n)
|
||||
* A || B -> !(A=n && B=n)
|
||||
* A && (B || C) -> !(A=n || (B=n && C=n))
|
||||
*
|
||||
* Allocates and returns a new expression.
|
||||
*/
|
||||
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
|
||||
{
|
||||
struct expr *e1, *e2;
|
||||
@@ -874,7 +982,6 @@ enum string_value_kind {
|
||||
k_string,
|
||||
k_signed,
|
||||
k_unsigned,
|
||||
k_invalid
|
||||
};
|
||||
|
||||
union string_value {
|
||||
@@ -893,7 +1000,10 @@ static enum string_value_kind expr_parse_string(const char *str,
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
return k_string;
|
||||
val->s = !strcmp(str, "n") ? 0 :
|
||||
!strcmp(str, "m") ? 1 :
|
||||
!strcmp(str, "y") ? 2 : -1;
|
||||
return k_signed;
|
||||
case S_INT:
|
||||
val->s = strtoll(str, &tail, 10);
|
||||
kind = k_signed;
|
||||
@@ -902,13 +1012,10 @@ static enum string_value_kind expr_parse_string(const char *str,
|
||||
val->u = strtoull(str, &tail, 16);
|
||||
kind = k_unsigned;
|
||||
break;
|
||||
case S_STRING:
|
||||
case S_UNKNOWN:
|
||||
default:
|
||||
val->s = strtoll(str, &tail, 0);
|
||||
kind = k_signed;
|
||||
break;
|
||||
default:
|
||||
return k_invalid;
|
||||
}
|
||||
return !errno && !*tail && tail > str && isxdigit(tail[-1])
|
||||
? kind : k_string;
|
||||
@@ -964,13 +1071,7 @@ tristate expr_calc_value(struct expr *e)
|
||||
|
||||
if (k1 == k_string || k2 == k_string)
|
||||
res = strcmp(str1, str2);
|
||||
else if (k1 == k_invalid || k2 == k_invalid) {
|
||||
if (e->type != E_EQUAL && e->type != E_UNEQUAL) {
|
||||
printf("Cannot compare \"%s\" and \"%s\"\n", str1, str2);
|
||||
return no;
|
||||
}
|
||||
res = strcmp(str1, str2);
|
||||
} else if (k1 == k_unsigned || k2 == k_unsigned)
|
||||
else if (k1 == k_unsigned || k2 == k_unsigned)
|
||||
res = (lval.u > rval.u) - (lval.u < rval.u);
|
||||
else /* if (k1 == k_signed && k2 == k_signed) */
|
||||
res = (lval.s > rval.s) - (lval.s < rval.s);
|
||||
@@ -1028,49 +1129,9 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct expr *
|
||||
expr_get_leftmost_symbol(const struct expr *e)
|
||||
{
|
||||
|
||||
if (e == NULL)
|
||||
return NULL;
|
||||
|
||||
while (e->type != E_SYMBOL)
|
||||
e = e->left.expr;
|
||||
|
||||
return expr_copy(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given expression `e1' and `e2', returns the leaf of the longest
|
||||
* sub-expression of `e1' not containing 'e2.
|
||||
*/
|
||||
struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
|
||||
{
|
||||
struct expr *ret;
|
||||
|
||||
switch (e1->type) {
|
||||
case E_OR:
|
||||
return expr_alloc_and(
|
||||
expr_simplify_unmet_dep(e1->left.expr, e2),
|
||||
expr_simplify_unmet_dep(e1->right.expr, e2));
|
||||
case E_AND: {
|
||||
struct expr *e;
|
||||
e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
|
||||
e = expr_eliminate_dups(e);
|
||||
ret = (!expr_eq(e, e1)) ? e1 : NULL;
|
||||
expr_free(e);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = e1;
|
||||
break;
|
||||
}
|
||||
|
||||
return expr_get_leftmost_symbol(ret);
|
||||
}
|
||||
|
||||
void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
|
||||
void expr_print(struct expr *e,
|
||||
void (*fn)(void *, struct symbol *, const char *),
|
||||
void *data, int prevtoken)
|
||||
{
|
||||
if (!e) {
|
||||
fn(data, NULL, "y");
|
||||
@@ -1113,7 +1174,7 @@ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *
|
||||
fn(data, e->left.sym, e->left.sym->name);
|
||||
else
|
||||
fn(data, NULL, "<choice>");
|
||||
fn(data, NULL, e->type == E_LEQ ? ">=" : ">");
|
||||
fn(data, NULL, e->type == E_GEQ ? ">=" : ">");
|
||||
fn(data, e->right.sym, e->right.sym->name);
|
||||
break;
|
||||
case E_UNEQUAL:
|
||||
@@ -1204,3 +1265,33 @@ void expr_gstr_print(struct expr *e, struct gstr *gs)
|
||||
{
|
||||
expr_print(e, expr_print_gstr_helper, gs, E_NONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform the top level "||" tokens into newlines and prepend each
|
||||
* line with a minus. This makes expressions much easier to read.
|
||||
* Suitable for reverse dependency expressions.
|
||||
*/
|
||||
static void expr_print_revdep(struct expr *e,
|
||||
void (*fn)(void *, struct symbol *, const char *),
|
||||
void *data, tristate pr_type, const char **title)
|
||||
{
|
||||
if (e->type == E_OR) {
|
||||
expr_print_revdep(e->left.expr, fn, data, pr_type, title);
|
||||
expr_print_revdep(e->right.expr, fn, data, pr_type, title);
|
||||
} else if (expr_calc_value(e) == pr_type) {
|
||||
if (*title) {
|
||||
fn(data, NULL, *title);
|
||||
*title = NULL;
|
||||
}
|
||||
|
||||
fn(data, NULL, " - ");
|
||||
expr_print(e, fn, data, E_NONE);
|
||||
fn(data, NULL, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
|
||||
tristate pr_type, const char *title)
|
||||
{
|
||||
expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title);
|
||||
}
|
||||
+101
-7
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#ifndef EXPR_H
|
||||
@@ -62,7 +62,7 @@ struct symbol_value {
|
||||
};
|
||||
|
||||
enum symbol_type {
|
||||
S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
|
||||
S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING
|
||||
};
|
||||
|
||||
/* enum values are used as index to symbol.def[] */
|
||||
@@ -74,20 +74,64 @@ enum {
|
||||
S_DEF_COUNT
|
||||
};
|
||||
|
||||
/*
|
||||
* Represents a configuration symbol.
|
||||
*
|
||||
* Choices are represented as a special kind of symbol and have the
|
||||
* SYMBOL_CHOICE bit set in 'flags'.
|
||||
*/
|
||||
struct symbol {
|
||||
/* The next symbol in the same bucket in the symbol hash table */
|
||||
struct symbol *next;
|
||||
|
||||
/* The name of the symbol, e.g. "FOO" for 'config FOO' */
|
||||
char *name;
|
||||
|
||||
/* S_BOOLEAN, S_TRISTATE, ... */
|
||||
enum symbol_type type;
|
||||
|
||||
/*
|
||||
* The calculated value of the symbol. The SYMBOL_VALID bit is set in
|
||||
* 'flags' when this is up to date. Note that this value might differ
|
||||
* from the user value set in e.g. a .config file, due to visibility.
|
||||
*/
|
||||
struct symbol_value curr;
|
||||
|
||||
/*
|
||||
* Values for the symbol provided from outside. def[S_DEF_USER] holds
|
||||
* the .config value.
|
||||
*/
|
||||
struct symbol_value def[S_DEF_COUNT];
|
||||
|
||||
/*
|
||||
* An upper bound on the tristate value the user can set for the symbol
|
||||
* if it is a boolean or tristate. Calculated from prompt dependencies,
|
||||
* which also inherit dependencies from enclosing menus, choices, and
|
||||
* ifs. If 'n', the user value will be ignored.
|
||||
*
|
||||
* Symbols lacking prompts always have visibility 'n'.
|
||||
*/
|
||||
tristate visible;
|
||||
|
||||
/* SYMBOL_* flags */
|
||||
int flags;
|
||||
|
||||
/* List of properties. See prop_type. */
|
||||
struct property *prop;
|
||||
|
||||
/* Dependencies from enclosing menus, choices, and ifs */
|
||||
struct expr_value dir_dep;
|
||||
|
||||
/* Reverse dependencies through being selected by other symbols */
|
||||
struct expr_value rev_dep;
|
||||
|
||||
/*
|
||||
* "Weak" reverse dependencies through being implied by other symbols
|
||||
*/
|
||||
struct expr_value implied;
|
||||
};
|
||||
|
||||
#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
|
||||
#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next)
|
||||
|
||||
#define SYMBOL_CONST 0x0001 /* symbol is const */
|
||||
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
|
||||
@@ -97,7 +141,8 @@ struct symbol {
|
||||
#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
|
||||
#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
|
||||
#define SYMBOL_CHANGED 0x0400 /* ? */
|
||||
#define SYMBOL_AUTO 0x1000 /* value from environment variable */
|
||||
#define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */
|
||||
#define SYMBOL_NO_WRITE 0x1000 /* Symbol for internal use only; it will not be written */
|
||||
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
|
||||
#define SYMBOL_WARNED 0x8000 /* warning has been issued */
|
||||
|
||||
@@ -127,17 +172,20 @@ struct symbol {
|
||||
* config BAZ
|
||||
* int "BAZ Value"
|
||||
* range 1..255
|
||||
*
|
||||
* Please, also check parser.y:print_symbol() when modifying the
|
||||
* list of property types!
|
||||
*/
|
||||
enum prop_type {
|
||||
P_UNKNOWN,
|
||||
P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */
|
||||
P_COMMENT, /* text associated with a comment */
|
||||
P_MENU, /* prompt associated with a menuconfig option */
|
||||
P_MENU, /* prompt associated with a menu or menuconfig symbol */
|
||||
P_DEFAULT, /* default y */
|
||||
P_CHOICE, /* choice value */
|
||||
P_SELECT, /* select BAR */
|
||||
P_IMPLY, /* imply BAR */
|
||||
P_RANGE, /* range 7..100 (for a symbol) */
|
||||
P_ENV, /* value from environment variable */
|
||||
P_SYMBOL, /* where a symbol is defined */
|
||||
};
|
||||
|
||||
@@ -164,22 +212,67 @@ struct property {
|
||||
for (st = sym->prop; st; st = st->next) \
|
||||
if (st->text)
|
||||
|
||||
/*
|
||||
* Represents a node in the menu tree, as seen in e.g. menuconfig (though used
|
||||
* for all front ends). Each symbol, menu, etc. defined in the Kconfig files
|
||||
* gets a node. A symbol defined in multiple locations gets one node at each
|
||||
* location.
|
||||
*/
|
||||
struct menu {
|
||||
/* The next menu node at the same level */
|
||||
struct menu *next;
|
||||
|
||||
/* The parent menu node, corresponding to e.g. a menu or choice */
|
||||
struct menu *parent;
|
||||
|
||||
/* The first child menu node, for e.g. menus and choices */
|
||||
struct menu *list;
|
||||
|
||||
/*
|
||||
* The symbol associated with the menu node. Choices are implemented as
|
||||
* a special kind of symbol. NULL for menus, comments, and ifs.
|
||||
*/
|
||||
struct symbol *sym;
|
||||
|
||||
/*
|
||||
* The prompt associated with the node. This holds the prompt for a
|
||||
* symbol as well as the text for a menu or comment, along with the
|
||||
* type (P_PROMPT, P_MENU, etc.)
|
||||
*/
|
||||
struct property *prompt;
|
||||
|
||||
/*
|
||||
* 'visible if' dependencies. If more than one is given, they will be
|
||||
* ANDed together.
|
||||
*/
|
||||
struct expr *visibility;
|
||||
|
||||
/*
|
||||
* Ordinary dependencies from e.g. 'depends on' and 'if', ANDed
|
||||
* together
|
||||
*/
|
||||
struct expr *dep;
|
||||
|
||||
/* MENU_* flags */
|
||||
unsigned int flags;
|
||||
|
||||
/* Any help text associated with the node */
|
||||
char *help;
|
||||
|
||||
/* The location where the menu node appears in the Kconfig files */
|
||||
struct file *file;
|
||||
int lineno;
|
||||
|
||||
/* For use by front ends that need to store auxiliary data */
|
||||
void *data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Set on a menu node when the corresponding symbol changes state in some way.
|
||||
* Can be checked by front ends.
|
||||
*/
|
||||
#define MENU_CHANGED 0x0001
|
||||
|
||||
#define MENU_ROOT 0x0002
|
||||
|
||||
struct jump_key {
|
||||
@@ -215,11 +308,12 @@ struct expr *expr_transform(struct expr *e);
|
||||
int expr_contains_symbol(struct expr *dep, struct symbol *sym);
|
||||
bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
|
||||
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
|
||||
struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
|
||||
|
||||
void expr_fprint(struct expr *e, FILE *out);
|
||||
struct gstr; /* forward */
|
||||
void expr_gstr_print(struct expr *e, struct gstr *gs);
|
||||
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
|
||||
tristate pr_type, const char *title);
|
||||
|
||||
static inline int expr_is_yes(struct expr *e)
|
||||
{
|
||||
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
PKG="gtk+-2.0 gmodule-2.0 libglade-2.0"
|
||||
|
||||
if [ -z "$(command -v pkg-config)" ]; then
|
||||
echo >&2 "*"
|
||||
echo >&2 "* 'make gconfig' requires 'pkg-config'. Please install it."
|
||||
echo >&2 "*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! pkg-config --exists $PKG; then
|
||||
echo >&2 "*"
|
||||
echo >&2 "* Unable to find the GTK+ installation. Please make sure that"
|
||||
echo >&2 "* the GTK+ 2.0 development package is correctly installed."
|
||||
echo >&2 "* You need $PKG"
|
||||
echo >&2 "*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! pkg-config --atleast-version=2.0.0 gtk+-2.0; then
|
||||
echo >&2 "*"
|
||||
echo >&2 "* GTK+ is present but version >= 2.0.0 is required."
|
||||
echo >&2 "*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo cflags=\"$(pkg-config --cflags $PKG)\"
|
||||
echo libs=\"$(pkg-config --libs $PKG)\"
|
||||
+16
-17
@@ -1,9 +1,6 @@
|
||||
/* Hey EMACS -*- linux-c -*- */
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -12,7 +9,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "lkc.h"
|
||||
#include "images.c"
|
||||
#include "images.h"
|
||||
|
||||
#include <glade/glade.h>
|
||||
#include <gtk/gtk.h>
|
||||
@@ -78,8 +75,8 @@ static gchar **fill_row(struct menu *menu);
|
||||
static void conf_changed(void);
|
||||
|
||||
/* Helping/Debugging Functions */
|
||||
|
||||
const char *dbg_sym_flags(int val)
|
||||
#ifdef DEBUG
|
||||
static const char *dbg_sym_flags(int val)
|
||||
{
|
||||
static char buf[256];
|
||||
|
||||
@@ -101,15 +98,16 @@ const char *dbg_sym_flags(int val)
|
||||
strcat(buf, "write/");
|
||||
if (val & SYMBOL_CHANGED)
|
||||
strcat(buf, "changed/");
|
||||
if (val & SYMBOL_AUTO)
|
||||
strcat(buf, "auto/");
|
||||
if (val & SYMBOL_NO_WRITE)
|
||||
strcat(buf, "no_write/");
|
||||
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
void replace_button_icon(GladeXML * xml, GdkDrawable * window,
|
||||
static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
|
||||
GtkStyle *style, gchar *btn_name, gchar **xpm)
|
||||
{
|
||||
GdkPixmap *pixmap;
|
||||
@@ -128,7 +126,7 @@ void replace_button_icon(GladeXML * xml, GdkDrawable * window,
|
||||
}
|
||||
|
||||
/* Main Window Initialization */
|
||||
void init_main_window(const gchar * glade_file)
|
||||
static void init_main_window(const gchar *glade_file)
|
||||
{
|
||||
GladeXML *xml;
|
||||
GtkWidget *widget;
|
||||
@@ -190,7 +188,7 @@ void init_main_window(const gchar * glade_file)
|
||||
gtk_widget_show(main_wnd);
|
||||
}
|
||||
|
||||
void init_tree_model(void)
|
||||
static void init_tree_model(void)
|
||||
{
|
||||
gint i;
|
||||
|
||||
@@ -220,7 +218,7 @@ void init_tree_model(void)
|
||||
model1 = GTK_TREE_MODEL(tree1);
|
||||
}
|
||||
|
||||
void init_left_tree(void)
|
||||
static void init_left_tree(void)
|
||||
{
|
||||
GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
|
||||
GtkCellRenderer *renderer;
|
||||
@@ -262,7 +260,7 @@ static void renderer_edited(GtkCellRendererText * cell,
|
||||
const gchar * path_string,
|
||||
const gchar * new_text, gpointer user_data);
|
||||
|
||||
void init_right_tree(void)
|
||||
static void init_right_tree(void)
|
||||
{
|
||||
GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
|
||||
GtkCellRenderer *renderer;
|
||||
@@ -525,6 +523,7 @@ void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
|
||||
{
|
||||
if (conf_write(NULL))
|
||||
text_insert_msg("Error", "Unable to save configuration !");
|
||||
conf_write_autoconf(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -914,7 +913,7 @@ on_treeview2_button_press_event(GtkWidget * widget,
|
||||
current = menu;
|
||||
display_tree_part();
|
||||
gtk_widget_set_sensitive(back_btn, TRUE);
|
||||
} else if ((col == COL_OPTION)) {
|
||||
} else if (col == COL_OPTION) {
|
||||
toggle_sym_value(menu);
|
||||
gtk_tree_view_expand_row(view, path, TRUE);
|
||||
}
|
||||
@@ -1211,7 +1210,7 @@ static GtkTreeIter found;
|
||||
/*
|
||||
* Find a menu in the GtkTree starting at parent.
|
||||
*/
|
||||
GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
|
||||
static GtkTreeIter *gtktree_iter_find_node(GtkTreeIter *parent,
|
||||
struct menu *tofind)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
@@ -1423,7 +1422,7 @@ static void display_list(void)
|
||||
tree = tree2;
|
||||
}
|
||||
|
||||
void fixup_rootmenu(struct menu *menu)
|
||||
static void fixup_rootmenu(struct menu *menu)
|
||||
{
|
||||
struct menu *child;
|
||||
static int menu_cnt = 0;
|
||||
|
||||
+18
-16
@@ -1,9 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
static const char *xpm_load[] = {
|
||||
#include "images.h"
|
||||
|
||||
const char *xpm_load[] = {
|
||||
"22 22 5 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
@@ -33,7 +35,7 @@ static const char *xpm_load[] = {
|
||||
"###############.......",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_save[] = {
|
||||
const char *xpm_save[] = {
|
||||
"22 22 5 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
@@ -63,7 +65,7 @@ static const char *xpm_save[] = {
|
||||
"..##################..",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_back[] = {
|
||||
const char *xpm_back[] = {
|
||||
"22 22 3 1",
|
||||
". c None",
|
||||
"# c #000083",
|
||||
@@ -91,7 +93,7 @@ static const char *xpm_back[] = {
|
||||
"......................",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_tree_view[] = {
|
||||
const char *xpm_tree_view[] = {
|
||||
"22 22 2 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
@@ -118,7 +120,7 @@ static const char *xpm_tree_view[] = {
|
||||
"......................",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_single_view[] = {
|
||||
const char *xpm_single_view[] = {
|
||||
"22 22 2 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
@@ -145,7 +147,7 @@ static const char *xpm_single_view[] = {
|
||||
"......................",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_split_view[] = {
|
||||
const char *xpm_split_view[] = {
|
||||
"22 22 2 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
@@ -172,7 +174,7 @@ static const char *xpm_split_view[] = {
|
||||
"......................",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_symbol_no[] = {
|
||||
const char *xpm_symbol_no[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
@@ -189,7 +191,7 @@ static const char *xpm_symbol_no[] = {
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_symbol_mod[] = {
|
||||
const char *xpm_symbol_mod[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
@@ -206,7 +208,7 @@ static const char *xpm_symbol_mod[] = {
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_symbol_yes[] = {
|
||||
const char *xpm_symbol_yes[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
@@ -223,7 +225,7 @@ static const char *xpm_symbol_yes[] = {
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_choice_no[] = {
|
||||
const char *xpm_choice_no[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
@@ -240,7 +242,7 @@ static const char *xpm_choice_no[] = {
|
||||
" .... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_choice_yes[] = {
|
||||
const char *xpm_choice_yes[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
@@ -257,7 +259,7 @@ static const char *xpm_choice_yes[] = {
|
||||
" .... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_menu[] = {
|
||||
const char *xpm_menu[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
@@ -274,7 +276,7 @@ static const char *xpm_menu[] = {
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_menu_inv[] = {
|
||||
const char *xpm_menu_inv[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
@@ -291,7 +293,7 @@ static const char *xpm_menu_inv[] = {
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_menuback[] = {
|
||||
const char *xpm_menuback[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
@@ -308,7 +310,7 @@ static const char *xpm_menuback[] = {
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_void[] = {
|
||||
const char *xpm_void[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
*/
|
||||
|
||||
#ifndef IMAGES_H
|
||||
#define IMAGES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char *xpm_load[];
|
||||
extern const char *xpm_save[];
|
||||
extern const char *xpm_back[];
|
||||
extern const char *xpm_tree_view[];
|
||||
extern const char *xpm_single_view[];
|
||||
extern const char *xpm_split_view[];
|
||||
extern const char *xpm_symbol_no[];
|
||||
extern const char *xpm_symbol_mod[];
|
||||
extern const char *xpm_symbol_yes[];
|
||||
extern const char *xpm_choice_no[];
|
||||
extern const char *xpm_choice_yes[];
|
||||
extern const char *xpm_menu[];
|
||||
extern const char *xpm_menu_inv[];
|
||||
extern const char *xpm_menuback[];
|
||||
extern const char *xpm_void[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* IMAGES_H */
|
||||
@@ -0,0 +1,471 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
*/
|
||||
%option nostdinit noyywrap never-interactive full ecs
|
||||
%option 8bit nodefault yylineno
|
||||
%x ASSIGN_VAL HELP STRING
|
||||
%{
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lkc.h"
|
||||
#include "parser.tab.h"
|
||||
|
||||
#define YY_DECL static int yylex1(void)
|
||||
|
||||
#define START_STRSIZE 16
|
||||
|
||||
static struct {
|
||||
struct file *file;
|
||||
int lineno;
|
||||
} current_pos;
|
||||
|
||||
static int prev_prev_token = T_EOL;
|
||||
static int prev_token = T_EOL;
|
||||
static char *text;
|
||||
static int text_size, text_asize;
|
||||
|
||||
struct buffer {
|
||||
struct buffer *parent;
|
||||
YY_BUFFER_STATE state;
|
||||
};
|
||||
|
||||
struct buffer *current_buf;
|
||||
|
||||
static int last_ts, first_ts;
|
||||
|
||||
static char *expand_token(const char *in, size_t n);
|
||||
static void append_expanded_string(const char *in);
|
||||
static void zconf_endhelp(void);
|
||||
static void zconf_endfile(void);
|
||||
|
||||
static void new_string(void)
|
||||
{
|
||||
text = xmalloc(START_STRSIZE);
|
||||
text_asize = START_STRSIZE;
|
||||
text_size = 0;
|
||||
*text = 0;
|
||||
}
|
||||
|
||||
static void append_string(const char *str, int size)
|
||||
{
|
||||
int new_size = text_size + size + 1;
|
||||
if (new_size > text_asize) {
|
||||
new_size += START_STRSIZE - 1;
|
||||
new_size &= -START_STRSIZE;
|
||||
text = xrealloc(text, new_size);
|
||||
text_asize = new_size;
|
||||
}
|
||||
memcpy(text + text_size, str, size);
|
||||
text_size += size;
|
||||
text[text_size] = 0;
|
||||
}
|
||||
|
||||
static void alloc_string(const char *str, int size)
|
||||
{
|
||||
text = xmalloc(size + 1);
|
||||
memcpy(text, str, size);
|
||||
text[size] = 0;
|
||||
}
|
||||
|
||||
static void warn_ignored_character(char chr)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s:%d:warning: ignoring unsupported character '%c'\n",
|
||||
current_file->name, yylineno, chr);
|
||||
}
|
||||
%}
|
||||
|
||||
n [A-Za-z0-9_-]
|
||||
|
||||
%%
|
||||
int str = 0;
|
||||
int ts, i;
|
||||
|
||||
#.* /* ignore comment */
|
||||
[ \t]* /* whitespaces */
|
||||
\\\n /* escaped new line */
|
||||
\n return T_EOL;
|
||||
"allnoconfig_y" return T_ALLNOCONFIG_Y;
|
||||
"bool" return T_BOOL;
|
||||
"choice" return T_CHOICE;
|
||||
"comment" return T_COMMENT;
|
||||
"config" return T_CONFIG;
|
||||
"def_bool" return T_DEF_BOOL;
|
||||
"def_tristate" return T_DEF_TRISTATE;
|
||||
"default" return T_DEFAULT;
|
||||
"defconfig_list" return T_DEFCONFIG_LIST;
|
||||
"depends" return T_DEPENDS;
|
||||
"endchoice" return T_ENDCHOICE;
|
||||
"endif" return T_ENDIF;
|
||||
"endmenu" return T_ENDMENU;
|
||||
"help"|"---help---" return T_HELP;
|
||||
"hex" return T_HEX;
|
||||
"if" return T_IF;
|
||||
"imply" return T_IMPLY;
|
||||
"int" return T_INT;
|
||||
"mainmenu" return T_MAINMENU;
|
||||
"menu" return T_MENU;
|
||||
"menuconfig" return T_MENUCONFIG;
|
||||
"modules" return T_MODULES;
|
||||
"on" return T_ON;
|
||||
"option" return T_OPTION;
|
||||
"optional" return T_OPTIONAL;
|
||||
"prompt" return T_PROMPT;
|
||||
"range" return T_RANGE;
|
||||
"select" return T_SELECT;
|
||||
"source" return T_SOURCE;
|
||||
"string" return T_STRING;
|
||||
"tristate" return T_TRISTATE;
|
||||
"visible" return T_VISIBLE;
|
||||
"||" return T_OR;
|
||||
"&&" return T_AND;
|
||||
"=" return T_EQUAL;
|
||||
"!=" return T_UNEQUAL;
|
||||
"<" return T_LESS;
|
||||
"<=" return T_LESS_EQUAL;
|
||||
">" return T_GREATER;
|
||||
">=" return T_GREATER_EQUAL;
|
||||
"!" return T_NOT;
|
||||
"(" return T_OPEN_PAREN;
|
||||
")" return T_CLOSE_PAREN;
|
||||
":=" return T_COLON_EQUAL;
|
||||
"+=" return T_PLUS_EQUAL;
|
||||
\"|\' {
|
||||
str = yytext[0];
|
||||
new_string();
|
||||
BEGIN(STRING);
|
||||
}
|
||||
{n}+ {
|
||||
alloc_string(yytext, yyleng);
|
||||
yylval.string = text;
|
||||
return T_WORD;
|
||||
}
|
||||
({n}|$)+ {
|
||||
/* this token includes at least one '$' */
|
||||
yylval.string = expand_token(yytext, yyleng);
|
||||
if (strlen(yylval.string))
|
||||
return T_WORD;
|
||||
free(yylval.string);
|
||||
}
|
||||
. warn_ignored_character(*yytext);
|
||||
|
||||
<ASSIGN_VAL>{
|
||||
[^[:blank:]\n]+.* {
|
||||
alloc_string(yytext, yyleng);
|
||||
yylval.string = text;
|
||||
return T_ASSIGN_VAL;
|
||||
}
|
||||
\n { BEGIN(INITIAL); return T_EOL; }
|
||||
.
|
||||
}
|
||||
|
||||
<STRING>{
|
||||
"$".* append_expanded_string(yytext);
|
||||
[^$'"\\\n]+ {
|
||||
append_string(yytext, yyleng);
|
||||
}
|
||||
\\.? {
|
||||
append_string(yytext + 1, yyleng - 1);
|
||||
}
|
||||
\'|\" {
|
||||
if (str == yytext[0]) {
|
||||
BEGIN(INITIAL);
|
||||
yylval.string = text;
|
||||
return T_WORD_QUOTE;
|
||||
} else
|
||||
append_string(yytext, 1);
|
||||
}
|
||||
\n {
|
||||
fprintf(stderr,
|
||||
"%s:%d:warning: multi-line strings not supported\n",
|
||||
zconf_curname(), zconf_lineno());
|
||||
unput('\n');
|
||||
BEGIN(INITIAL);
|
||||
yylval.string = text;
|
||||
return T_WORD_QUOTE;
|
||||
}
|
||||
<<EOF>> {
|
||||
BEGIN(INITIAL);
|
||||
yylval.string = text;
|
||||
return T_WORD_QUOTE;
|
||||
}
|
||||
}
|
||||
|
||||
<HELP>{
|
||||
[ \t]+ {
|
||||
ts = 0;
|
||||
for (i = 0; i < yyleng; i++) {
|
||||
if (yytext[i] == '\t')
|
||||
ts = (ts & ~7) + 8;
|
||||
else
|
||||
ts++;
|
||||
}
|
||||
last_ts = ts;
|
||||
if (first_ts) {
|
||||
if (ts < first_ts) {
|
||||
zconf_endhelp();
|
||||
return T_HELPTEXT;
|
||||
}
|
||||
ts -= first_ts;
|
||||
while (ts > 8) {
|
||||
append_string(" ", 8);
|
||||
ts -= 8;
|
||||
}
|
||||
append_string(" ", ts);
|
||||
}
|
||||
}
|
||||
[ \t]*\n/[^ \t\n] {
|
||||
zconf_endhelp();
|
||||
return T_HELPTEXT;
|
||||
}
|
||||
[ \t]*\n {
|
||||
append_string("\n", 1);
|
||||
}
|
||||
[^ \t\n].* {
|
||||
while (yyleng) {
|
||||
if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
|
||||
break;
|
||||
yyleng--;
|
||||
}
|
||||
append_string(yytext, yyleng);
|
||||
if (!first_ts)
|
||||
first_ts = last_ts;
|
||||
}
|
||||
<<EOF>> {
|
||||
zconf_endhelp();
|
||||
return T_HELPTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
<<EOF>> {
|
||||
BEGIN(INITIAL);
|
||||
|
||||
if (prev_token != T_EOL && prev_token != T_HELPTEXT)
|
||||
fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
|
||||
current_file->name, yylineno);
|
||||
|
||||
if (current_file) {
|
||||
zconf_endfile();
|
||||
return T_EOL;
|
||||
}
|
||||
fclose(yyin);
|
||||
yyterminate();
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
/* second stage lexer */
|
||||
int yylex(void)
|
||||
{
|
||||
int token;
|
||||
|
||||
repeat:
|
||||
token = yylex1();
|
||||
|
||||
if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
|
||||
if (token == T_EOL) {
|
||||
/* Do not pass unneeded T_EOL to the parser. */
|
||||
goto repeat;
|
||||
} else {
|
||||
/*
|
||||
* For the parser, update file/lineno at the first token
|
||||
* of each statement. Generally, \n is a statement
|
||||
* terminator in Kconfig, but it is not always true
|
||||
* because \n could be escaped by a backslash.
|
||||
*/
|
||||
current_pos.file = current_file;
|
||||
current_pos.lineno = yylineno;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev_prev_token == T_EOL && prev_token == T_WORD &&
|
||||
(token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL))
|
||||
BEGIN(ASSIGN_VAL);
|
||||
|
||||
prev_prev_token = prev_token;
|
||||
prev_token = token;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
static char *expand_token(const char *in, size_t n)
|
||||
{
|
||||
char *out;
|
||||
int c;
|
||||
char c2;
|
||||
const char *rest, *end;
|
||||
|
||||
new_string();
|
||||
append_string(in, n);
|
||||
|
||||
/* get the whole line because we do not know the end of token. */
|
||||
while ((c = input()) != EOF) {
|
||||
if (c == '\n') {
|
||||
unput(c);
|
||||
break;
|
||||
}
|
||||
c2 = c;
|
||||
append_string(&c2, 1);
|
||||
}
|
||||
|
||||
rest = text;
|
||||
out = expand_one_token(&rest);
|
||||
|
||||
/* push back unused characters to the input stream */
|
||||
end = rest + strlen(rest);
|
||||
while (end > rest)
|
||||
unput(*--end);
|
||||
|
||||
free(text);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void append_expanded_string(const char *str)
|
||||
{
|
||||
const char *end;
|
||||
char *res;
|
||||
|
||||
str++;
|
||||
|
||||
res = expand_dollar(&str);
|
||||
|
||||
/* push back unused characters to the input stream */
|
||||
end = str + strlen(str);
|
||||
while (end > str)
|
||||
unput(*--end);
|
||||
|
||||
append_string(res, strlen(res));
|
||||
|
||||
free(res);
|
||||
}
|
||||
|
||||
void zconf_starthelp(void)
|
||||
{
|
||||
new_string();
|
||||
last_ts = first_ts = 0;
|
||||
BEGIN(HELP);
|
||||
}
|
||||
|
||||
static void zconf_endhelp(void)
|
||||
{
|
||||
yylval.string = text;
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to open specified file with following names:
|
||||
* ./name
|
||||
* $(srctree)/name
|
||||
* The latter is used when srctree is separate from objtree
|
||||
* when compiling the kernel.
|
||||
* Return NULL if file is not found.
|
||||
*/
|
||||
FILE *zconf_fopen(const char *name)
|
||||
{
|
||||
char *env, fullname[PATH_MAX+1];
|
||||
FILE *f;
|
||||
|
||||
f = fopen(name, "r");
|
||||
if (!f && name != NULL && name[0] != '/') {
|
||||
env = getenv(SRCTREE);
|
||||
if (env) {
|
||||
snprintf(fullname, sizeof(fullname),
|
||||
"%s/%s", env, name);
|
||||
f = fopen(fullname, "r");
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void zconf_initscan(const char *name)
|
||||
{
|
||||
yyin = zconf_fopen(name);
|
||||
if (!yyin) {
|
||||
fprintf(stderr, "can't find file %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
current_buf = xmalloc(sizeof(*current_buf));
|
||||
memset(current_buf, 0, sizeof(*current_buf));
|
||||
|
||||
current_file = file_lookup(name);
|
||||
yylineno = 1;
|
||||
}
|
||||
|
||||
void zconf_nextfile(const char *name)
|
||||
{
|
||||
struct file *iter;
|
||||
struct file *file = file_lookup(name);
|
||||
struct buffer *buf = xmalloc(sizeof(*buf));
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
|
||||
current_buf->state = YY_CURRENT_BUFFER;
|
||||
yyin = zconf_fopen(file->name);
|
||||
if (!yyin) {
|
||||
fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
|
||||
zconf_curname(), zconf_lineno(), file->name);
|
||||
exit(1);
|
||||
}
|
||||
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
|
||||
buf->parent = current_buf;
|
||||
current_buf = buf;
|
||||
|
||||
current_file->lineno = yylineno;
|
||||
file->parent = current_file;
|
||||
|
||||
for (iter = current_file; iter; iter = iter->parent) {
|
||||
if (!strcmp(iter->name, file->name)) {
|
||||
fprintf(stderr,
|
||||
"Recursive inclusion detected.\n"
|
||||
"Inclusion path:\n"
|
||||
" current file : %s\n", file->name);
|
||||
iter = file;
|
||||
do {
|
||||
iter = iter->parent;
|
||||
fprintf(stderr, " included from: %s:%d\n",
|
||||
iter->name, iter->lineno - 1);
|
||||
} while (strcmp(iter->name, file->name));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
yylineno = 1;
|
||||
current_file = file;
|
||||
}
|
||||
|
||||
static void zconf_endfile(void)
|
||||
{
|
||||
struct buffer *parent;
|
||||
|
||||
current_file = current_file->parent;
|
||||
if (current_file)
|
||||
yylineno = current_file->lineno;
|
||||
|
||||
parent = current_buf->parent;
|
||||
if (parent) {
|
||||
fclose(yyin);
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
yy_switch_to_buffer(parent->state);
|
||||
}
|
||||
free(current_buf);
|
||||
current_buf = parent;
|
||||
}
|
||||
|
||||
int zconf_lineno(void)
|
||||
{
|
||||
return current_pos.lineno;
|
||||
}
|
||||
|
||||
const char *zconf_curname(void)
|
||||
{
|
||||
return current_pos.file ? current_pos.file->name : "<none>";
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
|
||||
+12
-26
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#ifndef LKC_H
|
||||
@@ -30,10 +30,6 @@ static inline const char *CONFIG_prefix(void)
|
||||
#undef CONFIG_
|
||||
#define CONFIG_ CONFIG_prefix()
|
||||
|
||||
#define TF_COMMAND 0x0001
|
||||
#define TF_PARAM 0x0002
|
||||
#define TF_OPTION 0x0004
|
||||
|
||||
enum conf_def_mode {
|
||||
def_default,
|
||||
def_yes,
|
||||
@@ -42,18 +38,7 @@ enum conf_def_mode {
|
||||
def_random
|
||||
};
|
||||
|
||||
#define T_OPT_MODULES 1
|
||||
#define T_OPT_DEFCONFIG_LIST 2
|
||||
#define T_OPT_ENV 3
|
||||
#define T_OPT_ALLNOCONFIG_Y 4
|
||||
|
||||
struct kconf_id {
|
||||
int name;
|
||||
int token;
|
||||
unsigned int flags;
|
||||
enum symbol_type stype;
|
||||
};
|
||||
|
||||
extern int yylineno;
|
||||
void zconfdump(FILE *out);
|
||||
void zconf_starthelp(void);
|
||||
FILE *zconf_fopen(const char *name);
|
||||
@@ -64,8 +49,6 @@ const char *zconf_curname(void);
|
||||
|
||||
/* confdata.c */
|
||||
const char *conf_get_configname(void);
|
||||
const char *conf_get_autoconfig_name(void);
|
||||
char *conf_get_default_confname(void);
|
||||
void sym_set_change_count(int count);
|
||||
void sym_add_change_count(int count);
|
||||
bool conf_set_all_new_symbols(enum conf_def_mode mode);
|
||||
@@ -86,21 +69,27 @@ void menu_warn(struct menu *menu, const char *fmt, ...);
|
||||
struct menu *menu_add_menu(void);
|
||||
void menu_end_menu(void);
|
||||
void menu_add_entry(struct symbol *sym);
|
||||
void menu_end_entry(void);
|
||||
void menu_add_dep(struct expr *dep);
|
||||
void menu_add_visibility(struct expr *dep);
|
||||
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
|
||||
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
|
||||
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
|
||||
void menu_add_option(int token, char *arg);
|
||||
void menu_add_option_modules(void);
|
||||
void menu_add_option_defconfig_list(void);
|
||||
void menu_add_option_allnoconfig_y(void);
|
||||
void menu_finalize(struct menu *parent);
|
||||
void menu_set_type(int type);
|
||||
|
||||
/* util.c */
|
||||
struct file *file_lookup(const char *name);
|
||||
int file_write_dep(const char *name);
|
||||
void *xmalloc(size_t size);
|
||||
void *xcalloc(size_t nmemb, size_t size);
|
||||
void *xrealloc(void *p, size_t size);
|
||||
char *xstrdup(const char *s);
|
||||
char *xstrndup(const char *s, size_t n);
|
||||
|
||||
/* lexer.l */
|
||||
int yylex(void);
|
||||
|
||||
struct gstr {
|
||||
size_t len;
|
||||
@@ -118,16 +107,13 @@ void str_printf(struct gstr *gs, const char *fmt, ...);
|
||||
const char *str_get(struct gstr *gs);
|
||||
|
||||
/* symbol.c */
|
||||
extern struct expr *sym_env_list;
|
||||
|
||||
void sym_init(void);
|
||||
void sym_clear_all_valid(void);
|
||||
struct symbol *sym_choice_default(struct symbol *sym);
|
||||
struct property *sym_get_range_prop(struct symbol *sym);
|
||||
const char *sym_get_string_default(struct symbol *sym);
|
||||
struct symbol *sym_check_deps(struct symbol *sym);
|
||||
struct property *prop_alloc(enum prop_type type, struct symbol *sym);
|
||||
struct symbol *prop_get_symbol(struct property *prop);
|
||||
struct property *sym_get_env_prop(struct symbol *sym);
|
||||
|
||||
static inline tristate sym_get_tristate_value(struct symbol *sym)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <stdarg.h>
|
||||
|
||||
/* confdata.c */
|
||||
@@ -6,10 +7,10 @@ int conf_read(const char *name);
|
||||
int conf_read_simple(const char *name, int);
|
||||
int conf_write_defconfig(const char *name);
|
||||
int conf_write(const char *name);
|
||||
int conf_write_autoconf(void);
|
||||
int conf_write_autoconf(int overwrite);
|
||||
bool conf_get_changed(void);
|
||||
void conf_set_changed_callback(void (*fn)(void));
|
||||
void conf_set_message_callback(void (*fn)(const char *fmt, va_list ap));
|
||||
void conf_set_message_callback(void (*fn)(const char *s));
|
||||
|
||||
/* menu.c */
|
||||
extern struct menu rootmenu;
|
||||
@@ -30,7 +31,6 @@ extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
|
||||
|
||||
struct symbol * sym_lookup(const char *name, int flags);
|
||||
struct symbol * sym_find(const char *name);
|
||||
const char * sym_expand_string_value(const char *in);
|
||||
const char * sym_escape_string_value(const char *in);
|
||||
struct symbol ** sym_re_search(const char *pattern);
|
||||
const char * sym_type_name(enum symbol_type type);
|
||||
@@ -42,11 +42,24 @@ tristate sym_toggle_tristate_value(struct symbol *sym);
|
||||
bool sym_string_valid(struct symbol *sym, const char *newval);
|
||||
bool sym_string_within_range(struct symbol *sym, const char *str);
|
||||
bool sym_set_string_value(struct symbol *sym, const char *newval);
|
||||
bool sym_is_changable(struct symbol *sym);
|
||||
bool sym_is_changeable(struct symbol *sym);
|
||||
struct property * sym_get_choice_prop(struct symbol *sym);
|
||||
const char * sym_get_string_value(struct symbol *sym);
|
||||
|
||||
const char * prop_get_type_name(enum prop_type type);
|
||||
|
||||
/* preprocess.c */
|
||||
enum variable_flavor {
|
||||
VAR_SIMPLE,
|
||||
VAR_RECURSIVE,
|
||||
VAR_APPEND,
|
||||
};
|
||||
void env_write_dep(FILE *f, const char *auto_conf_name);
|
||||
void variable_add(const char *name, const char *value,
|
||||
enum variable_flavor flavor);
|
||||
void variable_all_del(void);
|
||||
char *expand_dollar(const char **str);
|
||||
char *expand_one_token(const char **str);
|
||||
|
||||
/* expr.c */
|
||||
void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken);
|
||||
@@ -1,4 +0,0 @@
|
||||
#
|
||||
# Generated files
|
||||
#
|
||||
lxdialog
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Check ncurses compatibility
|
||||
|
||||
# What library to link
|
||||
ldflags()
|
||||
{
|
||||
pkg-config --libs ncursesw 2>/dev/null && exit
|
||||
pkg-config --libs ncurses 2>/dev/null && exit
|
||||
for ext in so a dll.a dylib ; do
|
||||
for lib in ncursesw ncurses curses ; do
|
||||
$cc -print-file-name=lib${lib}.${ext} | grep -q /
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "-l${lib}"
|
||||
exit
|
||||
fi
|
||||
done
|
||||
done
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Where is ncurses.h?
|
||||
ccflags()
|
||||
{
|
||||
if pkg-config --cflags ncursesw 2>/dev/null; then
|
||||
echo '-DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1'
|
||||
elif pkg-config --cflags ncurses 2>/dev/null; then
|
||||
echo '-DCURSES_LOC="<ncurses.h>"'
|
||||
elif [ -f /usr/include/ncursesw/curses.h ]; then
|
||||
echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"'
|
||||
echo ' -DNCURSES_WIDECHAR=1'
|
||||
elif [ -f /usr/include/ncurses/ncurses.h ]; then
|
||||
echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
|
||||
elif [ -f /usr/include/ncurses/curses.h ]; then
|
||||
echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"'
|
||||
elif [ -f /usr/include/ncurses.h ]; then
|
||||
echo '-DCURSES_LOC="<ncurses.h>"'
|
||||
else
|
||||
echo '-DCURSES_LOC="<curses.h>"'
|
||||
fi
|
||||
}
|
||||
|
||||
# Temp file, try to clean up after us
|
||||
tmp=.lxdialog.tmp
|
||||
trap "rm -f $tmp" 0 1 2 3 15
|
||||
|
||||
# Check if we can link to ncurses
|
||||
check() {
|
||||
$cc -x c - -o $tmp 2>/dev/null <<'EOF'
|
||||
#include CURSES_LOC
|
||||
main() {}
|
||||
EOF
|
||||
if [ $? != 0 ]; then
|
||||
echo " *** Unable to find the ncurses libraries or the" 1>&2
|
||||
echo " *** required header files." 1>&2
|
||||
echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
|
||||
echo " *** " 1>&2
|
||||
echo " *** Install ncurses (ncurses-devel) and try again." 1>&2
|
||||
echo " *** " 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cc=""
|
||||
case "$1" in
|
||||
"-check")
|
||||
shift
|
||||
cc="$@"
|
||||
check
|
||||
;;
|
||||
"-ccflags")
|
||||
ccflags
|
||||
;;
|
||||
"-ldflags")
|
||||
shift
|
||||
cc="$@"
|
||||
ldflags
|
||||
;;
|
||||
"*")
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* checklist.c -- implements the checklist box
|
||||
*
|
||||
@@ -5,20 +6,6 @@
|
||||
* Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
|
||||
* Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* dialog.h -- common declarations for all dialog modules
|
||||
*
|
||||
* AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -29,7 +16,7 @@
|
||||
#ifdef __sun__
|
||||
#define CURS_MACROS
|
||||
#endif
|
||||
#include CURSES_LOC
|
||||
#include <ncurses.h>
|
||||
|
||||
/*
|
||||
* Colors in ncurses 1.9.9e do not work properly since foreground and
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* inputbox.c -- implements the input box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
@@ -126,7 +113,8 @@ do_resize:
|
||||
case KEY_DOWN:
|
||||
break;
|
||||
case KEY_BACKSPACE:
|
||||
case 127:
|
||||
case 8: /* ^H */
|
||||
case 127: /* ^? */
|
||||
if (pos) {
|
||||
wattrset(dialog, dlg.inputbox.atr);
|
||||
if (input_x == 0) {
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* menubox.c -- implements the menu box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* textbox.c -- implements the text box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* util.c
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* yesno.c -- implements the yes/no box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
PKG="ncursesw"
|
||||
PKG2="ncurses"
|
||||
|
||||
if [ -n "$(command -v pkg-config)" ]; then
|
||||
if pkg-config --exists $PKG; then
|
||||
echo cflags=\"$(pkg-config --cflags $PKG)\"
|
||||
echo libs=\"$(pkg-config --libs $PKG)\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if pkg-config --exists $PKG2; then
|
||||
echo cflags=\"$(pkg-config --cflags $PKG2)\"
|
||||
echo libs=\"$(pkg-config --libs $PKG2)\"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check the default paths in case pkg-config is not installed.
|
||||
# (Even if it is installed, some distributions such as openSUSE cannot
|
||||
# find ncurses by pkg-config.)
|
||||
if [ -f /usr/include/ncursesw/ncurses.h ]; then
|
||||
echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\"
|
||||
echo libs=\"-lncursesw\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f /usr/include/ncurses/ncurses.h ]; then
|
||||
echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\"
|
||||
echo libs=\"-lncurses\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f /usr/include/ncurses.h ]; then
|
||||
echo cflags=\"-D_GNU_SOURCE\"
|
||||
echo libs=\"-lncurses\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo >&2 "*"
|
||||
echo >&2 "* Unable to find the ncurses package."
|
||||
echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
|
||||
echo >&2 "* depending on your distribution)."
|
||||
echo >&2 "*"
|
||||
exit 1
|
||||
+12
-15
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*
|
||||
* Introduced single menu mode (show all sub-menus in one large tree).
|
||||
* 2002-11-06 Petr Baudis <pasky@ucw.cz>
|
||||
@@ -245,7 +245,7 @@ search_help[] =
|
||||
" Selected by: BAR [=n]\n"
|
||||
"-----------------------------------------------------------------\n"
|
||||
"o The line 'Type:' shows the type of the configuration option for\n"
|
||||
" this symbol (boolean, tristate, string, ...)\n"
|
||||
" this symbol (bool, tristate, string, ...)\n"
|
||||
"o The line 'Prompt:' shows the text used in the menu structure for\n"
|
||||
" this symbol\n"
|
||||
"o The 'Defined at' line tells at what file / line number the symbol\n"
|
||||
@@ -490,7 +490,6 @@ static void build_conf(struct menu *menu)
|
||||
switch (prop->type) {
|
||||
case P_MENU:
|
||||
child_count++;
|
||||
prompt = prompt;
|
||||
if (single_menu_mode) {
|
||||
item_make("%s%*c%s",
|
||||
menu->data ? "-->" : "++>",
|
||||
@@ -537,7 +536,7 @@ static void build_conf(struct menu *menu)
|
||||
}
|
||||
|
||||
val = sym_get_tristate_value(sym);
|
||||
if (sym_is_changable(sym)) {
|
||||
if (sym_is_changeable(sym)) {
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
item_make("[%c]", val == no ? ' ' : '*');
|
||||
@@ -588,7 +587,7 @@ static void build_conf(struct menu *menu)
|
||||
} else {
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
if (sym_is_changable(sym))
|
||||
if (sym_is_changeable(sym))
|
||||
item_make("[%c]", val == no ? ' ' : '*');
|
||||
else
|
||||
item_make("-%c-", val == no ? ' ' : '*');
|
||||
@@ -601,7 +600,7 @@ static void build_conf(struct menu *menu)
|
||||
case mod: ch = 'M'; break;
|
||||
default: ch = ' '; break;
|
||||
}
|
||||
if (sym_is_changable(sym)) {
|
||||
if (sym_is_changeable(sym)) {
|
||||
if (sym->rev_dep.tri == mod)
|
||||
item_make("{%c}", ch);
|
||||
else
|
||||
@@ -618,7 +617,7 @@ static void build_conf(struct menu *menu)
|
||||
if (tmp < 0)
|
||||
tmp = 0;
|
||||
item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
|
||||
(sym_has_value(sym) || !sym_is_changable(sym)) ?
|
||||
(sym_has_value(sym) || !sym_is_changeable(sym)) ?
|
||||
"" : " (NEW)");
|
||||
item_set_tag('s');
|
||||
item_set_data(menu);
|
||||
@@ -626,7 +625,7 @@ static void build_conf(struct menu *menu)
|
||||
}
|
||||
}
|
||||
item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
|
||||
(sym_has_value(sym) || !sym_is_changable(sym)) ?
|
||||
(sym_has_value(sym) || !sym_is_changeable(sym)) ?
|
||||
"" : " (NEW)");
|
||||
if (menu->prompt->type == P_MENU) {
|
||||
item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->");
|
||||
@@ -772,16 +771,13 @@ static void show_helptext(const char *title, const char *text)
|
||||
show_textbox(title, text, 0, 0);
|
||||
}
|
||||
|
||||
static void conf_message_callback(const char *fmt, va_list ap)
|
||||
static void conf_message_callback(const char *s)
|
||||
{
|
||||
char buf[PATH_MAX+1];
|
||||
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
if (save_and_exit) {
|
||||
if (!silent)
|
||||
printf("%s", buf);
|
||||
printf("%s", s);
|
||||
} else {
|
||||
show_textbox(NULL, buf, 6, 60);
|
||||
show_textbox(NULL, s, 6, 60);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -940,7 +936,7 @@ static void conf_save(void)
|
||||
set_config_filename(dialog_input_result);
|
||||
return;
|
||||
}
|
||||
show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
|
||||
show_textbox(NULL, "Can't create file!", 5, 60);
|
||||
break;
|
||||
case 1:
|
||||
show_helptext("Save Alternate Configuration", save_config_help);
|
||||
@@ -977,6 +973,7 @@ static int handle_exit(void)
|
||||
"\n\n");
|
||||
return 1;
|
||||
}
|
||||
conf_write_autoconf(0);
|
||||
/* fall through */
|
||||
case -1:
|
||||
if (!silent)
|
||||
|
||||
+222
-52
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@@ -62,13 +62,8 @@ void menu_add_entry(struct symbol *sym)
|
||||
menu_add_symbol(P_SYMBOL, sym, NULL);
|
||||
}
|
||||
|
||||
void menu_end_entry(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct menu *menu_add_menu(void)
|
||||
{
|
||||
menu_end_entry();
|
||||
last_entry_ptr = ¤t_entry->list;
|
||||
return current_menu = current_entry;
|
||||
}
|
||||
@@ -79,19 +74,23 @@ void menu_end_menu(void)
|
||||
current_menu = current_menu->parent;
|
||||
}
|
||||
|
||||
static struct expr *menu_check_dep(struct expr *e)
|
||||
/*
|
||||
* Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
|
||||
* without modules
|
||||
*/
|
||||
static struct expr *rewrite_m(struct expr *e)
|
||||
{
|
||||
if (!e)
|
||||
return e;
|
||||
|
||||
switch (e->type) {
|
||||
case E_NOT:
|
||||
e->left.expr = menu_check_dep(e->left.expr);
|
||||
e->left.expr = rewrite_m(e->left.expr);
|
||||
break;
|
||||
case E_OR:
|
||||
case E_AND:
|
||||
e->left.expr = menu_check_dep(e->left.expr);
|
||||
e->right.expr = menu_check_dep(e->right.expr);
|
||||
e->left.expr = rewrite_m(e->left.expr);
|
||||
e->right.expr = rewrite_m(e->right.expr);
|
||||
break;
|
||||
case E_SYMBOL:
|
||||
/* change 'm' into 'm' && MODULES */
|
||||
@@ -106,7 +105,7 @@ static struct expr *menu_check_dep(struct expr *e)
|
||||
|
||||
void menu_add_dep(struct expr *dep)
|
||||
{
|
||||
current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
|
||||
current_entry->dep = expr_alloc_and(current_entry->dep, dep);
|
||||
}
|
||||
|
||||
void menu_set_type(int type)
|
||||
@@ -131,7 +130,7 @@ static struct property *menu_add_prop(enum prop_type type, char *prompt, struct
|
||||
|
||||
prop->menu = current_entry;
|
||||
prop->expr = expr;
|
||||
prop->visible.expr = menu_check_dep(dep);
|
||||
prop->visible.expr = dep;
|
||||
|
||||
if (prompt) {
|
||||
if (isspace(*prompt)) {
|
||||
@@ -196,31 +195,26 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
|
||||
menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
|
||||
}
|
||||
|
||||
void menu_add_option(int token, char *arg)
|
||||
void menu_add_option_modules(void)
|
||||
{
|
||||
switch (token) {
|
||||
case T_OPT_MODULES:
|
||||
if (modules_sym)
|
||||
zconf_error("symbol '%s' redefines option 'modules'"
|
||||
" already defined by symbol '%s'",
|
||||
current_entry->sym->name,
|
||||
modules_sym->name
|
||||
);
|
||||
zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'",
|
||||
current_entry->sym->name, modules_sym->name);
|
||||
modules_sym = current_entry->sym;
|
||||
break;
|
||||
case T_OPT_DEFCONFIG_LIST:
|
||||
}
|
||||
|
||||
void menu_add_option_defconfig_list(void)
|
||||
{
|
||||
if (!sym_defconfig_list)
|
||||
sym_defconfig_list = current_entry->sym;
|
||||
else if (sym_defconfig_list != current_entry->sym)
|
||||
zconf_error("trying to redefine defconfig symbol");
|
||||
break;
|
||||
case T_OPT_ENV:
|
||||
prop_add_env(arg);
|
||||
break;
|
||||
case T_OPT_ALLNOCONFIG_Y:
|
||||
current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
|
||||
break;
|
||||
sym_defconfig_list->flags |= SYMBOL_NO_WRITE;
|
||||
}
|
||||
|
||||
void menu_add_option_allnoconfig_y(void)
|
||||
{
|
||||
current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
|
||||
}
|
||||
|
||||
static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
|
||||
@@ -233,6 +227,8 @@ static void sym_check_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
struct symbol *sym2;
|
||||
char *use;
|
||||
|
||||
for (prop = sym->prop; prop; prop = prop->next) {
|
||||
switch (prop->type) {
|
||||
case P_DEFAULT:
|
||||
@@ -250,20 +246,32 @@ static void sym_check_prop(struct symbol *sym)
|
||||
"'%s': number is invalid",
|
||||
sym->name);
|
||||
}
|
||||
if (sym_is_choice(sym)) {
|
||||
struct property *choice_prop =
|
||||
sym_get_choice_prop(sym2);
|
||||
|
||||
if (!choice_prop ||
|
||||
prop_get_symbol(choice_prop) != sym)
|
||||
prop_warn(prop,
|
||||
"choice default symbol '%s' is not contained in the choice",
|
||||
sym2->name);
|
||||
}
|
||||
break;
|
||||
case P_SELECT:
|
||||
case P_IMPLY:
|
||||
use = prop->type == P_SELECT ? "select" : "imply";
|
||||
sym2 = prop_get_symbol(prop);
|
||||
if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
|
||||
prop_warn(prop,
|
||||
"config symbol '%s' uses select, but is "
|
||||
"not boolean or tristate", sym->name);
|
||||
"config symbol '%s' uses %s, but is "
|
||||
"not bool or tristate", sym->name, use);
|
||||
else if (sym2->type != S_UNKNOWN &&
|
||||
sym2->type != S_BOOLEAN &&
|
||||
sym2->type != S_TRISTATE)
|
||||
prop_warn(prop,
|
||||
"'%s' has wrong type. 'select' only "
|
||||
"accept arguments of boolean and "
|
||||
"tristate type", sym2->name);
|
||||
"'%s' has wrong type. '%s' only "
|
||||
"accept arguments of bool and "
|
||||
"tristate type", sym2->name, use);
|
||||
break;
|
||||
case P_RANGE:
|
||||
if (sym->type != S_INT && sym->type != S_HEX)
|
||||
@@ -288,6 +296,11 @@ void menu_finalize(struct menu *parent)
|
||||
|
||||
sym = parent->sym;
|
||||
if (parent->list) {
|
||||
/*
|
||||
* This menu node has children. We (recursively) process them
|
||||
* and propagate parent dependencies before moving on.
|
||||
*/
|
||||
|
||||
if (sym && sym_is_choice(sym)) {
|
||||
if (sym->type == S_UNKNOWN) {
|
||||
/* find the first choice value to find out choice type */
|
||||
@@ -305,65 +318,169 @@ void menu_finalize(struct menu *parent)
|
||||
if (menu->sym && menu->sym->type == S_UNKNOWN)
|
||||
menu_set_type(sym->type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the choice itself as the parent dependency of
|
||||
* the contained items. This turns the mode of the
|
||||
* choice into an upper bound on the visibility of the
|
||||
* choice value symbols.
|
||||
*/
|
||||
parentdep = expr_alloc_symbol(sym);
|
||||
} else if (parent->prompt)
|
||||
/* Menu node for 'menu' */
|
||||
parentdep = parent->prompt->visible.expr;
|
||||
else
|
||||
/* Menu node for 'if' */
|
||||
parentdep = parent->dep;
|
||||
|
||||
/* For each child menu node... */
|
||||
for (menu = parent->list; menu; menu = menu->next) {
|
||||
basedep = expr_transform(menu->dep);
|
||||
/*
|
||||
* Propagate parent dependencies to the child menu
|
||||
* node, also rewriting and simplifying expressions
|
||||
*/
|
||||
basedep = rewrite_m(menu->dep);
|
||||
basedep = expr_transform(basedep);
|
||||
basedep = expr_alloc_and(expr_copy(parentdep), basedep);
|
||||
basedep = expr_eliminate_dups(basedep);
|
||||
menu->dep = basedep;
|
||||
|
||||
if (menu->sym)
|
||||
/*
|
||||
* Note: For symbols, all prompts are included
|
||||
* too in the symbol's own property list
|
||||
*/
|
||||
prop = menu->sym->prop;
|
||||
else
|
||||
/*
|
||||
* For non-symbol menu nodes, we just need to
|
||||
* handle the prompt
|
||||
*/
|
||||
prop = menu->prompt;
|
||||
|
||||
/* For each property... */
|
||||
for (; prop; prop = prop->next) {
|
||||
if (prop->menu != menu)
|
||||
/*
|
||||
* Two possibilities:
|
||||
*
|
||||
* 1. The property lacks dependencies
|
||||
* and so isn't location-specific,
|
||||
* e.g. an 'option'
|
||||
*
|
||||
* 2. The property belongs to a symbol
|
||||
* defined in multiple locations and
|
||||
* is from some other location. It
|
||||
* will be handled there in that
|
||||
* case.
|
||||
*
|
||||
* Skip the property.
|
||||
*/
|
||||
continue;
|
||||
dep = expr_transform(prop->visible.expr);
|
||||
|
||||
/*
|
||||
* Propagate parent dependencies to the
|
||||
* property's condition, rewriting and
|
||||
* simplifying expressions at the same time
|
||||
*/
|
||||
dep = rewrite_m(prop->visible.expr);
|
||||
dep = expr_transform(dep);
|
||||
dep = expr_alloc_and(expr_copy(basedep), dep);
|
||||
dep = expr_eliminate_dups(dep);
|
||||
if (menu->sym && menu->sym->type != S_TRISTATE)
|
||||
dep = expr_trans_bool(dep);
|
||||
prop->visible.expr = dep;
|
||||
|
||||
/*
|
||||
* Handle selects and implies, which modify the
|
||||
* dependencies of the selected/implied symbol
|
||||
*/
|
||||
if (prop->type == P_SELECT) {
|
||||
struct symbol *es = prop_get_symbol(prop);
|
||||
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
|
||||
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
|
||||
} else if (prop->type == P_IMPLY) {
|
||||
struct symbol *es = prop_get_symbol(prop);
|
||||
es->implied.expr = expr_alloc_or(es->implied.expr,
|
||||
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sym && sym_is_choice(sym))
|
||||
expr_free(parentdep);
|
||||
|
||||
/*
|
||||
* Recursively process children in the same fashion before
|
||||
* moving on
|
||||
*/
|
||||
for (menu = parent->list; menu; menu = menu->next)
|
||||
menu_finalize(menu);
|
||||
} else if (sym) {
|
||||
/*
|
||||
* Automatic submenu creation. If sym is a symbol and A, B, C,
|
||||
* ... are consecutive items (symbols, menus, ifs, etc.) that
|
||||
* all depend on sym, then the following menu structure is
|
||||
* created:
|
||||
*
|
||||
* sym
|
||||
* +-A
|
||||
* +-B
|
||||
* +-C
|
||||
* ...
|
||||
*
|
||||
* This also works recursively, giving the following structure
|
||||
* if A is a symbol and B depends on A:
|
||||
*
|
||||
* sym
|
||||
* +-A
|
||||
* | +-B
|
||||
* +-C
|
||||
* ...
|
||||
*/
|
||||
|
||||
basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
|
||||
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
|
||||
basedep = expr_eliminate_dups(expr_transform(basedep));
|
||||
|
||||
/* Examine consecutive elements after sym */
|
||||
last_menu = NULL;
|
||||
for (menu = parent->next; menu; menu = menu->next) {
|
||||
dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
|
||||
if (!expr_contains_symbol(dep, sym))
|
||||
/* No dependency, quit */
|
||||
break;
|
||||
if (expr_depends_symbol(dep, sym))
|
||||
/* Absolute dependency, put in submenu */
|
||||
goto next;
|
||||
|
||||
/*
|
||||
* Also consider it a dependency on sym if our
|
||||
* dependencies contain sym and are a "superset" of
|
||||
* sym's dependencies, e.g. '(sym || Q) && R' when sym
|
||||
* depends on R.
|
||||
*
|
||||
* Note that 'R' might be from an enclosing menu or if,
|
||||
* making this a more common case than it might seem.
|
||||
*/
|
||||
dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
|
||||
dep = expr_eliminate_dups(expr_transform(dep));
|
||||
dep2 = expr_copy(basedep);
|
||||
expr_eliminate_eq(&dep, &dep2);
|
||||
expr_free(dep);
|
||||
if (!expr_is_yes(dep2)) {
|
||||
/* Not superset, quit */
|
||||
expr_free(dep2);
|
||||
break;
|
||||
}
|
||||
/* Superset, put in submenu */
|
||||
expr_free(dep2);
|
||||
next:
|
||||
menu_finalize(menu);
|
||||
menu->parent = parent;
|
||||
last_menu = menu;
|
||||
}
|
||||
expr_free(basedep);
|
||||
if (last_menu) {
|
||||
parent->list = parent->next;
|
||||
parent->next = last_menu->next;
|
||||
@@ -412,6 +529,35 @@ void menu_finalize(struct menu *parent)
|
||||
*ep = expr_alloc_one(E_LIST, NULL);
|
||||
(*ep)->right.sym = menu->sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* This code serves two purposes:
|
||||
*
|
||||
* (1) Flattening 'if' blocks, which do not specify a submenu
|
||||
* and only add dependencies.
|
||||
*
|
||||
* (Automatic submenu creation might still create a submenu
|
||||
* from an 'if' before this code runs.)
|
||||
*
|
||||
* (2) "Undoing" any automatic submenus created earlier below
|
||||
* promptless symbols.
|
||||
*
|
||||
* Before:
|
||||
*
|
||||
* A
|
||||
* if ... (or promptless symbol)
|
||||
* +-B
|
||||
* +-C
|
||||
* D
|
||||
*
|
||||
* After:
|
||||
*
|
||||
* A
|
||||
* if ... (or promptless symbol)
|
||||
* B
|
||||
* C
|
||||
* D
|
||||
*/
|
||||
if (menu->list && (!menu->prompt || !menu->prompt->text)) {
|
||||
for (last_menu = menu->list; ; last_menu = last_menu->next) {
|
||||
last_menu->parent = parent;
|
||||
@@ -436,6 +582,15 @@ void menu_finalize(struct menu *parent)
|
||||
sym->flags |= SYMBOL_WARNED;
|
||||
}
|
||||
|
||||
/*
|
||||
* For non-optional choices, add a reverse dependency (corresponding to
|
||||
* a select) of '<visibility> && m'. This prevents the user from
|
||||
* setting the choice mode to 'n' when the choice is visible.
|
||||
*
|
||||
* This would also work for non-choice symbols, but only non-optional
|
||||
* choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented
|
||||
* as a type of symbol.
|
||||
*/
|
||||
if (sym && !sym_is_optional(sym) && parent->prompt) {
|
||||
sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
|
||||
expr_alloc_and(parent->prompt->visible.expr,
|
||||
@@ -477,7 +632,7 @@ bool menu_is_visible(struct menu *menu)
|
||||
|
||||
if (menu->visibility) {
|
||||
if (expr_calc_value(menu->visibility) == no)
|
||||
return no;
|
||||
return false;
|
||||
}
|
||||
|
||||
sym = menu->sym;
|
||||
@@ -612,13 +767,30 @@ static struct property *get_symbol_prop(struct symbol *sym)
|
||||
return prop;
|
||||
}
|
||||
|
||||
static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
|
||||
enum prop_type tok, const char *prefix)
|
||||
{
|
||||
bool hit = false;
|
||||
struct property *prop;
|
||||
|
||||
for_all_properties(sym, prop, tok) {
|
||||
if (!hit) {
|
||||
str_append(r, prefix);
|
||||
hit = true;
|
||||
} else
|
||||
str_printf(r, " && ");
|
||||
expr_gstr_print(prop->expr, r);
|
||||
}
|
||||
if (hit)
|
||||
str_append(r, "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* head is optional and may be NULL
|
||||
*/
|
||||
static void get_symbol_str(struct gstr *r, struct symbol *sym,
|
||||
struct list_head *head)
|
||||
{
|
||||
bool hit;
|
||||
struct property *prop;
|
||||
|
||||
if (sym && sym->name) {
|
||||
@@ -648,22 +820,20 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
|
||||
}
|
||||
}
|
||||
|
||||
hit = false;
|
||||
for_all_properties(sym, prop, P_SELECT) {
|
||||
if (!hit) {
|
||||
str_append(r, " Selects: ");
|
||||
hit = true;
|
||||
} else
|
||||
str_printf(r, " && ");
|
||||
expr_gstr_print(prop->expr, r);
|
||||
}
|
||||
if (hit)
|
||||
str_append(r, "\n");
|
||||
get_symbol_props_str(r, sym, P_SELECT, " Selects: ");
|
||||
if (sym->rev_dep.expr) {
|
||||
str_append(r, " Selected by: ");
|
||||
expr_gstr_print(sym->rev_dep.expr, r);
|
||||
str_append(r, "\n");
|
||||
expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n");
|
||||
expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n");
|
||||
expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n");
|
||||
}
|
||||
|
||||
get_symbol_props_str(r, sym, P_IMPLY, " Implies: ");
|
||||
if (sym->implied.expr) {
|
||||
expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n");
|
||||
expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n");
|
||||
expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n");
|
||||
}
|
||||
|
||||
str_append(r, "\n\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# merge_config.sh - Takes a list of config fragment values, and merges
|
||||
# them one by one. Provides warnings on overridden values, and specified
|
||||
# values that did not make it to the resulting .config file (due to missed
|
||||
@@ -10,21 +12,13 @@
|
||||
#
|
||||
# Copyright (c) 2009-2010 Wind River Systems, Inc.
|
||||
# Copyright 2011 Linaro
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
|
||||
set -e
|
||||
|
||||
clean_up() {
|
||||
rm -f $TMP_FILE
|
||||
exit
|
||||
rm -f $MERGE_FILE
|
||||
}
|
||||
trap clean_up HUP INT TERM
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [OPTIONS] [CONFIG [...]]"
|
||||
@@ -32,13 +26,18 @@ usage() {
|
||||
echo " -m only merge the fragments, do not execute the make command"
|
||||
echo " -n use allnoconfig instead of alldefconfig"
|
||||
echo " -r list redundant entries when merging fragments"
|
||||
echo " -O dir to put generated output files"
|
||||
echo " -y make builtin have precedence over modules"
|
||||
echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead."
|
||||
echo
|
||||
echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ environment variable."
|
||||
}
|
||||
|
||||
RUNMAKE=true
|
||||
ALLTARGET=alldefconfig
|
||||
WARNREDUN=false
|
||||
BUILTIN=false
|
||||
OUTPUT=.
|
||||
CONFIG_PREFIX=${CONFIG_-CONFIG_}
|
||||
|
||||
while true; do
|
||||
case $1 in
|
||||
@@ -61,6 +60,11 @@ while true; do
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
"-y")
|
||||
BUILTIN=true
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
"-O")
|
||||
if [ -d $2 ];then
|
||||
OUTPUT=$(echo $2 | sed 's/\/*$//')
|
||||
@@ -77,11 +81,19 @@ while true; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$#" -lt 2 ] ; then
|
||||
if [ "$#" -lt 1 ] ; then
|
||||
usage
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$KCONFIG_CONFIG" ]; then
|
||||
if [ "$OUTPUT" != . ]; then
|
||||
KCONFIG_CONFIG=$(readlink -m -- "$OUTPUT/.config")
|
||||
else
|
||||
KCONFIG_CONFIG=.config
|
||||
fi
|
||||
fi
|
||||
|
||||
INITFILE=$1
|
||||
shift;
|
||||
|
||||
@@ -91,44 +103,61 @@ if [ ! -r "$INITFILE" ]; then
|
||||
fi
|
||||
|
||||
MERGE_LIST=$*
|
||||
SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p"
|
||||
SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p"
|
||||
SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p"
|
||||
|
||||
TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
|
||||
MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX)
|
||||
|
||||
echo "Using $INITFILE as base"
|
||||
|
||||
trap clean_up EXIT
|
||||
|
||||
cat $INITFILE > $TMP_FILE
|
||||
|
||||
# Merge files, printing warnings on overridden values
|
||||
for MERGE_FILE in $MERGE_LIST ; do
|
||||
echo "Merging $MERGE_FILE"
|
||||
if [ ! -r "$MERGE_FILE" ]; then
|
||||
echo "The merge file '$MERGE_FILE' does not exist. Exit." >&2
|
||||
for ORIG_MERGE_FILE in $MERGE_LIST ; do
|
||||
echo "Merging $ORIG_MERGE_FILE"
|
||||
if [ ! -r "$ORIG_MERGE_FILE" ]; then
|
||||
echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2
|
||||
exit 1
|
||||
fi
|
||||
CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE)
|
||||
cat $ORIG_MERGE_FILE > $MERGE_FILE
|
||||
CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE)
|
||||
|
||||
for CFG in $CFG_LIST ; do
|
||||
grep -q -w $CFG $TMP_FILE || continue
|
||||
PREV_VAL=$(grep -w $CFG $TMP_FILE)
|
||||
NEW_VAL=$(grep -w $CFG $MERGE_FILE)
|
||||
if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
|
||||
echo Value of $CFG is redefined by fragment $MERGE_FILE:
|
||||
BUILTIN_FLAG=false
|
||||
if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then
|
||||
echo Previous value: $PREV_VAL
|
||||
echo New value: $NEW_VAL
|
||||
echo -y passed, will not demote y to m
|
||||
echo
|
||||
BUILTIN_FLAG=true
|
||||
elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
|
||||
echo Value of $CFG is redefined by fragment $ORIG_MERGE_FILE:
|
||||
echo Previous value: $PREV_VAL
|
||||
echo New value: $NEW_VAL
|
||||
echo
|
||||
elif [ "$WARNREDUN" = "true" ]; then
|
||||
echo Value of $CFG is redundant by fragment $MERGE_FILE:
|
||||
echo Value of $CFG is redundant by fragment $ORIG_MERGE_FILE:
|
||||
fi
|
||||
if [ "$BUILTIN_FLAG" = "false" ]; then
|
||||
sed -i "/$CFG[ =]/d" $TMP_FILE
|
||||
else
|
||||
sed -i "/$CFG[ =]/d" $MERGE_FILE
|
||||
fi
|
||||
done
|
||||
cat $MERGE_FILE >> $TMP_FILE
|
||||
done
|
||||
|
||||
if [ "$RUNMAKE" = "false" ]; then
|
||||
cp $TMP_FILE $OUTPUT/.config
|
||||
cp -T -- "$TMP_FILE" "$KCONFIG_CONFIG"
|
||||
echo "#"
|
||||
echo "# merged configuration written to $OUTPUT/.config (needs make)"
|
||||
echo "# merged configuration written to $KCONFIG_CONFIG (needs make)"
|
||||
echo "#"
|
||||
clean_up
|
||||
exit
|
||||
fi
|
||||
|
||||
@@ -147,10 +176,10 @@ make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
|
||||
|
||||
|
||||
# Check all specified config values took (might have missed-dependency issues)
|
||||
for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
|
||||
for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do
|
||||
|
||||
REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
|
||||
ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config)
|
||||
ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG" || true)
|
||||
if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
|
||||
echo "Value requested for $CFG not in final .config"
|
||||
echo "Requested value: $REQUESTED_VAL"
|
||||
@@ -158,5 +187,3 @@ for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
clean_up
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
PKG="ncursesw menuw panelw"
|
||||
PKG2="ncurses menu panel"
|
||||
|
||||
if [ -n "$(command -v pkg-config)" ]; then
|
||||
if pkg-config --exists $PKG; then
|
||||
echo cflags=\"$(pkg-config --cflags $PKG)\"
|
||||
echo libs=\"$(pkg-config --libs $PKG)\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if pkg-config --exists $PKG2; then
|
||||
echo cflags=\"$(pkg-config --cflags $PKG2)\"
|
||||
echo libs=\"$(pkg-config --libs $PKG2)\"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check the default paths in case pkg-config is not installed.
|
||||
# (Even if it is installed, some distributions such as openSUSE cannot
|
||||
# find ncurses by pkg-config.)
|
||||
if [ -f /usr/include/ncursesw/ncurses.h ]; then
|
||||
echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\"
|
||||
echo libs=\"-lncursesw -lmenuw -lpanelw\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f /usr/include/ncurses/ncurses.h ]; then
|
||||
echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\"
|
||||
echo libs=\"-lncurses -lmenu -lpanel\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f /usr/include/ncurses.h ]; then
|
||||
echo cflags=\"-D_GNU_SOURCE\"
|
||||
echo libs=\"-lncurses -lmenu -lpanel\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo >&2 "*"
|
||||
echo >&2 "* Unable to find the ncurses package."
|
||||
echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
|
||||
echo >&2 "* depending on your distribution)."
|
||||
echo >&2 "*"
|
||||
exit 1
|
||||
+20
-22
@@ -1,11 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
|
||||
*
|
||||
* Derived from menuconfig.
|
||||
*
|
||||
*/
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -269,7 +270,7 @@ static struct mitem k_menu_items[MAX_MENU_ITEMS];
|
||||
static int items_num;
|
||||
static int global_exit;
|
||||
/* the currently selected button */
|
||||
const char *current_instructions = menu_instructions;
|
||||
static const char *current_instructions = menu_instructions;
|
||||
|
||||
static char *dialog_input_result;
|
||||
static int dialog_input_result_len;
|
||||
@@ -303,7 +304,7 @@ struct function_keys {
|
||||
};
|
||||
|
||||
static const int function_keys_num = 9;
|
||||
struct function_keys function_keys[] = {
|
||||
static struct function_keys function_keys[] = {
|
||||
{
|
||||
.key_str = "F1",
|
||||
.func = "Help",
|
||||
@@ -506,7 +507,7 @@ static int get_mext_match(const char *match_str, match_f flag)
|
||||
index = (index + items_num) % items_num;
|
||||
while (true) {
|
||||
char *str = k_menu_items[index].str;
|
||||
if (strcasestr(str, match_str) != 0)
|
||||
if (strcasestr(str, match_str) != NULL)
|
||||
return index;
|
||||
if (flag == FIND_NEXT_MATCH_UP ||
|
||||
flag == MATCH_TINKER_PATTERN_UP)
|
||||
@@ -672,6 +673,7 @@ static int do_exit(void)
|
||||
"Your configuration changes were NOT saved.",
|
||||
1,
|
||||
"<OK>");
|
||||
conf_write_autoconf(0);
|
||||
break;
|
||||
default:
|
||||
btn_dialog(
|
||||
@@ -801,7 +803,7 @@ static void build_conf(struct menu *menu)
|
||||
}
|
||||
|
||||
val = sym_get_tristate_value(sym);
|
||||
if (sym_is_changable(sym)) {
|
||||
if (sym_is_changeable(sym)) {
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
item_make(menu, 't', "[%c]",
|
||||
@@ -855,7 +857,7 @@ static void build_conf(struct menu *menu)
|
||||
} else {
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
if (sym_is_changable(sym))
|
||||
if (sym_is_changeable(sym))
|
||||
item_make(menu, 't', "[%c]",
|
||||
val == no ? ' ' : '*');
|
||||
else
|
||||
@@ -874,7 +876,7 @@ static void build_conf(struct menu *menu)
|
||||
ch = ' ';
|
||||
break;
|
||||
}
|
||||
if (sym_is_changable(sym)) {
|
||||
if (sym_is_changeable(sym)) {
|
||||
if (sym->rev_dep.tri == mod)
|
||||
item_make(menu,
|
||||
't', "{%c}", ch);
|
||||
@@ -894,14 +896,14 @@ static void build_conf(struct menu *menu)
|
||||
item_add_str("%*c%s%s", tmp, ' ',
|
||||
menu_get_prompt(menu),
|
||||
(sym_has_value(sym) ||
|
||||
!sym_is_changable(sym)) ? "" :
|
||||
!sym_is_changeable(sym)) ? "" :
|
||||
" (NEW)");
|
||||
goto conf_childs;
|
||||
}
|
||||
}
|
||||
item_add_str("%*c%s%s", indent + 1, ' ',
|
||||
menu_get_prompt(menu),
|
||||
(sym_has_value(sym) || !sym_is_changable(sym)) ?
|
||||
(sym_has_value(sym) || !sym_is_changeable(sym)) ?
|
||||
"" : " (NEW)");
|
||||
if (menu->prompt && menu->prompt->type == P_MENU) {
|
||||
item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->");
|
||||
@@ -1046,7 +1048,7 @@ static int do_match(int key, struct match_state *state, int *ans)
|
||||
state->match_direction = FIND_NEXT_MATCH_UP;
|
||||
*ans = get_mext_match(state->pattern,
|
||||
state->match_direction);
|
||||
} else if (key == KEY_BACKSPACE || key == 127) {
|
||||
} else if (key == KEY_BACKSPACE || key == 8 || key == 127) {
|
||||
state->pattern[strlen(state->pattern)-1] = '\0';
|
||||
adj_match_dir(&state->match_direction);
|
||||
} else
|
||||
@@ -1065,7 +1067,7 @@ static int do_match(int key, struct match_state *state, int *ans)
|
||||
|
||||
static void conf(struct menu *menu)
|
||||
{
|
||||
struct menu *submenu = 0;
|
||||
struct menu *submenu = NULL;
|
||||
const char *prompt = menu_get_prompt(menu);
|
||||
struct symbol *sym;
|
||||
int res;
|
||||
@@ -1208,12 +1210,9 @@ static void conf(struct menu *menu)
|
||||
}
|
||||
}
|
||||
|
||||
static void conf_message_callback(const char *fmt, va_list ap)
|
||||
static void conf_message_callback(const char *s)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
btn_dialog(main_window, buf, 1, "<OK>");
|
||||
btn_dialog(main_window, s, 1, "<OK>");
|
||||
}
|
||||
|
||||
static void show_help(struct menu *menu)
|
||||
@@ -1232,7 +1231,7 @@ static void show_help(struct menu *menu)
|
||||
static void conf_choice(struct menu *menu)
|
||||
{
|
||||
const char *prompt = menu_get_prompt(menu);
|
||||
struct menu *child = 0;
|
||||
struct menu *child = NULL;
|
||||
struct symbol *active;
|
||||
int selected_index = 0;
|
||||
int last_top_row = 0;
|
||||
@@ -1439,8 +1438,7 @@ static void conf_save(void)
|
||||
set_config_filename(dialog_input_result);
|
||||
return;
|
||||
}
|
||||
btn_dialog(main_window, "Can't create file! "
|
||||
"Probably a nonexistent directory.",
|
||||
btn_dialog(main_window, "Can't create file!",
|
||||
1, "<OK>");
|
||||
break;
|
||||
case 1:
|
||||
@@ -1454,7 +1452,7 @@ static void conf_save(void)
|
||||
}
|
||||
}
|
||||
|
||||
void setup_windows(void)
|
||||
static void setup_windows(void)
|
||||
{
|
||||
int lines, columns;
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
|
||||
*
|
||||
* Derived from menuconfig.
|
||||
*
|
||||
*/
|
||||
#include "nconf.h"
|
||||
#include "lkc.h"
|
||||
|
||||
/* a list of all the different widgets we use */
|
||||
attributes_t attributes[ATTR_MAX+1] = {0};
|
||||
@@ -129,7 +129,7 @@ static void no_colors_theme(void)
|
||||
mkattrn(FUNCTION_TEXT, A_REVERSE);
|
||||
}
|
||||
|
||||
void set_colors()
|
||||
void set_colors(void)
|
||||
{
|
||||
start_color();
|
||||
use_default_colors();
|
||||
@@ -192,7 +192,7 @@ const char *get_line(const char *text, int line_no)
|
||||
int lines = 0;
|
||||
|
||||
if (!text)
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
for (i = 0; text[i] != '\0' && lines < line_no; i++)
|
||||
if (text[i] == '\n')
|
||||
@@ -364,15 +364,17 @@ int dialog_inputbox(WINDOW *main_window,
|
||||
WINDOW *prompt_win;
|
||||
WINDOW *form_win;
|
||||
PANEL *panel;
|
||||
int i, x, y;
|
||||
int i, x, y, lines, columns, win_lines, win_cols;
|
||||
int res = -1;
|
||||
int cursor_position = strlen(init);
|
||||
int cursor_form_win;
|
||||
char *result = *resultp;
|
||||
|
||||
getmaxyx(stdscr, lines, columns);
|
||||
|
||||
if (strlen(init)+1 > *result_len) {
|
||||
*result_len = strlen(init)+1;
|
||||
*resultp = result = realloc(result, *result_len);
|
||||
*resultp = result = xrealloc(result, *result_len);
|
||||
}
|
||||
|
||||
/* find the widest line of msg: */
|
||||
@@ -386,14 +388,19 @@ int dialog_inputbox(WINDOW *main_window,
|
||||
if (title)
|
||||
prompt_width = max(prompt_width, strlen(title));
|
||||
|
||||
win_lines = min(prompt_lines+6, lines-2);
|
||||
win_cols = min(prompt_width+7, columns-2);
|
||||
prompt_lines = max(win_lines-6, 0);
|
||||
prompt_width = max(win_cols-7, 0);
|
||||
|
||||
/* place dialog in middle of screen */
|
||||
y = (getmaxy(stdscr)-(prompt_lines+4))/2;
|
||||
x = (getmaxx(stdscr)-(prompt_width+4))/2;
|
||||
y = (lines-win_lines)/2;
|
||||
x = (columns-win_cols)/2;
|
||||
|
||||
strncpy(result, init, *result_len);
|
||||
|
||||
/* create the windows */
|
||||
win = newwin(prompt_lines+6, prompt_width+7, y, x);
|
||||
win = newwin(win_lines, win_cols, y, x);
|
||||
prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
|
||||
form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
|
||||
keypad(form_win, TRUE);
|
||||
@@ -432,7 +439,8 @@ int dialog_inputbox(WINDOW *main_window,
|
||||
case KEY_F(F_EXIT):
|
||||
case KEY_F(F_BACK):
|
||||
break;
|
||||
case 127:
|
||||
case 8: /* ^H */
|
||||
case 127: /* ^? */
|
||||
case KEY_BACKSPACE:
|
||||
if (cursor_position > 0) {
|
||||
memmove(&result[cursor_position-1],
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
|
||||
*
|
||||
* Derived from menuconfig.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@@ -14,7 +13,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <curses.h>
|
||||
#include <ncurses.h>
|
||||
#include <menu.h>
|
||||
#include <panel.h>
|
||||
#include <form.h>
|
||||
@@ -23,8 +22,6 @@
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "ncurses.h"
|
||||
|
||||
#define max(a, b) ({\
|
||||
typeof(a) _a = a;\
|
||||
typeof(b) _b = b;\
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
%{
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
%{
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
@@ -20,62 +20,69 @@
|
||||
|
||||
int cdebug = PRINTD;
|
||||
|
||||
extern int zconflex(void);
|
||||
static void yyerror(const char *err);
|
||||
static void zconfprint(const char *err, ...);
|
||||
static void zconf_error(const char *err, ...);
|
||||
static void zconferror(const char *err);
|
||||
static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
|
||||
static bool zconf_endtoken(const char *tokenname,
|
||||
const char *expected_tokenname);
|
||||
|
||||
struct symbol *symbol_hash[SYMBOL_HASHSIZE];
|
||||
|
||||
static struct menu *current_menu, *current_entry;
|
||||
|
||||
%}
|
||||
%expect 30
|
||||
|
||||
%union
|
||||
{
|
||||
char *string;
|
||||
struct file *file;
|
||||
struct symbol *symbol;
|
||||
struct expr *expr;
|
||||
struct menu *menu;
|
||||
const struct kconf_id *id;
|
||||
enum symbol_type type;
|
||||
enum variable_flavor flavor;
|
||||
}
|
||||
|
||||
%token <id>T_MAINMENU
|
||||
%token <id>T_MENU
|
||||
%token <id>T_ENDMENU
|
||||
%token <id>T_SOURCE
|
||||
%token <id>T_CHOICE
|
||||
%token <id>T_ENDCHOICE
|
||||
%token <id>T_COMMENT
|
||||
%token <id>T_CONFIG
|
||||
%token <id>T_MENUCONFIG
|
||||
%token <id>T_HELP
|
||||
%token <string> T_HELPTEXT
|
||||
%token <id>T_IF
|
||||
%token <id>T_ENDIF
|
||||
%token <id>T_DEPENDS
|
||||
%token <id>T_OPTIONAL
|
||||
%token <id>T_PROMPT
|
||||
%token <id>T_TYPE
|
||||
%token <id>T_DEFAULT
|
||||
%token <id>T_SELECT
|
||||
%token <id>T_RANGE
|
||||
%token <id>T_VISIBLE
|
||||
%token <id>T_OPTION
|
||||
%token <id>T_ON
|
||||
%token <string> T_WORD
|
||||
%token <string> T_WORD_QUOTE
|
||||
%token T_UNEQUAL
|
||||
%token T_LESS
|
||||
%token T_LESS_EQUAL
|
||||
%token T_GREATER
|
||||
%token T_GREATER_EQUAL
|
||||
%token T_ALLNOCONFIG_Y
|
||||
%token T_BOOL
|
||||
%token T_CHOICE
|
||||
%token T_CLOSE_PAREN
|
||||
%token T_COLON_EQUAL
|
||||
%token T_COMMENT
|
||||
%token T_CONFIG
|
||||
%token T_DEFAULT
|
||||
%token T_DEFCONFIG_LIST
|
||||
%token T_DEF_BOOL
|
||||
%token T_DEF_TRISTATE
|
||||
%token T_DEPENDS
|
||||
%token T_ENDCHOICE
|
||||
%token T_ENDIF
|
||||
%token T_ENDMENU
|
||||
%token T_HELP
|
||||
%token T_HEX
|
||||
%token T_IF
|
||||
%token T_IMPLY
|
||||
%token T_INT
|
||||
%token T_MAINMENU
|
||||
%token T_MENU
|
||||
%token T_MENUCONFIG
|
||||
%token T_MODULES
|
||||
%token T_ON
|
||||
%token T_OPEN_PAREN
|
||||
%token T_OPTION
|
||||
%token T_OPTIONAL
|
||||
%token T_PLUS_EQUAL
|
||||
%token T_PROMPT
|
||||
%token T_RANGE
|
||||
%token T_SELECT
|
||||
%token T_SOURCE
|
||||
%token T_STRING
|
||||
%token T_TRISTATE
|
||||
%token T_VISIBLE
|
||||
%token T_EOL
|
||||
%token <string> T_ASSIGN_VAL
|
||||
|
||||
%left T_OR
|
||||
%left T_AND
|
||||
@@ -84,13 +91,15 @@ static struct menu *current_menu, *current_entry;
|
||||
%nonassoc T_NOT
|
||||
|
||||
%type <string> prompt
|
||||
%type <symbol> nonconst_symbol
|
||||
%type <symbol> symbol
|
||||
%type <type> type logic_type default
|
||||
%type <expr> expr
|
||||
%type <expr> if_expr
|
||||
%type <id> end
|
||||
%type <id> option_name
|
||||
%type <string> end
|
||||
%type <menu> if_entry menu_entry choice_entry
|
||||
%type <string> symbol_option_arg word_opt
|
||||
%type <string> word_opt assign_val
|
||||
%type <flavor> assign_op
|
||||
|
||||
%destructor {
|
||||
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
|
||||
@@ -99,71 +108,53 @@ static struct menu *current_menu, *current_entry;
|
||||
menu_end_menu();
|
||||
} if_entry menu_entry choice_entry
|
||||
|
||||
%{
|
||||
/* Include zconf.hash.c here so it can see the token constants. */
|
||||
#include "zconf.hash.c"
|
||||
%}
|
||||
|
||||
%%
|
||||
input: nl start | start;
|
||||
input: mainmenu_stmt stmt_list | stmt_list;
|
||||
|
||||
start: mainmenu_stmt stmt_list | stmt_list;
|
||||
/* mainmenu entry */
|
||||
|
||||
mainmenu_stmt: T_MAINMENU prompt T_EOL
|
||||
{
|
||||
menu_add_prompt(P_MENU, $2, NULL);
|
||||
};
|
||||
|
||||
stmt_list:
|
||||
/* empty */
|
||||
| stmt_list common_stmt
|
||||
| stmt_list choice_stmt
|
||||
| stmt_list menu_stmt
|
||||
| stmt_list end { zconf_error("unexpected end statement"); }
|
||||
| stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
|
||||
| stmt_list option_name error T_EOL
|
||||
{
|
||||
zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
|
||||
}
|
||||
| stmt_list error T_EOL { zconf_error("invalid statement"); }
|
||||
;
|
||||
|
||||
option_name:
|
||||
T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
|
||||
;
|
||||
|
||||
common_stmt:
|
||||
T_EOL
|
||||
| if_stmt
|
||||
if_stmt
|
||||
| comment_stmt
|
||||
| config_stmt
|
||||
| menuconfig_stmt
|
||||
| source_stmt
|
||||
| assignment_stmt
|
||||
;
|
||||
|
||||
option_error:
|
||||
T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); }
|
||||
| error T_EOL { zconf_error("invalid option"); }
|
||||
;
|
||||
|
||||
|
||||
/* config/menuconfig entry */
|
||||
|
||||
config_entry_start: T_CONFIG T_WORD T_EOL
|
||||
config_entry_start: T_CONFIG nonconst_symbol T_EOL
|
||||
{
|
||||
struct symbol *sym = sym_lookup($2, 0);
|
||||
sym->flags |= SYMBOL_OPTIONAL;
|
||||
menu_add_entry(sym);
|
||||
printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
|
||||
$2->flags |= SYMBOL_OPTIONAL;
|
||||
menu_add_entry($2);
|
||||
printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name);
|
||||
};
|
||||
|
||||
config_stmt: config_entry_start config_option_list
|
||||
{
|
||||
menu_end_entry();
|
||||
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
|
||||
menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
|
||||
{
|
||||
struct symbol *sym = sym_lookup($2, 0);
|
||||
sym->flags |= SYMBOL_OPTIONAL;
|
||||
menu_add_entry(sym);
|
||||
printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
|
||||
$2->flags |= SYMBOL_OPTIONAL;
|
||||
menu_add_entry($2);
|
||||
printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name);
|
||||
};
|
||||
|
||||
menuconfig_stmt: menuconfig_entry_start config_option_list
|
||||
@@ -172,26 +163,22 @@ menuconfig_stmt: menuconfig_entry_start config_option_list
|
||||
current_entry->prompt->type = P_MENU;
|
||||
else
|
||||
zconfprint("warning: menuconfig statement without prompt");
|
||||
menu_end_entry();
|
||||
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
config_option_list:
|
||||
/* empty */
|
||||
| config_option_list config_option
|
||||
| config_option_list symbol_option
|
||||
| config_option_list depends
|
||||
| config_option_list help
|
||||
| config_option_list option_error
|
||||
| config_option_list T_EOL
|
||||
;
|
||||
|
||||
config_option: T_TYPE prompt_stmt_opt T_EOL
|
||||
config_option: type prompt_stmt_opt T_EOL
|
||||
{
|
||||
menu_set_type($1->stype);
|
||||
menu_set_type($1);
|
||||
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
|
||||
zconf_curname(), zconf_lineno(),
|
||||
$1->stype);
|
||||
$1);
|
||||
};
|
||||
|
||||
config_option: T_PROMPT prompt if_expr T_EOL
|
||||
@@ -200,56 +187,58 @@ config_option: T_PROMPT prompt if_expr T_EOL
|
||||
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
config_option: T_DEFAULT expr if_expr T_EOL
|
||||
config_option: default expr if_expr T_EOL
|
||||
{
|
||||
menu_add_expr(P_DEFAULT, $2, $3);
|
||||
if ($1->stype != S_UNKNOWN)
|
||||
menu_set_type($1->stype);
|
||||
if ($1 != S_UNKNOWN)
|
||||
menu_set_type($1);
|
||||
printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
|
||||
zconf_curname(), zconf_lineno(),
|
||||
$1->stype);
|
||||
$1);
|
||||
};
|
||||
|
||||
config_option: T_SELECT T_WORD if_expr T_EOL
|
||||
config_option: T_SELECT nonconst_symbol if_expr T_EOL
|
||||
{
|
||||
menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
|
||||
menu_add_symbol(P_SELECT, $2, $3);
|
||||
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
config_option: T_IMPLY nonconst_symbol if_expr T_EOL
|
||||
{
|
||||
menu_add_symbol(P_IMPLY, $2, $3);
|
||||
printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
config_option: T_RANGE symbol symbol if_expr T_EOL
|
||||
{
|
||||
menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
|
||||
printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
symbol_option: T_OPTION symbol_option_list T_EOL
|
||||
;
|
||||
|
||||
symbol_option_list:
|
||||
/* empty */
|
||||
| symbol_option_list T_WORD symbol_option_arg
|
||||
config_option: T_OPTION T_MODULES T_EOL
|
||||
{
|
||||
const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
|
||||
if (id && id->flags & TF_OPTION)
|
||||
menu_add_option(id->token, $3);
|
||||
else
|
||||
zconfprint("warning: ignoring unknown option %s", $2);
|
||||
free($2);
|
||||
menu_add_option_modules();
|
||||
};
|
||||
|
||||
symbol_option_arg:
|
||||
/* empty */ { $$ = NULL; }
|
||||
| T_EQUAL prompt { $$ = $2; }
|
||||
;
|
||||
config_option: T_OPTION T_DEFCONFIG_LIST T_EOL
|
||||
{
|
||||
menu_add_option_defconfig_list();
|
||||
};
|
||||
|
||||
config_option: T_OPTION T_ALLNOCONFIG_Y T_EOL
|
||||
{
|
||||
menu_add_option_allnoconfig_y();
|
||||
};
|
||||
|
||||
/* choice entry */
|
||||
|
||||
choice: T_CHOICE word_opt T_EOL
|
||||
{
|
||||
struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
sym->flags |= SYMBOL_NO_WRITE;
|
||||
menu_add_entry(sym);
|
||||
menu_add_expr(P_CHOICE, NULL, NULL);
|
||||
free($2);
|
||||
printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
@@ -260,7 +249,7 @@ choice_entry: choice choice_option_list
|
||||
|
||||
choice_end: end
|
||||
{
|
||||
if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
|
||||
if (zconf_endtoken($1, "choice")) {
|
||||
menu_end_menu();
|
||||
printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
|
||||
}
|
||||
@@ -274,8 +263,6 @@ choice_option_list:
|
||||
| choice_option_list choice_option
|
||||
| choice_option_list depends
|
||||
| choice_option_list help
|
||||
| choice_option_list T_EOL
|
||||
| choice_option_list option_error
|
||||
;
|
||||
|
||||
choice_option: T_PROMPT prompt if_expr T_EOL
|
||||
@@ -284,15 +271,11 @@ choice_option: T_PROMPT prompt if_expr T_EOL
|
||||
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
choice_option: T_TYPE prompt_stmt_opt T_EOL
|
||||
choice_option: logic_type prompt_stmt_opt T_EOL
|
||||
{
|
||||
if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
|
||||
menu_set_type($1->stype);
|
||||
menu_set_type($1);
|
||||
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
|
||||
zconf_curname(), zconf_lineno(),
|
||||
$1->stype);
|
||||
} else
|
||||
YYERROR;
|
||||
zconf_curname(), zconf_lineno(), $1);
|
||||
};
|
||||
|
||||
choice_option: T_OPTIONAL T_EOL
|
||||
@@ -301,16 +284,28 @@ choice_option: T_OPTIONAL T_EOL
|
||||
printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
choice_option: T_DEFAULT T_WORD if_expr T_EOL
|
||||
choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
|
||||
{
|
||||
if ($1->stype == S_UNKNOWN) {
|
||||
menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
|
||||
menu_add_symbol(P_DEFAULT, $2, $3);
|
||||
printd(DEBUG_PARSE, "%s:%d:default\n",
|
||||
zconf_curname(), zconf_lineno());
|
||||
} else
|
||||
YYERROR;
|
||||
};
|
||||
|
||||
type:
|
||||
logic_type
|
||||
| T_INT { $$ = S_INT; }
|
||||
| T_HEX { $$ = S_HEX; }
|
||||
| T_STRING { $$ = S_STRING; }
|
||||
|
||||
logic_type:
|
||||
T_BOOL { $$ = S_BOOLEAN; }
|
||||
| T_TRISTATE { $$ = S_TRISTATE; }
|
||||
|
||||
default:
|
||||
T_DEFAULT { $$ = S_UNKNOWN; }
|
||||
| T_DEF_BOOL { $$ = S_BOOLEAN; }
|
||||
| T_DEF_TRISTATE { $$ = S_TRISTATE; }
|
||||
|
||||
choice_block:
|
||||
/* empty */
|
||||
| choice_block common_stmt
|
||||
@@ -318,7 +313,7 @@ choice_block:
|
||||
|
||||
/* if entry */
|
||||
|
||||
if_entry: T_IF expr nl
|
||||
if_entry: T_IF expr T_EOL
|
||||
{
|
||||
printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
|
||||
menu_add_entry(NULL);
|
||||
@@ -328,29 +323,15 @@ if_entry: T_IF expr nl
|
||||
|
||||
if_end: end
|
||||
{
|
||||
if (zconf_endtoken($1, T_IF, T_ENDIF)) {
|
||||
if (zconf_endtoken($1, "if")) {
|
||||
menu_end_menu();
|
||||
printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
|
||||
}
|
||||
};
|
||||
|
||||
if_stmt: if_entry if_block if_end
|
||||
if_stmt: if_entry stmt_list if_end
|
||||
;
|
||||
|
||||
if_block:
|
||||
/* empty */
|
||||
| if_block common_stmt
|
||||
| if_block menu_stmt
|
||||
| if_block choice_stmt
|
||||
;
|
||||
|
||||
/* mainmenu entry */
|
||||
|
||||
mainmenu_stmt: T_MAINMENU prompt nl
|
||||
{
|
||||
menu_add_prompt(P_MENU, $2, NULL);
|
||||
};
|
||||
|
||||
/* menu entry */
|
||||
|
||||
menu: T_MENU prompt T_EOL
|
||||
@@ -360,33 +341,33 @@ menu: T_MENU prompt T_EOL
|
||||
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
menu_entry: menu visibility_list depends_list
|
||||
menu_entry: menu menu_option_list
|
||||
{
|
||||
$$ = menu_add_menu();
|
||||
};
|
||||
|
||||
menu_end: end
|
||||
{
|
||||
if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
|
||||
if (zconf_endtoken($1, "menu")) {
|
||||
menu_end_menu();
|
||||
printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
|
||||
}
|
||||
};
|
||||
|
||||
menu_stmt: menu_entry menu_block menu_end
|
||||
menu_stmt: menu_entry stmt_list menu_end
|
||||
;
|
||||
|
||||
menu_block:
|
||||
menu_option_list:
|
||||
/* empty */
|
||||
| menu_block common_stmt
|
||||
| menu_block menu_stmt
|
||||
| menu_block choice_stmt
|
||||
| menu_option_list visible
|
||||
| menu_option_list depends
|
||||
;
|
||||
|
||||
source_stmt: T_SOURCE prompt T_EOL
|
||||
{
|
||||
printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
|
||||
zconf_nextfile($2);
|
||||
free($2);
|
||||
};
|
||||
|
||||
/* comment entry */
|
||||
@@ -398,10 +379,13 @@ comment: T_COMMENT prompt T_EOL
|
||||
printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
comment_stmt: comment depends_list
|
||||
{
|
||||
menu_end_entry();
|
||||
};
|
||||
comment_stmt: comment comment_option_list
|
||||
;
|
||||
|
||||
comment_option_list:
|
||||
/* empty */
|
||||
| comment_option_list depends
|
||||
;
|
||||
|
||||
/* help option */
|
||||
|
||||
@@ -413,18 +397,22 @@ help_start: T_HELP T_EOL
|
||||
|
||||
help: help_start T_HELPTEXT
|
||||
{
|
||||
if (current_entry->help) {
|
||||
free(current_entry->help);
|
||||
zconfprint("warning: '%s' defined with more than one help text -- only the last one will be used",
|
||||
current_entry->sym->name ?: "<choice>");
|
||||
}
|
||||
|
||||
/* Is the help text empty or all whitespace? */
|
||||
if ($2[strspn($2, " \f\n\r\t\v")] == '\0')
|
||||
zconfprint("warning: '%s' defined with blank help text",
|
||||
current_entry->sym->name ?: "<choice>");
|
||||
|
||||
current_entry->help = $2;
|
||||
};
|
||||
|
||||
/* depends option */
|
||||
|
||||
depends_list:
|
||||
/* empty */
|
||||
| depends_list depends
|
||||
| depends_list T_EOL
|
||||
| depends_list option_error
|
||||
;
|
||||
|
||||
depends: T_DEPENDS T_ON expr T_EOL
|
||||
{
|
||||
menu_add_dep($3);
|
||||
@@ -432,14 +420,7 @@ depends: T_DEPENDS T_ON expr T_EOL
|
||||
};
|
||||
|
||||
/* visibility option */
|
||||
|
||||
visibility_list:
|
||||
/* empty */
|
||||
| visibility_list visible
|
||||
| visibility_list T_EOL
|
||||
;
|
||||
|
||||
visible: T_VISIBLE if_expr
|
||||
visible: T_VISIBLE if_expr T_EOL
|
||||
{
|
||||
menu_add_visibility($2);
|
||||
};
|
||||
@@ -457,14 +438,9 @@ prompt: T_WORD
|
||||
| T_WORD_QUOTE
|
||||
;
|
||||
|
||||
end: T_ENDMENU T_EOL { $$ = $1; }
|
||||
| T_ENDCHOICE T_EOL { $$ = $1; }
|
||||
| T_ENDIF T_EOL { $$ = $1; }
|
||||
;
|
||||
|
||||
nl:
|
||||
T_EOL
|
||||
| nl T_EOL
|
||||
end: T_ENDMENU T_EOL { $$ = "menu"; }
|
||||
| T_ENDCHOICE T_EOL { $$ = "choice"; }
|
||||
| T_ENDIF T_EOL { $$ = "if"; }
|
||||
;
|
||||
|
||||
if_expr: /* empty */ { $$ = NULL; }
|
||||
@@ -484,13 +460,31 @@ expr: symbol { $$ = expr_alloc_symbol($1); }
|
||||
| expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
|
||||
;
|
||||
|
||||
symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
|
||||
/* For symbol definitions, selects, etc., where quotes are not accepted */
|
||||
nonconst_symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); };
|
||||
|
||||
symbol: nonconst_symbol
|
||||
| T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
|
||||
;
|
||||
|
||||
word_opt: /* empty */ { $$ = NULL; }
|
||||
| T_WORD
|
||||
|
||||
/* assignment statement */
|
||||
|
||||
assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); }
|
||||
|
||||
assign_op:
|
||||
T_EQUAL { $$ = VAR_RECURSIVE; }
|
||||
| T_COLON_EQUAL { $$ = VAR_SIMPLE; }
|
||||
| T_PLUS_EQUAL { $$ = VAR_APPEND; }
|
||||
;
|
||||
|
||||
assign_val:
|
||||
/* empty */ { $$ = xstrdup(""); };
|
||||
| T_ASSIGN_VAL
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void conf_parse(const char *name)
|
||||
@@ -500,61 +494,51 @@ void conf_parse(const char *name)
|
||||
|
||||
zconf_initscan(name);
|
||||
|
||||
sym_init();
|
||||
_menu_init();
|
||||
rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
|
||||
|
||||
if (getenv("ZCONF_DEBUG"))
|
||||
zconfdebug = 1;
|
||||
zconfparse();
|
||||
if (zconfnerrs)
|
||||
yydebug = 1;
|
||||
yyparse();
|
||||
|
||||
/* Variables are expanded in the parse phase. We can free them here. */
|
||||
variable_all_del();
|
||||
|
||||
if (yynerrs)
|
||||
exit(1);
|
||||
if (!modules_sym)
|
||||
modules_sym = sym_find( "n" );
|
||||
|
||||
rootmenu.prompt->text = rootmenu.prompt->text;
|
||||
rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
|
||||
if (!menu_has_prompt(&rootmenu)) {
|
||||
current_entry = &rootmenu;
|
||||
menu_add_prompt(P_MENU, "Main menu", NULL);
|
||||
}
|
||||
|
||||
menu_finalize(&rootmenu);
|
||||
for_all_symbols(i, sym) {
|
||||
if (sym_check_deps(sym))
|
||||
zconfnerrs++;
|
||||
yynerrs++;
|
||||
}
|
||||
if (zconfnerrs)
|
||||
if (yynerrs)
|
||||
exit(1);
|
||||
sym_set_change_count(1);
|
||||
}
|
||||
|
||||
static const char *zconf_tokenname(int token)
|
||||
static bool zconf_endtoken(const char *tokenname,
|
||||
const char *expected_tokenname)
|
||||
{
|
||||
switch (token) {
|
||||
case T_MENU: return "menu";
|
||||
case T_ENDMENU: return "endmenu";
|
||||
case T_CHOICE: return "choice";
|
||||
case T_ENDCHOICE: return "endchoice";
|
||||
case T_IF: return "if";
|
||||
case T_ENDIF: return "endif";
|
||||
case T_DEPENDS: return "depends";
|
||||
case T_VISIBLE: return "visible";
|
||||
}
|
||||
return "<token>";
|
||||
}
|
||||
|
||||
static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
|
||||
{
|
||||
if (id->token != endtoken) {
|
||||
if (strcmp(tokenname, expected_tokenname)) {
|
||||
zconf_error("unexpected '%s' within %s block",
|
||||
kconf_id_strings + id->name, zconf_tokenname(starttoken));
|
||||
zconfnerrs++;
|
||||
tokenname, expected_tokenname);
|
||||
yynerrs++;
|
||||
return false;
|
||||
}
|
||||
if (current_menu->file != current_file) {
|
||||
zconf_error("'%s' in different file than '%s'",
|
||||
kconf_id_strings + id->name, zconf_tokenname(starttoken));
|
||||
tokenname, expected_tokenname);
|
||||
fprintf(stderr, "%s:%d: location of the '%s'\n",
|
||||
current_menu->file->name, current_menu->lineno,
|
||||
zconf_tokenname(starttoken));
|
||||
zconfnerrs++;
|
||||
expected_tokenname);
|
||||
yynerrs++;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -575,7 +559,7 @@ static void zconf_error(const char *err, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
zconfnerrs++;
|
||||
yynerrs++;
|
||||
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
|
||||
va_start(ap, err);
|
||||
vfprintf(stderr, err, ap);
|
||||
@@ -583,7 +567,7 @@ static void zconf_error(const char *err, ...)
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void zconferror(const char *err)
|
||||
static void yyerror(const char *err)
|
||||
{
|
||||
fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
|
||||
}
|
||||
@@ -616,7 +600,7 @@ static void print_symbol(FILE *out, struct menu *menu)
|
||||
fprintf(out, "\nconfig %s\n", sym->name);
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
fputs(" boolean\n", out);
|
||||
fputs(" bool\n", out);
|
||||
break;
|
||||
case S_TRISTATE:
|
||||
fputs(" tristate\n", out);
|
||||
@@ -664,6 +648,11 @@ static void print_symbol(FILE *out, struct menu *menu)
|
||||
expr_fprint(prop->expr, out);
|
||||
fputc('\n', out);
|
||||
break;
|
||||
case P_IMPLY:
|
||||
fputs( " imply ", out);
|
||||
expr_fprint(prop->expr, out);
|
||||
fputc('\n', out);
|
||||
break;
|
||||
case P_RANGE:
|
||||
fputs( " range ", out);
|
||||
expr_fprint(prop->expr, out);
|
||||
@@ -674,6 +663,10 @@ static void print_symbol(FILE *out, struct menu *menu)
|
||||
print_quoted_string(out, prop->text);
|
||||
fputc('\n', out);
|
||||
break;
|
||||
case P_SYMBOL:
|
||||
fputs( " symbol ", out);
|
||||
fprintf(out, "%s\n", prop->sym->name);
|
||||
break;
|
||||
default:
|
||||
fprintf(out, " unknown prop %d!\n", prop->type);
|
||||
break;
|
||||
@@ -734,9 +727,5 @@ void zconfdump(FILE *out)
|
||||
}
|
||||
}
|
||||
|
||||
#include "zconf.lex.c"
|
||||
#include "util.c"
|
||||
#include "confdata.c"
|
||||
#include "expr.c"
|
||||
#include "symbol.c"
|
||||
#include "menu.c"
|
||||
@@ -0,0 +1,574 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "lkc.h"
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
static char *expand_string_with_args(const char *in, int argc, char *argv[]);
|
||||
static char *expand_string(const char *in);
|
||||
|
||||
static void __attribute__((noreturn)) pperror(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Environment variables
|
||||
*/
|
||||
static LIST_HEAD(env_list);
|
||||
|
||||
struct env {
|
||||
char *name;
|
||||
char *value;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static void env_add(const char *name, const char *value)
|
||||
{
|
||||
struct env *e;
|
||||
|
||||
e = xmalloc(sizeof(*e));
|
||||
e->name = xstrdup(name);
|
||||
e->value = xstrdup(value);
|
||||
|
||||
list_add_tail(&e->node, &env_list);
|
||||
}
|
||||
|
||||
static void env_del(struct env *e)
|
||||
{
|
||||
list_del(&e->node);
|
||||
free(e->name);
|
||||
free(e->value);
|
||||
free(e);
|
||||
}
|
||||
|
||||
/* The returned pointer must be freed when done */
|
||||
static char *env_expand(const char *name)
|
||||
{
|
||||
struct env *e;
|
||||
const char *value;
|
||||
|
||||
if (!*name)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(e, &env_list, node) {
|
||||
if (!strcmp(name, e->name))
|
||||
return xstrdup(e->value);
|
||||
}
|
||||
|
||||
value = getenv(name);
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* We need to remember all referenced environment variables.
|
||||
* They will be written out to include/config/auto.conf.cmd
|
||||
*/
|
||||
env_add(name, value);
|
||||
|
||||
return xstrdup(value);
|
||||
}
|
||||
|
||||
void env_write_dep(FILE *f, const char *autoconfig_name)
|
||||
{
|
||||
struct env *e, *tmp;
|
||||
|
||||
list_for_each_entry_safe(e, tmp, &env_list, node) {
|
||||
fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value);
|
||||
fprintf(f, "%s: FORCE\n", autoconfig_name);
|
||||
fprintf(f, "endif\n");
|
||||
env_del(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Built-in functions
|
||||
*/
|
||||
struct function {
|
||||
const char *name;
|
||||
unsigned int min_args;
|
||||
unsigned int max_args;
|
||||
char *(*func)(int argc, char *argv[]);
|
||||
};
|
||||
|
||||
static char *do_error_if(int argc, char *argv[])
|
||||
{
|
||||
if (!strcmp(argv[0], "y"))
|
||||
pperror("%s", argv[1]);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *do_filename(int argc, char *argv[])
|
||||
{
|
||||
return xstrdup(current_file->name);
|
||||
}
|
||||
|
||||
static char *do_info(int argc, char *argv[])
|
||||
{
|
||||
printf("%s\n", argv[0]);
|
||||
|
||||
return xstrdup("");
|
||||
}
|
||||
|
||||
static char *do_lineno(int argc, char *argv[])
|
||||
{
|
||||
char buf[16];
|
||||
|
||||
sprintf(buf, "%d", yylineno);
|
||||
|
||||
return xstrdup(buf);
|
||||
}
|
||||
|
||||
static char *do_shell(int argc, char *argv[])
|
||||
{
|
||||
FILE *p;
|
||||
char buf[256];
|
||||
char *cmd;
|
||||
size_t nread;
|
||||
int i;
|
||||
|
||||
cmd = argv[0];
|
||||
|
||||
p = popen(cmd, "r");
|
||||
if (!p) {
|
||||
perror(cmd);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
nread = fread(buf, 1, sizeof(buf), p);
|
||||
if (nread == sizeof(buf))
|
||||
nread--;
|
||||
|
||||
/* remove trailing new lines */
|
||||
while (nread > 0 && buf[nread - 1] == '\n')
|
||||
nread--;
|
||||
|
||||
buf[nread] = 0;
|
||||
|
||||
/* replace a new line with a space */
|
||||
for (i = 0; i < nread; i++) {
|
||||
if (buf[i] == '\n')
|
||||
buf[i] = ' ';
|
||||
}
|
||||
|
||||
if (pclose(p) == -1) {
|
||||
perror(cmd);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return xstrdup(buf);
|
||||
}
|
||||
|
||||
static char *do_warning_if(int argc, char *argv[])
|
||||
{
|
||||
if (!strcmp(argv[0], "y"))
|
||||
fprintf(stderr, "%s:%d: %s\n",
|
||||
current_file->name, yylineno, argv[1]);
|
||||
|
||||
return xstrdup("");
|
||||
}
|
||||
|
||||
static const struct function function_table[] = {
|
||||
/* Name MIN MAX Function */
|
||||
{ "error-if", 2, 2, do_error_if },
|
||||
{ "filename", 0, 0, do_filename },
|
||||
{ "info", 1, 1, do_info },
|
||||
{ "lineno", 0, 0, do_lineno },
|
||||
{ "shell", 1, 1, do_shell },
|
||||
{ "warning-if", 2, 2, do_warning_if },
|
||||
};
|
||||
|
||||
#define FUNCTION_MAX_ARGS 16
|
||||
|
||||
static char *function_expand(const char *name, int argc, char *argv[])
|
||||
{
|
||||
const struct function *f;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(function_table); i++) {
|
||||
f = &function_table[i];
|
||||
if (strcmp(f->name, name))
|
||||
continue;
|
||||
|
||||
if (argc < f->min_args)
|
||||
pperror("too few function arguments passed to '%s'",
|
||||
name);
|
||||
|
||||
if (argc > f->max_args)
|
||||
pperror("too many function arguments passed to '%s'",
|
||||
name);
|
||||
|
||||
return f->func(argc, argv);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Variables (and user-defined functions)
|
||||
*/
|
||||
static LIST_HEAD(variable_list);
|
||||
|
||||
struct variable {
|
||||
char *name;
|
||||
char *value;
|
||||
enum variable_flavor flavor;
|
||||
int exp_count;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static struct variable *variable_lookup(const char *name)
|
||||
{
|
||||
struct variable *v;
|
||||
|
||||
list_for_each_entry(v, &variable_list, node) {
|
||||
if (!strcmp(name, v->name))
|
||||
return v;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *variable_expand(const char *name, int argc, char *argv[])
|
||||
{
|
||||
struct variable *v;
|
||||
char *res;
|
||||
|
||||
v = variable_lookup(name);
|
||||
if (!v)
|
||||
return NULL;
|
||||
|
||||
if (argc == 0 && v->exp_count)
|
||||
pperror("Recursive variable '%s' references itself (eventually)",
|
||||
name);
|
||||
|
||||
if (v->exp_count > 1000)
|
||||
pperror("Too deep recursive expansion");
|
||||
|
||||
v->exp_count++;
|
||||
|
||||
if (v->flavor == VAR_RECURSIVE)
|
||||
res = expand_string_with_args(v->value, argc, argv);
|
||||
else
|
||||
res = xstrdup(v->value);
|
||||
|
||||
v->exp_count--;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void variable_add(const char *name, const char *value,
|
||||
enum variable_flavor flavor)
|
||||
{
|
||||
struct variable *v;
|
||||
char *new_value;
|
||||
bool append = false;
|
||||
|
||||
v = variable_lookup(name);
|
||||
if (v) {
|
||||
/* For defined variables, += inherits the existing flavor */
|
||||
if (flavor == VAR_APPEND) {
|
||||
flavor = v->flavor;
|
||||
append = true;
|
||||
} else {
|
||||
free(v->value);
|
||||
}
|
||||
} else {
|
||||
/* For undefined variables, += assumes the recursive flavor */
|
||||
if (flavor == VAR_APPEND)
|
||||
flavor = VAR_RECURSIVE;
|
||||
|
||||
v = xmalloc(sizeof(*v));
|
||||
v->name = xstrdup(name);
|
||||
v->exp_count = 0;
|
||||
list_add_tail(&v->node, &variable_list);
|
||||
}
|
||||
|
||||
v->flavor = flavor;
|
||||
|
||||
if (flavor == VAR_SIMPLE)
|
||||
new_value = expand_string(value);
|
||||
else
|
||||
new_value = xstrdup(value);
|
||||
|
||||
if (append) {
|
||||
v->value = xrealloc(v->value,
|
||||
strlen(v->value) + strlen(new_value) + 2);
|
||||
strcat(v->value, " ");
|
||||
strcat(v->value, new_value);
|
||||
free(new_value);
|
||||
} else {
|
||||
v->value = new_value;
|
||||
}
|
||||
}
|
||||
|
||||
static void variable_del(struct variable *v)
|
||||
{
|
||||
list_del(&v->node);
|
||||
free(v->name);
|
||||
free(v->value);
|
||||
free(v);
|
||||
}
|
||||
|
||||
void variable_all_del(void)
|
||||
{
|
||||
struct variable *v, *tmp;
|
||||
|
||||
list_for_each_entry_safe(v, tmp, &variable_list, node)
|
||||
variable_del(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate a clause with arguments. argc/argv are arguments from the upper
|
||||
* function call.
|
||||
*
|
||||
* Returned string must be freed when done
|
||||
*/
|
||||
static char *eval_clause(const char *str, size_t len, int argc, char *argv[])
|
||||
{
|
||||
char *tmp, *name, *res, *endptr, *prev, *p;
|
||||
int new_argc = 0;
|
||||
char *new_argv[FUNCTION_MAX_ARGS];
|
||||
int nest = 0;
|
||||
int i;
|
||||
unsigned long n;
|
||||
|
||||
tmp = xstrndup(str, len);
|
||||
|
||||
/*
|
||||
* If variable name is '1', '2', etc. It is generally an argument
|
||||
* from a user-function call (i.e. local-scope variable). If not
|
||||
* available, then look-up global-scope variables.
|
||||
*/
|
||||
n = strtoul(tmp, &endptr, 10);
|
||||
if (!*endptr && n > 0 && n <= argc) {
|
||||
res = xstrdup(argv[n - 1]);
|
||||
goto free_tmp;
|
||||
}
|
||||
|
||||
prev = p = tmp;
|
||||
|
||||
/*
|
||||
* Split into tokens
|
||||
* The function name and arguments are separated by a comma.
|
||||
* For example, if the function call is like this:
|
||||
* $(foo,$(x),$(y))
|
||||
*
|
||||
* The input string for this helper should be:
|
||||
* foo,$(x),$(y)
|
||||
*
|
||||
* and split into:
|
||||
* new_argv[0] = 'foo'
|
||||
* new_argv[1] = '$(x)'
|
||||
* new_argv[2] = '$(y)'
|
||||
*/
|
||||
while (*p) {
|
||||
if (nest == 0 && *p == ',') {
|
||||
*p = 0;
|
||||
if (new_argc >= FUNCTION_MAX_ARGS)
|
||||
pperror("too many function arguments");
|
||||
new_argv[new_argc++] = prev;
|
||||
prev = p + 1;
|
||||
} else if (*p == '(') {
|
||||
nest++;
|
||||
} else if (*p == ')') {
|
||||
nest--;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
new_argv[new_argc++] = prev;
|
||||
|
||||
/*
|
||||
* Shift arguments
|
||||
* new_argv[0] represents a function name or a variable name. Put it
|
||||
* into 'name', then shift the rest of the arguments. This simplifies
|
||||
* 'const' handling.
|
||||
*/
|
||||
name = expand_string_with_args(new_argv[0], argc, argv);
|
||||
new_argc--;
|
||||
for (i = 0; i < new_argc; i++)
|
||||
new_argv[i] = expand_string_with_args(new_argv[i + 1],
|
||||
argc, argv);
|
||||
|
||||
/* Search for variables */
|
||||
res = variable_expand(name, new_argc, new_argv);
|
||||
if (res)
|
||||
goto free;
|
||||
|
||||
/* Look for built-in functions */
|
||||
res = function_expand(name, new_argc, new_argv);
|
||||
if (res)
|
||||
goto free;
|
||||
|
||||
/* Last, try environment variable */
|
||||
if (new_argc == 0) {
|
||||
res = env_expand(name);
|
||||
if (res)
|
||||
goto free;
|
||||
}
|
||||
|
||||
res = xstrdup("");
|
||||
free:
|
||||
for (i = 0; i < new_argc; i++)
|
||||
free(new_argv[i]);
|
||||
free(name);
|
||||
free_tmp:
|
||||
free(tmp);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand a string that follows '$'
|
||||
*
|
||||
* For example, if the input string is
|
||||
* ($(FOO)$($(BAR)))$(BAZ)
|
||||
* this helper evaluates
|
||||
* $($(FOO)$($(BAR)))
|
||||
* and returns a new string containing the expansion (note that the string is
|
||||
* recursively expanded), also advancing 'str' to point to the next character
|
||||
* after the corresponding closing parenthesis, in this case, *str will be
|
||||
* $(BAR)
|
||||
*/
|
||||
static char *expand_dollar_with_args(const char **str, int argc, char *argv[])
|
||||
{
|
||||
const char *p = *str;
|
||||
const char *q;
|
||||
int nest = 0;
|
||||
|
||||
/*
|
||||
* In Kconfig, variable/function references always start with "$(".
|
||||
* Neither single-letter variables as in $A nor curly braces as in ${CC}
|
||||
* are supported. '$' not followed by '(' loses its special meaning.
|
||||
*/
|
||||
if (*p != '(') {
|
||||
*str = p;
|
||||
return xstrdup("$");
|
||||
}
|
||||
|
||||
p++;
|
||||
q = p;
|
||||
while (*q) {
|
||||
if (*q == '(') {
|
||||
nest++;
|
||||
} else if (*q == ')') {
|
||||
if (nest-- == 0)
|
||||
break;
|
||||
}
|
||||
q++;
|
||||
}
|
||||
|
||||
if (!*q)
|
||||
pperror("unterminated reference to '%s': missing ')'", p);
|
||||
|
||||
/* Advance 'str' to after the expanded initial portion of the string */
|
||||
*str = q + 1;
|
||||
|
||||
return eval_clause(p, q - p, argc, argv);
|
||||
}
|
||||
|
||||
char *expand_dollar(const char **str)
|
||||
{
|
||||
return expand_dollar_with_args(str, 0, NULL);
|
||||
}
|
||||
|
||||
static char *__expand_string(const char **str, bool (*is_end)(char c),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
const char *in, *p;
|
||||
char *expansion, *out;
|
||||
size_t in_len, out_len;
|
||||
|
||||
out = xmalloc(1);
|
||||
*out = 0;
|
||||
out_len = 1;
|
||||
|
||||
p = in = *str;
|
||||
|
||||
while (1) {
|
||||
if (*p == '$') {
|
||||
in_len = p - in;
|
||||
p++;
|
||||
expansion = expand_dollar_with_args(&p, argc, argv);
|
||||
out_len += in_len + strlen(expansion);
|
||||
out = xrealloc(out, out_len);
|
||||
strncat(out, in, in_len);
|
||||
strcat(out, expansion);
|
||||
free(expansion);
|
||||
in = p;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_end(*p))
|
||||
break;
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
in_len = p - in;
|
||||
out_len += in_len;
|
||||
out = xrealloc(out, out_len);
|
||||
strncat(out, in, in_len);
|
||||
|
||||
/* Advance 'str' to the end character */
|
||||
*str = p;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool is_end_of_str(char c)
|
||||
{
|
||||
return !c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand variables and functions in the given string. Undefined variables
|
||||
* expand to an empty string.
|
||||
* The returned string must be freed when done.
|
||||
*/
|
||||
static char *expand_string_with_args(const char *in, int argc, char *argv[])
|
||||
{
|
||||
return __expand_string(&in, is_end_of_str, argc, argv);
|
||||
}
|
||||
|
||||
static char *expand_string(const char *in)
|
||||
{
|
||||
return expand_string_with_args(in, 0, NULL);
|
||||
}
|
||||
|
||||
static bool is_end_of_token(char c)
|
||||
{
|
||||
return !(isalnum(c) || c == '_' || c == '-');
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand variables in a token. The parsing stops when a token separater
|
||||
* (in most cases, it is a whitespace) is encountered. 'str' is updated to
|
||||
* point to the next character.
|
||||
*
|
||||
* The returned string must be freed when done.
|
||||
*/
|
||||
char *expand_one_token(const char **str)
|
||||
{
|
||||
return __expand_string(str, is_end_of_token, 0, NULL);
|
||||
}
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
PKG="Qt5Core Qt5Gui Qt5Widgets"
|
||||
PKG2="QtCore QtGui"
|
||||
|
||||
if [ -z "$(command -v pkg-config)" ]; then
|
||||
echo >&2 "*"
|
||||
echo >&2 "* 'make xconfig' requires 'pkg-config'. Please install it."
|
||||
echo >&2 "*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if pkg-config --exists $PKG; then
|
||||
echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets)\"
|
||||
echo libs=\"$(pkg-config --libs $PKG)\"
|
||||
echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if pkg-config --exists $PKG2; then
|
||||
echo cflags=\"$(pkg-config --cflags $PKG2)\"
|
||||
echo libs=\"$(pkg-config --libs $PKG2)\"
|
||||
echo moc=\"$(pkg-config --variable=moc_location QtCore)\"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo >&2 "*"
|
||||
echo >&2 "* Could not find Qt via pkg-config."
|
||||
echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in PKG_CONFIG_PATH"
|
||||
echo >&2 "*"
|
||||
exit 1
|
||||
+423
-313
File diff suppressed because it is too large.
Load diff
+71
-78
@@ -1,28 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#if QT_VERSION < 0x040000
|
||||
#include <qlistview.h>
|
||||
#else
|
||||
#include <q3listview.h>
|
||||
#endif
|
||||
#include <QTextBrowser>
|
||||
#include <QTreeWidget>
|
||||
#include <QMainWindow>
|
||||
#include <QHeaderView>
|
||||
#include <qsettings.h>
|
||||
|
||||
#if QT_VERSION < 0x040000
|
||||
#define Q3ValueList QValueList
|
||||
#define Q3PopupMenu QPopupMenu
|
||||
#define Q3ListView QListView
|
||||
#define Q3ListViewItem QListViewItem
|
||||
#define Q3VBox QVBox
|
||||
#define Q3TextBrowser QTextBrowser
|
||||
#define Q3MainWindow QMainWindow
|
||||
#define Q3Action QAction
|
||||
#define Q3ToolBar QToolBar
|
||||
#define Q3ListViewItemIterator QListViewItemIterator
|
||||
#define Q3FileDialog QFileDialog
|
||||
#endif
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
#include <QLineEdit>
|
||||
#include <QSplitter>
|
||||
#include <QCheckBox>
|
||||
#include <QDialog>
|
||||
#include "expr.h"
|
||||
|
||||
class ConfigView;
|
||||
class ConfigList;
|
||||
@@ -33,8 +25,8 @@ class ConfigMainWindow;
|
||||
class ConfigSettings : public QSettings {
|
||||
public:
|
||||
ConfigSettings();
|
||||
Q3ValueList<int> readSizes(const QString& key, bool *ok);
|
||||
bool writeSizes(const QString& key, const Q3ValueList<int>& value);
|
||||
QList<int> readSizes(const QString& key, bool *ok);
|
||||
bool writeSizes(const QString& key, const QList<int>& value);
|
||||
};
|
||||
|
||||
enum colIdx {
|
||||
@@ -47,9 +39,9 @@ enum optionMode {
|
||||
normalOpt = 0, allOpt, promptOpt
|
||||
};
|
||||
|
||||
class ConfigList : public Q3ListView {
|
||||
class ConfigList : public QTreeWidget {
|
||||
Q_OBJECT
|
||||
typedef class Q3ListView Parent;
|
||||
typedef class QTreeWidget Parent;
|
||||
public:
|
||||
ConfigList(ConfigView* p, const char *name = 0);
|
||||
void reinit(void);
|
||||
@@ -61,10 +53,10 @@ public:
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void contentsMousePressEvent(QMouseEvent *e);
|
||||
void contentsMouseReleaseEvent(QMouseEvent *e);
|
||||
void contentsMouseMoveEvent(QMouseEvent *e);
|
||||
void contentsMouseDoubleClickEvent(QMouseEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||
void focusInEvent(QFocusEvent *e);
|
||||
void contextMenuEvent(QContextMenuEvent *e);
|
||||
|
||||
@@ -95,32 +87,23 @@ public:
|
||||
}
|
||||
ConfigItem* firstChild() const
|
||||
{
|
||||
return (ConfigItem *)Parent::firstChild();
|
||||
return (ConfigItem *)children().first();
|
||||
}
|
||||
int mapIdx(colIdx idx)
|
||||
void addColumn(colIdx idx)
|
||||
{
|
||||
return colMap[idx];
|
||||
}
|
||||
void addColumn(colIdx idx, const QString& label)
|
||||
{
|
||||
colMap[idx] = Parent::addColumn(label);
|
||||
colRevMap[colMap[idx]] = idx;
|
||||
showColumn(idx);
|
||||
}
|
||||
void removeColumn(colIdx idx)
|
||||
{
|
||||
int col = colMap[idx];
|
||||
if (col >= 0) {
|
||||
Parent::removeColumn(col);
|
||||
colRevMap[col] = colMap[idx] = -1;
|
||||
}
|
||||
hideColumn(idx);
|
||||
}
|
||||
void setAllOpen(bool open);
|
||||
void setParentMenu(void);
|
||||
|
||||
bool menuSkip(struct menu *);
|
||||
|
||||
template <class P>
|
||||
void updateMenuList(P*, struct menu*);
|
||||
void updateMenuList(ConfigItem *parent, struct menu*);
|
||||
void updateMenuList(ConfigList *parent, struct menu*);
|
||||
|
||||
bool updateAll;
|
||||
|
||||
@@ -132,30 +115,26 @@ public:
|
||||
enum listMode mode;
|
||||
enum optionMode optMode;
|
||||
struct menu *rootEntry;
|
||||
QColorGroup disabledColorGroup;
|
||||
QColorGroup inactivedColorGroup;
|
||||
Q3PopupMenu* headerPopup;
|
||||
|
||||
private:
|
||||
int colMap[colNr];
|
||||
int colRevMap[colNr];
|
||||
QPalette disabledColorGroup;
|
||||
QPalette inactivedColorGroup;
|
||||
QMenu* headerPopup;
|
||||
};
|
||||
|
||||
class ConfigItem : public Q3ListViewItem {
|
||||
typedef class Q3ListViewItem Parent;
|
||||
class ConfigItem : public QTreeWidgetItem {
|
||||
typedef class QTreeWidgetItem Parent;
|
||||
public:
|
||||
ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v)
|
||||
: Parent(parent, after), menu(m), visible(v), goParent(false)
|
||||
ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool v)
|
||||
: Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
|
||||
: Parent(parent, after), menu(m), visible(v), goParent(false)
|
||||
: Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
ConfigItem(Q3ListView *parent, ConfigItem *after, bool v)
|
||||
: Parent(parent, after), menu(0), visible(v), goParent(true)
|
||||
ConfigItem(ConfigList *parent, ConfigItem *after, bool v)
|
||||
: Parent(parent, after), nextItem(0), menu(0), visible(v), goParent(true)
|
||||
{
|
||||
init();
|
||||
}
|
||||
@@ -166,33 +145,43 @@ public:
|
||||
void testUpdateMenu(bool v);
|
||||
ConfigList* listView() const
|
||||
{
|
||||
return (ConfigList*)Parent::listView();
|
||||
return (ConfigList*)Parent::treeWidget();
|
||||
}
|
||||
ConfigItem* firstChild() const
|
||||
{
|
||||
return (ConfigItem *)Parent::firstChild();
|
||||
return (ConfigItem *)Parent::child(0);
|
||||
}
|
||||
ConfigItem* nextSibling() const
|
||||
ConfigItem* nextSibling()
|
||||
{
|
||||
return (ConfigItem *)Parent::nextSibling();
|
||||
ConfigItem *ret = NULL;
|
||||
ConfigItem *_parent = (ConfigItem *)parent();
|
||||
|
||||
if(_parent) {
|
||||
ret = (ConfigItem *)_parent->child(_parent->indexOfChild(this)+1);
|
||||
} else {
|
||||
QTreeWidget *_treeWidget = treeWidget();
|
||||
ret = (ConfigItem *)_treeWidget->topLevelItem(_treeWidget->indexOfTopLevelItem(this)+1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
void setText(colIdx idx, const QString& text)
|
||||
{
|
||||
Parent::setText(listView()->mapIdx(idx), text);
|
||||
Parent::setText(idx, text);
|
||||
}
|
||||
QString text(colIdx idx) const
|
||||
{
|
||||
return Parent::text(listView()->mapIdx(idx));
|
||||
return Parent::text(idx);
|
||||
}
|
||||
void setPixmap(colIdx idx, const QPixmap& pm)
|
||||
void setPixmap(colIdx idx, const QIcon &icon)
|
||||
{
|
||||
Parent::setPixmap(listView()->mapIdx(idx), pm);
|
||||
Parent::setIcon(idx, icon);
|
||||
}
|
||||
const QPixmap* pixmap(colIdx idx) const
|
||||
const QIcon pixmap(colIdx idx) const
|
||||
{
|
||||
return Parent::pixmap(listView()->mapIdx(idx));
|
||||
return icon(idx);
|
||||
}
|
||||
void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
|
||||
// TODO: Implement paintCell
|
||||
|
||||
ConfigItem* nextItem;
|
||||
struct menu *menu;
|
||||
@@ -216,9 +205,9 @@ public:
|
||||
ConfigItem *item;
|
||||
};
|
||||
|
||||
class ConfigView : public Q3VBox {
|
||||
class ConfigView : public QWidget {
|
||||
Q_OBJECT
|
||||
typedef class Q3VBox Parent;
|
||||
typedef class QWidget Parent;
|
||||
public:
|
||||
ConfigView(QWidget* parent, const char *name = 0);
|
||||
~ConfigView(void);
|
||||
@@ -249,9 +238,9 @@ public:
|
||||
static QAction *showPromptAction;
|
||||
};
|
||||
|
||||
class ConfigInfoView : public Q3TextBrowser {
|
||||
class ConfigInfoView : public QTextBrowser {
|
||||
Q_OBJECT
|
||||
typedef class Q3TextBrowser Parent;
|
||||
typedef class QTextBrowser Parent;
|
||||
public:
|
||||
ConfigInfoView(QWidget* parent, const char *name = 0);
|
||||
bool showDebug(void) const { return _showDebug; }
|
||||
@@ -271,8 +260,8 @@ protected:
|
||||
QString debug_info(struct symbol *sym);
|
||||
static QString print_filter(const QString &str);
|
||||
static void expr_print_help(void *data, struct symbol *sym, const char *str);
|
||||
Q3PopupMenu* createPopupMenu(const QPoint& pos);
|
||||
void contentsContextMenuEvent(QContextMenuEvent *e);
|
||||
QMenu *createStandardContextMenu(const QPoint & pos);
|
||||
void contextMenuEvent(QContextMenuEvent *e);
|
||||
|
||||
struct symbol *sym;
|
||||
struct menu *_menu;
|
||||
@@ -299,10 +288,11 @@ protected:
|
||||
struct symbol **result;
|
||||
};
|
||||
|
||||
class ConfigMainWindow : public Q3MainWindow {
|
||||
class ConfigMainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
static Q3Action *saveAction;
|
||||
char *configname;
|
||||
static QAction *saveAction;
|
||||
static void conf_changed(void);
|
||||
public:
|
||||
ConfigMainWindow(void);
|
||||
@@ -331,8 +321,11 @@ protected:
|
||||
ConfigView *configView;
|
||||
ConfigList *configList;
|
||||
ConfigInfoView *helpText;
|
||||
Q3ToolBar *toolBar;
|
||||
Q3Action *backAction;
|
||||
QToolBar *toolBar;
|
||||
QAction *backAction;
|
||||
QAction *singleViewAction;
|
||||
QAction *splitViewAction;
|
||||
QAction *fullViewAction;
|
||||
QSplitter *split1;
|
||||
QSplitter *split2;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/perl -w
|
||||
#!/usr/bin/env perl
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright 2005-2009 - Steven Rostedt
|
||||
# Licensed under the terms of the GNU GPL License version 2
|
||||
#
|
||||
# It's simple enough to figure out how this works.
|
||||
# If not, then you can ask me at stripconfig@goodmis.org
|
||||
@@ -42,6 +42,7 @@
|
||||
# mv config_strip .config
|
||||
# make oldconfig
|
||||
#
|
||||
use warnings;
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
@@ -164,10 +165,10 @@ sub read_kconfig {
|
||||
my $last_source = "";
|
||||
|
||||
# Check for any environment variables used
|
||||
while ($source =~ /\$(\w+)/ && $last_source ne $source) {
|
||||
while ($source =~ /\$\((\w+)\)/ && $last_source ne $source) {
|
||||
my $env = $1;
|
||||
$last_source = $source;
|
||||
$source =~ s/\$$env/$ENV{$env}/;
|
||||
$source =~ s/\$\($env\)/$ENV{$env}/;
|
||||
}
|
||||
|
||||
open(my $kinfile, '<', $source) || die "Can't open $kconfig";
|
||||
@@ -188,7 +189,7 @@ sub read_kconfig {
|
||||
$cont = 0;
|
||||
|
||||
# collect any Kconfig sources
|
||||
if (/^source\s*"(.*)"/) {
|
||||
if (/^source\s+"?([^"]+)/) {
|
||||
my $kconfig = $1;
|
||||
# prevent reading twice.
|
||||
if (!defined($read_kconfigs{$kconfig})) {
|
||||
@@ -237,7 +238,7 @@ sub read_kconfig {
|
||||
}
|
||||
|
||||
# configs without prompts must be selected
|
||||
} elsif ($state ne "NONE" && /^\s*tristate\s\S/) {
|
||||
} elsif ($state ne "NONE" && /^\s*(tristate\s+\S|prompt\b)/) {
|
||||
# note if the config has a prompt
|
||||
$prompts{$config} = 1;
|
||||
|
||||
@@ -256,8 +257,8 @@ sub read_kconfig {
|
||||
|
||||
$iflevel-- if ($iflevel);
|
||||
|
||||
# stop on "help"
|
||||
} elsif (/^\s*help\s*$/) {
|
||||
# stop on "help" and keywords that end a menu entry
|
||||
} elsif (/^\s*(---)?help(---)?\s*$/ || /^(comment|choice|menu)\b/) {
|
||||
$state = "NONE";
|
||||
}
|
||||
}
|
||||
@@ -454,7 +455,7 @@ sub parse_config_depends
|
||||
$p =~ s/^[^$valid]*[$valid]+//;
|
||||
|
||||
# We only need to process if the depend config is a module
|
||||
if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") {
|
||||
if (!defined($orig_configs{$conf}) || $orig_configs{$conf} eq "y") {
|
||||
next;
|
||||
}
|
||||
|
||||
@@ -610,6 +611,40 @@ foreach my $line (@config_file) {
|
||||
next;
|
||||
}
|
||||
|
||||
if (/CONFIG_MODULE_SIG_KEY="(.+)"/) {
|
||||
my $orig_cert = $1;
|
||||
my $default_cert = "certs/signing_key.pem";
|
||||
|
||||
# Check that the logic in this script still matches the one in Kconfig
|
||||
if (!defined($depends{"MODULE_SIG_KEY"}) ||
|
||||
$depends{"MODULE_SIG_KEY"} !~ /"\Q$default_cert\E"/) {
|
||||
print STDERR "WARNING: MODULE_SIG_KEY assertion failure, ",
|
||||
"update needed to ", __FILE__, " line ", __LINE__, "\n";
|
||||
print;
|
||||
} elsif ($orig_cert ne $default_cert && ! -f $orig_cert) {
|
||||
print STDERR "Module signature verification enabled but ",
|
||||
"module signing key \"$orig_cert\" not found. Resetting ",
|
||||
"signing key to default value.\n";
|
||||
print "CONFIG_MODULE_SIG_KEY=\"$default_cert\"\n";
|
||||
} else {
|
||||
print;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if (/CONFIG_SYSTEM_TRUSTED_KEYS="(.+)"/) {
|
||||
my $orig_keys = $1;
|
||||
|
||||
if (! -f $orig_keys) {
|
||||
print STDERR "System keyring enabled but keys \"$orig_keys\" ",
|
||||
"not found. Resetting keys to default value.\n";
|
||||
print "CONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n";
|
||||
} else {
|
||||
print;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if (/^(CONFIG.*)=(m|y)/) {
|
||||
if (defined($configs{$1})) {
|
||||
if ($localyesconfig) {
|
||||
|
||||
+123
-168
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@@ -33,33 +33,6 @@ struct symbol *sym_defconfig_list;
|
||||
struct symbol *modules_sym;
|
||||
tristate modules_val;
|
||||
|
||||
struct expr *sym_env_list;
|
||||
|
||||
static void sym_add_default(struct symbol *sym, const char *def)
|
||||
{
|
||||
struct property *prop = prop_alloc(P_DEFAULT, sym);
|
||||
|
||||
prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
|
||||
}
|
||||
|
||||
void sym_init(void)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct utsname uts;
|
||||
static bool inited = false;
|
||||
|
||||
if (inited)
|
||||
return;
|
||||
inited = true;
|
||||
|
||||
uname(&uts);
|
||||
|
||||
sym = sym_lookup("UNAME_RELEASE", 0);
|
||||
sym->type = S_STRING;
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
sym_add_default(sym, uts.release);
|
||||
}
|
||||
|
||||
enum symbol_type sym_get_type(struct symbol *sym)
|
||||
{
|
||||
enum symbol_type type = sym->type;
|
||||
@@ -77,7 +50,7 @@ const char *sym_type_name(enum symbol_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
return "boolean";
|
||||
return "bool";
|
||||
case S_TRISTATE:
|
||||
return "tristate";
|
||||
case S_INT:
|
||||
@@ -88,8 +61,6 @@ const char *sym_type_name(enum symbol_type type)
|
||||
return "string";
|
||||
case S_UNKNOWN:
|
||||
return "unknown";
|
||||
case S_OTHER:
|
||||
break;
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
@@ -103,15 +74,6 @@ struct property *sym_get_choice_prop(struct symbol *sym)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct property *sym_get_env_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
for_all_properties(sym, prop, P_ENV)
|
||||
return prop;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct property *sym_get_default_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
@@ -124,7 +86,7 @@ static struct property *sym_get_default_prop(struct symbol *sym)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct property *sym_get_range_prop(struct symbol *sym)
|
||||
struct property *sym_get_range_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
@@ -183,7 +145,7 @@ static void sym_validate_range(struct symbol *sym)
|
||||
sprintf(str, "%lld", val2);
|
||||
else
|
||||
sprintf(str, "0x%llx", val2);
|
||||
sym->curr.val = strdup(str);
|
||||
sym->curr.val = xstrdup(str);
|
||||
}
|
||||
|
||||
static void sym_set_changed(struct symbol *sym)
|
||||
@@ -209,12 +171,26 @@ static void sym_set_all_changed(void)
|
||||
static void sym_calc_visibility(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
struct symbol *choice_sym = NULL;
|
||||
tristate tri;
|
||||
|
||||
/* any prompt visible? */
|
||||
tri = no;
|
||||
|
||||
if (sym_is_choice_value(sym))
|
||||
choice_sym = prop_get_symbol(sym_get_choice_prop(sym));
|
||||
|
||||
for_all_prompts(sym, prop) {
|
||||
prop->visible.tri = expr_calc_value(prop->visible.expr);
|
||||
/*
|
||||
* Tristate choice_values with visibility 'mod' are
|
||||
* not visible if the corresponding choice's value is
|
||||
* 'yes'.
|
||||
*/
|
||||
if (choice_sym && sym->type == S_TRISTATE &&
|
||||
prop->visible.tri == mod && choice_sym->curr.tri == yes)
|
||||
prop->visible.tri = no;
|
||||
|
||||
tri = EXPR_OR(tri, prop->visible.tri);
|
||||
}
|
||||
if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
|
||||
@@ -229,7 +205,7 @@ static void sym_calc_visibility(struct symbol *sym)
|
||||
tri = yes;
|
||||
if (sym->dir_dep.expr)
|
||||
tri = expr_calc_value(sym->dir_dep.expr);
|
||||
if (tri == mod)
|
||||
if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
|
||||
tri = yes;
|
||||
if (sym->dir_dep.tri != tri) {
|
||||
sym->dir_dep.tri = tri;
|
||||
@@ -244,6 +220,15 @@ static void sym_calc_visibility(struct symbol *sym)
|
||||
sym->rev_dep.tri = tri;
|
||||
sym_set_changed(sym);
|
||||
}
|
||||
tri = no;
|
||||
if (sym->implied.expr && sym->dir_dep.tri != no)
|
||||
tri = expr_calc_value(sym->implied.expr);
|
||||
if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
|
||||
tri = yes;
|
||||
if (sym->implied.tri != tri) {
|
||||
sym->implied.tri = tri;
|
||||
sym_set_changed(sym);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -310,6 +295,27 @@ static struct symbol *sym_calc_choice(struct symbol *sym)
|
||||
return def_sym;
|
||||
}
|
||||
|
||||
static void sym_warn_unmet_dep(struct symbol *sym)
|
||||
{
|
||||
struct gstr gs = str_new();
|
||||
|
||||
str_printf(&gs,
|
||||
"\nWARNING: unmet direct dependencies detected for %s\n",
|
||||
sym->name);
|
||||
str_printf(&gs,
|
||||
" Depends on [%c]: ",
|
||||
sym->dir_dep.tri == mod ? 'm' : 'n');
|
||||
expr_gstr_print(sym->dir_dep.expr, &gs);
|
||||
str_printf(&gs, "\n");
|
||||
|
||||
expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes,
|
||||
" Selected by [y]:\n");
|
||||
expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod,
|
||||
" Selected by [m]:\n");
|
||||
|
||||
fputs(str_get(&gs), stderr);
|
||||
}
|
||||
|
||||
void sym_calc_value(struct symbol *sym)
|
||||
{
|
||||
struct symbol_value newval, oldval;
|
||||
@@ -348,11 +354,13 @@ void sym_calc_value(struct symbol *sym)
|
||||
sym->curr.tri = no;
|
||||
return;
|
||||
}
|
||||
if (!sym_is_choice_value(sym))
|
||||
sym->flags &= ~SYMBOL_WRITE;
|
||||
|
||||
sym_calc_visibility(sym);
|
||||
|
||||
if (sym->visible != no)
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
|
||||
/* set default if recursively called */
|
||||
sym->curr = newval;
|
||||
|
||||
@@ -367,7 +375,6 @@ void sym_calc_value(struct symbol *sym)
|
||||
/* if the symbol is visible use the user value
|
||||
* if available, otherwise try the default value
|
||||
*/
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
if (sym_has_value(sym)) {
|
||||
newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
|
||||
sym->visible);
|
||||
@@ -379,39 +386,32 @@ void sym_calc_value(struct symbol *sym)
|
||||
if (!sym_is_choice(sym)) {
|
||||
prop = sym_get_default_prop(sym);
|
||||
if (prop) {
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
newval.tri = EXPR_AND(expr_calc_value(prop->expr),
|
||||
prop->visible.tri);
|
||||
if (newval.tri != no)
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
}
|
||||
if (sym->implied.tri != no) {
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
newval.tri = EXPR_OR(newval.tri, sym->implied.tri);
|
||||
}
|
||||
}
|
||||
calc_newval:
|
||||
if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
|
||||
struct expr *e;
|
||||
e = expr_simplify_unmet_dep(sym->rev_dep.expr,
|
||||
sym->dir_dep.expr);
|
||||
fprintf(stderr, "warning: (");
|
||||
expr_fprint(e, stderr);
|
||||
fprintf(stderr, ") selects %s which has unmet direct dependencies (",
|
||||
sym->name);
|
||||
expr_fprint(sym->dir_dep.expr, stderr);
|
||||
fprintf(stderr, ")\n");
|
||||
expr_free(e);
|
||||
}
|
||||
if (sym->dir_dep.tri < sym->rev_dep.tri)
|
||||
sym_warn_unmet_dep(sym);
|
||||
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
|
||||
}
|
||||
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
|
||||
if (newval.tri == mod &&
|
||||
(sym_get_type(sym) == S_BOOLEAN || sym->implied.tri == yes))
|
||||
newval.tri = yes;
|
||||
break;
|
||||
case S_STRING:
|
||||
case S_HEX:
|
||||
case S_INT:
|
||||
if (sym->visible != no) {
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
if (sym_has_value(sym)) {
|
||||
if (sym->visible != no && sym_has_value(sym)) {
|
||||
newval.val = sym->def[S_DEF_USER].val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop = sym_get_default_prop(sym);
|
||||
if (prop) {
|
||||
struct symbol *ds = prop_get_symbol(prop);
|
||||
@@ -452,7 +452,7 @@ void sym_calc_value(struct symbol *sym)
|
||||
}
|
||||
}
|
||||
|
||||
if (sym->flags & SYMBOL_AUTO)
|
||||
if (sym->flags & SYMBOL_NO_WRITE)
|
||||
sym->flags &= ~SYMBOL_WRITE;
|
||||
|
||||
if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
|
||||
@@ -484,6 +484,8 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
|
||||
return false;
|
||||
if (sym->visible <= sym->rev_dep.tri)
|
||||
return false;
|
||||
if (sym->implied.tri == yes && val == mod)
|
||||
return false;
|
||||
if (sym_is_choice_value(sym) && sym->visible == yes)
|
||||
return val == yes;
|
||||
return val >= sym->rev_dep.tri && val <= sym->visible;
|
||||
@@ -736,6 +738,10 @@ const char *sym_get_string_default(struct symbol *sym)
|
||||
if (sym->type == S_BOOLEAN && val == mod)
|
||||
val = yes;
|
||||
|
||||
/* adjust the default value if this symbol is implied by another */
|
||||
if (val < sym->implied.tri)
|
||||
val = sym->implied.tri;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
@@ -749,7 +755,6 @@ const char *sym_get_string_default(struct symbol *sym)
|
||||
return str;
|
||||
case S_STRING:
|
||||
return str;
|
||||
case S_OTHER:
|
||||
case S_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
@@ -780,7 +785,7 @@ const char *sym_get_string_value(struct symbol *sym)
|
||||
return (const char *)sym->curr.val;
|
||||
}
|
||||
|
||||
bool sym_is_changable(struct symbol *sym)
|
||||
bool sym_is_changeable(struct symbol *sym)
|
||||
{
|
||||
return sym->visible > sym->rev_dep.tri;
|
||||
}
|
||||
@@ -817,7 +822,7 @@ struct symbol *sym_lookup(const char *name, int flags)
|
||||
: !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
|
||||
return symbol;
|
||||
}
|
||||
new_name = strdup(name);
|
||||
new_name = xstrdup(name);
|
||||
} else {
|
||||
new_name = NULL;
|
||||
hash = 0;
|
||||
@@ -862,55 +867,6 @@ struct symbol *sym_find(const char *name)
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand symbol's names embedded in the string given in argument. Symbols'
|
||||
* name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
|
||||
* the empty string.
|
||||
*/
|
||||
const char *sym_expand_string_value(const char *in)
|
||||
{
|
||||
const char *src;
|
||||
char *res;
|
||||
size_t reslen;
|
||||
|
||||
reslen = strlen(in) + 1;
|
||||
res = xmalloc(reslen);
|
||||
res[0] = '\0';
|
||||
|
||||
while ((src = strchr(in, '$'))) {
|
||||
char *p, name[SYMBOL_MAXLENGTH];
|
||||
const char *symval = "";
|
||||
struct symbol *sym;
|
||||
size_t newlen;
|
||||
|
||||
strncat(res, in, src - in);
|
||||
src++;
|
||||
|
||||
p = name;
|
||||
while (isalnum(*src) || *src == '_')
|
||||
*p++ = *src++;
|
||||
*p = '\0';
|
||||
|
||||
sym = sym_find(name);
|
||||
if (sym != NULL) {
|
||||
sym_calc_value(sym);
|
||||
symval = sym_get_string_value(sym);
|
||||
}
|
||||
|
||||
newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
|
||||
if (newlen > reslen) {
|
||||
reslen = newlen;
|
||||
res = realloc(res, reslen);
|
||||
}
|
||||
|
||||
strcat(res, symval);
|
||||
in = src;
|
||||
}
|
||||
strcat(res, in);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const char *sym_escape_string_value(const char *in)
|
||||
{
|
||||
const char *p;
|
||||
@@ -1027,7 +983,7 @@ struct symbol **sym_re_search(const char *pattern)
|
||||
}
|
||||
if (sym_match_arr) {
|
||||
qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
|
||||
sym_arr = malloc((cnt+1) * sizeof(struct symbol));
|
||||
sym_arr = malloc((cnt+1) * sizeof(struct symbol *));
|
||||
if (!sym_arr)
|
||||
goto sym_re_search_free;
|
||||
for (i = 0; i < cnt; i++)
|
||||
@@ -1052,7 +1008,7 @@ static struct dep_stack {
|
||||
struct dep_stack *prev, *next;
|
||||
struct symbol *sym;
|
||||
struct property *prop;
|
||||
struct expr *expr;
|
||||
struct expr **expr;
|
||||
} *check_top;
|
||||
|
||||
static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
|
||||
@@ -1116,18 +1072,8 @@ static void sym_check_print_recursive(struct symbol *last_sym)
|
||||
if (stack->sym == last_sym)
|
||||
fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
|
||||
prop->file->name, prop->lineno);
|
||||
if (stack->expr) {
|
||||
fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
|
||||
prop->file->name, prop->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
prop_get_type_name(prop->type),
|
||||
next_sym->name ? next_sym->name : "<choice>");
|
||||
} else if (stack->prop) {
|
||||
fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
|
||||
prop->file->name, prop->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
next_sym->name ? next_sym->name : "<choice>");
|
||||
} else if (sym_is_choice(sym)) {
|
||||
|
||||
if (sym_is_choice(sym)) {
|
||||
fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
|
||||
menu->file->name, menu->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
@@ -1137,14 +1083,41 @@ static void sym_check_print_recursive(struct symbol *last_sym)
|
||||
menu->file->name, menu->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
next_sym->name ? next_sym->name : "<choice>");
|
||||
} else {
|
||||
} else if (stack->expr == &sym->dir_dep.expr) {
|
||||
fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
|
||||
prop->file->name, prop->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
next_sym->name ? next_sym->name : "<choice>");
|
||||
} else if (stack->expr == &sym->rev_dep.expr) {
|
||||
fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
|
||||
prop->file->name, prop->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
next_sym->name ? next_sym->name : "<choice>");
|
||||
} else if (stack->expr == &sym->implied.expr) {
|
||||
fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n",
|
||||
prop->file->name, prop->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
next_sym->name ? next_sym->name : "<choice>");
|
||||
} else if (stack->expr) {
|
||||
fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
|
||||
prop->file->name, prop->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
prop_get_type_name(prop->type),
|
||||
next_sym->name ? next_sym->name : "<choice>");
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n",
|
||||
prop->file->name, prop->lineno,
|
||||
sym->name ? sym->name : "<choice>",
|
||||
prop_get_type_name(prop->type),
|
||||
next_sym->name ? next_sym->name : "<choice>");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"For a resolution refer to Documentation/kbuild/kconfig-language.rst\n"
|
||||
"subsection \"Kconfig recursive dependency limitations\"\n"
|
||||
"\n");
|
||||
|
||||
if (check_top == &cv_stack)
|
||||
dep_stack_remove();
|
||||
}
|
||||
@@ -1179,7 +1152,7 @@ static struct symbol *sym_check_expr_deps(struct expr *e)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("Oops! How to check %d?\n", e->type);
|
||||
fprintf(stderr, "Oops! How to check %d?\n", e->type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1192,12 +1165,26 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym)
|
||||
|
||||
dep_stack_insert(&stack, sym);
|
||||
|
||||
stack.expr = &sym->dir_dep.expr;
|
||||
sym2 = sym_check_expr_deps(sym->dir_dep.expr);
|
||||
if (sym2)
|
||||
goto out;
|
||||
|
||||
stack.expr = &sym->rev_dep.expr;
|
||||
sym2 = sym_check_expr_deps(sym->rev_dep.expr);
|
||||
if (sym2)
|
||||
goto out;
|
||||
|
||||
stack.expr = &sym->implied.expr;
|
||||
sym2 = sym_check_expr_deps(sym->implied.expr);
|
||||
if (sym2)
|
||||
goto out;
|
||||
|
||||
stack.expr = NULL;
|
||||
|
||||
for (prop = sym->prop; prop; prop = prop->next) {
|
||||
if (prop->type == P_CHOICE || prop->type == P_SELECT)
|
||||
if (prop->type == P_CHOICE || prop->type == P_SELECT ||
|
||||
prop->type == P_IMPLY)
|
||||
continue;
|
||||
stack.prop = prop;
|
||||
sym2 = sym_check_expr_deps(prop->visible.expr);
|
||||
@@ -1205,7 +1192,7 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym)
|
||||
break;
|
||||
if (prop->type != P_DEFAULT || sym_is_choice(sym))
|
||||
continue;
|
||||
stack.expr = prop->expr;
|
||||
stack.expr = &prop->expr;
|
||||
sym2 = sym_check_expr_deps(prop->expr);
|
||||
if (sym2)
|
||||
break;
|
||||
@@ -1283,9 +1270,6 @@ struct symbol *sym_check_deps(struct symbol *sym)
|
||||
sym->flags &= ~SYMBOL_CHECK;
|
||||
}
|
||||
|
||||
if (sym2 && sym2 == sym)
|
||||
sym2 = NULL;
|
||||
|
||||
return sym2;
|
||||
}
|
||||
|
||||
@@ -1324,8 +1308,6 @@ const char *prop_get_type_name(enum prop_type type)
|
||||
switch (type) {
|
||||
case P_PROMPT:
|
||||
return "prompt";
|
||||
case P_ENV:
|
||||
return "env";
|
||||
case P_COMMENT:
|
||||
return "comment";
|
||||
case P_MENU:
|
||||
@@ -1336,6 +1318,8 @@ const char *prop_get_type_name(enum prop_type type)
|
||||
return "choice";
|
||||
case P_SELECT:
|
||||
return "select";
|
||||
case P_IMPLY:
|
||||
return "imply";
|
||||
case P_RANGE:
|
||||
return "range";
|
||||
case P_SYMBOL:
|
||||
@@ -1345,32 +1329,3 @@ const char *prop_get_type_name(enum prop_type type)
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void prop_add_env(const char *env)
|
||||
{
|
||||
struct symbol *sym, *sym2;
|
||||
struct property *prop;
|
||||
char *p;
|
||||
|
||||
sym = current_entry->sym;
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
for_all_properties(sym, prop, P_ENV) {
|
||||
sym2 = prop_get_symbol(prop);
|
||||
if (strcmp(sym2->name, env))
|
||||
menu_warn(current_entry, "redefining environment symbol from %s",
|
||||
sym2->name);
|
||||
return;
|
||||
}
|
||||
|
||||
prop = prop_alloc(P_ENV, sym);
|
||||
prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
|
||||
|
||||
sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
|
||||
sym_env_list->right.sym = sym;
|
||||
|
||||
p = getenv(env);
|
||||
if (p)
|
||||
sym_add_default(sym, p);
|
||||
else
|
||||
menu_warn(current_entry, "environment variable %s undefined", env);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
default y
|
||||
|
||||
config A0
|
||||
bool "A0"
|
||||
depends on A
|
||||
default y
|
||||
help
|
||||
This depends on A, so should be a submenu of A.
|
||||
|
||||
config A0_0
|
||||
bool "A1_0"
|
||||
depends on A0
|
||||
help
|
||||
Submenus are created recursively.
|
||||
This should be a submenu of A0.
|
||||
|
||||
config A1
|
||||
bool "A1"
|
||||
depends on A
|
||||
default y
|
||||
help
|
||||
This should line up with A0.
|
||||
|
||||
choice
|
||||
prompt "choice"
|
||||
depends on A1
|
||||
help
|
||||
Choice should become a submenu as well.
|
||||
|
||||
config A1_0
|
||||
bool "A1_0"
|
||||
|
||||
config A1_1
|
||||
bool "A1_1"
|
||||
|
||||
endchoice
|
||||
|
||||
config B
|
||||
bool "B"
|
||||
help
|
||||
This is independent of A.
|
||||
|
||||
config C
|
||||
bool "C"
|
||||
depends on A
|
||||
help
|
||||
This depends on A, but not a consecutive item, so can/should not
|
||||
be a submenu.
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Create submenu for symbols that depend on the preceding one.
|
||||
|
||||
If a symbols has dependency on the preceding symbol, the menu entry
|
||||
should become the submenu of the preceding one, and displayed with
|
||||
deeper indentation.
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stdout_contains('expected_stdout')
|
||||
@@ -0,0 +1,10 @@
|
||||
A (A) [Y/n/?] (NEW)
|
||||
A0 (A0) [Y/n/?] (NEW)
|
||||
A1_0 (A0_0) [N/y/?] (NEW)
|
||||
A1 (A1) [Y/n/?] (NEW)
|
||||
choice
|
||||
> 1. A1_0 (A1_0) (NEW)
|
||||
2. A1_1 (A1_1) (NEW)
|
||||
choice[1-2?]:
|
||||
B (B) [N/y/?] (NEW)
|
||||
C (C) [N/y/?] (NEW)
|
||||
@@ -0,0 +1,56 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config MODULES
|
||||
bool "Enable loadable module support"
|
||||
option modules
|
||||
default y
|
||||
|
||||
choice
|
||||
prompt "boolean choice"
|
||||
default BOOL_CHOICE1
|
||||
|
||||
config BOOL_CHOICE0
|
||||
bool "choice 0"
|
||||
|
||||
config BOOL_CHOICE1
|
||||
bool "choice 1"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "optional boolean choice"
|
||||
optional
|
||||
default OPT_BOOL_CHOICE1
|
||||
|
||||
config OPT_BOOL_CHOICE0
|
||||
bool "choice 0"
|
||||
|
||||
config OPT_BOOL_CHOICE1
|
||||
bool "choice 1"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "tristate choice"
|
||||
default TRI_CHOICE1
|
||||
|
||||
config TRI_CHOICE0
|
||||
tristate "choice 0"
|
||||
|
||||
config TRI_CHOICE1
|
||||
tristate "choice 1"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "optional tristate choice"
|
||||
optional
|
||||
default OPT_TRI_CHOICE1
|
||||
|
||||
config OPT_TRI_CHOICE0
|
||||
tristate "choice 0"
|
||||
|
||||
config OPT_TRI_CHOICE1
|
||||
tristate "choice 1"
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,41 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Basic choice tests.
|
||||
|
||||
The handling of 'choice' is a bit complicated part in Kconfig.
|
||||
|
||||
The behavior of 'y' choice is intuitive. If choice values are tristate,
|
||||
the choice can be 'm' where each value can be enabled independently.
|
||||
Also, if a choice is marked as 'optional', the whole choice can be
|
||||
invisible.
|
||||
"""
|
||||
|
||||
|
||||
def test_oldask0(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stdout_contains('oldask0_expected_stdout')
|
||||
|
||||
|
||||
def test_oldask1(conf):
|
||||
assert conf.oldaskconfig('oldask1_config') == 0
|
||||
assert conf.stdout_contains('oldask1_expected_stdout')
|
||||
|
||||
|
||||
def test_allyes(conf):
|
||||
assert conf.allyesconfig() == 0
|
||||
assert conf.config_contains('allyes_expected_config')
|
||||
|
||||
|
||||
def test_allmod(conf):
|
||||
assert conf.allmodconfig() == 0
|
||||
assert conf.config_contains('allmod_expected_config')
|
||||
|
||||
|
||||
def test_allno(conf):
|
||||
assert conf.allnoconfig() == 0
|
||||
assert conf.config_contains('allno_expected_config')
|
||||
|
||||
|
||||
def test_alldef(conf):
|
||||
assert conf.alldefconfig() == 0
|
||||
assert conf.config_contains('alldef_expected_config')
|
||||
@@ -0,0 +1,5 @@
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BOOL_CHOICE0 is not set
|
||||
CONFIG_BOOL_CHOICE1=y
|
||||
# CONFIG_TRI_CHOICE0 is not set
|
||||
# CONFIG_TRI_CHOICE1 is not set
|
||||
@@ -0,0 +1,9 @@
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BOOL_CHOICE0 is not set
|
||||
CONFIG_BOOL_CHOICE1=y
|
||||
# CONFIG_OPT_BOOL_CHOICE0 is not set
|
||||
CONFIG_OPT_BOOL_CHOICE1=y
|
||||
CONFIG_TRI_CHOICE0=m
|
||||
CONFIG_TRI_CHOICE1=m
|
||||
CONFIG_OPT_TRI_CHOICE0=m
|
||||
CONFIG_OPT_TRI_CHOICE1=m
|
||||
@@ -0,0 +1,5 @@
|
||||
# CONFIG_MODULES is not set
|
||||
# CONFIG_BOOL_CHOICE0 is not set
|
||||
CONFIG_BOOL_CHOICE1=y
|
||||
# CONFIG_TRI_CHOICE0 is not set
|
||||
CONFIG_TRI_CHOICE1=y
|
||||
@@ -0,0 +1,9 @@
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BOOL_CHOICE0 is not set
|
||||
CONFIG_BOOL_CHOICE1=y
|
||||
# CONFIG_OPT_BOOL_CHOICE0 is not set
|
||||
CONFIG_OPT_BOOL_CHOICE1=y
|
||||
# CONFIG_TRI_CHOICE0 is not set
|
||||
CONFIG_TRI_CHOICE1=y
|
||||
# CONFIG_OPT_TRI_CHOICE0 is not set
|
||||
CONFIG_OPT_TRI_CHOICE1=y
|
||||
@@ -0,0 +1,10 @@
|
||||
Enable loadable module support (MODULES) [Y/n/?] (NEW)
|
||||
boolean choice
|
||||
1. choice 0 (BOOL_CHOICE0) (NEW)
|
||||
> 2. choice 1 (BOOL_CHOICE1) (NEW)
|
||||
choice[1-2?]:
|
||||
optional boolean choice [N/y/?] (NEW)
|
||||
tristate choice [M/y/?] (NEW)
|
||||
choice 0 (TRI_CHOICE0) [N/m/?] (NEW)
|
||||
choice 1 (TRI_CHOICE1) [N/m/?] (NEW)
|
||||
optional tristate choice [N/m/y/?] (NEW)
|
||||
@@ -0,0 +1,2 @@
|
||||
# CONFIG_MODULES is not set
|
||||
CONFIG_OPT_BOOL_CHOICE0=y
|
||||
@@ -0,0 +1,15 @@
|
||||
Enable loadable module support (MODULES) [N/y/?]
|
||||
boolean choice
|
||||
1. choice 0 (BOOL_CHOICE0) (NEW)
|
||||
> 2. choice 1 (BOOL_CHOICE1) (NEW)
|
||||
choice[1-2?]:
|
||||
optional boolean choice [Y/n/?] (NEW)
|
||||
optional boolean choice
|
||||
> 1. choice 0 (OPT_BOOL_CHOICE0)
|
||||
2. choice 1 (OPT_BOOL_CHOICE1) (NEW)
|
||||
choice[1-2?]:
|
||||
tristate choice
|
||||
1. choice 0 (TRI_CHOICE0) (NEW)
|
||||
> 2. choice 1 (TRI_CHOICE1) (NEW)
|
||||
choice[1-2?]:
|
||||
optional tristate choice [N/y/?]
|
||||
@@ -0,0 +1,21 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config MODULES
|
||||
def_bool y
|
||||
option modules
|
||||
|
||||
config DEP
|
||||
tristate
|
||||
default m
|
||||
|
||||
choice
|
||||
prompt "Tristate Choice"
|
||||
|
||||
config CHOICE0
|
||||
tristate "Choice 0"
|
||||
|
||||
config CHOICE1
|
||||
tristate "Choice 1"
|
||||
depends on DEP
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Hide tristate choice values with mod dependency in y choice.
|
||||
|
||||
If tristate choice values depend on symbols set to 'm', they should be
|
||||
hidden when the choice containing them is changed from 'm' to 'y'
|
||||
(i.e. exclusive choice).
|
||||
|
||||
Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig('config', 'y') == 0
|
||||
assert conf.config_contains('expected_config')
|
||||
assert conf.stdout_contains('expected_stdout')
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_CHOICE0=m
|
||||
CONFIG_CHOICE1=m
|
||||
@@ -0,0 +1,3 @@
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_DEP=m
|
||||
CONFIG_CHOICE0=y
|
||||
@@ -0,0 +1,4 @@
|
||||
Tristate Choice [M/y/?] y
|
||||
Tristate Choice
|
||||
> 1. Choice 0 (CHOICE0)
|
||||
choice[1]: 1
|
||||
@@ -0,0 +1,291 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
#
|
||||
|
||||
"""
|
||||
Kconfig unit testing framework.
|
||||
|
||||
This provides fixture functions commonly used from test files.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
CONF_PATH = os.path.abspath(os.path.join('scripts', 'kconfig', 'conf'))
|
||||
|
||||
|
||||
class Conf:
|
||||
"""Kconfig runner and result checker.
|
||||
|
||||
This class provides methods to run text-based interface of Kconfig
|
||||
(scripts/kconfig/conf) and retrieve the resulted configuration,
|
||||
stdout, and stderr. It also provides methods to compare those
|
||||
results with expectations.
|
||||
"""
|
||||
|
||||
def __init__(self, request):
|
||||
"""Create a new Conf instance.
|
||||
|
||||
request: object to introspect the requesting test module
|
||||
"""
|
||||
# the directory of the test being run
|
||||
self._test_dir = os.path.dirname(str(request.fspath))
|
||||
|
||||
# runners
|
||||
def _run_conf(self, mode, dot_config=None, out_file='.config',
|
||||
interactive=False, in_keys=None, extra_env={}):
|
||||
"""Run text-based Kconfig executable and save the result.
|
||||
|
||||
mode: input mode option (--oldaskconfig, --defconfig=<file> etc.)
|
||||
dot_config: .config file to use for configuration base
|
||||
out_file: file name to contain the output config data
|
||||
interactive: flag to specify the interactive mode
|
||||
in_keys: key inputs for interactive modes
|
||||
extra_env: additional environments
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
command = [CONF_PATH, mode, 'Kconfig']
|
||||
|
||||
# Override 'srctree' environment to make the test as the top directory
|
||||
extra_env['srctree'] = self._test_dir
|
||||
|
||||
# Run Kconfig in a temporary directory.
|
||||
# This directory is automatically removed when done.
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
|
||||
# if .config is given, copy it to the working directory
|
||||
if dot_config:
|
||||
shutil.copyfile(os.path.join(self._test_dir, dot_config),
|
||||
os.path.join(temp_dir, '.config'))
|
||||
|
||||
ps = subprocess.Popen(command,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
cwd=temp_dir,
|
||||
env=dict(os.environ, **extra_env))
|
||||
|
||||
# If input key sequence is given, feed it to stdin.
|
||||
if in_keys:
|
||||
ps.stdin.write(in_keys.encode('utf-8'))
|
||||
|
||||
while ps.poll() is None:
|
||||
# For interactive modes such as oldaskconfig, oldconfig,
|
||||
# send 'Enter' key until the program finishes.
|
||||
if interactive:
|
||||
ps.stdin.write(b'\n')
|
||||
|
||||
self.retcode = ps.returncode
|
||||
self.stdout = ps.stdout.read().decode()
|
||||
self.stderr = ps.stderr.read().decode()
|
||||
|
||||
# Retrieve the resulted config data only when .config is supposed
|
||||
# to exist. If the command fails, the .config does not exist.
|
||||
# 'listnewconfig' does not produce .config in the first place.
|
||||
if self.retcode == 0 and out_file:
|
||||
with open(os.path.join(temp_dir, out_file)) as f:
|
||||
self.config = f.read()
|
||||
else:
|
||||
self.config = None
|
||||
|
||||
# Logging:
|
||||
# Pytest captures the following information by default. In failure
|
||||
# of tests, the captured log will be displayed. This will be useful to
|
||||
# figure out what has happened.
|
||||
|
||||
print("[command]\n{}\n".format(' '.join(command)))
|
||||
|
||||
print("[retcode]\n{}\n".format(self.retcode))
|
||||
|
||||
print("[stdout]")
|
||||
print(self.stdout)
|
||||
|
||||
print("[stderr]")
|
||||
print(self.stderr)
|
||||
|
||||
if self.config is not None:
|
||||
print("[output for '{}']".format(out_file))
|
||||
print(self.config)
|
||||
|
||||
return self.retcode
|
||||
|
||||
def oldaskconfig(self, dot_config=None, in_keys=None):
|
||||
"""Run oldaskconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
in_key: key inputs (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--oldaskconfig', dot_config=dot_config,
|
||||
interactive=True, in_keys=in_keys)
|
||||
|
||||
def oldconfig(self, dot_config=None, in_keys=None):
|
||||
"""Run oldconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
in_key: key inputs (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--oldconfig', dot_config=dot_config,
|
||||
interactive=True, in_keys=in_keys)
|
||||
|
||||
def olddefconfig(self, dot_config=None):
|
||||
"""Run olddefconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--olddefconfig', dot_config=dot_config)
|
||||
|
||||
def defconfig(self, defconfig):
|
||||
"""Run defconfig.
|
||||
|
||||
defconfig: defconfig file for input
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
defconfig_path = os.path.join(self._test_dir, defconfig)
|
||||
return self._run_conf('--defconfig={}'.format(defconfig_path))
|
||||
|
||||
def _allconfig(self, mode, all_config):
|
||||
if all_config:
|
||||
all_config_path = os.path.join(self._test_dir, all_config)
|
||||
extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
|
||||
else:
|
||||
extra_env = {}
|
||||
|
||||
return self._run_conf('--{}config'.format(mode), extra_env=extra_env)
|
||||
|
||||
def allyesconfig(self, all_config=None):
|
||||
"""Run allyesconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('allyes', all_config)
|
||||
|
||||
def allmodconfig(self, all_config=None):
|
||||
"""Run allmodconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('allmod', all_config)
|
||||
|
||||
def allnoconfig(self, all_config=None):
|
||||
"""Run allnoconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('allno', all_config)
|
||||
|
||||
def alldefconfig(self, all_config=None):
|
||||
"""Run alldefconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('alldef', all_config)
|
||||
|
||||
def randconfig(self, all_config=None):
|
||||
"""Run randconfig.
|
||||
|
||||
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._allconfig('rand', all_config)
|
||||
|
||||
def savedefconfig(self, dot_config):
|
||||
"""Run savedefconfig.
|
||||
|
||||
dot_config: .config file for input
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--savedefconfig', out_file='defconfig')
|
||||
|
||||
def listnewconfig(self, dot_config=None):
|
||||
"""Run listnewconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--listnewconfig', dot_config=dot_config,
|
||||
out_file=None)
|
||||
|
||||
# checkers
|
||||
def _read_and_compare(self, compare, expected):
|
||||
"""Compare the result with expectation.
|
||||
|
||||
compare: function to compare the result with expectation
|
||||
expected: file that contains the expected data
|
||||
"""
|
||||
with open(os.path.join(self._test_dir, expected)) as f:
|
||||
expected_data = f.read()
|
||||
return compare(self, expected_data)
|
||||
|
||||
def _contains(self, attr, expected):
|
||||
return self._read_and_compare(
|
||||
lambda s, e: getattr(s, attr).find(e) >= 0,
|
||||
expected)
|
||||
|
||||
def _matches(self, attr, expected):
|
||||
return self._read_and_compare(lambda s, e: getattr(s, attr) == e,
|
||||
expected)
|
||||
|
||||
def config_contains(self, expected):
|
||||
"""Check if resulted configuration contains expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result contains the expected data, False otherwise
|
||||
"""
|
||||
return self._contains('config', expected)
|
||||
|
||||
def config_matches(self, expected):
|
||||
"""Check if resulted configuration exactly matches expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result matches the expected data, False otherwise
|
||||
"""
|
||||
return self._matches('config', expected)
|
||||
|
||||
def stdout_contains(self, expected):
|
||||
"""Check if resulted stdout contains expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result contains the expected data, False otherwise
|
||||
"""
|
||||
return self._contains('stdout', expected)
|
||||
|
||||
def stdout_matches(self, expected):
|
||||
"""Check if resulted stdout exactly matches expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result matches the expected data, False otherwise
|
||||
"""
|
||||
return self._matches('stdout', expected)
|
||||
|
||||
def stderr_contains(self, expected):
|
||||
"""Check if resulted stderr contains expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result contains the expected data, False otherwise
|
||||
"""
|
||||
return self._contains('stderr', expected)
|
||||
|
||||
def stderr_matches(self, expected):
|
||||
"""Check if resulted stderr exactly matches expected data.
|
||||
|
||||
expected: file that contains the expected data
|
||||
returncode: True if result matches the expected data, False otherwise
|
||||
"""
|
||||
return self._matches('stderr', expected)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def conf(request):
|
||||
"""Create a Conf instance and provide it to test functions."""
|
||||
return Conf(request)
|
||||
@@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# depends on itself
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
depends on A
|
||||
|
||||
# select itself
|
||||
|
||||
config B
|
||||
bool
|
||||
select B
|
||||
|
||||
# depends on each other
|
||||
|
||||
config C1
|
||||
bool "C1"
|
||||
depends on C2
|
||||
|
||||
config C2
|
||||
bool "C2"
|
||||
depends on C1
|
||||
|
||||
# depends on and select
|
||||
|
||||
config D1
|
||||
bool "D1"
|
||||
depends on D2
|
||||
select D2
|
||||
|
||||
config D2
|
||||
bool
|
||||
|
||||
# depends on and imply
|
||||
|
||||
config E1
|
||||
bool "E1"
|
||||
depends on E2
|
||||
imply E2
|
||||
|
||||
config E2
|
||||
bool "E2"
|
||||
|
||||
# property
|
||||
|
||||
config F1
|
||||
bool "F1"
|
||||
default F2
|
||||
|
||||
config F2
|
||||
bool "F2"
|
||||
depends on F1
|
||||
|
||||
# menu
|
||||
|
||||
menu "menu depending on its content"
|
||||
depends on G
|
||||
|
||||
config G
|
||||
bool "G"
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Detect recursive dependency error.
|
||||
|
||||
Recursive dependency should be treated as an error.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 1
|
||||
assert conf.stderr_contains('expected_stderr')
|
||||
@@ -0,0 +1,38 @@
|
||||
Kconfig:11:error: recursive dependency detected!
|
||||
Kconfig:11: symbol B is selected by B
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
Kconfig:5:error: recursive dependency detected!
|
||||
Kconfig:5: symbol A depends on A
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
Kconfig:17:error: recursive dependency detected!
|
||||
Kconfig:17: symbol C1 depends on C2
|
||||
Kconfig:21: symbol C2 depends on C1
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
Kconfig:32:error: recursive dependency detected!
|
||||
Kconfig:32: symbol D2 is selected by D1
|
||||
Kconfig:27: symbol D1 depends on D2
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
Kconfig:37:error: recursive dependency detected!
|
||||
Kconfig:37: symbol E1 depends on E2
|
||||
Kconfig:42: symbol E2 is implied by E1
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
Kconfig:60:error: recursive dependency detected!
|
||||
Kconfig:60: symbol G depends on G
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
Kconfig:51:error: recursive dependency detected!
|
||||
Kconfig:51: symbol F2 depends on F1
|
||||
Kconfig:49: symbol F1 default value contains F2
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
@@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
source "Kconfig.inc1"
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
|
||||
|
||||
source "Kconfig.inc2"
|
||||
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
|
||||
source "Kconfig.inc3"
|
||||
@@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
source "Kconfig.inc1"
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Detect recursive inclusion error.
|
||||
|
||||
If recursive inclusion is detected, it should fail with error messages.
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() != 0
|
||||
assert conf.stderr_contains('expected_stderr')
|
||||
@@ -0,0 +1,6 @@
|
||||
Recursive inclusion detected.
|
||||
Inclusion path:
|
||||
current file : Kconfig.inc1
|
||||
included from: Kconfig.inc3:2
|
||||
included from: Kconfig.inc2:4
|
||||
included from: Kconfig.inc1:5
|
||||
@@ -0,0 +1,25 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config MODULES
|
||||
def_bool y
|
||||
option modules
|
||||
|
||||
choice
|
||||
prompt "Choice"
|
||||
|
||||
config CHOICE_VAL0
|
||||
tristate "Choice 0"
|
||||
|
||||
config CHOIVE_VAL1
|
||||
tristate "Choice 1"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Another choice"
|
||||
depends on CHOICE_VAL0
|
||||
|
||||
config DUMMY
|
||||
bool "dummy"
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Do not affect user-assigned choice value by another choice.
|
||||
|
||||
Handling of state flags for choices is complecated. In old days,
|
||||
the defconfig result of a choice could be affected by another choice
|
||||
if those choices interact by 'depends on', 'select', etc.
|
||||
|
||||
Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.defconfig('defconfig') == 0
|
||||
assert conf.config_contains('expected_config')
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_CHOICE_VAL0=y
|
||||
@@ -0,0 +1,4 @@
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_CHOICE_VAL0=y
|
||||
# CONFIG_CHOIVE_VAL1 is not set
|
||||
CONFIG_DUMMY=y
|
||||
@@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
help
|
||||
This is a new symbol.
|
||||
|
||||
choice
|
||||
prompt "Choice ?"
|
||||
depends on A
|
||||
help
|
||||
"depends on A" has been newly added.
|
||||
|
||||
config CHOICE_B
|
||||
bool "Choice B"
|
||||
|
||||
config CHOICE_C
|
||||
bool "Choice C"
|
||||
help
|
||||
This is a new symbol, so should be asked.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Choice2 ?"
|
||||
|
||||
config CHOICE_D
|
||||
bool "Choice D"
|
||||
|
||||
config CHOICE_E
|
||||
bool "Choice E"
|
||||
|
||||
config CHOICE_F
|
||||
bool "Choice F"
|
||||
depends on A
|
||||
help
|
||||
This is a new symbol, so should be asked.
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Ask new choice values when they become visible.
|
||||
|
||||
If new choice values are added with new dependency, and they become
|
||||
visible during user configuration, oldconfig should recognize them
|
||||
as (NEW), and ask the user for choice.
|
||||
|
||||
Related Linux commit: 5d09598d488f081e3be23f885ed65cbbe2d073b5
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldconfig('config', 'y') == 0
|
||||
assert conf.stdout_contains('expected_stdout')
|
||||
@@ -0,0 +1,3 @@
|
||||
CONFIG_CHOICE_B=y
|
||||
# CONFIG_CHOICE_D is not set
|
||||
CONFIG_CHOICE_E=y
|
||||
@@ -0,0 +1,10 @@
|
||||
A (A) [N/y/?] (NEW) y
|
||||
Choice ?
|
||||
> 1. Choice B (CHOICE_B)
|
||||
2. Choice C (CHOICE_C) (NEW)
|
||||
choice[1-2?]:
|
||||
Choice2 ?
|
||||
1. Choice D (CHOICE_D)
|
||||
> 2. Choice E (CHOICE_E)
|
||||
3. Choice F (CHOICE_F) (NEW)
|
||||
choice[1-3?]:
|
||||
@@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config A
|
||||
bool "A"
|
||||
|
||||
choice
|
||||
prompt "Choice ?"
|
||||
depends on A
|
||||
|
||||
config CHOICE_B
|
||||
bool "Choice B"
|
||||
|
||||
config CHOICE_C
|
||||
bool "Choice C"
|
||||
|
||||
endchoice
|
||||
@@ -0,0 +1,20 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Do not write choice values to .config if the dependency is unmet.
|
||||
|
||||
"# CONFIG_... is not set" should not be written into the .config file
|
||||
for symbols with unmet dependency.
|
||||
|
||||
This was not working correctly for choice values because choice needs
|
||||
a bit different symbol computation.
|
||||
|
||||
This checks that no unneeded "# COFIG_... is not set" is contained in
|
||||
the .config file.
|
||||
|
||||
Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig('config', 'n') == 0
|
||||
assert conf.config_matches('expected_config')
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_A=y
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
# CONFIG_A is not set
|
||||
@@ -0,0 +1,27 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# 'info' prints the argument to stdout.
|
||||
$(info,hello world 0)
|
||||
|
||||
# 'warning-if', if the first argument is y, sends the second argument to stderr,
|
||||
# and the message is prefixed with the current file name and line number.
|
||||
$(warning-if,y,hello world 1)
|
||||
|
||||
# 'error-if' is similar, but it terminates the parsing immediately.
|
||||
# The following is just no-op since the first argument is not y.
|
||||
$(error-if,n,this should not be printed)
|
||||
|
||||
# Shorthand
|
||||
warning = $(warning-if,y,$(1))
|
||||
|
||||
# 'shell' executes a command, and returns its stdout.
|
||||
$(warning,$(shell,echo hello world 3))
|
||||
|
||||
# Every newline in the output is replaced with a space,
|
||||
# but any trailing newlines are deleted.
|
||||
$(warning,$(shell,printf 'hello\nworld\n\n4\n\n\n'))
|
||||
|
||||
# 'filename' is expanded to the currently parsed file name,
|
||||
# 'lineno' to the line number.
|
||||
$(warning,filename=$(filename))
|
||||
$(warning,lineno=$(lineno))
|
||||
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Built-in function tests.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stdout_contains('expected_stdout')
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
@@ -0,0 +1,5 @@
|
||||
Kconfig:8: hello world 1
|
||||
Kconfig:18: hello world 3
|
||||
Kconfig:22: hello world 4
|
||||
Kconfig:26: filename=Kconfig
|
||||
Kconfig:27: lineno=27
|
||||
@@ -0,0 +1 @@
|
||||
hello world 0
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
X = $(Y)
|
||||
Y = $(X)
|
||||
$(info $(X))
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Detect circular variable expansion.
|
||||
|
||||
If a recursively expanded variable references itself (eventually),
|
||||
it should fail with an error message.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() != 0
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
@@ -0,0 +1 @@
|
||||
Kconfig:5: Recursive variable 'X' references itself (eventually)
|
||||
@@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Shorthand
|
||||
warning = $(warning-if,y,$(1))
|
||||
|
||||
# You can not pass commas directly to a function since they are treated as
|
||||
# delimiters. You can use the following trick to do so.
|
||||
comma := ,
|
||||
$(warning,hello$(comma) world)
|
||||
|
||||
# Like Make, single quotes, double quotes, spaces are treated verbatim.
|
||||
# The following prints the text as-is.
|
||||
$(warning, ' " '" ' ''' "'")
|
||||
|
||||
# Unlike Make, '$' has special meaning only when it is followed by '('.
|
||||
# No need to escape '$' itself.
|
||||
$(warning,$)
|
||||
$(warning,$$)
|
||||
$ := 1
|
||||
$(warning,$($))
|
||||
|
||||
# You need a trick to escape '$' followed by '('
|
||||
# The following should print "$(X)". It should not be expanded further.
|
||||
dollar := $
|
||||
$(warning,$(dollar)(X))
|
||||
|
||||
# You need a trick to treat unbalanced parentheses.
|
||||
# The following should print "(".
|
||||
left_paren := (
|
||||
$(warning,$(left_paren))
|
||||
|
||||
# A simple expanded should not be expanded multiple times.
|
||||
# The following should print "$(X)". It should not be expanded further.
|
||||
Y := $(dollar)(X)
|
||||
$(warning,$(Y))
|
||||
|
||||
# The following should print "$(X)" as well.
|
||||
Y = $(dollar)(X)
|
||||
$(warning,$(Y))
|
||||
|
||||
# The following should print "$(".
|
||||
# It should not be emit "unterminated reference" error.
|
||||
unterminated := $(dollar)(
|
||||
$(warning,$(unterminated))
|
||||
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Escape sequence tests.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
@@ -0,0 +1,10 @@
|
||||
Kconfig:9: hello, world
|
||||
Kconfig:13: ' " '" ' ''' "'"
|
||||
Kconfig:17: $
|
||||
Kconfig:18: $$
|
||||
Kconfig:20: 1
|
||||
Kconfig:25: $(X)
|
||||
Kconfig:30: (
|
||||
Kconfig:35: $(X)
|
||||
Kconfig:39: $(X)
|
||||
Kconfig:44: $(
|
||||
@@ -0,0 +1,53 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Shorthand
|
||||
warning = $(warning-if,y,$(1))
|
||||
|
||||
# Simply expanded variable.
|
||||
X := 1
|
||||
SIMPLE := $(X)
|
||||
X := 2
|
||||
$(warning,SIMPLE = $(SIMPLE))
|
||||
|
||||
# Recursively expanded variable.
|
||||
X := 1
|
||||
RECURSIVE = $(X)
|
||||
X := 2
|
||||
$(warning,RECURSIVE = $(RECURSIVE))
|
||||
|
||||
# Append something to a simply expanded variable.
|
||||
Y := 3
|
||||
SIMPLE += $(Y)
|
||||
Y := 4
|
||||
$(warning,SIMPLE = $(SIMPLE))
|
||||
|
||||
# Append something to a recursively expanded variable.
|
||||
Y := 3
|
||||
RECURSIVE += $(Y)
|
||||
Y := 4
|
||||
$(warning,RECURSIVE = $(RECURSIVE))
|
||||
|
||||
# Use += operator to an undefined variable.
|
||||
# This works as a recursively expanded variable.
|
||||
Y := 3
|
||||
UNDEFINED_VARIABLE += $(Y)
|
||||
Y := 4
|
||||
$(warning,UNDEFINED_VARIABLE = $(UNDEFINED_VARIABLE))
|
||||
|
||||
# You can use variable references for the lefthand side of assignment statement.
|
||||
X := A
|
||||
Y := B
|
||||
$(X)$(Y) := 5
|
||||
$(warning,AB = $(AB))
|
||||
|
||||
# User-defined function.
|
||||
greeting = $(1), my name is $(2).
|
||||
$(warning,$(greeting,Hello,John))
|
||||
|
||||
# The number of arguments is not checked for user-defined functions.
|
||||
# If some arguments are optional, it is useful to pass fewer parameters.
|
||||
# $(2) will be blank in this case.
|
||||
$(warning,$(greeting,Hello))
|
||||
|
||||
# Unreferenced parameters are just ignored.
|
||||
$(warning,$(greeting,Hello,John,ignored,ignored))
|
||||
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Variable and user-defined function tests.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.oldaskconfig() == 0
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
@@ -0,0 +1,9 @@
|
||||
Kconfig:10: SIMPLE = 1
|
||||
Kconfig:16: RECURSIVE = 2
|
||||
Kconfig:22: SIMPLE = 1 3
|
||||
Kconfig:28: RECURSIVE = 2 4
|
||||
Kconfig:35: UNDEFINED_VARIABLE = 4
|
||||
Kconfig:41: AB = 5
|
||||
Kconfig:45: Hello, my name is John.
|
||||
Kconfig:50: Hello, my name is .
|
||||
Kconfig:53: Hello, my name is John.
|
||||
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff.
Show more