2018-12-18 12:13:35 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
|
|
|
*/
|
|
|
|
|
2011-06-01 20:06:22 +00:00
|
|
|
#include <ctype.h>
|
2011-06-01 20:00:46 +00:00
|
|
|
#include <stdarg.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2024-07-20 07:27:38 +00:00
|
|
|
#include <list.h>
|
2024-08-12 12:48:50 +00:00
|
|
|
#include <xalloc.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "lkc.h"
|
2021-04-13 15:08:17 +00:00
|
|
|
#include "internal.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2011-08-04 01:52:07 +00:00
|
|
|
static const char nohelp_text[] = "There is no help available for this option.";
|
2009-07-12 08:11:44 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
struct menu rootmenu;
|
|
|
|
static struct menu **last_entry_ptr;
|
|
|
|
|
2024-04-21 09:02:51 +00:00
|
|
|
/**
|
|
|
|
* menu_next - return the next menu entry with depth-first traversal
|
|
|
|
* @menu: pointer to the current menu
|
|
|
|
* @root: root of the sub-tree to traverse. If NULL is given, the traveral
|
|
|
|
* continues until it reaches the end of the entire menu tree.
|
|
|
|
* return: the menu to visit next, or NULL when it reaches the end.
|
|
|
|
*/
|
|
|
|
struct menu *menu_next(struct menu *menu, struct menu *root)
|
|
|
|
{
|
|
|
|
if (menu->list)
|
|
|
|
return menu->list;
|
|
|
|
|
|
|
|
while (menu != root && !menu->next)
|
|
|
|
menu = menu->parent;
|
|
|
|
|
|
|
|
if (menu == root)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return menu->next;
|
|
|
|
}
|
|
|
|
|
2024-07-07 15:38:05 +00:00
|
|
|
void menu_warn(const struct menu *menu, const char *fmt, ...)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2024-02-02 15:58:09 +00:00
|
|
|
fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
|
2005-04-16 22:20:36 +00:00
|
|
|
vfprintf(stderr, fmt, ap);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2024-07-07 15:38:05 +00:00
|
|
|
static void prop_warn(const struct property *prop, const char *fmt, ...)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2024-02-02 15:58:10 +00:00
|
|
|
fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
|
2005-04-16 22:20:36 +00:00
|
|
|
vfprintf(stderr, fmt, ap);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2009-11-25 10:28:43 +00:00
|
|
|
void _menu_init(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
current_entry = current_menu = &rootmenu;
|
|
|
|
last_entry_ptr = &rootmenu.list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void menu_add_entry(struct symbol *sym)
|
|
|
|
{
|
|
|
|
struct menu *menu;
|
|
|
|
|
2012-11-06 14:32:08 +00:00
|
|
|
menu = xmalloc(sizeof(*menu));
|
2005-04-16 22:20:36 +00:00
|
|
|
memset(menu, 0, sizeof(*menu));
|
|
|
|
menu->sym = sym;
|
|
|
|
menu->parent = current_menu;
|
2024-02-02 15:58:09 +00:00
|
|
|
menu->filename = cur_filename;
|
2024-02-02 15:58:08 +00:00
|
|
|
menu->lineno = cur_lineno;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
*last_entry_ptr = menu;
|
|
|
|
last_entry_ptr = &menu->next;
|
|
|
|
current_entry = menu;
|
2024-08-12 11:49:46 +00:00
|
|
|
if (sym)
|
2024-03-03 04:00:33 +00:00
|
|
|
list_add_tail(&menu->link, &sym->menus);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2005-11-09 05:34:53 +00:00
|
|
|
struct menu *menu_add_menu(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
last_entry_ptr = ¤t_entry->list;
|
2020-04-13 15:35:42 +00:00
|
|
|
current_menu = current_entry;
|
|
|
|
return current_menu;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void menu_end_menu(void)
|
|
|
|
{
|
|
|
|
last_entry_ptr = ¤t_menu->next;
|
|
|
|
current_menu = current_menu->parent;
|
|
|
|
}
|
|
|
|
|
2017-10-05 12:01:13 +00:00
|
|
|
/*
|
|
|
|
* Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
|
|
|
|
* without modules
|
|
|
|
*/
|
|
|
|
static struct expr *rewrite_m(struct expr *e)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
if (!e)
|
|
|
|
return e;
|
|
|
|
|
|
|
|
switch (e->type) {
|
|
|
|
case E_NOT:
|
kconfig: use hash table to reuse expressions
Currently, every expression in Kconfig files produces a new abstract
syntax tree (AST), even if it is identical to a previously encountered
one.
Consider the following code:
config FOO
bool "FOO"
depends on (A || B) && C
config BAR
bool "BAR"
depends on (A || B) && C
config BAZ
bool "BAZ"
depends on A || B
The "depends on" lines are similar, but currently a separate AST is
allocated for each one.
The current data structure looks like this:
FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR
/ \ / \ / \
OR C OR C A B
/ \ / \
A B A B
This is redundant; FOO->dep and BAR->dep have identical ASTs but
different memory instances.
We can optimize this; FOO->dep and BAR->dep can share the same AST, and
BAZ->dep can reference its sub tree.
The optimized data structure looks like this:
FOO->dep, BAR->dep ==> AND
/ \
BAZ->dep ==> OR C
/ \
A B
This commit introduces a hash table to keep track of allocated
expressions. If an identical expression is found, it is reused.
This does not necessarily result in memory savings, as menu_finalize()
transforms expressions without freeing up stale ones. This will be
addressed later.
One optimization that can be easily implemented is caching the
expression's value. Once FOO's dependency, (A || B) && C, is calculated,
it can be cached, eliminating the need to recalculate it for BAR.
This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix
multiple references to expressions in menu_add_prop()").
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-09-08 12:43:20 +00:00
|
|
|
e = expr_alloc_one(E_NOT, rewrite_m(e->left.expr));
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case E_OR:
|
|
|
|
case E_AND:
|
kconfig: use hash table to reuse expressions
Currently, every expression in Kconfig files produces a new abstract
syntax tree (AST), even if it is identical to a previously encountered
one.
Consider the following code:
config FOO
bool "FOO"
depends on (A || B) && C
config BAR
bool "BAR"
depends on (A || B) && C
config BAZ
bool "BAZ"
depends on A || B
The "depends on" lines are similar, but currently a separate AST is
allocated for each one.
The current data structure looks like this:
FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR
/ \ / \ / \
OR C OR C A B
/ \ / \
A B A B
This is redundant; FOO->dep and BAR->dep have identical ASTs but
different memory instances.
We can optimize this; FOO->dep and BAR->dep can share the same AST, and
BAZ->dep can reference its sub tree.
The optimized data structure looks like this:
FOO->dep, BAR->dep ==> AND
/ \
BAZ->dep ==> OR C
/ \
A B
This commit introduces a hash table to keep track of allocated
expressions. If an identical expression is found, it is reused.
This does not necessarily result in memory savings, as menu_finalize()
transforms expressions without freeing up stale ones. This will be
addressed later.
One optimization that can be easily implemented is caching the
expression's value. Once FOO's dependency, (A || B) && C, is calculated,
it can be cached, eliminating the need to recalculate it for BAR.
This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix
multiple references to expressions in menu_add_prop()").
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-09-08 12:43:20 +00:00
|
|
|
e = expr_alloc_two(e->type,
|
|
|
|
rewrite_m(e->left.expr),
|
|
|
|
rewrite_m(e->right.expr));
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case E_SYMBOL:
|
|
|
|
/* change 'm' into 'm' && MODULES */
|
|
|
|
if (e->left.sym == &symbol_mod)
|
|
|
|
return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
void menu_add_dep(struct expr *dep)
|
|
|
|
{
|
kconfig: Clean up modules handling and fix crash
Kconfig currently doesn't handle 'm' appearing in a Kconfig file before
the modules symbol is defined (the symbol with 'option modules'). The
problem is the following code, which runs during parsing:
/* change 'm' into 'm' && MODULES */
if (e->left.sym == &symbol_mod)
return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
If the modules symbol has not yet been defined, modules_sym is NULL,
giving an invalid expression.
Here is a test file where both BEFORE_1 and BEFORE_2 trigger a segfault.
If the modules symbol is removed, all symbols trigger segfaults.
config BEFORE_1
def_tristate y if m
if m
config BEFORE_2
def_tristate y
endif
config MODULES
def_bool y
option modules
config AFTER_1
def_tristate y if m
if m
config AFTER_2
def_tristate y
endif
Fix the issue by rewriting 'm' in menu_finalize() instead. This function
runs after parsing and is the proper place to do it. The following
existing code in conf_parse() in zconf.y ensures that the modules symbol
exists at that point:
if (!modules_sym)
modules_sym = sym_find( "n" );
...
menu_finalize(&rootmenu);
The following tests were done to ensure no functional changes for
configurations that don't reference 'm' before the modules symbol:
- zconfdump(stdout) was run with ARCH=x86 and ARCH=arm before
and after the change and verified to produce identical output.
This function prints all symbols, choices, and menus together
with their properties and their dependency expressions. A
rewritten 'm' appears as 'm && MODULES'.
A small annoyance is that the assert(len != 0) in xfwrite()
needs to be disabled in order to use zconfdump(), because it
chokes on e.g. 'default ""'.
- The Kconfiglib test suite was run to indirectly verify that
alldefconfig, allyesconfig, allnoconfig, and all defconfigs in
the kernel still generate the same final .config.
- Valgrind was used to check for memory errors and (new) memory
leaks.
Signed-off-by: Ulf Magnusson <ulfalizer@gmail.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2017-10-05 12:01:15 +00:00
|
|
|
current_entry->dep = expr_alloc_and(current_entry->dep, dep);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void menu_set_type(int type)
|
|
|
|
{
|
|
|
|
struct symbol *sym = current_entry->sym;
|
|
|
|
|
|
|
|
if (sym->type == type)
|
|
|
|
return;
|
|
|
|
if (sym->type == S_UNKNOWN) {
|
|
|
|
sym->type = type;
|
|
|
|
return;
|
|
|
|
}
|
2013-10-03 16:32:02 +00:00
|
|
|
menu_warn(current_entry,
|
|
|
|
"ignoring type redefinition of '%s' from '%s' to '%s'",
|
|
|
|
sym->name ? sym->name : "<choice>",
|
|
|
|
sym_type_name(sym->type), sym_type_name(type));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2019-12-17 04:14:21 +00:00
|
|
|
static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
|
|
|
|
struct expr *dep)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2019-12-17 04:14:23 +00:00
|
|
|
struct property *prop;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2019-12-17 04:14:23 +00:00
|
|
|
prop = xmalloc(sizeof(*prop));
|
|
|
|
memset(prop, 0, sizeof(*prop));
|
|
|
|
prop->type = type;
|
2024-02-02 15:58:10 +00:00
|
|
|
prop->filename = cur_filename;
|
2024-02-02 15:58:08 +00:00
|
|
|
prop->lineno = cur_lineno;
|
2005-04-16 22:20:36 +00:00
|
|
|
prop->menu = current_entry;
|
|
|
|
prop->expr = expr;
|
kconfig: Clean up modules handling and fix crash
Kconfig currently doesn't handle 'm' appearing in a Kconfig file before
the modules symbol is defined (the symbol with 'option modules'). The
problem is the following code, which runs during parsing:
/* change 'm' into 'm' && MODULES */
if (e->left.sym == &symbol_mod)
return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
If the modules symbol has not yet been defined, modules_sym is NULL,
giving an invalid expression.
Here is a test file where both BEFORE_1 and BEFORE_2 trigger a segfault.
If the modules symbol is removed, all symbols trigger segfaults.
config BEFORE_1
def_tristate y if m
if m
config BEFORE_2
def_tristate y
endif
config MODULES
def_bool y
option modules
config AFTER_1
def_tristate y if m
if m
config AFTER_2
def_tristate y
endif
Fix the issue by rewriting 'm' in menu_finalize() instead. This function
runs after parsing and is the proper place to do it. The following
existing code in conf_parse() in zconf.y ensures that the modules symbol
exists at that point:
if (!modules_sym)
modules_sym = sym_find( "n" );
...
menu_finalize(&rootmenu);
The following tests were done to ensure no functional changes for
configurations that don't reference 'm' before the modules symbol:
- zconfdump(stdout) was run with ARCH=x86 and ARCH=arm before
and after the change and verified to produce identical output.
This function prints all symbols, choices, and menus together
with their properties and their dependency expressions. A
rewritten 'm' appears as 'm && MODULES'.
A small annoyance is that the assert(len != 0) in xfwrite()
needs to be disabled in order to use zconfdump(), because it
chokes on e.g. 'default ""'.
- The Kconfiglib test suite was run to indirectly verify that
alldefconfig, allyesconfig, allnoconfig, and all defconfigs in
the kernel still generate the same final .config.
- Valgrind was used to check for memory errors and (new) memory
leaks.
Signed-off-by: Ulf Magnusson <ulfalizer@gmail.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2017-10-05 12:01:15 +00:00
|
|
|
prop->visible.expr = dep;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2019-12-17 04:14:23 +00:00
|
|
|
/* append property to the prop list of symbol */
|
|
|
|
if (current_entry->sym) {
|
|
|
|
struct property **propp;
|
|
|
|
|
|
|
|
for (propp = ¤t_entry->sym->prop;
|
|
|
|
*propp;
|
|
|
|
propp = &(*propp)->next)
|
|
|
|
;
|
|
|
|
*propp = prop;
|
|
|
|
}
|
|
|
|
|
2019-12-17 04:14:20 +00:00
|
|
|
return prop;
|
|
|
|
}
|
|
|
|
|
2024-07-07 15:38:05 +00:00
|
|
|
struct property *menu_add_prompt(enum prop_type type, const char *prompt,
|
2019-12-17 04:14:20 +00:00
|
|
|
struct expr *dep)
|
|
|
|
{
|
2019-12-17 04:14:21 +00:00
|
|
|
struct property *prop = menu_add_prop(type, NULL, dep);
|
2010-12-09 08:11:38 +00:00
|
|
|
|
2019-12-17 04:14:20 +00:00
|
|
|
if (isspace(*prompt)) {
|
|
|
|
prop_warn(prop, "leading whitespace ignored");
|
|
|
|
while (isspace(*prompt))
|
|
|
|
prompt++;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2019-12-17 04:14:20 +00:00
|
|
|
if (current_entry->prompt)
|
|
|
|
prop_warn(prop, "prompt redefined");
|
|
|
|
|
|
|
|
/* Apply all upper menus' visibilities to actual prompts. */
|
|
|
|
if (type == P_PROMPT) {
|
|
|
|
struct menu *menu = current_entry;
|
|
|
|
|
|
|
|
while ((menu = menu->parent) != NULL) {
|
|
|
|
|
|
|
|
if (!menu->visibility)
|
|
|
|
continue;
|
|
|
|
prop->visible.expr = expr_alloc_and(prop->visible.expr,
|
kconfig: use hash table to reuse expressions
Currently, every expression in Kconfig files produces a new abstract
syntax tree (AST), even if it is identical to a previously encountered
one.
Consider the following code:
config FOO
bool "FOO"
depends on (A || B) && C
config BAR
bool "BAR"
depends on (A || B) && C
config BAZ
bool "BAZ"
depends on A || B
The "depends on" lines are similar, but currently a separate AST is
allocated for each one.
The current data structure looks like this:
FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR
/ \ / \ / \
OR C OR C A B
/ \ / \
A B A B
This is redundant; FOO->dep and BAR->dep have identical ASTs but
different memory instances.
We can optimize this; FOO->dep and BAR->dep can share the same AST, and
BAZ->dep can reference its sub tree.
The optimized data structure looks like this:
FOO->dep, BAR->dep ==> AND
/ \
BAZ->dep ==> OR C
/ \
A B
This commit introduces a hash table to keep track of allocated
expressions. If an identical expression is found, it is reused.
This does not necessarily result in memory savings, as menu_finalize()
transforms expressions without freeing up stale ones. This will be
addressed later.
One optimization that can be easily implemented is caching the
expression's value. Once FOO's dependency, (A || B) && C, is calculated,
it can be cached, eliminating the need to recalculate it for BAR.
This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix
multiple references to expressions in menu_add_prop()").
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-09-08 12:43:20 +00:00
|
|
|
menu->visibility);
|
2019-12-17 04:14:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
current_entry->prompt = prop;
|
2006-06-09 05:12:48 +00:00
|
|
|
prop->text = prompt;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
return prop;
|
|
|
|
}
|
|
|
|
|
2010-11-06 21:30:23 +00:00
|
|
|
void menu_add_visibility(struct expr *expr)
|
|
|
|
{
|
|
|
|
current_entry->visibility = expr_alloc_and(current_entry->visibility,
|
|
|
|
expr);
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
|
|
|
|
{
|
2019-12-17 04:14:21 +00:00
|
|
|
menu_add_prop(type, expr, dep);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
|
|
|
|
{
|
2019-12-17 04:14:21 +00:00
|
|
|
menu_add_prop(type, expr_alloc_symbol(sym), dep);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2010-12-05 06:29:25 +00:00
|
|
|
static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
|
2005-11-09 05:34:49 +00:00
|
|
|
{
|
|
|
|
return sym2->type == S_INT || sym2->type == S_HEX ||
|
|
|
|
(sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
|
|
|
|
}
|
|
|
|
|
2009-09-18 19:49:23 +00:00
|
|
|
static void sym_check_prop(struct symbol *sym)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct property *prop;
|
|
|
|
struct symbol *sym2;
|
2016-11-11 05:10:05 +00:00
|
|
|
char *use;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
for (prop = sym->prop; prop; prop = prop->next) {
|
|
|
|
switch (prop->type) {
|
|
|
|
case P_DEFAULT:
|
|
|
|
if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
|
|
|
|
prop->expr->type != E_SYMBOL)
|
|
|
|
prop_warn(prop,
|
2010-04-14 03:44:05 +00:00
|
|
|
"default for config symbol '%s'"
|
2005-04-16 22:20:36 +00:00
|
|
|
" must be a single symbol", sym->name);
|
2010-12-05 06:29:25 +00:00
|
|
|
if (prop->expr->type != E_SYMBOL)
|
|
|
|
break;
|
|
|
|
sym2 = prop_get_symbol(prop);
|
|
|
|
if (sym->type == S_HEX || sym->type == S_INT) {
|
|
|
|
if (!menu_validate_number(sym, sym2))
|
|
|
|
prop_warn(prop,
|
|
|
|
"'%s': number is invalid",
|
|
|
|
sym->name);
|
|
|
|
}
|
2017-10-03 23:25:46 +00:00
|
|
|
if (sym_is_choice(sym)) {
|
2024-05-13 23:31:42 +00:00
|
|
|
struct menu *choice = sym_get_choice_menu(sym2);
|
2017-10-03 23:25:46 +00:00
|
|
|
|
2024-05-13 23:31:42 +00:00
|
|
|
if (!choice || choice->sym != sym)
|
2017-10-03 23:25:46 +00:00
|
|
|
prop_warn(prop,
|
|
|
|
"choice default symbol '%s' is not contained in the choice",
|
|
|
|
sym2->name);
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case P_SELECT:
|
2016-11-11 05:10:05 +00:00
|
|
|
case P_IMPLY:
|
|
|
|
use = prop->type == P_SELECT ? "select" : "imply";
|
2005-04-16 22:20:36 +00:00
|
|
|
sym2 = prop_get_symbol(prop);
|
|
|
|
if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
|
|
|
|
prop_warn(prop,
|
2016-11-11 05:10:05 +00:00
|
|
|
"config symbol '%s' uses %s, but is "
|
2017-12-15 15:38:02 +00:00
|
|
|
"not bool or tristate", sym->name, use);
|
2008-02-02 20:09:57 +00:00
|
|
|
else if (sym2->type != S_UNKNOWN &&
|
2014-06-10 10:08:13 +00:00
|
|
|
sym2->type != S_BOOLEAN &&
|
|
|
|
sym2->type != S_TRISTATE)
|
2005-04-16 22:20:36 +00:00
|
|
|
prop_warn(prop,
|
2016-11-11 05:10:05 +00:00
|
|
|
"'%s' has wrong type. '%s' only "
|
2017-12-15 15:38:02 +00:00
|
|
|
"accept arguments of bool and "
|
2016-11-11 05:10:05 +00:00
|
|
|
"tristate type", sym2->name, use);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case P_RANGE:
|
|
|
|
if (sym->type != S_INT && sym->type != S_HEX)
|
|
|
|
prop_warn(prop, "range is only allowed "
|
2014-06-10 10:08:13 +00:00
|
|
|
"for int or hex symbols");
|
2010-12-05 06:29:25 +00:00
|
|
|
if (!menu_validate_number(sym, prop->expr->left.sym) ||
|
|
|
|
!menu_validate_number(sym, prop->expr->right.sym))
|
2005-04-16 22:20:36 +00:00
|
|
|
prop_warn(prop, "range is invalid");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-23 08:51:01 +00:00
|
|
|
static void _menu_finalize(struct menu *parent, bool inside_choice)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct menu *menu, *last_menu;
|
|
|
|
struct symbol *sym;
|
|
|
|
struct property *prop;
|
kconfig: fix conditional prompt behavior for choice
When a prompt is followed by "if <expr>", the symbol is configurable
when the if-conditional evaluates to true.
A typical usage is as follows:
menuconfig BLOCK
bool "Enable the block layer" if EXPERT
default y
When EXPERT=n, the prompt is hidden, but this config entry is still
active, and BLOCK is set to its default value 'y'. When EXPERT=y, the
prompt is shown, making BLOCK a user-configurable option.
This usage is common throughout the kernel tree, but it has never worked
within a choice block.
[Test Code]
config EXPERT
bool "Allow expert users to modify more options"
choice
prompt "Choose" if EXPERT
config A
bool "A"
config B
bool "B"
endchoice
[Result]
# CONFIG_EXPERT is not set
When the prompt is hidden, the choice block should produce the default
without asking for the user's preference. Hence, the output should be:
# CONFIG_EXPERT is not set
CONFIG_A=y
# CONFIG_B is not set
Removing unnecessary hacks fixes the issue.
This commit also changes the behavior of 'select' by choice members.
[Test Code 2]
config MODULES
def_bool y
modules
config DEP
def_tristate m
if DEP
choice
prompt "choose"
config A
bool "A"
select C
endchoice
config B
def_bool y
select D
endif
config C
tristate
config D
tristate
The current output is as follows:
CONFIG_MODULES=y
CONFIG_DEP=m
CONFIG_A=y
CONFIG_B=y
CONFIG_C=y
CONFIG_D=m
With this commit, the output will be changed as follows:
CONFIG_MODULES=y
CONFIG_DEP=m
CONFIG_A=y
CONFIG_B=y
CONFIG_C=m
CONFIG_D=m
CONFIG_C will be changed to 'm' because 'select C' will inherit the
dependency on DEP, which is 'm'.
This change is aligned with the behavior of 'select' outside a choice
block; 'select D' depends on DEP, therefore D is selected by (B && DEP).
Note:
With this commit, allmodconfig will set CONFIG_USB_ROLE_SWITCH to 'm'
instead of 'y'. I did not see any build regression with this change.
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-06-26 18:22:01 +00:00
|
|
|
struct expr *basedep, *dep, *dep2;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
sym = parent->sym;
|
|
|
|
if (parent->list) {
|
2017-10-05 12:01:14 +00:00
|
|
|
/*
|
|
|
|
* This menu node has children. We (recursively) process them
|
|
|
|
* and propagate parent dependencies before moving on.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* For each child menu node... */
|
2005-04-16 22:20:36 +00:00
|
|
|
for (menu = parent->list; menu; menu = menu->next) {
|
2017-10-05 12:01:14 +00:00
|
|
|
/*
|
|
|
|
* Propagate parent dependencies to the child menu
|
|
|
|
* node, also rewriting and simplifying expressions
|
|
|
|
*/
|
kconfig: Clean up modules handling and fix crash
Kconfig currently doesn't handle 'm' appearing in a Kconfig file before
the modules symbol is defined (the symbol with 'option modules'). The
problem is the following code, which runs during parsing:
/* change 'm' into 'm' && MODULES */
if (e->left.sym == &symbol_mod)
return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
If the modules symbol has not yet been defined, modules_sym is NULL,
giving an invalid expression.
Here is a test file where both BEFORE_1 and BEFORE_2 trigger a segfault.
If the modules symbol is removed, all symbols trigger segfaults.
config BEFORE_1
def_tristate y if m
if m
config BEFORE_2
def_tristate y
endif
config MODULES
def_bool y
option modules
config AFTER_1
def_tristate y if m
if m
config AFTER_2
def_tristate y
endif
Fix the issue by rewriting 'm' in menu_finalize() instead. This function
runs after parsing and is the proper place to do it. The following
existing code in conf_parse() in zconf.y ensures that the modules symbol
exists at that point:
if (!modules_sym)
modules_sym = sym_find( "n" );
...
menu_finalize(&rootmenu);
The following tests were done to ensure no functional changes for
configurations that don't reference 'm' before the modules symbol:
- zconfdump(stdout) was run with ARCH=x86 and ARCH=arm before
and after the change and verified to produce identical output.
This function prints all symbols, choices, and menus together
with their properties and their dependency expressions. A
rewritten 'm' appears as 'm && MODULES'.
A small annoyance is that the assert(len != 0) in xfwrite()
needs to be disabled in order to use zconfdump(), because it
chokes on e.g. 'default ""'.
- The Kconfiglib test suite was run to indirectly verify that
alldefconfig, allyesconfig, allnoconfig, and all defconfigs in
the kernel still generate the same final .config.
- Valgrind was used to check for memory errors and (new) memory
leaks.
Signed-off-by: Ulf Magnusson <ulfalizer@gmail.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2017-10-05 12:01:15 +00:00
|
|
|
basedep = rewrite_m(menu->dep);
|
|
|
|
basedep = expr_transform(basedep);
|
kconfig: use hash table to reuse expressions
Currently, every expression in Kconfig files produces a new abstract
syntax tree (AST), even if it is identical to a previously encountered
one.
Consider the following code:
config FOO
bool "FOO"
depends on (A || B) && C
config BAR
bool "BAR"
depends on (A || B) && C
config BAZ
bool "BAZ"
depends on A || B
The "depends on" lines are similar, but currently a separate AST is
allocated for each one.
The current data structure looks like this:
FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR
/ \ / \ / \
OR C OR C A B
/ \ / \
A B A B
This is redundant; FOO->dep and BAR->dep have identical ASTs but
different memory instances.
We can optimize this; FOO->dep and BAR->dep can share the same AST, and
BAZ->dep can reference its sub tree.
The optimized data structure looks like this:
FOO->dep, BAR->dep ==> AND
/ \
BAZ->dep ==> OR C
/ \
A B
This commit introduces a hash table to keep track of allocated
expressions. If an identical expression is found, it is reused.
This does not necessarily result in memory savings, as menu_finalize()
transforms expressions without freeing up stale ones. This will be
addressed later.
One optimization that can be easily implemented is caching the
expression's value. Once FOO's dependency, (A || B) && C, is calculated,
it can be cached, eliminating the need to recalculate it for BAR.
This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix
multiple references to expressions in menu_add_prop()").
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-09-08 12:43:20 +00:00
|
|
|
basedep = expr_alloc_and(parent->dep, basedep);
|
2005-04-16 22:20:36 +00:00
|
|
|
basedep = expr_eliminate_dups(basedep);
|
|
|
|
menu->dep = basedep;
|
2017-10-05 12:01:14 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (menu->sym)
|
2017-10-05 12:01:14 +00:00
|
|
|
/*
|
|
|
|
* Note: For symbols, all prompts are included
|
|
|
|
* too in the symbol's own property list
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
prop = menu->sym->prop;
|
|
|
|
else
|
2017-10-05 12:01:14 +00:00
|
|
|
/*
|
|
|
|
* For non-symbol menu nodes, we just need to
|
|
|
|
* handle the prompt
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
prop = menu->prompt;
|
2017-10-05 12:01:14 +00:00
|
|
|
|
|
|
|
/* For each property... */
|
2005-04-16 22:20:36 +00:00
|
|
|
for (; prop; prop = prop->next) {
|
|
|
|
if (prop->menu != menu)
|
2017-10-05 12:01:14 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
2017-10-05 12:01:14 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Propagate parent dependencies to the
|
|
|
|
* property's condition, rewriting and
|
|
|
|
* simplifying expressions at the same time
|
|
|
|
*/
|
kconfig: Clean up modules handling and fix crash
Kconfig currently doesn't handle 'm' appearing in a Kconfig file before
the modules symbol is defined (the symbol with 'option modules'). The
problem is the following code, which runs during parsing:
/* change 'm' into 'm' && MODULES */
if (e->left.sym == &symbol_mod)
return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
If the modules symbol has not yet been defined, modules_sym is NULL,
giving an invalid expression.
Here is a test file where both BEFORE_1 and BEFORE_2 trigger a segfault.
If the modules symbol is removed, all symbols trigger segfaults.
config BEFORE_1
def_tristate y if m
if m
config BEFORE_2
def_tristate y
endif
config MODULES
def_bool y
option modules
config AFTER_1
def_tristate y if m
if m
config AFTER_2
def_tristate y
endif
Fix the issue by rewriting 'm' in menu_finalize() instead. This function
runs after parsing and is the proper place to do it. The following
existing code in conf_parse() in zconf.y ensures that the modules symbol
exists at that point:
if (!modules_sym)
modules_sym = sym_find( "n" );
...
menu_finalize(&rootmenu);
The following tests were done to ensure no functional changes for
configurations that don't reference 'm' before the modules symbol:
- zconfdump(stdout) was run with ARCH=x86 and ARCH=arm before
and after the change and verified to produce identical output.
This function prints all symbols, choices, and menus together
with their properties and their dependency expressions. A
rewritten 'm' appears as 'm && MODULES'.
A small annoyance is that the assert(len != 0) in xfwrite()
needs to be disabled in order to use zconfdump(), because it
chokes on e.g. 'default ""'.
- The Kconfiglib test suite was run to indirectly verify that
alldefconfig, allyesconfig, allnoconfig, and all defconfigs in
the kernel still generate the same final .config.
- Valgrind was used to check for memory errors and (new) memory
leaks.
Signed-off-by: Ulf Magnusson <ulfalizer@gmail.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2017-10-05 12:01:15 +00:00
|
|
|
dep = rewrite_m(prop->visible.expr);
|
|
|
|
dep = expr_transform(dep);
|
kconfig: use hash table to reuse expressions
Currently, every expression in Kconfig files produces a new abstract
syntax tree (AST), even if it is identical to a previously encountered
one.
Consider the following code:
config FOO
bool "FOO"
depends on (A || B) && C
config BAR
bool "BAR"
depends on (A || B) && C
config BAZ
bool "BAZ"
depends on A || B
The "depends on" lines are similar, but currently a separate AST is
allocated for each one.
The current data structure looks like this:
FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR
/ \ / \ / \
OR C OR C A B
/ \ / \
A B A B
This is redundant; FOO->dep and BAR->dep have identical ASTs but
different memory instances.
We can optimize this; FOO->dep and BAR->dep can share the same AST, and
BAZ->dep can reference its sub tree.
The optimized data structure looks like this:
FOO->dep, BAR->dep ==> AND
/ \
BAZ->dep ==> OR C
/ \
A B
This commit introduces a hash table to keep track of allocated
expressions. If an identical expression is found, it is reused.
This does not necessarily result in memory savings, as menu_finalize()
transforms expressions without freeing up stale ones. This will be
addressed later.
One optimization that can be easily implemented is caching the
expression's value. Once FOO's dependency, (A || B) && C, is calculated,
it can be cached, eliminating the need to recalculate it for BAR.
This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix
multiple references to expressions in menu_add_prop()").
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-09-08 12:43:20 +00:00
|
|
|
dep = expr_alloc_and(basedep, dep);
|
2005-04-16 22:20:36 +00:00
|
|
|
dep = expr_eliminate_dups(dep);
|
|
|
|
prop->visible.expr = dep;
|
2017-10-05 12:01:14 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle selects and implies, which modify the
|
|
|
|
* dependencies of the selected/implied symbol
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
if (prop->type == P_SELECT) {
|
|
|
|
struct symbol *es = prop_get_symbol(prop);
|
|
|
|
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
|
kconfig: use hash table to reuse expressions
Currently, every expression in Kconfig files produces a new abstract
syntax tree (AST), even if it is identical to a previously encountered
one.
Consider the following code:
config FOO
bool "FOO"
depends on (A || B) && C
config BAR
bool "BAR"
depends on (A || B) && C
config BAZ
bool "BAZ"
depends on A || B
The "depends on" lines are similar, but currently a separate AST is
allocated for each one.
The current data structure looks like this:
FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR
/ \ / \ / \
OR C OR C A B
/ \ / \
A B A B
This is redundant; FOO->dep and BAR->dep have identical ASTs but
different memory instances.
We can optimize this; FOO->dep and BAR->dep can share the same AST, and
BAZ->dep can reference its sub tree.
The optimized data structure looks like this:
FOO->dep, BAR->dep ==> AND
/ \
BAZ->dep ==> OR C
/ \
A B
This commit introduces a hash table to keep track of allocated
expressions. If an identical expression is found, it is reused.
This does not necessarily result in memory savings, as menu_finalize()
transforms expressions without freeing up stale ones. This will be
addressed later.
One optimization that can be easily implemented is caching the
expression's value. Once FOO's dependency, (A || B) && C, is calculated,
it can be cached, eliminating the need to recalculate it for BAR.
This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix
multiple references to expressions in menu_add_prop()").
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-09-08 12:43:20 +00:00
|
|
|
expr_alloc_and(expr_alloc_symbol(menu->sym), dep));
|
2016-11-11 05:10:05 +00:00
|
|
|
} else if (prop->type == P_IMPLY) {
|
|
|
|
struct symbol *es = prop_get_symbol(prop);
|
|
|
|
es->implied.expr = expr_alloc_or(es->implied.expr,
|
kconfig: use hash table to reuse expressions
Currently, every expression in Kconfig files produces a new abstract
syntax tree (AST), even if it is identical to a previously encountered
one.
Consider the following code:
config FOO
bool "FOO"
depends on (A || B) && C
config BAR
bool "BAR"
depends on (A || B) && C
config BAZ
bool "BAZ"
depends on A || B
The "depends on" lines are similar, but currently a separate AST is
allocated for each one.
The current data structure looks like this:
FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR
/ \ / \ / \
OR C OR C A B
/ \ / \
A B A B
This is redundant; FOO->dep and BAR->dep have identical ASTs but
different memory instances.
We can optimize this; FOO->dep and BAR->dep can share the same AST, and
BAZ->dep can reference its sub tree.
The optimized data structure looks like this:
FOO->dep, BAR->dep ==> AND
/ \
BAZ->dep ==> OR C
/ \
A B
This commit introduces a hash table to keep track of allocated
expressions. If an identical expression is found, it is reused.
This does not necessarily result in memory savings, as menu_finalize()
transforms expressions without freeing up stale ones. This will be
addressed later.
One optimization that can be easily implemented is caching the
expression's value. Once FOO's dependency, (A || B) && C, is calculated,
it can be cached, eliminating the need to recalculate it for BAR.
This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix
multiple references to expressions in menu_add_prop()").
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-09-08 12:43:20 +00:00
|
|
|
expr_alloc_and(expr_alloc_symbol(menu->sym), dep));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-05 12:01:14 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Recursively process children in the same fashion before
|
|
|
|
* moving on
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
for (menu = parent->list; menu; menu = menu->next)
|
kconfig: fix conditional prompt behavior for choice
When a prompt is followed by "if <expr>", the symbol is configurable
when the if-conditional evaluates to true.
A typical usage is as follows:
menuconfig BLOCK
bool "Enable the block layer" if EXPERT
default y
When EXPERT=n, the prompt is hidden, but this config entry is still
active, and BLOCK is set to its default value 'y'. When EXPERT=y, the
prompt is shown, making BLOCK a user-configurable option.
This usage is common throughout the kernel tree, but it has never worked
within a choice block.
[Test Code]
config EXPERT
bool "Allow expert users to modify more options"
choice
prompt "Choose" if EXPERT
config A
bool "A"
config B
bool "B"
endchoice
[Result]
# CONFIG_EXPERT is not set
When the prompt is hidden, the choice block should produce the default
without asking for the user's preference. Hence, the output should be:
# CONFIG_EXPERT is not set
CONFIG_A=y
# CONFIG_B is not set
Removing unnecessary hacks fixes the issue.
This commit also changes the behavior of 'select' by choice members.
[Test Code 2]
config MODULES
def_bool y
modules
config DEP
def_tristate m
if DEP
choice
prompt "choose"
config A
bool "A"
select C
endchoice
config B
def_bool y
select D
endif
config C
tristate
config D
tristate
The current output is as follows:
CONFIG_MODULES=y
CONFIG_DEP=m
CONFIG_A=y
CONFIG_B=y
CONFIG_C=y
CONFIG_D=m
With this commit, the output will be changed as follows:
CONFIG_MODULES=y
CONFIG_DEP=m
CONFIG_A=y
CONFIG_B=y
CONFIG_C=m
CONFIG_D=m
CONFIG_C will be changed to 'm' because 'select C' will inherit the
dependency on DEP, which is 'm'.
This change is aligned with the behavior of 'select' outside a choice
block; 'select D' depends on DEP, therefore D is selected by (B && DEP).
Note:
With this commit, allmodconfig will set CONFIG_USB_ROLE_SWITCH to 'm'
instead of 'y'. I did not see any build regression with this change.
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-06-26 18:22:01 +00:00
|
|
|
_menu_finalize(menu, sym && sym_is_choice(sym));
|
2024-03-23 08:51:01 +00:00
|
|
|
} else if (!inside_choice && sym) {
|
2017-10-08 17:42:18 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* ...
|
|
|
|
*/
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
|
|
|
|
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
|
|
|
|
basedep = expr_eliminate_dups(expr_transform(basedep));
|
2017-10-08 17:42:18 +00:00
|
|
|
|
|
|
|
/* Examine consecutive elements after sym */
|
2005-04-16 22:20:36 +00:00
|
|
|
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))
|
2017-10-08 17:42:18 +00:00
|
|
|
/* No dependency, quit */
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
if (expr_depends_symbol(dep, sym))
|
2017-10-08 17:42:18 +00:00
|
|
|
/* Absolute dependency, put in submenu */
|
2005-04-16 22:20:36 +00:00
|
|
|
goto next;
|
2017-10-08 17:42:18 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
|
|
|
|
dep = expr_eliminate_dups(expr_transform(dep));
|
kconfig: use hash table to reuse expressions
Currently, every expression in Kconfig files produces a new abstract
syntax tree (AST), even if it is identical to a previously encountered
one.
Consider the following code:
config FOO
bool "FOO"
depends on (A || B) && C
config BAR
bool "BAR"
depends on (A || B) && C
config BAZ
bool "BAZ"
depends on A || B
The "depends on" lines are similar, but currently a separate AST is
allocated for each one.
The current data structure looks like this:
FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR
/ \ / \ / \
OR C OR C A B
/ \ / \
A B A B
This is redundant; FOO->dep and BAR->dep have identical ASTs but
different memory instances.
We can optimize this; FOO->dep and BAR->dep can share the same AST, and
BAZ->dep can reference its sub tree.
The optimized data structure looks like this:
FOO->dep, BAR->dep ==> AND
/ \
BAZ->dep ==> OR C
/ \
A B
This commit introduces a hash table to keep track of allocated
expressions. If an identical expression is found, it is reused.
This does not necessarily result in memory savings, as menu_finalize()
transforms expressions without freeing up stale ones. This will be
addressed later.
One optimization that can be easily implemented is caching the
expression's value. Once FOO's dependency, (A || B) && C, is calculated,
it can be cached, eliminating the need to recalculate it for BAR.
This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix
multiple references to expressions in menu_add_prop()").
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2024-09-08 12:43:20 +00:00
|
|
|
dep2 = basedep;
|
2005-04-16 22:20:36 +00:00
|
|
|
expr_eliminate_eq(&dep, &dep2);
|
|
|
|
if (!expr_is_yes(dep2)) {
|
2017-10-08 17:42:18 +00:00
|
|
|
/* Not superset, quit */
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-10-08 17:42:18 +00:00
|
|
|
/* Superset, put in submenu */
|
2005-04-16 22:20:36 +00:00
|
|
|
next:
|
2024-03-23 08:51:01 +00:00
|
|
|
_menu_finalize(menu, false);
|
2005-04-16 22:20:36 +00:00
|
|
|
menu->parent = parent;
|
|
|
|
last_menu = menu;
|
|
|
|
}
|
|
|
|
if (last_menu) {
|
|
|
|
parent->list = parent->next;
|
|
|
|
parent->next = last_menu->next;
|
|
|
|
last_menu->next = NULL;
|
|
|
|
}
|
2010-09-26 20:22:03 +00:00
|
|
|
|
2011-06-08 05:42:11 +00:00
|
|
|
sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
for (menu = parent->list; menu; menu = menu->next) {
|
2018-01-14 14:49:26 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
if (menu->list && (!menu->prompt || !menu->prompt->text)) {
|
|
|
|
for (last_menu = menu->list; ; last_menu = last_menu->next) {
|
|
|
|
last_menu->parent = parent;
|
|
|
|
if (!last_menu->next)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
last_menu->next = menu->next;
|
|
|
|
menu->next = menu->list;
|
|
|
|
menu->list = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym && !(sym->flags & SYMBOL_WARNED)) {
|
|
|
|
if (sym->type == S_UNKNOWN)
|
2006-06-09 05:12:48 +00:00
|
|
|
menu_warn(parent, "config symbol defined without type");
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* Check properties connected to this symbol */
|
|
|
|
sym_check_prop(sym);
|
|
|
|
sym->flags |= SYMBOL_WARNED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-23 08:51:01 +00:00
|
|
|
void menu_finalize(void)
|
|
|
|
{
|
|
|
|
_menu_finalize(&rootmenu, false);
|
|
|
|
}
|
|
|
|
|
2024-07-07 15:38:05 +00:00
|
|
|
bool menu_has_prompt(const struct menu *menu)
|
menuconfig: add support to show hidden options which have prompts
Usage:
Press <Z> to show all config symbols which have prompts.
Quote Tim Bird:
| I've been bitten by this numerous times. I most often
| use ftrace on ARM, but when I go back to x86, I almost
| always go through a sequence of searching for the
| function graph tracer in the menus, then realizing it's
| completely missing until I disable CC_OPTIMIZE_FOR_SIZE.
|
| Is there any way to have the menu item appear, but be
| unsettable unless the SIZE option is disabled? I'm
| not a Kconfig guru...
I myself found this useful too. For example, I need to test
ftrace/tracing and want to be sure all the tracing features are
enabled, so I enter the "Tracers" menu, and press <Z> to
see if there is any config hidden.
I also noticed gconfig and xconfig have a button "Show all options",
but that's a bit too much, and I think normally what we are not
interested in those configs which have no prompt thus can't be
changed by users.
Exmaple:
--- Tracers
-*- Kernel Function Tracer
- - Kernel Function Graph Tracer
[*] Interrupts-off Latency Tracer
- - Preemption-off Latency Tracer
[*] Sysprof Tracer
Here you can see 2 tracers are not selectable, and then can find
out how to make them selectable.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-04-14 03:46:02 +00:00
|
|
|
{
|
|
|
|
if (!menu->prompt)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-19 19:49:34 +00:00
|
|
|
/*
|
|
|
|
* Determine if a menu is empty.
|
|
|
|
* A menu is considered empty if it contains no or only
|
|
|
|
* invisible entries.
|
|
|
|
*/
|
|
|
|
bool menu_is_empty(struct menu *menu)
|
|
|
|
{
|
|
|
|
struct menu *child;
|
|
|
|
|
|
|
|
for (child = menu->list; child; child = child->next) {
|
|
|
|
if (menu_is_visible(child))
|
|
|
|
return(false);
|
|
|
|
}
|
|
|
|
return(true);
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
bool menu_is_visible(struct menu *menu)
|
|
|
|
{
|
2024-10-26 17:55:50 +00:00
|
|
|
struct menu *child;
|
2005-04-16 22:20:36 +00:00
|
|
|
struct symbol *sym;
|
|
|
|
tristate visible;
|
|
|
|
|
|
|
|
if (!menu->prompt)
|
|
|
|
return false;
|
menuconfig: add support to show hidden options which have prompts
Usage:
Press <Z> to show all config symbols which have prompts.
Quote Tim Bird:
| I've been bitten by this numerous times. I most often
| use ftrace on ARM, but when I go back to x86, I almost
| always go through a sequence of searching for the
| function graph tracer in the menus, then realizing it's
| completely missing until I disable CC_OPTIMIZE_FOR_SIZE.
|
| Is there any way to have the menu item appear, but be
| unsettable unless the SIZE option is disabled? I'm
| not a Kconfig guru...
I myself found this useful too. For example, I need to test
ftrace/tracing and want to be sure all the tracing features are
enabled, so I enter the "Tracers" menu, and press <Z> to
see if there is any config hidden.
I also noticed gconfig and xconfig have a button "Show all options",
but that's a bit too much, and I think normally what we are not
interested in those configs which have no prompt thus can't be
changed by users.
Exmaple:
--- Tracers
-*- Kernel Function Tracer
- - Kernel Function Graph Tracer
[*] Interrupts-off Latency Tracer
- - Preemption-off Latency Tracer
[*] Sysprof Tracer
Here you can see 2 tracers are not selectable, and then can find
out how to make them selectable.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-04-14 03:46:02 +00:00
|
|
|
|
2010-11-06 21:30:23 +00:00
|
|
|
if (menu->visibility) {
|
|
|
|
if (expr_calc_value(menu->visibility) == no)
|
2016-01-01 16:34:05 +00:00
|
|
|
return false;
|
2010-11-06 21:30:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
sym = menu->sym;
|
|
|
|
if (sym) {
|
|
|
|
sym_calc_value(sym);
|
|
|
|
visible = menu->prompt->visible.tri;
|
|
|
|
} else
|
|
|
|
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
|
|
|
|
|
2024-10-26 17:55:50 +00:00
|
|
|
if (visible != no)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!sym || sym_get_tristate_value(menu->sym) == no)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (child = menu->list; child; child = child->next)
|
|
|
|
if (menu_is_visible(child))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2024-07-07 15:38:05 +00:00
|
|
|
const char *menu_get_prompt(const struct menu *menu)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
if (menu->prompt)
|
2008-01-11 22:53:43 +00:00
|
|
|
return menu->prompt->text;
|
2005-04-16 22:20:36 +00:00
|
|
|
else if (menu->sym)
|
2008-01-11 22:53:43 +00:00
|
|
|
return menu->sym->name;
|
2005-04-16 22:20:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct menu *menu_get_parent_menu(struct menu *menu)
|
|
|
|
{
|
|
|
|
enum prop_type type;
|
|
|
|
|
|
|
|
for (; menu != &rootmenu; menu = menu->parent) {
|
|
|
|
type = menu->prompt ? menu->prompt->type : 0;
|
|
|
|
if (type == P_MENU)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
2024-07-07 15:38:05 +00:00
|
|
|
static void get_def_str(struct gstr *r, const struct menu *menu)
|
kconfig: list all definitions of a symbol in help text
In Kconfig, each symbol (representing a config option) can be defined in
multiple places. Each definition may or may not have a prompt, which
allows the option to be set via an interface like menuconfig. Each
definition has a set of dependencies, which determine whether its prompt
is visible and whether other pieces of the definition, like a default
value, take effect.
Historically, a symbol's help text (i.e. what's shown when a user
presses '?' in menuconfig) contained some symbol-wide information not
tied to any particular definition (e.g. what other symbols it selects)
as well as the location (file name and line number) and dependencies of
each prompt. Notably, the help text did not show the location or
dependencies of definitions without prompts.
Because this made it hard to reason about symbols that had no prompts,
commit bcdedcc1afd6 ("menuconfig: print more info for symbol without
prompts") changed the help text so that, instead of containing the
location and dependencies of each prompt, it contained the location and
dependencies of the symbol's first definition, regardless of whether or
not that definition had a prompt.
For symbols with only one definition, that change makes sense. However,
it breaks down for symbols with multiple definitions: each definition
has its own set of dependencies (the `dep` field of `struct menu`), and
those dependencies are ORed together to get the symbol's dependency list
(the `dir_dep` field of `struct symbol`). By printing only the
dependencies of the first definition, the help text misleads users into
believing that an option is more narrowly-applicable than it actually
is.
For an extreme example of this, we can look at the SYS_TEXT_BASE symbol
in the Das U-Boot project (version 2019.10), which also uses Kconfig. (I
unfortunately could not find an illustrative example in Linux.) This
config option specifies the load address of the built binary and, as
such, is applicable to basically every configuration possible. And yet,
without this patch, its help text is as follows:
Symbol: SYS_TEXT_BASE [=]
Type : hex
Prompt: U-Boot base address
Location:
-> ARM architecture
Prompt: Text Base
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
The help text indicates that the option is applicable only for a
specific unselected architecture (aspeed), because that architecture's
promptless definition (which just sets a default value), happens to be
the first one seen. No definition or dependency information is printed
for either of the two prompts listed.
Because source locations and dependencies are fundamentally properties
of definitions and not of symbols, we should treat them as such. This
patch brings back the pre-bcdedcc1afd6 behavior for definitions with
prompts but also separately prints the location and dependencies of
those without prompts, solving the original problem in a different way.
With this change, our SYS_TEXT_BASE example becomes
Symbol: SYS_TEXT_BASE [=]
Type : hex
Defined at arch/arm/mach-stm32mp/Kconfig:83
Prompt: U-Boot base address
Depends on: ARM [=n] && ARCH_STM32MP [=n]
Location:
-> ARM architecture
Defined at Kconfig:532
Prompt: Text Base
Depends on: !NIOS2 [=n] && !XTENSA [=n] && !EFI_APP [=n]
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
Defined at arch/arm/mach-socfpga/Kconfig:25
Depends on: ARM [=n] && ARCH_SOCFPGA [=n]
<snip>
Defined at board/sifive/fu540/Kconfig:15
Depends on: RISCV [=n] && TARGET_SIFIVE_FU540 [=n]
which is a much more accurate representation.
Note that there is one notable difference between what gets printed for
prompts after this change and what got printed before bcdedcc1afd6: the
"Depends on" line now accurately represents the prompt's dependencies
instead of conflating those with the prompt's visibility (which can
include extra conditions). See the patch later in this series titled
"kconfig: distinguish between dependencies and visibility in help text"
for more details and better handling of that nuance.
Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2019-12-17 16:15:43 +00:00
|
|
|
{
|
|
|
|
str_printf(r, "Defined at %s:%d\n",
|
2024-02-02 15:58:09 +00:00
|
|
|
menu->filename, menu->lineno);
|
kconfig: list all definitions of a symbol in help text
In Kconfig, each symbol (representing a config option) can be defined in
multiple places. Each definition may or may not have a prompt, which
allows the option to be set via an interface like menuconfig. Each
definition has a set of dependencies, which determine whether its prompt
is visible and whether other pieces of the definition, like a default
value, take effect.
Historically, a symbol's help text (i.e. what's shown when a user
presses '?' in menuconfig) contained some symbol-wide information not
tied to any particular definition (e.g. what other symbols it selects)
as well as the location (file name and line number) and dependencies of
each prompt. Notably, the help text did not show the location or
dependencies of definitions without prompts.
Because this made it hard to reason about symbols that had no prompts,
commit bcdedcc1afd6 ("menuconfig: print more info for symbol without
prompts") changed the help text so that, instead of containing the
location and dependencies of each prompt, it contained the location and
dependencies of the symbol's first definition, regardless of whether or
not that definition had a prompt.
For symbols with only one definition, that change makes sense. However,
it breaks down for symbols with multiple definitions: each definition
has its own set of dependencies (the `dep` field of `struct menu`), and
those dependencies are ORed together to get the symbol's dependency list
(the `dir_dep` field of `struct symbol`). By printing only the
dependencies of the first definition, the help text misleads users into
believing that an option is more narrowly-applicable than it actually
is.
For an extreme example of this, we can look at the SYS_TEXT_BASE symbol
in the Das U-Boot project (version 2019.10), which also uses Kconfig. (I
unfortunately could not find an illustrative example in Linux.) This
config option specifies the load address of the built binary and, as
such, is applicable to basically every configuration possible. And yet,
without this patch, its help text is as follows:
Symbol: SYS_TEXT_BASE [=]
Type : hex
Prompt: U-Boot base address
Location:
-> ARM architecture
Prompt: Text Base
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
The help text indicates that the option is applicable only for a
specific unselected architecture (aspeed), because that architecture's
promptless definition (which just sets a default value), happens to be
the first one seen. No definition or dependency information is printed
for either of the two prompts listed.
Because source locations and dependencies are fundamentally properties
of definitions and not of symbols, we should treat them as such. This
patch brings back the pre-bcdedcc1afd6 behavior for definitions with
prompts but also separately prints the location and dependencies of
those without prompts, solving the original problem in a different way.
With this change, our SYS_TEXT_BASE example becomes
Symbol: SYS_TEXT_BASE [=]
Type : hex
Defined at arch/arm/mach-stm32mp/Kconfig:83
Prompt: U-Boot base address
Depends on: ARM [=n] && ARCH_STM32MP [=n]
Location:
-> ARM architecture
Defined at Kconfig:532
Prompt: Text Base
Depends on: !NIOS2 [=n] && !XTENSA [=n] && !EFI_APP [=n]
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
Defined at arch/arm/mach-socfpga/Kconfig:25
Depends on: ARM [=n] && ARCH_SOCFPGA [=n]
<snip>
Defined at board/sifive/fu540/Kconfig:15
Depends on: RISCV [=n] && TARGET_SIFIVE_FU540 [=n]
which is a much more accurate representation.
Note that there is one notable difference between what gets printed for
prompts after this change and what got printed before bcdedcc1afd6: the
"Depends on" line now accurately represents the prompt's dependencies
instead of conflating those with the prompt's visibility (which can
include extra conditions). See the patch later in this series titled
"kconfig: distinguish between dependencies and visibility in help text"
for more details and better handling of that nuance.
Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2019-12-17 16:15:43 +00:00
|
|
|
}
|
|
|
|
|
2024-07-07 15:38:05 +00:00
|
|
|
static void get_dep_str(struct gstr *r, const struct expr *expr,
|
|
|
|
const char *prefix)
|
kconfig: list all definitions of a symbol in help text
In Kconfig, each symbol (representing a config option) can be defined in
multiple places. Each definition may or may not have a prompt, which
allows the option to be set via an interface like menuconfig. Each
definition has a set of dependencies, which determine whether its prompt
is visible and whether other pieces of the definition, like a default
value, take effect.
Historically, a symbol's help text (i.e. what's shown when a user
presses '?' in menuconfig) contained some symbol-wide information not
tied to any particular definition (e.g. what other symbols it selects)
as well as the location (file name and line number) and dependencies of
each prompt. Notably, the help text did not show the location or
dependencies of definitions without prompts.
Because this made it hard to reason about symbols that had no prompts,
commit bcdedcc1afd6 ("menuconfig: print more info for symbol without
prompts") changed the help text so that, instead of containing the
location and dependencies of each prompt, it contained the location and
dependencies of the symbol's first definition, regardless of whether or
not that definition had a prompt.
For symbols with only one definition, that change makes sense. However,
it breaks down for symbols with multiple definitions: each definition
has its own set of dependencies (the `dep` field of `struct menu`), and
those dependencies are ORed together to get the symbol's dependency list
(the `dir_dep` field of `struct symbol`). By printing only the
dependencies of the first definition, the help text misleads users into
believing that an option is more narrowly-applicable than it actually
is.
For an extreme example of this, we can look at the SYS_TEXT_BASE symbol
in the Das U-Boot project (version 2019.10), which also uses Kconfig. (I
unfortunately could not find an illustrative example in Linux.) This
config option specifies the load address of the built binary and, as
such, is applicable to basically every configuration possible. And yet,
without this patch, its help text is as follows:
Symbol: SYS_TEXT_BASE [=]
Type : hex
Prompt: U-Boot base address
Location:
-> ARM architecture
Prompt: Text Base
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
The help text indicates that the option is applicable only for a
specific unselected architecture (aspeed), because that architecture's
promptless definition (which just sets a default value), happens to be
the first one seen. No definition or dependency information is printed
for either of the two prompts listed.
Because source locations and dependencies are fundamentally properties
of definitions and not of symbols, we should treat them as such. This
patch brings back the pre-bcdedcc1afd6 behavior for definitions with
prompts but also separately prints the location and dependencies of
those without prompts, solving the original problem in a different way.
With this change, our SYS_TEXT_BASE example becomes
Symbol: SYS_TEXT_BASE [=]
Type : hex
Defined at arch/arm/mach-stm32mp/Kconfig:83
Prompt: U-Boot base address
Depends on: ARM [=n] && ARCH_STM32MP [=n]
Location:
-> ARM architecture
Defined at Kconfig:532
Prompt: Text Base
Depends on: !NIOS2 [=n] && !XTENSA [=n] && !EFI_APP [=n]
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
Defined at arch/arm/mach-socfpga/Kconfig:25
Depends on: ARM [=n] && ARCH_SOCFPGA [=n]
<snip>
Defined at board/sifive/fu540/Kconfig:15
Depends on: RISCV [=n] && TARGET_SIFIVE_FU540 [=n]
which is a much more accurate representation.
Note that there is one notable difference between what gets printed for
prompts after this change and what got printed before bcdedcc1afd6: the
"Depends on" line now accurately represents the prompt's dependencies
instead of conflating those with the prompt's visibility (which can
include extra conditions). See the patch later in this series titled
"kconfig: distinguish between dependencies and visibility in help text"
for more details and better handling of that nuance.
Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2019-12-17 16:15:43 +00:00
|
|
|
{
|
|
|
|
if (!expr_is_yes(expr)) {
|
|
|
|
str_append(r, prefix);
|
|
|
|
expr_gstr_print(expr, r);
|
|
|
|
str_append(r, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-16 04:55:07 +00:00
|
|
|
int __attribute__((weak)) get_jump_key_char(void)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-23 18:55:08 +00:00
|
|
|
static void get_prompt_str(struct gstr *r, struct property *prop,
|
2012-10-21 09:27:53 +00:00
|
|
|
struct list_head *head)
|
2009-07-12 08:11:44 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
2012-08-23 18:55:06 +00:00
|
|
|
struct menu *submenu[8], *menu, *location = NULL;
|
2014-11-04 11:01:59 +00:00
|
|
|
struct jump_key *jump = NULL;
|
2009-07-12 08:11:44 +00:00
|
|
|
|
kconfig: list all definitions of a symbol in help text
In Kconfig, each symbol (representing a config option) can be defined in
multiple places. Each definition may or may not have a prompt, which
allows the option to be set via an interface like menuconfig. Each
definition has a set of dependencies, which determine whether its prompt
is visible and whether other pieces of the definition, like a default
value, take effect.
Historically, a symbol's help text (i.e. what's shown when a user
presses '?' in menuconfig) contained some symbol-wide information not
tied to any particular definition (e.g. what other symbols it selects)
as well as the location (file name and line number) and dependencies of
each prompt. Notably, the help text did not show the location or
dependencies of definitions without prompts.
Because this made it hard to reason about symbols that had no prompts,
commit bcdedcc1afd6 ("menuconfig: print more info for symbol without
prompts") changed the help text so that, instead of containing the
location and dependencies of each prompt, it contained the location and
dependencies of the symbol's first definition, regardless of whether or
not that definition had a prompt.
For symbols with only one definition, that change makes sense. However,
it breaks down for symbols with multiple definitions: each definition
has its own set of dependencies (the `dep` field of `struct menu`), and
those dependencies are ORed together to get the symbol's dependency list
(the `dir_dep` field of `struct symbol`). By printing only the
dependencies of the first definition, the help text misleads users into
believing that an option is more narrowly-applicable than it actually
is.
For an extreme example of this, we can look at the SYS_TEXT_BASE symbol
in the Das U-Boot project (version 2019.10), which also uses Kconfig. (I
unfortunately could not find an illustrative example in Linux.) This
config option specifies the load address of the built binary and, as
such, is applicable to basically every configuration possible. And yet,
without this patch, its help text is as follows:
Symbol: SYS_TEXT_BASE [=]
Type : hex
Prompt: U-Boot base address
Location:
-> ARM architecture
Prompt: Text Base
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
The help text indicates that the option is applicable only for a
specific unselected architecture (aspeed), because that architecture's
promptless definition (which just sets a default value), happens to be
the first one seen. No definition or dependency information is printed
for either of the two prompts listed.
Because source locations and dependencies are fundamentally properties
of definitions and not of symbols, we should treat them as such. This
patch brings back the pre-bcdedcc1afd6 behavior for definitions with
prompts but also separately prints the location and dependencies of
those without prompts, solving the original problem in a different way.
With this change, our SYS_TEXT_BASE example becomes
Symbol: SYS_TEXT_BASE [=]
Type : hex
Defined at arch/arm/mach-stm32mp/Kconfig:83
Prompt: U-Boot base address
Depends on: ARM [=n] && ARCH_STM32MP [=n]
Location:
-> ARM architecture
Defined at Kconfig:532
Prompt: Text Base
Depends on: !NIOS2 [=n] && !XTENSA [=n] && !EFI_APP [=n]
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
Defined at arch/arm/mach-socfpga/Kconfig:25
Depends on: ARM [=n] && ARCH_SOCFPGA [=n]
<snip>
Defined at board/sifive/fu540/Kconfig:15
Depends on: RISCV [=n] && TARGET_SIFIVE_FU540 [=n]
which is a much more accurate representation.
Note that there is one notable difference between what gets printed for
prompts after this change and what got printed before bcdedcc1afd6: the
"Depends on" line now accurately represents the prompt's dependencies
instead of conflating those with the prompt's visibility (which can
include extra conditions). See the patch later in this series titled
"kconfig: distinguish between dependencies and visibility in help text"
for more details and better handling of that nuance.
Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2019-12-17 16:15:43 +00:00
|
|
|
str_printf(r, " Prompt: %s\n", prop->text);
|
|
|
|
|
|
|
|
get_dep_str(r, prop->menu->dep, " Depends on: ");
|
kconfig: distinguish between dependencies and visibility in help text
Kconfig makes a distinction between dependencies (defined by "depends
on" expressions and enclosing "if" blocks) and visibility (which
includes all dependencies, but also includes inline "if" expressions of
individual properties as well as, for prompts, "visible if" expressions
of enclosing menus).
Before commit bcdedcc1afd6 ("menuconfig: print more info for symbol
without prompts"), the "Depends on" lines of a symbol's help text
indicated the visibility of the prompt property they appeared under.
After bcdedcc1afd, there was always only a single "Depends on" line,
which indicated the visibility of the first P_SYMBOL property of the
symbol. Since P_SYMBOLs never have inline if expressions, this was in
effect the same as the dependencies of the menu item that the P_SYMBOL
was attached to.
Neither of these situations accurately conveyed the dependencies of a
symbol--the first because it was actually the visibility, and the second
because it only showed the dependencies from a single definition.
With this series, we are back to printing separate dependencies for each
definition, but we print the actual dependencies (rather than the
visibility) in the "Depends on" line. However, it can still be useful to
know the visibility of a prompt, so this patch adds a "Visible if" line
that shows the visibility only if the visibility is different from the
dependencies (which it isn't for most prompts in Linux).
Before:
Symbol: THUMB2_KERNEL [=n]
Type : bool
Defined at arch/arm/Kconfig:1417
Prompt: Compile the kernel in Thumb-2 mode
Depends on: (CPU_V7 [=y] || CPU_V7M [=n]) && !CPU_V6 [=n] && !CPU_V6K [=n]
Location:
-> Kernel Features
Selects: ARM_UNWIND [=n]
After:
Symbol: THUMB2_KERNEL [=n]
Type : bool
Defined at arch/arm/Kconfig:1417
Prompt: Compile the kernel in Thumb-2 mode
Depends on: (CPU_V7 [=y] || CPU_V7M [=n]) && !CPU_V6 [=n] && !CPU_V6K [=n]
Visible if: (CPU_V7 [=y] || CPU_V7M [=n]) && !CPU_V6 [=n] && !CPU_V6K [=n] && !CPU_THUMBONLY [=n]
Location:
-> Kernel Features
Selects: ARM_UNWIND [=n]
Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2019-12-17 16:15:44 +00:00
|
|
|
/*
|
|
|
|
* Most prompts in Linux have visibility that exactly matches their
|
|
|
|
* dependencies. For these, we print only the dependencies to improve
|
|
|
|
* readability. However, prompts with inline "if" expressions and
|
|
|
|
* prompts with a parent that has a "visible if" expression have
|
|
|
|
* differing dependencies and visibility. In these rare cases, we
|
|
|
|
* print both.
|
|
|
|
*/
|
|
|
|
if (!expr_eq(prop->menu->dep, prop->visible.expr))
|
|
|
|
get_dep_str(r, prop->visible.expr, " Visible if: ");
|
|
|
|
|
2022-10-23 19:10:55 +00:00
|
|
|
menu = prop->menu;
|
|
|
|
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
|
2009-07-12 08:11:44 +00:00
|
|
|
submenu[i++] = menu;
|
2022-11-13 10:59:41 +00:00
|
|
|
if (location == NULL && menu_is_visible(menu))
|
2012-08-23 18:55:06 +00:00
|
|
|
location = menu;
|
|
|
|
}
|
2012-08-23 18:55:08 +00:00
|
|
|
if (head && location) {
|
2012-11-06 14:32:08 +00:00
|
|
|
jump = xmalloc(sizeof(struct jump_key));
|
2022-10-23 19:10:55 +00:00
|
|
|
jump->target = location;
|
2012-10-21 09:27:53 +00:00
|
|
|
list_add_tail(&jump->entries, head);
|
2012-08-23 18:55:08 +00:00
|
|
|
}
|
2012-08-23 18:55:06 +00:00
|
|
|
|
2021-09-13 16:45:14 +00:00
|
|
|
str_printf(r, " Location:\n");
|
2023-07-16 04:55:07 +00:00
|
|
|
for (j = 0; --i >= 0; j++) {
|
|
|
|
int jk = -1;
|
|
|
|
int indent = 2 * j + 4;
|
|
|
|
|
2021-09-13 16:45:14 +00:00
|
|
|
menu = submenu[i];
|
2023-07-16 04:55:07 +00:00
|
|
|
if (jump && menu == location) {
|
2021-09-13 16:45:14 +00:00
|
|
|
jump->offset = strlen(r->s);
|
2023-07-16 04:55:07 +00:00
|
|
|
jk = get_jump_key_char();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (jk >= 0) {
|
|
|
|
str_printf(r, "(%c)", jk);
|
|
|
|
indent -= 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu));
|
2021-09-13 16:45:14 +00:00
|
|
|
if (menu->sym) {
|
|
|
|
str_printf(r, " (%s [=%s])", menu->sym->name ?
|
|
|
|
menu->sym->name : "<choice>",
|
|
|
|
sym_get_string_value(menu->sym));
|
2009-07-12 08:11:44 +00:00
|
|
|
}
|
2021-09-13 16:45:14 +00:00
|
|
|
str_append(r, "\n");
|
2009-07-12 08:11:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-11 05:10:05 +00:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2012-08-23 18:55:06 +00:00
|
|
|
/*
|
2012-08-23 18:55:08 +00:00
|
|
|
* head is optional and may be NULL
|
2012-08-23 18:55:06 +00:00
|
|
|
*/
|
2015-02-24 15:37:13 +00:00
|
|
|
static void get_symbol_str(struct gstr *r, struct symbol *sym,
|
2012-10-21 09:27:53 +00:00
|
|
|
struct list_head *head)
|
2009-07-12 08:11:44 +00:00
|
|
|
{
|
|
|
|
struct property *prop;
|
2024-03-03 04:00:34 +00:00
|
|
|
struct menu *menu;
|
2009-07-12 08:11:44 +00:00
|
|
|
|
2010-05-07 05:56:33 +00:00
|
|
|
if (sym && sym->name) {
|
2009-07-12 08:11:44 +00:00
|
|
|
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
|
|
|
|
sym_get_string_value(sym));
|
2010-05-07 05:56:33 +00:00
|
|
|
str_printf(r, "Type : %s\n", sym_type_name(sym->type));
|
2010-05-07 05:56:50 +00:00
|
|
|
if (sym->type == S_INT || sym->type == S_HEX) {
|
|
|
|
prop = sym_get_range_prop(sym);
|
|
|
|
if (prop) {
|
|
|
|
str_printf(r, "Range : ");
|
|
|
|
expr_gstr_print(prop->expr, r);
|
|
|
|
str_append(r, "\n");
|
|
|
|
}
|
|
|
|
}
|
2010-05-07 05:56:33 +00:00
|
|
|
}
|
kconfig: list all definitions of a symbol in help text
In Kconfig, each symbol (representing a config option) can be defined in
multiple places. Each definition may or may not have a prompt, which
allows the option to be set via an interface like menuconfig. Each
definition has a set of dependencies, which determine whether its prompt
is visible and whether other pieces of the definition, like a default
value, take effect.
Historically, a symbol's help text (i.e. what's shown when a user
presses '?' in menuconfig) contained some symbol-wide information not
tied to any particular definition (e.g. what other symbols it selects)
as well as the location (file name and line number) and dependencies of
each prompt. Notably, the help text did not show the location or
dependencies of definitions without prompts.
Because this made it hard to reason about symbols that had no prompts,
commit bcdedcc1afd6 ("menuconfig: print more info for symbol without
prompts") changed the help text so that, instead of containing the
location and dependencies of each prompt, it contained the location and
dependencies of the symbol's first definition, regardless of whether or
not that definition had a prompt.
For symbols with only one definition, that change makes sense. However,
it breaks down for symbols with multiple definitions: each definition
has its own set of dependencies (the `dep` field of `struct menu`), and
those dependencies are ORed together to get the symbol's dependency list
(the `dir_dep` field of `struct symbol`). By printing only the
dependencies of the first definition, the help text misleads users into
believing that an option is more narrowly-applicable than it actually
is.
For an extreme example of this, we can look at the SYS_TEXT_BASE symbol
in the Das U-Boot project (version 2019.10), which also uses Kconfig. (I
unfortunately could not find an illustrative example in Linux.) This
config option specifies the load address of the built binary and, as
such, is applicable to basically every configuration possible. And yet,
without this patch, its help text is as follows:
Symbol: SYS_TEXT_BASE [=]
Type : hex
Prompt: U-Boot base address
Location:
-> ARM architecture
Prompt: Text Base
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
The help text indicates that the option is applicable only for a
specific unselected architecture (aspeed), because that architecture's
promptless definition (which just sets a default value), happens to be
the first one seen. No definition or dependency information is printed
for either of the two prompts listed.
Because source locations and dependencies are fundamentally properties
of definitions and not of symbols, we should treat them as such. This
patch brings back the pre-bcdedcc1afd6 behavior for definitions with
prompts but also separately prints the location and dependencies of
those without prompts, solving the original problem in a different way.
With this change, our SYS_TEXT_BASE example becomes
Symbol: SYS_TEXT_BASE [=]
Type : hex
Defined at arch/arm/mach-stm32mp/Kconfig:83
Prompt: U-Boot base address
Depends on: ARM [=n] && ARCH_STM32MP [=n]
Location:
-> ARM architecture
Defined at Kconfig:532
Prompt: Text Base
Depends on: !NIOS2 [=n] && !XTENSA [=n] && !EFI_APP [=n]
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
Defined at arch/arm/mach-socfpga/Kconfig:25
Depends on: ARM [=n] && ARCH_SOCFPGA [=n]
<snip>
Defined at board/sifive/fu540/Kconfig:15
Depends on: RISCV [=n] && TARGET_SIFIVE_FU540 [=n]
which is a much more accurate representation.
Note that there is one notable difference between what gets printed for
prompts after this change and what got printed before bcdedcc1afd6: the
"Depends on" line now accurately represents the prompt's dependencies
instead of conflating those with the prompt's visibility (which can
include extra conditions). See the patch later in this series titled
"kconfig: distinguish between dependencies and visibility in help text"
for more details and better handling of that nuance.
Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2019-12-17 16:15:43 +00:00
|
|
|
|
|
|
|
/* Print the definitions with prompts before the ones without */
|
2024-03-03 04:00:34 +00:00
|
|
|
list_for_each_entry(menu, &sym->menus, link) {
|
|
|
|
if (menu->prompt) {
|
|
|
|
get_def_str(r, menu);
|
|
|
|
get_prompt_str(r, menu->prompt, head);
|
kconfig: list all definitions of a symbol in help text
In Kconfig, each symbol (representing a config option) can be defined in
multiple places. Each definition may or may not have a prompt, which
allows the option to be set via an interface like menuconfig. Each
definition has a set of dependencies, which determine whether its prompt
is visible and whether other pieces of the definition, like a default
value, take effect.
Historically, a symbol's help text (i.e. what's shown when a user
presses '?' in menuconfig) contained some symbol-wide information not
tied to any particular definition (e.g. what other symbols it selects)
as well as the location (file name and line number) and dependencies of
each prompt. Notably, the help text did not show the location or
dependencies of definitions without prompts.
Because this made it hard to reason about symbols that had no prompts,
commit bcdedcc1afd6 ("menuconfig: print more info for symbol without
prompts") changed the help text so that, instead of containing the
location and dependencies of each prompt, it contained the location and
dependencies of the symbol's first definition, regardless of whether or
not that definition had a prompt.
For symbols with only one definition, that change makes sense. However,
it breaks down for symbols with multiple definitions: each definition
has its own set of dependencies (the `dep` field of `struct menu`), and
those dependencies are ORed together to get the symbol's dependency list
(the `dir_dep` field of `struct symbol`). By printing only the
dependencies of the first definition, the help text misleads users into
believing that an option is more narrowly-applicable than it actually
is.
For an extreme example of this, we can look at the SYS_TEXT_BASE symbol
in the Das U-Boot project (version 2019.10), which also uses Kconfig. (I
unfortunately could not find an illustrative example in Linux.) This
config option specifies the load address of the built binary and, as
such, is applicable to basically every configuration possible. And yet,
without this patch, its help text is as follows:
Symbol: SYS_TEXT_BASE [=]
Type : hex
Prompt: U-Boot base address
Location:
-> ARM architecture
Prompt: Text Base
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
The help text indicates that the option is applicable only for a
specific unselected architecture (aspeed), because that architecture's
promptless definition (which just sets a default value), happens to be
the first one seen. No definition or dependency information is printed
for either of the two prompts listed.
Because source locations and dependencies are fundamentally properties
of definitions and not of symbols, we should treat them as such. This
patch brings back the pre-bcdedcc1afd6 behavior for definitions with
prompts but also separately prints the location and dependencies of
those without prompts, solving the original problem in a different way.
With this change, our SYS_TEXT_BASE example becomes
Symbol: SYS_TEXT_BASE [=]
Type : hex
Defined at arch/arm/mach-stm32mp/Kconfig:83
Prompt: U-Boot base address
Depends on: ARM [=n] && ARCH_STM32MP [=n]
Location:
-> ARM architecture
Defined at Kconfig:532
Prompt: Text Base
Depends on: !NIOS2 [=n] && !XTENSA [=n] && !EFI_APP [=n]
Location:
-> Boot images
Defined at arch/arm/mach-aspeed/Kconfig:9
Depends on: ARM [=n] && ARCH_ASPEED [=n]
Defined at arch/arm/mach-socfpga/Kconfig:25
Depends on: ARM [=n] && ARCH_SOCFPGA [=n]
<snip>
Defined at board/sifive/fu540/Kconfig:15
Depends on: RISCV [=n] && TARGET_SIFIVE_FU540 [=n]
which is a much more accurate representation.
Note that there is one notable difference between what gets printed for
prompts after this change and what got printed before bcdedcc1afd6: the
"Depends on" line now accurately represents the prompt's dependencies
instead of conflating those with the prompt's visibility (which can
include extra conditions). See the patch later in this series titled
"kconfig: distinguish between dependencies and visibility in help text"
for more details and better handling of that nuance.
Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2019-12-17 16:15:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-03 04:00:34 +00:00
|
|
|
list_for_each_entry(menu, &sym->menus, link) {
|
|
|
|
if (!menu->prompt) {
|
|
|
|
get_def_str(r, menu);
|
|
|
|
get_dep_str(r, menu->dep, " Depends on: ");
|
2013-05-07 13:56:54 +00:00
|
|
|
}
|
2013-04-30 22:28:46 +00:00
|
|
|
}
|
2013-05-07 13:56:54 +00:00
|
|
|
|
2019-12-17 16:15:45 +00:00
|
|
|
get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
|
2009-07-12 08:11:44 +00:00
|
|
|
if (sym->rev_dep.expr) {
|
2019-12-17 16:15:45 +00:00
|
|
|
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");
|
2009-07-12 08:11:44 +00:00
|
|
|
}
|
2016-11-11 05:10:05 +00:00
|
|
|
|
2019-12-17 16:15:45 +00:00
|
|
|
get_symbol_props_str(r, sym, P_IMPLY, "Implies: ");
|
2016-11-11 05:10:05 +00:00
|
|
|
if (sym->implied.expr) {
|
2019-12-17 16:15:45 +00:00
|
|
|
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");
|
2016-11-11 05:10:05 +00:00
|
|
|
}
|
|
|
|
|
2009-07-12 08:11:44 +00:00
|
|
|
str_append(r, "\n\n");
|
|
|
|
}
|
|
|
|
|
2012-10-21 09:27:53 +00:00
|
|
|
struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
|
2009-11-25 10:28:43 +00:00
|
|
|
{
|
|
|
|
struct symbol *sym;
|
|
|
|
struct gstr res = str_new();
|
2012-08-23 18:55:08 +00:00
|
|
|
int i;
|
2009-11-25 10:28:43 +00:00
|
|
|
|
|
|
|
for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
|
2012-08-23 18:55:08 +00:00
|
|
|
get_symbol_str(&res, sym, head);
|
2009-11-25 10:28:43 +00:00
|
|
|
if (!i)
|
2018-05-22 19:36:12 +00:00
|
|
|
str_append(&res, "No matches found.\n");
|
2009-11-25 10:28:43 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-12 08:11:44 +00:00
|
|
|
void menu_get_ext_help(struct menu *menu, struct gstr *help)
|
|
|
|
{
|
|
|
|
struct symbol *sym = menu->sym;
|
2011-08-04 01:52:07 +00:00
|
|
|
const char *help_text = nohelp_text;
|
2009-07-12 08:11:44 +00:00
|
|
|
|
2023-12-03 10:25:25 +00:00
|
|
|
if (menu->help) {
|
2011-08-02 17:49:52 +00:00
|
|
|
if (sym->name)
|
2010-08-15 03:57:43 +00:00
|
|
|
str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
|
2023-12-03 10:25:25 +00:00
|
|
|
help_text = menu->help;
|
2009-07-12 08:11:44 +00:00
|
|
|
}
|
2018-05-22 19:36:12 +00:00
|
|
|
str_printf(help, "%s\n", help_text);
|
2009-07-12 08:11:46 +00:00
|
|
|
if (sym)
|
2012-08-23 18:55:08 +00:00
|
|
|
get_symbol_str(help, sym, NULL);
|
2009-07-12 08:11:44 +00:00
|
|
|
}
|