OpenCloudOS-Kernel/scripts/kconfig/menu.c

878 lines
22 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "lkc.h"
static const char nohelp_text[] = "There is no help available for this option.";
struct menu rootmenu;
static struct menu **last_entry_ptr;
struct file *file_list;
struct file *current_file;
void menu_warn(struct menu *menu, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
}
static void prop_warn(struct property *prop, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
}
void _menu_init(void)
{
current_entry = current_menu = &rootmenu;
last_entry_ptr = &rootmenu.list;
}
void menu_add_entry(struct symbol *sym)
{
struct menu *menu;
menu = xmalloc(sizeof(*menu));
memset(menu, 0, sizeof(*menu));
menu->sym = sym;
menu->parent = current_menu;
menu->file = current_file;
menu->lineno = zconf_lineno();
*last_entry_ptr = menu;
last_entry_ptr = &menu->next;
current_entry = menu;
if (sym)
menu_add_symbol(P_SYMBOL, sym, NULL);
}
struct menu *menu_add_menu(void)
{
last_entry_ptr = &current_entry->list;
current_menu = current_entry;
return current_menu;
}
void menu_end_menu(void)
{
last_entry_ptr = &current_menu->next;
current_menu = current_menu->parent;
}
/*
* 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 = rewrite_m(e->left.expr);
break;
case E_OR:
case E_AND:
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 */
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 20:01:15 +08:00
current_entry->dep = expr_alloc_and(current_entry->dep, dep);
}
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;
}
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));
}
static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
struct expr *dep)
{
struct property *prop;
prop = xmalloc(sizeof(*prop));
memset(prop, 0, sizeof(*prop));
prop->type = type;
prop->file = current_file;
prop->lineno = zconf_lineno();
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 20:01:15 +08:00
prop->visible.expr = dep;
/* append property to the prop list of symbol */
if (current_entry->sym) {
struct property **propp;
for (propp = &current_entry->sym->prop;
*propp;
propp = &(*propp)->next)
;
*propp = prop;
}
return prop;
}
struct property *menu_add_prompt(enum prop_type type, char *prompt,
struct expr *dep)
{
struct property *prop = menu_add_prop(type, NULL, dep);
if (isspace(*prompt)) {
prop_warn(prop, "leading whitespace ignored");
while (isspace(*prompt))
prompt++;
}
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) {
struct expr *dup_expr;
if (!menu->visibility)
continue;
/*
* Do not add a reference to the menu's visibility
* expression but use a copy of it. Otherwise the
* expression reduction functions will modify
* expressions that have multiple references which
* can cause unwanted side effects.
*/
dup_expr = expr_copy(menu->visibility);
prop->visible.expr = expr_alloc_and(prop->visible.expr,
dup_expr);
}
}
current_entry->prompt = prop;
prop->text = prompt;
return prop;
}
void menu_add_visibility(struct expr *expr)
{
current_entry->visibility = expr_alloc_and(current_entry->visibility,
expr);
}
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
{
menu_add_prop(type, expr, dep);
}
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
{
menu_add_prop(type, expr_alloc_symbol(sym), dep);
}
static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
{
return sym2->type == S_INT || sym2->type == S_HEX ||
(sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
}
static void sym_check_prop(struct symbol *sym)
{
struct property *prop;
struct symbol *sym2;
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
char *use;
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,
"default for config symbol '%s'"
" must be a single symbol", sym->name);
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);
}
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:
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
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,
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
"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,
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
"'%s' has wrong type. '%s' only "
"accept arguments of bool and "
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
"tristate type", sym2->name, use);
break;
case P_RANGE:
if (sym->type != S_INT && sym->type != S_HEX)
prop_warn(prop, "range is only allowed "
"for int or hex symbols");
if (!menu_validate_number(sym, prop->expr->left.sym) ||
!menu_validate_number(sym, prop->expr->right.sym))
prop_warn(prop, "range is invalid");
break;
default:
;
}
}
}
void menu_finalize(struct menu *parent)
{
struct menu *menu, *last_menu;
struct symbol *sym;
struct property *prop;
struct expr *parentdep, *basedep, *dep, *dep2, **ep;
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 */
current_entry = parent;
for (menu = parent->list; menu; menu = menu->next) {
if (menu->sym && menu->sym->type != S_UNKNOWN) {
menu_set_type(menu->sym->type);
break;
}
}
}
/* set the type of the remaining choice values */
for (menu = parent->list; menu; menu = menu->next) {
current_entry = menu;
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 {
/* Menu node for 'menu', 'if' */
parentdep = parent->dep;
}
/* For each child menu node... */
for (menu = parent->list; menu; menu = menu->next) {
/*
* 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 20:01:15 +08:00
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;
/*
* 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 20:01:15 +08:00
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)));
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
} 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;
last_menu->next = NULL;
}
sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
}
for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) &&
menu->sym && !sym_is_choice_value(menu->sym)) {
current_entry = menu;
menu->sym->flags |= SYMBOL_CHOICEVAL;
if (!menu->prompt)
menu_warn(menu, "choice value must have a prompt");
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->type == P_DEFAULT)
prop_warn(prop, "defaults for choice "
"values not supported");
if (prop->menu == menu)
continue;
if (prop->type == P_PROMPT &&
prop->menu->parent->sym != sym)
prop_warn(prop, "choice value used outside its choice group");
}
/* Non-tristate choice values of tristate choices must
* depend on the choice being set to Y. The choice
* values' dependencies were propagated to their
* properties above, so the change here must be re-
* propagated.
*/
if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
menu->dep = expr_alloc_and(basedep, menu->dep);
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->menu != menu)
continue;
prop->visible.expr = expr_alloc_and(expr_copy(basedep),
prop->visible.expr);
}
}
menu_add_symbol(P_CHOICE, sym, NULL);
prop = sym_get_choice_prop(sym);
for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
;
*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;
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)
menu_warn(parent, "config symbol defined without type");
if (sym_is_choice(sym) && !parent->prompt)
menu_warn(parent, "choice must have a prompt");
/* Check properties connected to this symbol */
sym_check_prop(sym);
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,
expr_alloc_symbol(&symbol_mod)));
}
}
bool menu_has_prompt(struct menu *menu)
{
if (!menu->prompt)
return false;
return true;
}
/*
* 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);
}
bool menu_is_visible(struct menu *menu)
{
struct menu *child;
struct symbol *sym;
tristate visible;
if (!menu->prompt)
return false;
if (menu->visibility) {
if (expr_calc_value(menu->visibility) == no)
return false;
}
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);
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)) {
if (sym)
sym->flags |= SYMBOL_DEF_USER;
return true;
}
}
return false;
}
const char *menu_get_prompt(struct menu *menu)
{
if (menu->prompt)
return menu->prompt->text;
else if (menu->sym)
return menu->sym->name;
return NULL;
}
struct menu *menu_get_root_menu(struct menu *menu)
{
return &rootmenu;
}
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;
}
bool menu_has_help(struct menu *menu)
{
return menu->help != NULL;
}
const char *menu_get_help(struct menu *menu)
{
if (menu->help)
return menu->help;
else
return "";
}
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-18 00:15:43 +08:00
static void get_def_str(struct gstr *r, struct menu *menu)
{
str_printf(r, "Defined at %s:%d\n",
menu->file->name, menu->lineno);
}
static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix)
{
if (!expr_is_yes(expr)) {
str_append(r, prefix);
expr_gstr_print(expr, r);
str_append(r, "\n");
}
}
static void get_prompt_str(struct gstr *r, struct property *prop,
struct list_head *head)
{
int i, j;
struct menu *submenu[8], *menu, *location = NULL;
struct jump_key *jump = NULL;
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-18 00:15:43 +08: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-18 00:15:44 +08: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: ");
menu = prop->menu->parent;
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
bool accessible = menu_is_visible(menu);
submenu[i++] = menu;
if (location == NULL && accessible)
location = menu;
}
if (head && location) {
jump = xmalloc(sizeof(struct jump_key));
if (menu_is_visible(prop->menu)) {
/*
* There is not enough room to put the hint at the
* beginning of the "Prompt" line. Put the hint on the
* last "Location" line even when it would belong on
* the former.
*/
jump->target = prop->menu;
} else
jump->target = location;
if (list_empty(head))
jump->index = 0;
else
jump->index = list_entry(head->prev, struct jump_key,
entries)->index + 1;
list_add_tail(&jump->entries, head);
}
if (i > 0) {
str_printf(r, " Location:\n");
for (j = 4; --i >= 0; j += 2) {
menu = submenu[i];
if (jump && menu == location)
jump->offset = strlen(r->s);
str_printf(r, "%*c-> %s", j, ' ',
menu_get_prompt(menu));
if (menu->sym) {
str_printf(r, " (%s [=%s])", menu->sym->name ?
menu->sym->name : "<choice>",
sym_get_string_value(menu->sym));
}
str_append(r, "\n");
}
}
}
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08: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");
}
/*
* head is optional and may be NULL
*/
static void get_symbol_str(struct gstr *r, struct symbol *sym,
struct list_head *head)
{
struct property *prop;
if (sym && sym->name) {
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
sym_get_string_value(sym));
str_printf(r, "Type : %s\n", sym_type_name(sym->type));
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");
}
}
}
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-18 00:15:43 +08:00
/* Print the definitions with prompts before the ones without */
for_all_properties(sym, prop, P_SYMBOL) {
if (prop->menu->prompt) {
get_def_str(r, prop->menu);
get_prompt_str(r, prop->menu->prompt, head);
}
}
for_all_properties(sym, prop, P_SYMBOL) {
if (!prop->menu->prompt) {
get_def_str(r, prop->menu);
get_dep_str(r, prop->menu->dep, " Depends on: ");
}
}
get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
if (sym->rev_dep.expr) {
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");
}
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
get_symbol_props_str(r, sym, P_IMPLY, "Implies: ");
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
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");
Kconfig: Introduce the "imply" keyword The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. 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. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-11-11 13:10:05 +08:00
}
str_append(r, "\n\n");
}
struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
{
struct symbol *sym;
struct gstr res = str_new();
int i;
for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
get_symbol_str(&res, sym, head);
if (!i)
str_append(&res, "No matches found.\n");
return res;
}
void menu_get_ext_help(struct menu *menu, struct gstr *help)
{
struct symbol *sym = menu->sym;
const char *help_text = nohelp_text;
if (menu_has_help(menu)) {
if (sym->name)
str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
help_text = menu_get_help(menu);
}
str_printf(help, "%s\n", help_text);
if (sym)
get_symbol_str(help, sym, NULL);
}