OpenCloudOS-Kernel/scripts/kconfig/symbol.c

1269 lines
28 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include "lkc.h"
struct symbol symbol_yes = {
.name = "y",
.curr = { "y", yes },
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
struct symbol symbol_mod = {
.name = "m",
.curr = { "m", mod },
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
struct symbol symbol_no = {
.name = "n",
.curr = { "n", no },
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
static struct symbol symbol_empty = {
.name = "",
.curr = { "", no },
.flags = SYMBOL_VALID,
};
struct symbol *modules_sym;
static tristate modules_val;
enum symbol_type sym_get_type(struct symbol *sym)
{
enum symbol_type type = sym->type;
if (type == S_TRISTATE) {
if (sym_is_choice_value(sym) && sym->visible == yes)
type = S_BOOLEAN;
else if (modules_val == no)
type = S_BOOLEAN;
}
return type;
}
const char *sym_type_name(enum symbol_type type)
{
switch (type) {
case S_BOOLEAN:
return "bool";
case S_TRISTATE:
return "tristate";
case S_INT:
return "integer";
case S_HEX:
return "hex";
case S_STRING:
return "string";
case S_UNKNOWN:
return "unknown";
}
return "???";
}
struct property *sym_get_choice_prop(struct symbol *sym)
{
struct property *prop;
for_all_choices(sym, prop)
return prop;
return NULL;
}
static struct property *sym_get_default_prop(struct symbol *sym)
{
struct property *prop;
for_all_defaults(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
if (prop->visible.tri != no)
return prop;
}
return NULL;
}
struct property *sym_get_range_prop(struct symbol *sym)
{
struct property *prop;
for_all_properties(sym, prop, P_RANGE) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
if (prop->visible.tri != no)
return prop;
}
return NULL;
}
static long long sym_get_range_val(struct symbol *sym, int base)
{
sym_calc_value(sym);
switch (sym->type) {
case S_INT:
base = 10;
break;
case S_HEX:
base = 16;
break;
default:
break;
}
return strtoll(sym->curr.val, NULL, base);
}
static void sym_validate_range(struct symbol *sym)
{
struct property *prop;
struct symbol *range_sym;
int base;
long long val, val2;
switch (sym->type) {
case S_INT:
base = 10;
break;
case S_HEX:
base = 16;
break;
default:
return;
}
prop = sym_get_range_prop(sym);
if (!prop)
return;
val = strtoll(sym->curr.val, NULL, base);
range_sym = prop->expr->left.sym;
val2 = sym_get_range_val(range_sym, base);
if (val >= val2) {
range_sym = prop->expr->right.sym;
val2 = sym_get_range_val(range_sym, base);
if (val <= val2)
return;
}
sym->curr.val = range_sym->curr.val;
}
static void sym_set_changed(struct symbol *sym)
{
struct property *prop;
sym->flags |= SYMBOL_CHANGED;
for (prop = sym->prop; prop; prop = prop->next) {
if (prop->menu)
prop->menu->flags |= MENU_CHANGED;
}
}
static void sym_set_all_changed(void)
{
struct symbol *sym;
int i;
for_all_symbols(i, sym)
sym_set_changed(sym);
}
static void sym_calc_visibility(struct symbol *sym)
{
struct property *prop;
struct symbol *choice_sym = NULL;
tristate tri;
/* any prompt visible? */
tri = no;
if (sym_is_choice_value(sym))
choice_sym = prop_get_symbol(sym_get_choice_prop(sym));
for_all_prompts(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
/*
* Tristate choice_values with visibility 'mod' are
* not visible if the corresponding choice's value is
* 'yes'.
*/
if (choice_sym && sym->type == S_TRISTATE &&
prop->visible.tri == mod && choice_sym->curr.tri == yes)
prop->visible.tri = no;
tri = EXPR_OR(tri, prop->visible.tri);
}
if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
tri = yes;
if (sym->visible != tri) {
sym->visible = tri;
sym_set_changed(sym);
}
if (sym_is_choice_value(sym))
return;
/* defaulting to "yes" if no explicit "depends on" are given */
tri = yes;
if (sym->dir_dep.expr)
tri = expr_calc_value(sym->dir_dep.expr);
if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
tri = yes;
if (sym->dir_dep.tri != tri) {
sym->dir_dep.tri = tri;
sym_set_changed(sym);
}
tri = no;
if (sym->rev_dep.expr)
tri = expr_calc_value(sym->rev_dep.expr);
if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
tri = yes;
if (sym->rev_dep.tri != tri) {
sym->rev_dep.tri = tri;
sym_set_changed(sym);
}
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
tri = no;
if (sym->implied.expr)
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
tri = expr_calc_value(sym->implied.expr);
if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
tri = yes;
if (sym->implied.tri != tri) {
sym->implied.tri = tri;
sym_set_changed(sym);
}
}
/*
* Find the default symbol for a choice.
* First try the default values for the choice symbol
* Next locate the first visible choice value
* Return NULL if none was found
*/
struct symbol *sym_choice_default(struct symbol *sym)
{
struct symbol *def_sym;
struct property *prop;
struct expr *e;
/* any of the defaults visible? */
for_all_defaults(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
if (prop->visible.tri == no)
continue;
def_sym = prop_get_symbol(prop);
if (def_sym->visible != no)
return def_sym;
}
/* just get the first visible value */
prop = sym_get_choice_prop(sym);
expr_list_for_each_sym(prop->expr, e, def_sym)
if (def_sym->visible != no)
return def_sym;
/* failed to locate any defaults */
return NULL;
}
static struct symbol *sym_calc_choice(struct symbol *sym)
{
struct symbol *def_sym;
struct property *prop;
struct expr *e;
int flags;
/* first calculate all choice values' visibilities */
flags = sym->flags;
prop = sym_get_choice_prop(sym);
expr_list_for_each_sym(prop->expr, e, def_sym) {
sym_calc_visibility(def_sym);
if (def_sym->visible != no)
flags &= def_sym->flags;
}
sym->flags &= flags | ~SYMBOL_DEF_USER;
/* is the user choice visible? */
def_sym = sym->def[S_DEF_USER].val;
if (def_sym && def_sym->visible != no)
return def_sym;
def_sym = sym_choice_default(sym);
if (def_sym == NULL)
/* no choice? reset tristate value */
sym->curr.tri = no;
return def_sym;
}
kconfig: make unmet dependency warnings readable Currently, the unmet dependency warnings end up with endlessly long expressions, most of which are false positives. Here is test code to demonstrate how it currently works. [Test Case] config DEP1 def_bool y config DEP2 bool "DEP2" config A bool "A" select E config B bool "B" depends on DEP2 select E config C bool "C" depends on DEP1 && DEP2 select E config D def_bool n select E config E bool depends on DEP1 && DEP2 [Result] $ make config scripts/kconfig/conf --oldaskconfig Kconfig * * Linux Kernel Configuration * DEP2 (DEP2) [N/y/?] (NEW) n A (A) [N/y/?] (NEW) y warning: (A && B && D) selects E which has unmet direct dependencies (DEP1 && DEP2) Here, I see some points to be improved. First, '(A || B || D)' would make more sense than '(A && B && D)'. I am not sure if this is intentional, but expr_simplify_unmet_dep() turns OR expressions into AND, like follows: case E_OR: return expr_alloc_and( Second, we see false positives. 'A' is a real unmet dependency. 'B' is false positive because 'DEP1' is fixed to 'y', and 'B' depends on 'DEP2'. 'C' was correctly dropped by expr_simplify_unmet_dep(). 'D' is also false positive because it has no chance to be enabled. Current expr_simplify_unmet_dep() cannot avoid those false positives. After all, I decided to use the same helpers as used for printing reverse dependencies in the help. With this commit, unreadable warnings (most of the reported symbols are false positives) in the real world: $ make ARCH=score allyesconfig scripts/kconfig/conf --allyesconfig Kconfig warning: (HWSPINLOCK_QCOM && AHCI_MTK && STMMAC_PLATFORM && DWMAC_IPQ806X && DWMAC_LPC18XX && DWMAC_OXNAS && DWMAC_ROCKCHIP && DWMAC_SOCFPGA && DWMAC_STI && TI_CPSW && PINCTRL_GEMINI && PINCTRL_OXNAS && PINCTRL_ROCKCHIP && PINCTRL_DOVE && PINCTRL_ARMADA_37XX && PINCTRL_STM32 && S3C2410_WATCHDOG && VIDEO_OMAP3 && VIDEO_S5P_FIMC && USB_XHCI_MTK && RTC_DRV_AT91SAM9 && LPC18XX_DMAMUX && VIDEO_OMAP4 && COMMON_CLK_GEMINI && COMMON_CLK_ASPEED && COMMON_CLK_NXP && COMMON_CLK_OXNAS && COMMON_CLK_BOSTON && QCOM_ADSP_PIL && QCOM_Q6V5_PIL && QCOM_GSBI && ATMEL_EBI && ST_IRQCHIP && RESET_IMX7 && PHY_HI6220_USB && PHY_RALINK_USB && PHY_ROCKCHIP_PCIE && PHY_DA8XX_USB) selects MFD_SYSCON which has unmet direct dependencies (HAS_IOMEM) warning: (PINCTRL_AT91 && PINCTRL_AT91PIO4 && PINCTRL_OXNAS && PINCTRL_PISTACHIO && PINCTRL_PIC32 && PINCTRL_MESON && PINCTRL_NOMADIK && PINCTRL_MTK && PINCTRL_MT7622 && GPIO_TB10X) selects OF_GPIO which has unmet direct dependencies (GPIOLIB && OF && HAS_IOMEM) warning: (FAULT_INJECTION_STACKTRACE_FILTER && LATENCYTOP && LOCKDEP) selects FRAME_POINTER which has unmet direct dependencies (DEBUG_KERNEL && (CRIS || M68K || FRV || UML || SUPERH || BLACKFIN || MN10300 || METAG) || ARCH_WANT_FRAME_POINTERS) will be turned into: $ make ARCH=score allyesconfig scripts/kconfig/conf --allyesconfig Kconfig WARNING: unmet direct dependencies detected for MFD_SYSCON Depends on [n]: HAS_IOMEM [=n] Selected by [y]: - PINCTRL_STM32 [=y] && PINCTRL [=y] && (ARCH_STM32 || COMPILE_TEST [=y]) && OF [=y] - RTC_DRV_AT91SAM9 [=y] && RTC_CLASS [=y] && (ARCH_AT91 || COMPILE_TEST [=y]) - RESET_IMX7 [=y] && RESET_CONTROLLER [=y] - PHY_HI6220_USB [=y] && (ARCH_HISI && ARM64 || COMPILE_TEST [=y]) - PHY_RALINK_USB [=y] && (RALINK || COMPILE_TEST [=y]) - PHY_ROCKCHIP_PCIE [=y] && (ARCH_ROCKCHIP && OF [=y] || COMPILE_TEST [=y]) WARNING: unmet direct dependencies detected for OF_GPIO Depends on [n]: GPIOLIB [=y] && OF [=y] && HAS_IOMEM [=n] Selected by [y]: - PINCTRL_MTK [=y] && PINCTRL [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && OF [=y] - PINCTRL_MT7622 [=y] && PINCTRL [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && OF [=y] && (ARM64 || COMPILE_TEST [=y]) WARNING: unmet direct dependencies detected for FRAME_POINTER Depends on [n]: DEBUG_KERNEL [=y] && (CRIS || M68K || FRV || UML || SUPERH || BLACKFIN || MN10300 || METAG) || ARCH_WANT_FRAME_POINTERS [=n] Selected by [y]: - LATENCYTOP [=y] && DEBUG_KERNEL [=y] && STACKTRACE_SUPPORT [=y] && PROC_FS [=y] && !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC && !X86 Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Reviewed-by: Petr Vorel <petr.vorel@gmail.com>
2018-03-13 17:56:08 +08:00
static void sym_warn_unmet_dep(struct symbol *sym)
{
struct gstr gs = str_new();
str_printf(&gs,
"\nWARNING: unmet direct dependencies detected for %s\n",
sym->name);
str_printf(&gs,
" Depends on [%c]: ",
sym->dir_dep.tri == mod ? 'm' : 'n');
expr_gstr_print(sym->dir_dep.expr, &gs);
str_printf(&gs, "\n");
expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes,
" Selected by [y]:\n");
expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod,
" Selected by [m]:\n");
fputs(str_get(&gs), stderr);
}
void sym_calc_value(struct symbol *sym)
{
struct symbol_value newval, oldval;
struct property *prop;
struct expr *e;
if (!sym)
return;
if (sym->flags & SYMBOL_VALID)
return;
kconfig: Fix defconfig when one choice menu selects options that another choice menu depends on The defconfig and Kconfig combination below, which is based on 3.10-rc4 Kconfigs, resulted in several options getting set to "m" instead of "y". defconfig.choice: ---8<--- CONFIG_MODULES=y CONFIG_USB_ZERO=y ---8<--- Kconfig.choice: ---8<--- menuconfig MODULES bool "Enable loadable module support" config CONFIGFS_FS tristate "Userspace-driven configuration filesystem" config OCFS2_FS tristate "OCFS2 file system support" depends on CONFIGFS_FS select CRC32 config USB_LIBCOMPOSITE tristate select CONFIGFS_FS choice tristate "USB Gadget Drivers" default USB_ETH config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE config USB_ETH tristate "Ethernet Gadget (with CDC Ethernet support)" select USB_LIBCOMPOSITE endchoice config CRC32 tristate "CRC32/CRC32c functions" default y choice prompt "CRC32 implementation" depends on CRC32 default CRC32_SLICEBY8 config CRC32_SLICEBY8 bool "Slice by 8 bytes" endchoice ---8<--- $ scripts/kconfig/conf --defconfig=defconfig.choice Kconfig.choice would result in: .config: ---8<--- CONFIG_MODULES=y CONFIG_CONFIGFS_FS=m CONFIG_USB_LIBCOMPOSITE=m CONFIG_USB_ZERO=m CONFIG_CRC32=y CONFIG_CRC32_SLICEBY8=y ---8<--- when the expected result would be: .config: ---8<--- CONFIG_MODULES=y CONFIG_CONFIGFS_FS=y CONFIG_USB_LIBCOMPOSITE=y CONFIG_USB_ZERO=y CONFIG_CRC32=y CONFIG_CRC32_SLICEBY8=y ---8<--- Signed-off-by: Arve Hjønnevåg <arve@android.com> [yann.morin.1998@free.fr: add the resulting .config to commit log, remove unneeded USB_GADGET from the defconfig] Tested-by: "Yann E. MORIN" <yann.morin.1998@free.fr> Reviewed-by: "Yann E. MORIN" <yann.morin.1998@free.fr> Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
2013-06-07 11:37:00 +08:00
if (sym_is_choice_value(sym) &&
sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) {
sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES;
prop = sym_get_choice_prop(sym);
sym_calc_value(prop_get_symbol(prop));
}
sym->flags |= SYMBOL_VALID;
oldval = sym->curr;
switch (sym->type) {
case S_INT:
case S_HEX:
case S_STRING:
newval = symbol_empty.curr;
break;
case S_BOOLEAN:
case S_TRISTATE:
newval = symbol_no.curr;
break;
default:
sym->curr.val = sym->name;
sym->curr.tri = no;
return;
}
kconfig: do not write choice values when their dependency becomes n "# CONFIG_... is not set" for choice values are wrongly written into the .config file if they are once visible, then become invisible later. Test case --------- ---------------------------(Kconfig)---------------------------- config A bool "A" choice prompt "Choice ?" depends on A config CHOICE_B bool "Choice B" config CHOICE_C bool "Choice C" endchoice ---------------------------------------------------------------- ---------------------------(.config)---------------------------- CONFIG_A=y ---------------------------------------------------------------- With the Kconfig and .config above, $ make config scripts/kconfig/conf --oldaskconfig Kconfig * * Linux Kernel Configuration * A (A) [Y/n] n # # configuration written to .config # $ cat .config # # Automatically generated file; DO NOT EDIT. # Linux Kernel Configuration # # CONFIG_A is not set # CONFIG_CHOICE_B is not set # CONFIG_CHOICE_C is not set Here, # CONFIG_CHOICE_B is not set # CONFIG_CHOICE_C is not set should not be written into the .config file because their dependency "depends on A" is unmet. Currently, there is no code that clears SYMBOL_WRITE of choice values. Clear SYMBOL_WRITE for all symbols in sym_calc_value(), then set it again after calculating visibility. To simplify the logic, set the flag if they have non-n visibility, regardless of types, and regardless of whether they are choice values or not. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Reviewed-by: Ulf Magnusson <ulfalizer@gmail.com>
2018-02-06 08:34:42 +08:00
sym->flags &= ~SYMBOL_WRITE;
sym_calc_visibility(sym);
kconfig: do not write choice values when their dependency becomes n "# CONFIG_... is not set" for choice values are wrongly written into the .config file if they are once visible, then become invisible later. Test case --------- ---------------------------(Kconfig)---------------------------- config A bool "A" choice prompt "Choice ?" depends on A config CHOICE_B bool "Choice B" config CHOICE_C bool "Choice C" endchoice ---------------------------------------------------------------- ---------------------------(.config)---------------------------- CONFIG_A=y ---------------------------------------------------------------- With the Kconfig and .config above, $ make config scripts/kconfig/conf --oldaskconfig Kconfig * * Linux Kernel Configuration * A (A) [Y/n] n # # configuration written to .config # $ cat .config # # Automatically generated file; DO NOT EDIT. # Linux Kernel Configuration # # CONFIG_A is not set # CONFIG_CHOICE_B is not set # CONFIG_CHOICE_C is not set Here, # CONFIG_CHOICE_B is not set # CONFIG_CHOICE_C is not set should not be written into the .config file because their dependency "depends on A" is unmet. Currently, there is no code that clears SYMBOL_WRITE of choice values. Clear SYMBOL_WRITE for all symbols in sym_calc_value(), then set it again after calculating visibility. To simplify the logic, set the flag if they have non-n visibility, regardless of types, and regardless of whether they are choice values or not. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Reviewed-by: Ulf Magnusson <ulfalizer@gmail.com>
2018-02-06 08:34:42 +08:00
if (sym->visible != no)
sym->flags |= SYMBOL_WRITE;
/* set default if recursively called */
sym->curr = newval;
switch (sym_get_type(sym)) {
case S_BOOLEAN:
case S_TRISTATE:
if (sym_is_choice_value(sym) && sym->visible == yes) {
prop = sym_get_choice_prop(sym);
newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
} else {
if (sym->visible != no) {
/* if the symbol is visible use the user value
* if available, otherwise try the default value
*/
if (sym_has_value(sym)) {
newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
sym->visible);
goto calc_newval;
}
}
if (sym->rev_dep.tri != no)
sym->flags |= SYMBOL_WRITE;
if (!sym_is_choice(sym)) {
prop = sym_get_default_prop(sym);
if (prop) {
newval.tri = EXPR_AND(expr_calc_value(prop->expr),
prop->visible.tri);
kconfig: only write '# CONFIG_FOO is not set' for visible symbols === Background === - Visible n-valued bool/tristate symbols generate a '# CONFIG_FOO is not set' line in the .config file. The idea is to remember the user selection without having to set a Makefile variable. Having n correspond to the variable being undefined in the Makefiles makes for easy CONFIG_* tests. - Invisible n-valued bool/tristate symbols normally do not generate a '# CONFIG_FOO is not set' line, because user values from .config files have no effect on invisible symbols anyway. Currently, there is one exception to this rule: Any bool/tristate symbol that gets the value n through a 'default' property generates a '# CONFIG_FOO is not set' line, even if the symbol is invisible. Note that this only applies to explicitly given defaults, and not when the symbol implicitly defaults to n (like bool/tristate symbols without 'default' properties do). This is inconsistent, and seems redundant: - As mentioned, the '# CONFIG_FOO is not set' won't affect the symbol once the .config is read back in. - Even if the symbol is invisible at first but becomes visible later, there shouldn't be any harm in recalculating the default value rather than viewing the '# CONFIG_FOO is not set' as a previous user value of n. === Changes === Change sym_calc_value() to only set SYMBOL_WRITE (write to .config) for non-n-valued 'default' properties. Note that SYMBOL_WRITE is always set for visible symbols regardless of whether they have 'default' properties or not, so this change only affects invisible symbols. This reduces the size of the x86 .config on my system by about 1% (due to removed '# CONFIG_FOO is not set' entries). One side effect of (and the main motivation for) this change is making the following two definitions behave exactly the same: config FOO bool config FOO bool default n With this change, neither of these will generate a '# CONFIG_FOO is not set' line (assuming FOO isn't selected/implied). That might make it clearer to people that a bare 'default n' is redundant. This change only affects generated .config files and not autoconf.h: autoconf.h only includes #defines for non-n bool/tristate symbols. === Testing === The following testing was done with the x86 Kconfigs: - .config files generated before and after the change were compared to verify that the only difference is some '# CONFIG_FOO is not set' entries disappearing. A couple of these were inspected manually, and most turned out to be from redundant 'default n/def_bool n' properties. - The generated include/generated/autoconf.h was compared before and after the change and verified to be identical. - As a sanity check, the same modification was done to Kconfiglib. The Kconfiglib test suite was then run to check for any mismatches against the output of the C implementation. Signed-off-by: Ulf Magnusson <ulfalizer@gmail.com> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-02-23 19:49:01 +08:00
if (newval.tri != no)
sym->flags |= SYMBOL_WRITE;
}
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.tri != no) {
sym->flags |= SYMBOL_WRITE;
newval.tri = EXPR_OR(newval.tri, sym->implied.tri);
newval.tri = EXPR_AND(newval.tri,
sym->dir_dep.tri);
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
}
}
calc_newval:
kconfig: make unmet dependency warnings readable Currently, the unmet dependency warnings end up with endlessly long expressions, most of which are false positives. Here is test code to demonstrate how it currently works. [Test Case] config DEP1 def_bool y config DEP2 bool "DEP2" config A bool "A" select E config B bool "B" depends on DEP2 select E config C bool "C" depends on DEP1 && DEP2 select E config D def_bool n select E config E bool depends on DEP1 && DEP2 [Result] $ make config scripts/kconfig/conf --oldaskconfig Kconfig * * Linux Kernel Configuration * DEP2 (DEP2) [N/y/?] (NEW) n A (A) [N/y/?] (NEW) y warning: (A && B && D) selects E which has unmet direct dependencies (DEP1 && DEP2) Here, I see some points to be improved. First, '(A || B || D)' would make more sense than '(A && B && D)'. I am not sure if this is intentional, but expr_simplify_unmet_dep() turns OR expressions into AND, like follows: case E_OR: return expr_alloc_and( Second, we see false positives. 'A' is a real unmet dependency. 'B' is false positive because 'DEP1' is fixed to 'y', and 'B' depends on 'DEP2'. 'C' was correctly dropped by expr_simplify_unmet_dep(). 'D' is also false positive because it has no chance to be enabled. Current expr_simplify_unmet_dep() cannot avoid those false positives. After all, I decided to use the same helpers as used for printing reverse dependencies in the help. With this commit, unreadable warnings (most of the reported symbols are false positives) in the real world: $ make ARCH=score allyesconfig scripts/kconfig/conf --allyesconfig Kconfig warning: (HWSPINLOCK_QCOM && AHCI_MTK && STMMAC_PLATFORM && DWMAC_IPQ806X && DWMAC_LPC18XX && DWMAC_OXNAS && DWMAC_ROCKCHIP && DWMAC_SOCFPGA && DWMAC_STI && TI_CPSW && PINCTRL_GEMINI && PINCTRL_OXNAS && PINCTRL_ROCKCHIP && PINCTRL_DOVE && PINCTRL_ARMADA_37XX && PINCTRL_STM32 && S3C2410_WATCHDOG && VIDEO_OMAP3 && VIDEO_S5P_FIMC && USB_XHCI_MTK && RTC_DRV_AT91SAM9 && LPC18XX_DMAMUX && VIDEO_OMAP4 && COMMON_CLK_GEMINI && COMMON_CLK_ASPEED && COMMON_CLK_NXP && COMMON_CLK_OXNAS && COMMON_CLK_BOSTON && QCOM_ADSP_PIL && QCOM_Q6V5_PIL && QCOM_GSBI && ATMEL_EBI && ST_IRQCHIP && RESET_IMX7 && PHY_HI6220_USB && PHY_RALINK_USB && PHY_ROCKCHIP_PCIE && PHY_DA8XX_USB) selects MFD_SYSCON which has unmet direct dependencies (HAS_IOMEM) warning: (PINCTRL_AT91 && PINCTRL_AT91PIO4 && PINCTRL_OXNAS && PINCTRL_PISTACHIO && PINCTRL_PIC32 && PINCTRL_MESON && PINCTRL_NOMADIK && PINCTRL_MTK && PINCTRL_MT7622 && GPIO_TB10X) selects OF_GPIO which has unmet direct dependencies (GPIOLIB && OF && HAS_IOMEM) warning: (FAULT_INJECTION_STACKTRACE_FILTER && LATENCYTOP && LOCKDEP) selects FRAME_POINTER which has unmet direct dependencies (DEBUG_KERNEL && (CRIS || M68K || FRV || UML || SUPERH || BLACKFIN || MN10300 || METAG) || ARCH_WANT_FRAME_POINTERS) will be turned into: $ make ARCH=score allyesconfig scripts/kconfig/conf --allyesconfig Kconfig WARNING: unmet direct dependencies detected for MFD_SYSCON Depends on [n]: HAS_IOMEM [=n] Selected by [y]: - PINCTRL_STM32 [=y] && PINCTRL [=y] && (ARCH_STM32 || COMPILE_TEST [=y]) && OF [=y] - RTC_DRV_AT91SAM9 [=y] && RTC_CLASS [=y] && (ARCH_AT91 || COMPILE_TEST [=y]) - RESET_IMX7 [=y] && RESET_CONTROLLER [=y] - PHY_HI6220_USB [=y] && (ARCH_HISI && ARM64 || COMPILE_TEST [=y]) - PHY_RALINK_USB [=y] && (RALINK || COMPILE_TEST [=y]) - PHY_ROCKCHIP_PCIE [=y] && (ARCH_ROCKCHIP && OF [=y] || COMPILE_TEST [=y]) WARNING: unmet direct dependencies detected for OF_GPIO Depends on [n]: GPIOLIB [=y] && OF [=y] && HAS_IOMEM [=n] Selected by [y]: - PINCTRL_MTK [=y] && PINCTRL [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && OF [=y] - PINCTRL_MT7622 [=y] && PINCTRL [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && OF [=y] && (ARM64 || COMPILE_TEST [=y]) WARNING: unmet direct dependencies detected for FRAME_POINTER Depends on [n]: DEBUG_KERNEL [=y] && (CRIS || M68K || FRV || UML || SUPERH || BLACKFIN || MN10300 || METAG) || ARCH_WANT_FRAME_POINTERS [=n] Selected by [y]: - LATENCYTOP [=y] && DEBUG_KERNEL [=y] && STACKTRACE_SUPPORT [=y] && PROC_FS [=y] && !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC && !X86 Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Reviewed-by: Petr Vorel <petr.vorel@gmail.com>
2018-03-13 17:56:08 +08:00
if (sym->dir_dep.tri < sym->rev_dep.tri)
sym_warn_unmet_dep(sym);
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
}
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
newval.tri = yes;
break;
case S_STRING:
case S_HEX:
case S_INT:
kconfig: do not write choice values when their dependency becomes n "# CONFIG_... is not set" for choice values are wrongly written into the .config file if they are once visible, then become invisible later. Test case --------- ---------------------------(Kconfig)---------------------------- config A bool "A" choice prompt "Choice ?" depends on A config CHOICE_B bool "Choice B" config CHOICE_C bool "Choice C" endchoice ---------------------------------------------------------------- ---------------------------(.config)---------------------------- CONFIG_A=y ---------------------------------------------------------------- With the Kconfig and .config above, $ make config scripts/kconfig/conf --oldaskconfig Kconfig * * Linux Kernel Configuration * A (A) [Y/n] n # # configuration written to .config # $ cat .config # # Automatically generated file; DO NOT EDIT. # Linux Kernel Configuration # # CONFIG_A is not set # CONFIG_CHOICE_B is not set # CONFIG_CHOICE_C is not set Here, # CONFIG_CHOICE_B is not set # CONFIG_CHOICE_C is not set should not be written into the .config file because their dependency "depends on A" is unmet. Currently, there is no code that clears SYMBOL_WRITE of choice values. Clear SYMBOL_WRITE for all symbols in sym_calc_value(), then set it again after calculating visibility. To simplify the logic, set the flag if they have non-n visibility, regardless of types, and regardless of whether they are choice values or not. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Reviewed-by: Ulf Magnusson <ulfalizer@gmail.com>
2018-02-06 08:34:42 +08:00
if (sym->visible != no && sym_has_value(sym)) {
newval.val = sym->def[S_DEF_USER].val;
break;
}
prop = sym_get_default_prop(sym);
if (prop) {
struct symbol *ds = prop_get_symbol(prop);
if (ds) {
sym->flags |= SYMBOL_WRITE;
sym_calc_value(ds);
newval.val = ds->curr.val;
}
}
break;
default:
;
}
sym->curr = newval;
if (sym_is_choice(sym) && newval.tri == yes)
sym->curr.val = sym_calc_choice(sym);
sym_validate_range(sym);
if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
sym_set_changed(sym);
if (modules_sym == sym) {
sym_set_all_changed();
modules_val = modules_sym->curr.tri;
}
}
if (sym_is_choice(sym)) {
struct symbol *choice_sym;
prop = sym_get_choice_prop(sym);
expr_list_for_each_sym(prop->expr, e, choice_sym) {
if ((sym->flags & SYMBOL_WRITE) &&
choice_sym->visible != no)
choice_sym->flags |= SYMBOL_WRITE;
if (sym->flags & SYMBOL_CHANGED)
sym_set_changed(choice_sym);
}
}
if (sym->flags & SYMBOL_NO_WRITE)
sym->flags &= ~SYMBOL_WRITE;
kconfig: Fix defconfig when one choice menu selects options that another choice menu depends on The defconfig and Kconfig combination below, which is based on 3.10-rc4 Kconfigs, resulted in several options getting set to "m" instead of "y". defconfig.choice: ---8<--- CONFIG_MODULES=y CONFIG_USB_ZERO=y ---8<--- Kconfig.choice: ---8<--- menuconfig MODULES bool "Enable loadable module support" config CONFIGFS_FS tristate "Userspace-driven configuration filesystem" config OCFS2_FS tristate "OCFS2 file system support" depends on CONFIGFS_FS select CRC32 config USB_LIBCOMPOSITE tristate select CONFIGFS_FS choice tristate "USB Gadget Drivers" default USB_ETH config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE config USB_ETH tristate "Ethernet Gadget (with CDC Ethernet support)" select USB_LIBCOMPOSITE endchoice config CRC32 tristate "CRC32/CRC32c functions" default y choice prompt "CRC32 implementation" depends on CRC32 default CRC32_SLICEBY8 config CRC32_SLICEBY8 bool "Slice by 8 bytes" endchoice ---8<--- $ scripts/kconfig/conf --defconfig=defconfig.choice Kconfig.choice would result in: .config: ---8<--- CONFIG_MODULES=y CONFIG_CONFIGFS_FS=m CONFIG_USB_LIBCOMPOSITE=m CONFIG_USB_ZERO=m CONFIG_CRC32=y CONFIG_CRC32_SLICEBY8=y ---8<--- when the expected result would be: .config: ---8<--- CONFIG_MODULES=y CONFIG_CONFIGFS_FS=y CONFIG_USB_LIBCOMPOSITE=y CONFIG_USB_ZERO=y CONFIG_CRC32=y CONFIG_CRC32_SLICEBY8=y ---8<--- Signed-off-by: Arve Hjønnevåg <arve@android.com> [yann.morin.1998@free.fr: add the resulting .config to commit log, remove unneeded USB_GADGET from the defconfig] Tested-by: "Yann E. MORIN" <yann.morin.1998@free.fr> Reviewed-by: "Yann E. MORIN" <yann.morin.1998@free.fr> Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
2013-06-07 11:37:00 +08:00
if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
set_all_choice_values(sym);
}
void sym_clear_all_valid(void)
{
struct symbol *sym;
int i;
for_all_symbols(i, sym)
sym->flags &= ~SYMBOL_VALID;
conf_set_changed(true);
sym_calc_value(modules_sym);
}
bool sym_tristate_within_range(struct symbol *sym, tristate val)
{
int type = sym_get_type(sym);
if (sym->visible == no)
return false;
if (type != S_BOOLEAN && type != S_TRISTATE)
return false;
if (type == S_BOOLEAN && val == mod)
return false;
if (sym->visible <= sym->rev_dep.tri)
return false;
if (sym_is_choice_value(sym) && sym->visible == yes)
return val == yes;
return val >= sym->rev_dep.tri && val <= sym->visible;
}
bool sym_set_tristate_value(struct symbol *sym, tristate val)
{
tristate oldval = sym_get_tristate_value(sym);
if (oldval != val && !sym_tristate_within_range(sym, val))
return false;
if (!(sym->flags & SYMBOL_DEF_USER)) {
sym->flags |= SYMBOL_DEF_USER;
sym_set_changed(sym);
}
/*
* setting a choice value also resets the new flag of the choice
* symbol and all other choice values.
*/
if (sym_is_choice_value(sym) && val == yes) {
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
struct property *prop;
struct expr *e;
cs->def[S_DEF_USER].val = sym;
cs->flags |= SYMBOL_DEF_USER;
prop = sym_get_choice_prop(cs);
for (e = prop->expr; e; e = e->left.expr) {
if (e->right.sym->visible != no)
e->right.sym->flags |= SYMBOL_DEF_USER;
}
}
sym->def[S_DEF_USER].tri = val;
if (oldval != val)
sym_clear_all_valid();
return true;
}
tristate sym_toggle_tristate_value(struct symbol *sym)
{
tristate oldval, newval;
oldval = newval = sym_get_tristate_value(sym);
do {
switch (newval) {
case no:
newval = mod;
break;
case mod:
newval = yes;
break;
case yes:
newval = no;
break;
}
if (sym_set_tristate_value(sym, newval))
break;
} while (oldval != newval);
return newval;
}
bool sym_string_valid(struct symbol *sym, const char *str)
{
signed char ch;
switch (sym->type) {
case S_STRING:
return true;
case S_INT:
ch = *str++;
if (ch == '-')
ch = *str++;
if (!isdigit(ch))
return false;
if (ch == '0' && *str != 0)
return false;
while ((ch = *str++)) {
if (!isdigit(ch))
return false;
}
return true;
case S_HEX:
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
str += 2;
ch = *str++;
do {
if (!isxdigit(ch))
return false;
} while ((ch = *str++));
return true;
case S_BOOLEAN:
case S_TRISTATE:
switch (str[0]) {
case 'y': case 'Y':
case 'm': case 'M':
case 'n': case 'N':
return true;
}
return false;
default:
return false;
}
}
bool sym_string_within_range(struct symbol *sym, const char *str)
{
struct property *prop;
long long val;
switch (sym->type) {
case S_STRING:
return sym_string_valid(sym, str);
case S_INT:
if (!sym_string_valid(sym, str))
return false;
prop = sym_get_range_prop(sym);
if (!prop)
return true;
val = strtoll(str, NULL, 10);
return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
val <= sym_get_range_val(prop->expr->right.sym, 10);
case S_HEX:
if (!sym_string_valid(sym, str))
return false;
prop = sym_get_range_prop(sym);
if (!prop)
return true;
val = strtoll(str, NULL, 16);
return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
val <= sym_get_range_val(prop->expr->right.sym, 16);
case S_BOOLEAN:
case S_TRISTATE:
switch (str[0]) {
case 'y': case 'Y':
return sym_tristate_within_range(sym, yes);
case 'm': case 'M':
return sym_tristate_within_range(sym, mod);
case 'n': case 'N':
return sym_tristate_within_range(sym, no);
}
return false;
default:
return false;
}
}
bool sym_set_string_value(struct symbol *sym, const char *newval)
{
const char *oldval;
char *val;
int size;
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
switch (newval[0]) {
case 'y': case 'Y':
return sym_set_tristate_value(sym, yes);
case 'm': case 'M':
return sym_set_tristate_value(sym, mod);
case 'n': case 'N':
return sym_set_tristate_value(sym, no);
}
return false;
default:
;
}
if (!sym_string_within_range(sym, newval))
return false;
if (!(sym->flags & SYMBOL_DEF_USER)) {
sym->flags |= SYMBOL_DEF_USER;
sym_set_changed(sym);
}
oldval = sym->def[S_DEF_USER].val;
size = strlen(newval) + 1;
if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
size += 2;
sym->def[S_DEF_USER].val = val = xmalloc(size);
*val++ = '0';
*val++ = 'x';
} else if (!oldval || strcmp(oldval, newval))
sym->def[S_DEF_USER].val = val = xmalloc(size);
else
return true;
strcpy(val, newval);
free((void *)oldval);
sym_clear_all_valid();
return true;
}
/*
* Find the default value associated to a symbol.
* For tristate symbol handle the modules=n case
* in which case "m" becomes "y".
* If the symbol does not have any default then fallback
* to the fixed default values.
*/
const char *sym_get_string_default(struct symbol *sym)
{
struct property *prop;
struct symbol *ds;
const char *str;
tristate val;
sym_calc_visibility(sym);
sym_calc_value(modules_sym);
val = symbol_no.curr.tri;
str = symbol_empty.curr.val;
/* If symbol has a default value look it up */
prop = sym_get_default_prop(sym);
if (prop != NULL) {
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
/* The visibility may limit the value from yes => mod */
val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
break;
default:
/*
* The following fails to handle the situation
* where a default value is further limited by
* the valid range.
*/
ds = prop_get_symbol(prop);
if (ds != NULL) {
sym_calc_value(ds);
str = (const char *)ds->curr.val;
}
}
}
/* Handle select statements */
val = EXPR_OR(val, sym->rev_dep.tri);
/* transpose mod to yes if modules are not enabled */
if (val == mod)
if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
val = yes;
/* transpose mod to yes if type is bool */
if (sym->type == S_BOOLEAN && val == mod)
val = yes;
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
/* adjust the default value if this symbol is implied by another */
if (val < sym->implied.tri)
val = sym->implied.tri;
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
switch (val) {
case no: return "n";
case mod: return "m";
case yes: return "y";
}
case S_INT:
case S_HEX:
return str;
case S_STRING:
return str;
case S_UNKNOWN:
break;
}
return "";
}
const char *sym_get_string_value(struct symbol *sym)
{
tristate val;
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
val = sym_get_tristate_value(sym);
switch (val) {
case no:
return "n";
case mod:
sym_calc_value(modules_sym);
return (modules_sym->curr.tri == no) ? "n" : "m";
case yes:
return "y";
}
break;
default:
;
}
return (const char *)sym->curr.val;
}
bool sym_is_changeable(struct symbol *sym)
{
return sym->visible > sym->rev_dep.tri;
}
Improve kconfig symbol hashing While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-01-14 00:02:44 +08:00
static unsigned strhash(const char *s)
{
/* fnv32 hash */
unsigned hash = 2166136261U;
for (; *s; s++)
hash = (hash ^ *s) * 0x01000193;
return hash;
}
struct symbol *sym_lookup(const char *name, int flags)
{
struct symbol *symbol;
char *new_name;
Improve kconfig symbol hashing While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-01-14 00:02:44 +08:00
int hash;
if (name) {
if (name[0] && !name[1]) {
switch (name[0]) {
case 'y': return &symbol_yes;
case 'm': return &symbol_mod;
case 'n': return &symbol_no;
}
}
Improve kconfig symbol hashing While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-01-14 00:02:44 +08:00
hash = strhash(name) % SYMBOL_HASHSIZE;
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
Improve kconfig symbol hashing While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-01-14 00:02:44 +08:00
if (symbol->name &&
!strcmp(symbol->name, name) &&
(flags ? symbol->flags & flags
: !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
return symbol;
}
new_name = xstrdup(name);
} else {
new_name = NULL;
Improve kconfig symbol hashing While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-01-14 00:02:44 +08:00
hash = 0;
}
symbol = xmalloc(sizeof(*symbol));
memset(symbol, 0, sizeof(*symbol));
symbol->name = new_name;
symbol->type = S_UNKNOWN;
symbol->flags = flags;
symbol->next = symbol_hash[hash];
symbol_hash[hash] = symbol;
return symbol;
}
struct symbol *sym_find(const char *name)
{
struct symbol *symbol = NULL;
int hash = 0;
if (!name)
return NULL;
if (name[0] && !name[1]) {
switch (name[0]) {
case 'y': return &symbol_yes;
case 'm': return &symbol_mod;
case 'n': return &symbol_no;
}
}
Improve kconfig symbol hashing While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-01-14 00:02:44 +08:00
hash = strhash(name) % SYMBOL_HASHSIZE;
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
Improve kconfig symbol hashing While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz>
2010-01-14 00:02:44 +08:00
if (symbol->name &&
!strcmp(symbol->name, name) &&
!(symbol->flags & SYMBOL_CONST))
break;
}
return symbol;
}
struct sym_match {
struct symbol *sym;
off_t so, eo;
};
/* Compare matched symbols as thus:
* - first, symbols that match exactly
* - then, alphabetical sort
*/
static int sym_rel_comp(const void *sym1, const void *sym2)
{
const struct sym_match *s1 = sym1;
const struct sym_match *s2 = sym2;
int exact1, exact2;
/* Exact match:
* - if matched length on symbol s1 is the length of that symbol,
* then this symbol should come first;
* - if matched length on symbol s2 is the length of that symbol,
* then this symbol should come first.
* Note: since the search can be a regexp, both symbols may match
* exactly; if this is the case, we can't decide which comes first,
* and we fallback to sorting alphabetically.
*/
exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
exact2 = (s2->eo - s2->so) == strlen(s2->sym->name);
if (exact1 && !exact2)
return -1;
if (!exact1 && exact2)
return 1;
/* As a fallback, sort symbols alphabetically */
return strcmp(s1->sym->name, s2->sym->name);
}
struct symbol **sym_re_search(const char *pattern)
{
struct symbol *sym, **sym_arr = NULL;
struct sym_match *sym_match_arr = NULL;
int i, cnt, size;
regex_t re;
regmatch_t match[1];
cnt = size = 0;
/* Skip if empty */
if (strlen(pattern) == 0)
return NULL;
if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
return NULL;
for_all_symbols(i, sym) {
if (sym->flags & SYMBOL_CONST || !sym->name)
continue;
if (regexec(&re, sym->name, 1, match, 0))
continue;
if (cnt >= size) {
void *tmp;
size += 16;
tmp = realloc(sym_match_arr, size * sizeof(struct sym_match));
if (!tmp)
goto sym_re_search_free;
sym_match_arr = tmp;
}
sym_calc_value(sym);
/* As regexec returned 0, we know we have a match, so
* we can use match[0].rm_[se]o without further checks
*/
sym_match_arr[cnt].so = match[0].rm_so;
sym_match_arr[cnt].eo = match[0].rm_eo;
sym_match_arr[cnt++].sym = sym;
}
if (sym_match_arr) {
qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
sym_arr = malloc((cnt+1) * sizeof(struct symbol *));
if (!sym_arr)
goto sym_re_search_free;
for (i = 0; i < cnt; i++)
sym_arr[i] = sym_match_arr[i].sym;
sym_arr[cnt] = NULL;
}
sym_re_search_free:
/* sym_match_arr can be NULL if no match, but free(NULL) is OK */
free(sym_match_arr);
regfree(&re);
return sym_arr;
}
/*
* When we check for recursive dependencies we use a stack to save
* current state so we can print out relevant info to user.
* The entries are located on the call stack so no need to free memory.
* Note insert() remove() must always match to properly clear the stack.
*/
static struct dep_stack {
struct dep_stack *prev, *next;
struct symbol *sym;
struct property *prop;
struct expr **expr;
} *check_top;
static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
{
memset(stack, 0, sizeof(*stack));
if (check_top)
check_top->next = stack;
stack->prev = check_top;
stack->sym = sym;
check_top = stack;
}
static void dep_stack_remove(void)
{
check_top = check_top->prev;
if (check_top)
check_top->next = NULL;
}
/*
* Called when we have detected a recursive dependency.
* check_top point to the top of the stact so we use
* the ->prev pointer to locate the bottom of the stack.
*/
static void sym_check_print_recursive(struct symbol *last_sym)
{
struct dep_stack *stack;
struct symbol *sym, *next_sym;
struct menu *menu = NULL;
struct property *prop;
struct dep_stack cv_stack;
if (sym_is_choice_value(last_sym)) {
dep_stack_insert(&cv_stack, last_sym);
last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
}
for (stack = check_top; stack != NULL; stack = stack->prev)
if (stack->sym == last_sym)
break;
if (!stack) {
fprintf(stderr, "unexpected recursive dependency error\n");
return;
}
for (; stack; stack = stack->next) {
sym = stack->sym;
next_sym = stack->next ? stack->next->sym : last_sym;
prop = stack->prop;
if (prop == NULL)
prop = stack->sym->prop;
/* for choice values find the menu entry (used below) */
if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
for (prop = sym->prop; prop; prop = prop->next) {
menu = prop->menu;
if (prop->menu)
break;
}
}
if (stack->sym == last_sym)
fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
prop->file->name, prop->lineno);
if (sym_is_choice(sym)) {
fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
menu->file->name, menu->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (sym_is_choice_value(sym)) {
fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
menu->file->name, menu->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (stack->expr == &sym->dir_dep.expr) {
fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
prop->file->name, prop->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (stack->expr == &sym->rev_dep.expr) {
fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
prop->file->name, prop->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (stack->expr == &sym->implied.expr) {
fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n",
prop->file->name, prop->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (stack->expr) {
fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
prop->file->name, prop->lineno,
sym->name ? sym->name : "<choice>",
prop_get_type_name(prop->type),
next_sym->name ? next_sym->name : "<choice>");
} else {
fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n",
prop->file->name, prop->lineno,
sym->name ? sym->name : "<choice>",
prop_get_type_name(prop->type),
next_sym->name ? next_sym->name : "<choice>");
}
}
fprintf(stderr,
"For a resolution refer to Documentation/kbuild/kconfig-language.rst\n"
"subsection \"Kconfig recursive dependency limitations\"\n"
"\n");
if (check_top == &cv_stack)
dep_stack_remove();
}
static struct symbol *sym_check_expr_deps(struct expr *e)
{
struct symbol *sym;
if (!e)
return NULL;
switch (e->type) {
case E_OR:
case E_AND:
sym = sym_check_expr_deps(e->left.expr);
if (sym)
return sym;
return sym_check_expr_deps(e->right.expr);
case E_NOT:
return sym_check_expr_deps(e->left.expr);
case E_EQUAL:
case E_GEQ:
case E_GTH:
case E_LEQ:
case E_LTH:
case E_UNEQUAL:
sym = sym_check_deps(e->left.sym);
if (sym)
return sym;
return sym_check_deps(e->right.sym);
case E_SYMBOL:
return sym_check_deps(e->left.sym);
default:
break;
}
fprintf(stderr, "Oops! How to check %d?\n", e->type);
return NULL;
}
/* return NULL when dependencies are OK */
static struct symbol *sym_check_sym_deps(struct symbol *sym)
{
struct symbol *sym2;
struct property *prop;
struct dep_stack stack;
dep_stack_insert(&stack, sym);
stack.expr = &sym->dir_dep.expr;
sym2 = sym_check_expr_deps(sym->dir_dep.expr);
if (sym2)
goto out;
stack.expr = &sym->rev_dep.expr;
sym2 = sym_check_expr_deps(sym->rev_dep.expr);
if (sym2)
goto out;
stack.expr = &sym->implied.expr;
sym2 = sym_check_expr_deps(sym->implied.expr);
if (sym2)
goto out;
stack.expr = NULL;
for (prop = sym->prop; prop; prop = prop->next) {
if (prop->type == P_CHOICE || prop->type == P_SELECT ||
prop->type == P_IMPLY)
continue;
stack.prop = prop;
sym2 = sym_check_expr_deps(prop->visible.expr);
if (sym2)
break;
if (prop->type != P_DEFAULT || sym_is_choice(sym))
continue;
stack.expr = &prop->expr;
sym2 = sym_check_expr_deps(prop->expr);
if (sym2)
break;
stack.expr = NULL;
}
out:
dep_stack_remove();
return sym2;
}
static struct symbol *sym_check_choice_deps(struct symbol *choice)
{
struct symbol *sym, *sym2;
struct property *prop;
struct expr *e;
struct dep_stack stack;
dep_stack_insert(&stack, choice);
prop = sym_get_choice_prop(choice);
expr_list_for_each_sym(prop->expr, e, sym)
sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
sym2 = sym_check_sym_deps(choice);
choice->flags &= ~SYMBOL_CHECK;
if (sym2)
goto out;
expr_list_for_each_sym(prop->expr, e, sym) {
sym2 = sym_check_sym_deps(sym);
if (sym2)
break;
}
out:
expr_list_for_each_sym(prop->expr, e, sym)
sym->flags &= ~SYMBOL_CHECK;
if (sym2 && sym_is_choice_value(sym2) &&
prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
sym2 = choice;
dep_stack_remove();
return sym2;
}
struct symbol *sym_check_deps(struct symbol *sym)
{
struct symbol *sym2;
struct property *prop;
if (sym->flags & SYMBOL_CHECK) {
sym_check_print_recursive(sym);
return sym;
}
if (sym->flags & SYMBOL_CHECKED)
return NULL;
if (sym_is_choice_value(sym)) {
struct dep_stack stack;
/* for choice groups start the check with main choice symbol */
dep_stack_insert(&stack, sym);
prop = sym_get_choice_prop(sym);
sym2 = sym_check_deps(prop_get_symbol(prop));
dep_stack_remove();
} else if (sym_is_choice(sym)) {
sym2 = sym_check_choice_deps(sym);
} else {
sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
sym2 = sym_check_sym_deps(sym);
sym->flags &= ~SYMBOL_CHECK;
}
return sym2;
}
struct symbol *prop_get_symbol(struct property *prop)
{
if (prop->expr && (prop->expr->type == E_SYMBOL ||
prop->expr->type == E_LIST))
return prop->expr->left.sym;
return NULL;
}
const char *prop_get_type_name(enum prop_type type)
{
switch (type) {
case P_PROMPT:
return "prompt";
case P_COMMENT:
return "comment";
case P_MENU:
return "menu";
case P_DEFAULT:
return "default";
case P_CHOICE:
return "choice";
case P_SELECT:
return "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:
return "imply";
case P_RANGE:
return "range";
case P_SYMBOL:
return "symbol";
case P_UNKNOWN:
break;
}
return "unknown";
}