mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-26 16:41:25 +00:00
Kconfig updates for v4.17
- improve checkpatch for more precise Kconfig code checking - clarify effective selects by grouping reverse dependencies in help - do not write out '# CONFIG_FOO is not set' from invisible symbols - make oldconfig as silent as it should be - rename 'silentoldconfig' to 'syncconfig' - add unit-test framework and several test cases - warn unmet dependency of tristate symbols - make unmet dependency warnings readable, removing false positives - improve recursive include detection - use yylineno to simplify the line number tracking - misc cleanups -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJaw6i1AAoJED2LAQed4NsGU7oP/Rc5DJmtQXbqONvEfVskfNzL NaQekDa4QuWRCbrAdRZM+8dlAgX76kXHd0I1LnL6XeCZ2KZ7f93zxpqBKHZAteGU Y6b06tDXiW9qIdI0wzfKB3KdZo0Jc1LELv7SMRrZ7+wFXZKmhh5M0mVX17sKrQai L3wPMqiu15ve2Ya9s8F8+PGFBZfqzhOBEzYij8YtTZWFWVEfoLDDD5YDUxQNcJrS FXO+fZH5EUpoWj+JseiIPuOKASChsyeqtwqCND444IrjqDQ0TLAyJSZJhSm+6bX3 qP/yMH0K+kMMkvKp8CCnaTfwkOJ2BZo+91Ydw1mnqLdnZ8gZndnyexrBFubIv+fJ 0KxX9IyGA+RBnwArsnF1yIoryktG3xtaR5diO2p5ztd8xgptKG+PqQfJ40DHjpu4 iZNpoVPIPh669w/Dfx033t1RZVhov8Mau2dZ5RCtpvXAAS6oRe+UmaazqUGt7O2z V8ekSNL3g7FN3YYx0awXJWzX8e3BDMOcUjRvw/SI16XBk0BdHiBMrYfnRN+e3mpy FjhzZdXajJclNwMVbUOAPaQypvbBQJjBMy0ryz05ZyTPEsmJqM+WjkPSLDppnMYT 8L3C5KSqC7WKdf1bj55YdGWyfyU0P9bCO026IClnvZNZDI/bg+3gB9ocyRfZG0sL 0Q7GJF+BixbUUQeUcejm =sKto -----END PGP SIGNATURE----- Merge tag 'kconfig-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild Pull Kconfig updates from Masahiro Yamada: - improve checkpatch for more precise Kconfig code checking - clarify effective selects by grouping reverse dependencies in help - do not write out '# CONFIG_FOO is not set' from invisible symbols - make oldconfig as silent as it should be - rename 'silentoldconfig' to 'syncconfig' - add unit-test framework and several test cases - warn unmet dependency of tristate symbols - make unmet dependency warnings readable, removing false positives - improve recursive include detection - use yylineno to simplify the line number tracking - misc cleanups * tag 'kconfig-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild: (30 commits) kconfig: use yylineno option instead of manual lineno increments kconfig: detect recursive inclusion earlier kconfig: remove duplicated file name and lineno of recursive inclusion kconfig: do not include both curses.h and ncurses.h for nconfig kconfig: make unmet dependency warnings readable kconfig: warn unmet direct dependency of tristate symbols selected by y kconfig: tests: test if recursive inclusion is detected kconfig: tests: test if recursive dependencies are detected kconfig: tests: test randconfig for choice in choice kconfig: tests: test defconfig when two choices interact kconfig: tests: check visibility of tristate choice values in y choice kconfig: tests: check unneeded "is not set" with unmet dependency kconfig: tests: test if new symbols in choice are asked kconfig: tests: test automatic submenu creation kconfig: tests: add basic choice tests kconfig: tests: add framework for Kconfig unit testing kbuild: add PYTHON2 and PYTHON3 variables kconfig: remove redundant streamline_config.pl prerequisite kconfig: rename silentoldconfig to syncconfig kconfig: invoke oldconfig instead of silentoldconfig from local*config ...
This commit is contained in:
commit
147a89bc71
58 changed files with 1043 additions and 139 deletions
|
@ -119,7 +119,7 @@ Examples:
|
||||||
15% of tristates will be set to 'y', 15% to 'm', 70% to 'n'
|
15% of tristates will be set to 'y', 15% to 'm', 70% to 'n'
|
||||||
|
|
||||||
______________________________________________________________________
|
______________________________________________________________________
|
||||||
Environment variables for 'silentoldconfig'
|
Environment variables for 'syncconfig'
|
||||||
|
|
||||||
KCONFIG_NOSILENTUPDATE
|
KCONFIG_NOSILENTUPDATE
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
|
@ -32,7 +32,7 @@ Enabling the driver
|
||||||
The driver is enabled via the standard kernel configuration system,
|
The driver is enabled via the standard kernel configuration system,
|
||||||
using the make command:
|
using the make command:
|
||||||
|
|
||||||
Make oldconfig/silentoldconfig/menuconfig/etc.
|
make config/oldconfig/menuconfig/etc.
|
||||||
|
|
||||||
The driver is located in the menu structure at:
|
The driver is located in the menu structure at:
|
||||||
|
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -386,6 +386,8 @@ INSTALLKERNEL := installkernel
|
||||||
DEPMOD = /sbin/depmod
|
DEPMOD = /sbin/depmod
|
||||||
PERL = perl
|
PERL = perl
|
||||||
PYTHON = python
|
PYTHON = python
|
||||||
|
PYTHON2 = python2
|
||||||
|
PYTHON3 = python3
|
||||||
CHECK = sparse
|
CHECK = sparse
|
||||||
|
|
||||||
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
|
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
|
||||||
|
@ -432,7 +434,7 @@ GCC_PLUGINS_CFLAGS :=
|
||||||
|
|
||||||
export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
|
export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
|
||||||
export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES
|
export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES
|
||||||
export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
|
export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE
|
||||||
export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
|
export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
|
||||||
|
|
||||||
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
|
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
|
||||||
|
@ -591,7 +593,7 @@ $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
|
||||||
# include/generated/ and include/config/. Update them if .config is newer than
|
# include/generated/ and include/config/. Update them if .config is newer than
|
||||||
# include/config/auto.conf (which mirrors .config).
|
# include/config/auto.conf (which mirrors .config).
|
||||||
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
|
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
|
||||||
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
|
$(Q)$(MAKE) -f $(srctree)/Makefile syncconfig
|
||||||
else
|
else
|
||||||
# external modules needs include/generated/autoconf.h and include/config/auto.conf
|
# external modules needs include/generated/autoconf.h and include/config/auto.conf
|
||||||
# but do not care if they are up-to-date. Use auto.conf to trigger the test
|
# but do not care if they are up-to-date. Use auto.conf to trigger the test
|
||||||
|
|
|
@ -2797,7 +2797,10 @@ sub process {
|
||||||
# Only applies when adding the entry originally, after that we do not have
|
# Only applies when adding the entry originally, after that we do not have
|
||||||
# sufficient context to determine whether it is indeed long enough.
|
# sufficient context to determine whether it is indeed long enough.
|
||||||
if ($realfile =~ /Kconfig/ &&
|
if ($realfile =~ /Kconfig/ &&
|
||||||
$line =~ /^\+\s*config\s+/) {
|
# 'choice' is usually the last thing on the line (though
|
||||||
|
# Kconfig supports named choices), so use a word boundary
|
||||||
|
# (\b) rather than a whitespace character (\s)
|
||||||
|
$line =~ /^\+\s*(?:config|menuconfig|choice)\b/) {
|
||||||
my $length = 0;
|
my $length = 0;
|
||||||
my $cnt = $realcnt;
|
my $cnt = $realcnt;
|
||||||
my $ln = $linenr + 1;
|
my $ln = $linenr + 1;
|
||||||
|
@ -2812,9 +2815,13 @@ sub process {
|
||||||
next if ($f =~ /^-/);
|
next if ($f =~ /^-/);
|
||||||
last if (!$file && $f =~ /^\@\@/);
|
last if (!$file && $f =~ /^\@\@/);
|
||||||
|
|
||||||
if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) {
|
if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) {
|
||||||
$is_start = 1;
|
$is_start = 1;
|
||||||
} elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) {
|
} elsif ($lines[$ln - 1] =~ /^\+\s*(?:help|---help---)\s*$/) {
|
||||||
|
if ($lines[$ln - 1] =~ "---help---") {
|
||||||
|
WARN("CONFIG_DESCRIPTION",
|
||||||
|
"prefer 'help' over '---help---' for new help texts\n" . $herecurr);
|
||||||
|
}
|
||||||
$length = -1;
|
$length = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2822,7 +2829,13 @@ sub process {
|
||||||
$f =~ s/#.*//;
|
$f =~ s/#.*//;
|
||||||
$f =~ s/^\s+//;
|
$f =~ s/^\s+//;
|
||||||
next if ($f =~ /^$/);
|
next if ($f =~ /^$/);
|
||||||
if ($f =~ /^\s*config\s/) {
|
|
||||||
|
# This only checks context lines in the patch
|
||||||
|
# and so hopefully shouldn't trigger false
|
||||||
|
# positives, even though some of these are
|
||||||
|
# common words in help texts
|
||||||
|
if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice|
|
||||||
|
if|endif|menu|endmenu|source)\b/x) {
|
||||||
$is_end = 1;
|
$is_end = 1;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Kernel configuration targets
|
# Kernel configuration targets
|
||||||
# These targets are used from top-level makefile
|
# These targets are used from top-level makefile
|
||||||
|
|
||||||
PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \
|
PHONY += xconfig gconfig menuconfig config syncconfig update-po-config \
|
||||||
localmodconfig localyesconfig
|
localmodconfig localyesconfig
|
||||||
|
|
||||||
ifdef KBUILD_KCONFIG
|
ifdef KBUILD_KCONFIG
|
||||||
|
@ -36,22 +36,22 @@ nconfig: $(obj)/nconf
|
||||||
|
|
||||||
# This has become an internal implementation detail and is now deprecated
|
# This has become an internal implementation detail and is now deprecated
|
||||||
# for external use.
|
# for external use.
|
||||||
silentoldconfig: $(obj)/conf
|
syncconfig: $(obj)/conf
|
||||||
$(Q)mkdir -p include/config include/generated
|
$(Q)mkdir -p include/config include/generated
|
||||||
$< $(silent) --$@ $(Kconfig)
|
$< $(silent) --$@ $(Kconfig)
|
||||||
|
|
||||||
localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
|
localyesconfig localmodconfig: $(obj)/conf
|
||||||
$(Q)mkdir -p include/config include/generated
|
$(Q)mkdir -p include/config include/generated
|
||||||
$(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config
|
$(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config
|
||||||
$(Q)if [ -f .config ]; then \
|
$(Q)if [ -f .config ]; then \
|
||||||
cmp -s .tmp.config .config || \
|
cmp -s .tmp.config .config || \
|
||||||
(mv -f .config .config.old.1; \
|
(mv -f .config .config.old.1; \
|
||||||
mv -f .tmp.config .config; \
|
mv -f .tmp.config .config; \
|
||||||
$(obj)/conf $(silent) --silentoldconfig $(Kconfig); \
|
$< $(silent) --oldconfig $(Kconfig); \
|
||||||
mv -f .config.old.1 .config.old) \
|
mv -f .config.old.1 .config.old) \
|
||||||
else \
|
else \
|
||||||
mv -f .tmp.config .config; \
|
mv -f .tmp.config .config; \
|
||||||
$(obj)/conf $(silent) --silentoldconfig $(Kconfig); \
|
$< $(silent) --oldconfig $(Kconfig); \
|
||||||
fi
|
fi
|
||||||
$(Q)rm -f .tmp.config
|
$(Q)rm -f .tmp.config
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ PHONY += $(simple-targets)
|
||||||
$(simple-targets): $(obj)/conf
|
$(simple-targets): $(obj)/conf
|
||||||
$< $(silent) --$@ $(Kconfig)
|
$< $(silent) --$@ $(Kconfig)
|
||||||
|
|
||||||
PHONY += oldnoconfig savedefconfig defconfig
|
PHONY += oldnoconfig silentoldconfig savedefconfig defconfig
|
||||||
|
|
||||||
# oldnoconfig is an alias of olddefconfig, because people already are dependent
|
# oldnoconfig is an alias of olddefconfig, because people already are dependent
|
||||||
# on its behavior (sets new symbols to their default value but not 'n') with the
|
# on its behavior (sets new symbols to their default value but not 'n') with the
|
||||||
|
@ -95,6 +95,13 @@ oldnoconfig: olddefconfig
|
||||||
@echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19"
|
@echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19"
|
||||||
@echo " Please use \"olddefconfig\" instead, which is an alias."
|
@echo " Please use \"olddefconfig\" instead, which is an alias."
|
||||||
|
|
||||||
|
# We do not expect manual invokcation of "silentoldcofig" (or "syncconfig").
|
||||||
|
silentoldconfig: syncconfig
|
||||||
|
@echo " WARNING: \"silentoldconfig\" has been renamed to \"syncconfig\""
|
||||||
|
@echo " and is now an internal implementation detail."
|
||||||
|
@echo " What you want is probably \"oldconfig\"."
|
||||||
|
@echo " \"silentoldconfig\" will be removed after Linux 4.19"
|
||||||
|
|
||||||
savedefconfig: $(obj)/conf
|
savedefconfig: $(obj)/conf
|
||||||
$< $(silent) --$@=defconfig $(Kconfig)
|
$< $(silent) --$@=defconfig $(Kconfig)
|
||||||
|
|
||||||
|
@ -133,6 +140,14 @@ PHONY += tinyconfig
|
||||||
tinyconfig:
|
tinyconfig:
|
||||||
$(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
|
$(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
|
||||||
|
|
||||||
|
# CHECK: -o cache_dir=<path> working?
|
||||||
|
PHONY += testconfig
|
||||||
|
testconfig: $(obj)/conf
|
||||||
|
$(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
|
||||||
|
-o cache_dir=$(abspath $(obj)/tests/.cache) \
|
||||||
|
$(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no)
|
||||||
|
clean-dirs += tests/.cache
|
||||||
|
|
||||||
# Help text used by make help
|
# Help text used by make help
|
||||||
help:
|
help:
|
||||||
@echo ' config - Update current config utilising a line-oriented program'
|
@echo ' config - Update current config utilising a line-oriented program'
|
||||||
|
|
|
@ -23,7 +23,7 @@ static void check_conf(struct menu *menu);
|
||||||
|
|
||||||
enum input_mode {
|
enum input_mode {
|
||||||
oldaskconfig,
|
oldaskconfig,
|
||||||
silentoldconfig,
|
syncconfig,
|
||||||
oldconfig,
|
oldconfig,
|
||||||
allnoconfig,
|
allnoconfig,
|
||||||
allyesconfig,
|
allyesconfig,
|
||||||
|
@ -100,7 +100,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
|
||||||
|
|
||||||
switch (input_mode) {
|
switch (input_mode) {
|
||||||
case oldconfig:
|
case oldconfig:
|
||||||
case silentoldconfig:
|
case syncconfig:
|
||||||
if (sym_has_value(sym)) {
|
if (sym_has_value(sym)) {
|
||||||
printf("%s\n", def);
|
printf("%s\n", def);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -293,7 +293,7 @@ static int conf_choice(struct menu *menu)
|
||||||
printf("[1-%d?]: ", cnt);
|
printf("[1-%d?]: ", cnt);
|
||||||
switch (input_mode) {
|
switch (input_mode) {
|
||||||
case oldconfig:
|
case oldconfig:
|
||||||
case silentoldconfig:
|
case syncconfig:
|
||||||
if (!is_new) {
|
if (!is_new) {
|
||||||
cnt = def;
|
cnt = def;
|
||||||
printf("%d\n", cnt);
|
printf("%d\n", cnt);
|
||||||
|
@ -358,10 +358,11 @@ static void conf(struct menu *menu)
|
||||||
|
|
||||||
switch (prop->type) {
|
switch (prop->type) {
|
||||||
case P_MENU:
|
case P_MENU:
|
||||||
if ((input_mode == silentoldconfig ||
|
/*
|
||||||
input_mode == listnewconfig ||
|
* Except in oldaskconfig mode, we show only menus that
|
||||||
input_mode == olddefconfig) &&
|
* contain new symbols.
|
||||||
rootEntry != menu) {
|
*/
|
||||||
|
if (input_mode != oldaskconfig && rootEntry != menu) {
|
||||||
check_conf(menu);
|
check_conf(menu);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -424,7 +425,7 @@ static void check_conf(struct menu *menu)
|
||||||
if (sym->name && !sym_is_choice_value(sym)) {
|
if (sym->name && !sym_is_choice_value(sym)) {
|
||||||
printf("%s%s\n", CONFIG_, sym->name);
|
printf("%s%s\n", CONFIG_, sym->name);
|
||||||
}
|
}
|
||||||
} else if (input_mode != olddefconfig) {
|
} else {
|
||||||
if (!conf_cnt++)
|
if (!conf_cnt++)
|
||||||
printf(_("*\n* Restart config...\n*\n"));
|
printf(_("*\n* Restart config...\n*\n"));
|
||||||
rootEntry = menu_get_parent_menu(menu);
|
rootEntry = menu_get_parent_menu(menu);
|
||||||
|
@ -440,7 +441,7 @@ static void check_conf(struct menu *menu)
|
||||||
static struct option long_opts[] = {
|
static struct option long_opts[] = {
|
||||||
{"oldaskconfig", no_argument, NULL, oldaskconfig},
|
{"oldaskconfig", no_argument, NULL, oldaskconfig},
|
||||||
{"oldconfig", no_argument, NULL, oldconfig},
|
{"oldconfig", no_argument, NULL, oldconfig},
|
||||||
{"silentoldconfig", no_argument, NULL, silentoldconfig},
|
{"syncconfig", no_argument, NULL, syncconfig},
|
||||||
{"defconfig", optional_argument, NULL, defconfig},
|
{"defconfig", optional_argument, NULL, defconfig},
|
||||||
{"savedefconfig", required_argument, NULL, savedefconfig},
|
{"savedefconfig", required_argument, NULL, savedefconfig},
|
||||||
{"allnoconfig", no_argument, NULL, allnoconfig},
|
{"allnoconfig", no_argument, NULL, allnoconfig},
|
||||||
|
@ -467,8 +468,8 @@ static void conf_usage(const char *progname)
|
||||||
printf(" --listnewconfig List new options\n");
|
printf(" --listnewconfig List new options\n");
|
||||||
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
|
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
|
||||||
printf(" --oldconfig Update a configuration using a provided .config as base\n");
|
printf(" --oldconfig Update a configuration using a provided .config as base\n");
|
||||||
printf(" --silentoldconfig Similar to oldconfig but generates configuration in\n"
|
printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
|
||||||
" include/{generated/,config/} (oldconfig used to be more verbose)\n");
|
" include/{generated/,config/}\n");
|
||||||
printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
|
printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
|
||||||
printf(" --oldnoconfig An alias of olddefconfig\n");
|
printf(" --oldnoconfig An alias of olddefconfig\n");
|
||||||
printf(" --defconfig <file> New config with default defined in <file>\n");
|
printf(" --defconfig <file> New config with default defined in <file>\n");
|
||||||
|
@ -500,7 +501,7 @@ int main(int ac, char **av)
|
||||||
}
|
}
|
||||||
input_mode = (enum input_mode)opt;
|
input_mode = (enum input_mode)opt;
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case silentoldconfig:
|
case syncconfig:
|
||||||
sync_kconfig = 1;
|
sync_kconfig = 1;
|
||||||
break;
|
break;
|
||||||
case defconfig:
|
case defconfig:
|
||||||
|
@ -582,7 +583,7 @@ int main(int ac, char **av)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case savedefconfig:
|
case savedefconfig:
|
||||||
case silentoldconfig:
|
case syncconfig:
|
||||||
case oldaskconfig:
|
case oldaskconfig:
|
||||||
case oldconfig:
|
case oldconfig:
|
||||||
case listnewconfig:
|
case listnewconfig:
|
||||||
|
@ -662,24 +663,24 @@ int main(int ac, char **av)
|
||||||
case oldaskconfig:
|
case oldaskconfig:
|
||||||
rootEntry = &rootmenu;
|
rootEntry = &rootmenu;
|
||||||
conf(&rootmenu);
|
conf(&rootmenu);
|
||||||
input_mode = silentoldconfig;
|
input_mode = oldconfig;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case oldconfig:
|
case oldconfig:
|
||||||
case listnewconfig:
|
case listnewconfig:
|
||||||
case olddefconfig:
|
case syncconfig:
|
||||||
case silentoldconfig:
|
|
||||||
/* Update until a loop caused no more changes */
|
/* Update until a loop caused no more changes */
|
||||||
do {
|
do {
|
||||||
conf_cnt = 0;
|
conf_cnt = 0;
|
||||||
check_conf(&rootmenu);
|
check_conf(&rootmenu);
|
||||||
} while (conf_cnt &&
|
} while (conf_cnt);
|
||||||
(input_mode != listnewconfig &&
|
break;
|
||||||
input_mode != olddefconfig));
|
case olddefconfig:
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync_kconfig) {
|
if (sync_kconfig) {
|
||||||
/* silentoldconfig is used during the build so we shall update autoconf.
|
/* syncconfig is used during the build so we shall update autoconf.
|
||||||
* All other commands are only used to generate a config.
|
* All other commands are only used to generate a config.
|
||||||
*/
|
*/
|
||||||
if (conf_get_changed() && conf_write(NULL)) {
|
if (conf_get_changed() && conf_write(NULL)) {
|
||||||
|
|
|
@ -1137,49 +1137,9 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct expr *
|
void expr_print(struct expr *e,
|
||||||
expr_get_leftmost_symbol(const struct expr *e)
|
void (*fn)(void *, struct symbol *, const char *),
|
||||||
{
|
void *data, int prevtoken)
|
||||||
|
|
||||||
if (e == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
while (e->type != E_SYMBOL)
|
|
||||||
e = e->left.expr;
|
|
||||||
|
|
||||||
return expr_copy(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Given expression `e1' and `e2', returns the leaf of the longest
|
|
||||||
* sub-expression of `e1' not containing 'e2.
|
|
||||||
*/
|
|
||||||
struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
|
|
||||||
{
|
|
||||||
struct expr *ret;
|
|
||||||
|
|
||||||
switch (e1->type) {
|
|
||||||
case E_OR:
|
|
||||||
return expr_alloc_and(
|
|
||||||
expr_simplify_unmet_dep(e1->left.expr, e2),
|
|
||||||
expr_simplify_unmet_dep(e1->right.expr, e2));
|
|
||||||
case E_AND: {
|
|
||||||
struct expr *e;
|
|
||||||
e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
|
|
||||||
e = expr_eliminate_dups(e);
|
|
||||||
ret = (!expr_eq(e, e1)) ? e1 : NULL;
|
|
||||||
expr_free(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ret = e1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return expr_get_leftmost_symbol(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken, bool revdep)
|
|
||||||
{
|
{
|
||||||
if (!e) {
|
if (!e) {
|
||||||
fn(data, NULL, "y");
|
fn(data, NULL, "y");
|
||||||
|
@ -1234,14 +1194,9 @@ static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, con
|
||||||
fn(data, e->right.sym, e->right.sym->name);
|
fn(data, e->right.sym, e->right.sym->name);
|
||||||
break;
|
break;
|
||||||
case E_OR:
|
case E_OR:
|
||||||
if (revdep && e->left.expr->type != E_OR)
|
expr_print(e->left.expr, fn, data, E_OR);
|
||||||
fn(data, NULL, "\n - ");
|
|
||||||
__expr_print(e->left.expr, fn, data, E_OR, revdep);
|
|
||||||
if (revdep)
|
|
||||||
fn(data, NULL, "\n - ");
|
|
||||||
else
|
|
||||||
fn(data, NULL, " || ");
|
fn(data, NULL, " || ");
|
||||||
__expr_print(e->right.expr, fn, data, E_OR, revdep);
|
expr_print(e->right.expr, fn, data, E_OR);
|
||||||
break;
|
break;
|
||||||
case E_AND:
|
case E_AND:
|
||||||
expr_print(e->left.expr, fn, data, E_AND);
|
expr_print(e->left.expr, fn, data, E_AND);
|
||||||
|
@ -1274,11 +1229,6 @@ static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, con
|
||||||
fn(data, NULL, ")");
|
fn(data, NULL, ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
|
|
||||||
{
|
|
||||||
__expr_print(e, fn, data, prevtoken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
|
static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
|
||||||
{
|
{
|
||||||
xfwrite(str, strlen(str), 1, data);
|
xfwrite(str, strlen(str), 1, data);
|
||||||
|
@ -1329,7 +1279,27 @@ void expr_gstr_print(struct expr *e, struct gstr *gs)
|
||||||
* line with a minus. This makes expressions much easier to read.
|
* line with a minus. This makes expressions much easier to read.
|
||||||
* Suitable for reverse dependency expressions.
|
* Suitable for reverse dependency expressions.
|
||||||
*/
|
*/
|
||||||
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs)
|
static void expr_print_revdep(struct expr *e,
|
||||||
|
void (*fn)(void *, struct symbol *, const char *),
|
||||||
|
void *data, tristate pr_type, const char **title)
|
||||||
{
|
{
|
||||||
__expr_print(e, expr_print_gstr_helper, gs, E_NONE, true);
|
if (e->type == E_OR) {
|
||||||
|
expr_print_revdep(e->left.expr, fn, data, pr_type, title);
|
||||||
|
expr_print_revdep(e->right.expr, fn, data, pr_type, title);
|
||||||
|
} else if (expr_calc_value(e) == pr_type) {
|
||||||
|
if (*title) {
|
||||||
|
fn(data, NULL, *title);
|
||||||
|
*title = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn(data, NULL, " - ");
|
||||||
|
expr_print(e, fn, data, E_NONE);
|
||||||
|
fn(data, NULL, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
|
||||||
|
tristate pr_type, const char *title)
|
||||||
|
{
|
||||||
|
expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title);
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,12 +305,12 @@ struct expr *expr_transform(struct expr *e);
|
||||||
int expr_contains_symbol(struct expr *dep, struct symbol *sym);
|
int expr_contains_symbol(struct expr *dep, struct symbol *sym);
|
||||||
bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
|
bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
|
||||||
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
|
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
|
||||||
struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
|
|
||||||
|
|
||||||
void expr_fprint(struct expr *e, FILE *out);
|
void expr_fprint(struct expr *e, FILE *out);
|
||||||
struct gstr; /* forward */
|
struct gstr; /* forward */
|
||||||
void expr_gstr_print(struct expr *e, struct gstr *gs);
|
void expr_gstr_print(struct expr *e, struct gstr *gs);
|
||||||
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs);
|
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
|
||||||
|
tristate pr_type, const char *title);
|
||||||
|
|
||||||
static inline int expr_is_yes(struct expr *e)
|
static inline int expr_is_yes(struct expr *e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,6 +68,7 @@ struct kconf_id {
|
||||||
enum symbol_type stype;
|
enum symbol_type stype;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern int yylineno;
|
||||||
void zconfdump(FILE *out);
|
void zconfdump(FILE *out);
|
||||||
void zconf_starthelp(void);
|
void zconf_starthelp(void);
|
||||||
FILE *zconf_fopen(const char *name);
|
FILE *zconf_fopen(const char *name);
|
||||||
|
|
|
@ -828,16 +828,16 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
|
||||||
|
|
||||||
get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
|
get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
|
||||||
if (sym->rev_dep.expr) {
|
if (sym->rev_dep.expr) {
|
||||||
str_append(r, _(" Selected by: "));
|
expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n");
|
||||||
expr_gstr_print_revdep(sym->rev_dep.expr, r);
|
expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n");
|
||||||
str_append(r, "\n");
|
expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: "));
|
get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: "));
|
||||||
if (sym->implied.expr) {
|
if (sym->implied.expr) {
|
||||||
str_append(r, _(" Implied by: "));
|
expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n");
|
||||||
expr_gstr_print_revdep(sym->implied.expr, r);
|
expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n");
|
||||||
str_append(r, "\n");
|
expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
str_append(r, "\n\n");
|
str_append(r, "\n\n");
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <curses.h>
|
#include <ncurses.h>
|
||||||
#include <menu.h>
|
#include <menu.h>
|
||||||
#include <panel.h>
|
#include <panel.h>
|
||||||
#include <form.h>
|
#include <form.h>
|
||||||
|
@ -24,8 +24,6 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "ncurses.h"
|
|
||||||
|
|
||||||
#define max(a, b) ({\
|
#define max(a, b) ({\
|
||||||
typeof(a) _a = a;\
|
typeof(a) _a = a;\
|
||||||
typeof(b) _b = b;\
|
typeof(b) _b = b;\
|
||||||
|
|
|
@ -243,7 +243,7 @@ static void sym_calc_visibility(struct symbol *sym)
|
||||||
tri = yes;
|
tri = yes;
|
||||||
if (sym->dir_dep.expr)
|
if (sym->dir_dep.expr)
|
||||||
tri = expr_calc_value(sym->dir_dep.expr);
|
tri = expr_calc_value(sym->dir_dep.expr);
|
||||||
if (tri == mod)
|
if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
|
||||||
tri = yes;
|
tri = yes;
|
||||||
if (sym->dir_dep.tri != tri) {
|
if (sym->dir_dep.tri != tri) {
|
||||||
sym->dir_dep.tri = tri;
|
sym->dir_dep.tri = tri;
|
||||||
|
@ -333,6 +333,27 @@ static struct symbol *sym_calc_choice(struct symbol *sym)
|
||||||
return def_sym;
|
return def_sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sym_warn_unmet_dep(struct symbol *sym)
|
||||||
|
{
|
||||||
|
struct gstr gs = str_new();
|
||||||
|
|
||||||
|
str_printf(&gs,
|
||||||
|
"\nWARNING: unmet direct dependencies detected for %s\n",
|
||||||
|
sym->name);
|
||||||
|
str_printf(&gs,
|
||||||
|
" Depends on [%c]: ",
|
||||||
|
sym->dir_dep.tri == mod ? 'm' : 'n');
|
||||||
|
expr_gstr_print(sym->dir_dep.expr, &gs);
|
||||||
|
str_printf(&gs, "\n");
|
||||||
|
|
||||||
|
expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes,
|
||||||
|
" Selected by [y]:\n");
|
||||||
|
expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod,
|
||||||
|
" Selected by [m]:\n");
|
||||||
|
|
||||||
|
fputs(str_get(&gs), stderr);
|
||||||
|
}
|
||||||
|
|
||||||
void sym_calc_value(struct symbol *sym)
|
void sym_calc_value(struct symbol *sym)
|
||||||
{
|
{
|
||||||
struct symbol_value newval, oldval;
|
struct symbol_value newval, oldval;
|
||||||
|
@ -403,9 +424,10 @@ void sym_calc_value(struct symbol *sym)
|
||||||
if (!sym_is_choice(sym)) {
|
if (!sym_is_choice(sym)) {
|
||||||
prop = sym_get_default_prop(sym);
|
prop = sym_get_default_prop(sym);
|
||||||
if (prop) {
|
if (prop) {
|
||||||
sym->flags |= SYMBOL_WRITE;
|
|
||||||
newval.tri = EXPR_AND(expr_calc_value(prop->expr),
|
newval.tri = EXPR_AND(expr_calc_value(prop->expr),
|
||||||
prop->visible.tri);
|
prop->visible.tri);
|
||||||
|
if (newval.tri != no)
|
||||||
|
sym->flags |= SYMBOL_WRITE;
|
||||||
}
|
}
|
||||||
if (sym->implied.tri != no) {
|
if (sym->implied.tri != no) {
|
||||||
sym->flags |= SYMBOL_WRITE;
|
sym->flags |= SYMBOL_WRITE;
|
||||||
|
@ -413,18 +435,8 @@ void sym_calc_value(struct symbol *sym)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
calc_newval:
|
calc_newval:
|
||||||
if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
|
if (sym->dir_dep.tri < sym->rev_dep.tri)
|
||||||
struct expr *e;
|
sym_warn_unmet_dep(sym);
|
||||||
e = expr_simplify_unmet_dep(sym->rev_dep.expr,
|
|
||||||
sym->dir_dep.expr);
|
|
||||||
fprintf(stderr, "warning: (");
|
|
||||||
expr_fprint(e, stderr);
|
|
||||||
fprintf(stderr, ") selects %s which has unmet direct dependencies (",
|
|
||||||
sym->name);
|
|
||||||
expr_fprint(sym->dir_dep.expr, stderr);
|
|
||||||
fprintf(stderr, ")\n");
|
|
||||||
expr_free(e);
|
|
||||||
}
|
|
||||||
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
|
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
|
||||||
}
|
}
|
||||||
if (newval.tri == mod &&
|
if (newval.tri == mod &&
|
||||||
|
|
50
scripts/kconfig/tests/auto_submenu/Kconfig
Normal file
50
scripts/kconfig/tests/auto_submenu/Kconfig
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
config A
|
||||||
|
bool "A"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config A0
|
||||||
|
bool "A0"
|
||||||
|
depends on A
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This depends on A, so should be a submenu of A.
|
||||||
|
|
||||||
|
config A0_0
|
||||||
|
bool "A1_0"
|
||||||
|
depends on A0
|
||||||
|
help
|
||||||
|
Submenus are created recursively.
|
||||||
|
This should be a submenu of A0.
|
||||||
|
|
||||||
|
config A1
|
||||||
|
bool "A1"
|
||||||
|
depends on A
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This should line up with A0.
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "choice"
|
||||||
|
depends on A1
|
||||||
|
help
|
||||||
|
Choice should become a submenu as well.
|
||||||
|
|
||||||
|
config A1_0
|
||||||
|
bool "A1_0"
|
||||||
|
|
||||||
|
config A1_1
|
||||||
|
bool "A1_1"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config B
|
||||||
|
bool "B"
|
||||||
|
help
|
||||||
|
This is independent of A.
|
||||||
|
|
||||||
|
config C
|
||||||
|
bool "C"
|
||||||
|
depends on A
|
||||||
|
help
|
||||||
|
This depends on A, but not a consecutive item, so can/should not
|
||||||
|
be a submenu.
|
12
scripts/kconfig/tests/auto_submenu/__init__.py
Normal file
12
scripts/kconfig/tests/auto_submenu/__init__.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
"""
|
||||||
|
Create submenu for symbols that depend on the preceding one.
|
||||||
|
|
||||||
|
If a symbols has dependency on the preceding symbol, the menu entry
|
||||||
|
should become the submenu of the preceding one, and displayed with
|
||||||
|
deeper indentation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test(conf):
|
||||||
|
assert conf.oldaskconfig() == 0
|
||||||
|
assert conf.stdout_contains('expected_stdout')
|
10
scripts/kconfig/tests/auto_submenu/expected_stdout
Normal file
10
scripts/kconfig/tests/auto_submenu/expected_stdout
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
A (A) [Y/n/?] (NEW)
|
||||||
|
A0 (A0) [Y/n/?] (NEW)
|
||||||
|
A1_0 (A0_0) [N/y/?] (NEW)
|
||||||
|
A1 (A1) [Y/n/?] (NEW)
|
||||||
|
choice
|
||||||
|
> 1. A1_0 (A1_0) (NEW)
|
||||||
|
2. A1_1 (A1_1) (NEW)
|
||||||
|
choice[1-2?]:
|
||||||
|
B (B) [N/y/?] (NEW)
|
||||||
|
C (C) [N/y/?] (NEW)
|
54
scripts/kconfig/tests/choice/Kconfig
Normal file
54
scripts/kconfig/tests/choice/Kconfig
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
config MODULES
|
||||||
|
bool "Enable loadable module support"
|
||||||
|
option modules
|
||||||
|
default y
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "boolean choice"
|
||||||
|
default BOOL_CHOICE1
|
||||||
|
|
||||||
|
config BOOL_CHOICE0
|
||||||
|
bool "choice 0"
|
||||||
|
|
||||||
|
config BOOL_CHOICE1
|
||||||
|
bool "choice 1"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "optional boolean choice"
|
||||||
|
optional
|
||||||
|
default OPT_BOOL_CHOICE1
|
||||||
|
|
||||||
|
config OPT_BOOL_CHOICE0
|
||||||
|
bool "choice 0"
|
||||||
|
|
||||||
|
config OPT_BOOL_CHOICE1
|
||||||
|
bool "choice 1"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "tristate choice"
|
||||||
|
default TRI_CHOICE1
|
||||||
|
|
||||||
|
config TRI_CHOICE0
|
||||||
|
tristate "choice 0"
|
||||||
|
|
||||||
|
config TRI_CHOICE1
|
||||||
|
tristate "choice 1"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "optional tristate choice"
|
||||||
|
optional
|
||||||
|
default OPT_TRI_CHOICE1
|
||||||
|
|
||||||
|
config OPT_TRI_CHOICE0
|
||||||
|
tristate "choice 0"
|
||||||
|
|
||||||
|
config OPT_TRI_CHOICE1
|
||||||
|
tristate "choice 1"
|
||||||
|
|
||||||
|
endchoice
|
40
scripts/kconfig/tests/choice/__init__.py
Normal file
40
scripts/kconfig/tests/choice/__init__.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
"""
|
||||||
|
Basic choice tests.
|
||||||
|
|
||||||
|
The handling of 'choice' is a bit complicated part in Kconfig.
|
||||||
|
|
||||||
|
The behavior of 'y' choice is intuitive. If choice values are tristate,
|
||||||
|
the choice can be 'm' where each value can be enabled independently.
|
||||||
|
Also, if a choice is marked as 'optional', the whole choice can be
|
||||||
|
invisible.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_oldask0(conf):
|
||||||
|
assert conf.oldaskconfig() == 0
|
||||||
|
assert conf.stdout_contains('oldask0_expected_stdout')
|
||||||
|
|
||||||
|
|
||||||
|
def test_oldask1(conf):
|
||||||
|
assert conf.oldaskconfig('oldask1_config') == 0
|
||||||
|
assert conf.stdout_contains('oldask1_expected_stdout')
|
||||||
|
|
||||||
|
|
||||||
|
def test_allyes(conf):
|
||||||
|
assert conf.allyesconfig() == 0
|
||||||
|
assert conf.config_contains('allyes_expected_config')
|
||||||
|
|
||||||
|
|
||||||
|
def test_allmod(conf):
|
||||||
|
assert conf.allmodconfig() == 0
|
||||||
|
assert conf.config_contains('allmod_expected_config')
|
||||||
|
|
||||||
|
|
||||||
|
def test_allno(conf):
|
||||||
|
assert conf.allnoconfig() == 0
|
||||||
|
assert conf.config_contains('allno_expected_config')
|
||||||
|
|
||||||
|
|
||||||
|
def test_alldef(conf):
|
||||||
|
assert conf.alldefconfig() == 0
|
||||||
|
assert conf.config_contains('alldef_expected_config')
|
5
scripts/kconfig/tests/choice/alldef_expected_config
Normal file
5
scripts/kconfig/tests/choice/alldef_expected_config
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
CONFIG_MODULES=y
|
||||||
|
# CONFIG_BOOL_CHOICE0 is not set
|
||||||
|
CONFIG_BOOL_CHOICE1=y
|
||||||
|
# CONFIG_TRI_CHOICE0 is not set
|
||||||
|
# CONFIG_TRI_CHOICE1 is not set
|
9
scripts/kconfig/tests/choice/allmod_expected_config
Normal file
9
scripts/kconfig/tests/choice/allmod_expected_config
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
CONFIG_MODULES=y
|
||||||
|
# CONFIG_BOOL_CHOICE0 is not set
|
||||||
|
CONFIG_BOOL_CHOICE1=y
|
||||||
|
# CONFIG_OPT_BOOL_CHOICE0 is not set
|
||||||
|
CONFIG_OPT_BOOL_CHOICE1=y
|
||||||
|
CONFIG_TRI_CHOICE0=m
|
||||||
|
CONFIG_TRI_CHOICE1=m
|
||||||
|
CONFIG_OPT_TRI_CHOICE0=m
|
||||||
|
CONFIG_OPT_TRI_CHOICE1=m
|
5
scripts/kconfig/tests/choice/allno_expected_config
Normal file
5
scripts/kconfig/tests/choice/allno_expected_config
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# CONFIG_MODULES is not set
|
||||||
|
# CONFIG_BOOL_CHOICE0 is not set
|
||||||
|
CONFIG_BOOL_CHOICE1=y
|
||||||
|
# CONFIG_TRI_CHOICE0 is not set
|
||||||
|
CONFIG_TRI_CHOICE1=y
|
9
scripts/kconfig/tests/choice/allyes_expected_config
Normal file
9
scripts/kconfig/tests/choice/allyes_expected_config
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
CONFIG_MODULES=y
|
||||||
|
# CONFIG_BOOL_CHOICE0 is not set
|
||||||
|
CONFIG_BOOL_CHOICE1=y
|
||||||
|
# CONFIG_OPT_BOOL_CHOICE0 is not set
|
||||||
|
CONFIG_OPT_BOOL_CHOICE1=y
|
||||||
|
# CONFIG_TRI_CHOICE0 is not set
|
||||||
|
CONFIG_TRI_CHOICE1=y
|
||||||
|
# CONFIG_OPT_TRI_CHOICE0 is not set
|
||||||
|
CONFIG_OPT_TRI_CHOICE1=y
|
10
scripts/kconfig/tests/choice/oldask0_expected_stdout
Normal file
10
scripts/kconfig/tests/choice/oldask0_expected_stdout
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Enable loadable module support (MODULES) [Y/n/?] (NEW)
|
||||||
|
boolean choice
|
||||||
|
1. choice 0 (BOOL_CHOICE0) (NEW)
|
||||||
|
> 2. choice 1 (BOOL_CHOICE1) (NEW)
|
||||||
|
choice[1-2?]:
|
||||||
|
optional boolean choice [N/y/?] (NEW)
|
||||||
|
tristate choice [M/y/?] (NEW)
|
||||||
|
choice 0 (TRI_CHOICE0) [N/m/?] (NEW)
|
||||||
|
choice 1 (TRI_CHOICE1) [N/m/?] (NEW)
|
||||||
|
optional tristate choice [N/m/y/?] (NEW)
|
2
scripts/kconfig/tests/choice/oldask1_config
Normal file
2
scripts/kconfig/tests/choice/oldask1_config
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# CONFIG_MODULES is not set
|
||||||
|
CONFIG_OPT_BOOL_CHOICE0=y
|
15
scripts/kconfig/tests/choice/oldask1_expected_stdout
Normal file
15
scripts/kconfig/tests/choice/oldask1_expected_stdout
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Enable loadable module support (MODULES) [N/y/?]
|
||||||
|
boolean choice
|
||||||
|
1. choice 0 (BOOL_CHOICE0) (NEW)
|
||||||
|
> 2. choice 1 (BOOL_CHOICE1) (NEW)
|
||||||
|
choice[1-2?]:
|
||||||
|
optional boolean choice [Y/n/?] (NEW)
|
||||||
|
optional boolean choice
|
||||||
|
> 1. choice 0 (OPT_BOOL_CHOICE0)
|
||||||
|
2. choice 1 (OPT_BOOL_CHOICE1) (NEW)
|
||||||
|
choice[1-2?]:
|
||||||
|
tristate choice
|
||||||
|
1. choice 0 (TRI_CHOICE0) (NEW)
|
||||||
|
> 2. choice 1 (TRI_CHOICE1) (NEW)
|
||||||
|
choice[1-2?]:
|
||||||
|
optional tristate choice [N/y/?]
|
19
scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
Normal file
19
scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
config MODULES
|
||||||
|
def_bool y
|
||||||
|
option modules
|
||||||
|
|
||||||
|
config DEP
|
||||||
|
tristate
|
||||||
|
default m
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Tristate Choice"
|
||||||
|
|
||||||
|
config CHOICE0
|
||||||
|
tristate "Choice 0"
|
||||||
|
|
||||||
|
config CHOICE1
|
||||||
|
tristate "Choice 1"
|
||||||
|
depends on DEP
|
||||||
|
|
||||||
|
endchoice
|
15
scripts/kconfig/tests/choice_value_with_m_dep/__init__.py
Normal file
15
scripts/kconfig/tests/choice_value_with_m_dep/__init__.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
"""
|
||||||
|
Hide tristate choice values with mod dependency in y choice.
|
||||||
|
|
||||||
|
If tristate choice values depend on symbols set to 'm', they should be
|
||||||
|
hidden when the choice containing them is changed from 'm' to 'y'
|
||||||
|
(i.e. exclusive choice).
|
||||||
|
|
||||||
|
Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test(conf):
|
||||||
|
assert conf.oldaskconfig('config', 'y') == 0
|
||||||
|
assert conf.config_contains('expected_config')
|
||||||
|
assert conf.stdout_contains('expected_stdout')
|
2
scripts/kconfig/tests/choice_value_with_m_dep/config
Normal file
2
scripts/kconfig/tests/choice_value_with_m_dep/config
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
CONFIG_CHOICE0=m
|
||||||
|
CONFIG_CHOICE1=m
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_MODULES=y
|
||||||
|
CONFIG_DEP=m
|
||||||
|
CONFIG_CHOICE0=y
|
|
@ -0,0 +1,4 @@
|
||||||
|
Tristate Choice [M/y/?] y
|
||||||
|
Tristate Choice
|
||||||
|
> 1. Choice 0 (CHOICE0)
|
||||||
|
choice[1]: 1
|
291
scripts/kconfig/tests/conftest.py
Normal file
291
scripts/kconfig/tests/conftest.py
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Kconfig unit testing framework.
|
||||||
|
|
||||||
|
This provides fixture functions commonly used from test files.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
CONF_PATH = os.path.abspath(os.path.join('scripts', 'kconfig', 'conf'))
|
||||||
|
|
||||||
|
|
||||||
|
class Conf:
|
||||||
|
"""Kconfig runner and result checker.
|
||||||
|
|
||||||
|
This class provides methods to run text-based interface of Kconfig
|
||||||
|
(scripts/kconfig/conf) and retrieve the resulted configuration,
|
||||||
|
stdout, and stderr. It also provides methods to compare those
|
||||||
|
results with expectations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, request):
|
||||||
|
"""Create a new Conf instance.
|
||||||
|
|
||||||
|
request: object to introspect the requesting test module
|
||||||
|
"""
|
||||||
|
# the directory of the test being run
|
||||||
|
self._test_dir = os.path.dirname(str(request.fspath))
|
||||||
|
|
||||||
|
# runners
|
||||||
|
def _run_conf(self, mode, dot_config=None, out_file='.config',
|
||||||
|
interactive=False, in_keys=None, extra_env={}):
|
||||||
|
"""Run text-based Kconfig executable and save the result.
|
||||||
|
|
||||||
|
mode: input mode option (--oldaskconfig, --defconfig=<file> etc.)
|
||||||
|
dot_config: .config file to use for configuration base
|
||||||
|
out_file: file name to contain the output config data
|
||||||
|
interactive: flag to specify the interactive mode
|
||||||
|
in_keys: key inputs for interactive modes
|
||||||
|
extra_env: additional environments
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
command = [CONF_PATH, mode, 'Kconfig']
|
||||||
|
|
||||||
|
# Override 'srctree' environment to make the test as the top directory
|
||||||
|
extra_env['srctree'] = self._test_dir
|
||||||
|
|
||||||
|
# Run Kconfig in a temporary directory.
|
||||||
|
# This directory is automatically removed when done.
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
|
||||||
|
# if .config is given, copy it to the working directory
|
||||||
|
if dot_config:
|
||||||
|
shutil.copyfile(os.path.join(self._test_dir, dot_config),
|
||||||
|
os.path.join(temp_dir, '.config'))
|
||||||
|
|
||||||
|
ps = subprocess.Popen(command,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
cwd=temp_dir,
|
||||||
|
env=dict(os.environ, **extra_env))
|
||||||
|
|
||||||
|
# If input key sequence is given, feed it to stdin.
|
||||||
|
if in_keys:
|
||||||
|
ps.stdin.write(in_keys.encode('utf-8'))
|
||||||
|
|
||||||
|
while ps.poll() is None:
|
||||||
|
# For interactive modes such as oldaskconfig, oldconfig,
|
||||||
|
# send 'Enter' key until the program finishes.
|
||||||
|
if interactive:
|
||||||
|
ps.stdin.write(b'\n')
|
||||||
|
|
||||||
|
self.retcode = ps.returncode
|
||||||
|
self.stdout = ps.stdout.read().decode()
|
||||||
|
self.stderr = ps.stderr.read().decode()
|
||||||
|
|
||||||
|
# Retrieve the resulted config data only when .config is supposed
|
||||||
|
# to exist. If the command fails, the .config does not exist.
|
||||||
|
# 'listnewconfig' does not produce .config in the first place.
|
||||||
|
if self.retcode == 0 and out_file:
|
||||||
|
with open(os.path.join(temp_dir, out_file)) as f:
|
||||||
|
self.config = f.read()
|
||||||
|
else:
|
||||||
|
self.config = None
|
||||||
|
|
||||||
|
# Logging:
|
||||||
|
# Pytest captures the following information by default. In failure
|
||||||
|
# of tests, the captured log will be displayed. This will be useful to
|
||||||
|
# figure out what has happened.
|
||||||
|
|
||||||
|
print("[command]\n{}\n".format(' '.join(command)))
|
||||||
|
|
||||||
|
print("[retcode]\n{}\n".format(self.retcode))
|
||||||
|
|
||||||
|
print("[stdout]")
|
||||||
|
print(self.stdout)
|
||||||
|
|
||||||
|
print("[stderr]")
|
||||||
|
print(self.stderr)
|
||||||
|
|
||||||
|
if self.config is not None:
|
||||||
|
print("[output for '{}']".format(out_file))
|
||||||
|
print(self.config)
|
||||||
|
|
||||||
|
return self.retcode
|
||||||
|
|
||||||
|
def oldaskconfig(self, dot_config=None, in_keys=None):
|
||||||
|
"""Run oldaskconfig.
|
||||||
|
|
||||||
|
dot_config: .config file to use for configuration base (optional)
|
||||||
|
in_key: key inputs (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._run_conf('--oldaskconfig', dot_config=dot_config,
|
||||||
|
interactive=True, in_keys=in_keys)
|
||||||
|
|
||||||
|
def oldconfig(self, dot_config=None, in_keys=None):
|
||||||
|
"""Run oldconfig.
|
||||||
|
|
||||||
|
dot_config: .config file to use for configuration base (optional)
|
||||||
|
in_key: key inputs (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._run_conf('--oldconfig', dot_config=dot_config,
|
||||||
|
interactive=True, in_keys=in_keys)
|
||||||
|
|
||||||
|
def olddefconfig(self, dot_config=None):
|
||||||
|
"""Run olddefconfig.
|
||||||
|
|
||||||
|
dot_config: .config file to use for configuration base (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._run_conf('--olddefconfig', dot_config=dot_config)
|
||||||
|
|
||||||
|
def defconfig(self, defconfig):
|
||||||
|
"""Run defconfig.
|
||||||
|
|
||||||
|
defconfig: defconfig file for input
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
defconfig_path = os.path.join(self._test_dir, defconfig)
|
||||||
|
return self._run_conf('--defconfig={}'.format(defconfig_path))
|
||||||
|
|
||||||
|
def _allconfig(self, mode, all_config):
|
||||||
|
if all_config:
|
||||||
|
all_config_path = os.path.join(self._test_dir, all_config)
|
||||||
|
extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
|
||||||
|
else:
|
||||||
|
extra_env = {}
|
||||||
|
|
||||||
|
return self._run_conf('--{}config'.format(mode), extra_env=extra_env)
|
||||||
|
|
||||||
|
def allyesconfig(self, all_config=None):
|
||||||
|
"""Run allyesconfig.
|
||||||
|
|
||||||
|
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._allconfig('allyes', all_config)
|
||||||
|
|
||||||
|
def allmodconfig(self, all_config=None):
|
||||||
|
"""Run allmodconfig.
|
||||||
|
|
||||||
|
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._allconfig('allmod', all_config)
|
||||||
|
|
||||||
|
def allnoconfig(self, all_config=None):
|
||||||
|
"""Run allnoconfig.
|
||||||
|
|
||||||
|
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._allconfig('allno', all_config)
|
||||||
|
|
||||||
|
def alldefconfig(self, all_config=None):
|
||||||
|
"""Run alldefconfig.
|
||||||
|
|
||||||
|
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._allconfig('alldef', all_config)
|
||||||
|
|
||||||
|
def randconfig(self, all_config=None):
|
||||||
|
"""Run randconfig.
|
||||||
|
|
||||||
|
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._allconfig('rand', all_config)
|
||||||
|
|
||||||
|
def savedefconfig(self, dot_config):
|
||||||
|
"""Run savedefconfig.
|
||||||
|
|
||||||
|
dot_config: .config file for input
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._run_conf('--savedefconfig', out_file='defconfig')
|
||||||
|
|
||||||
|
def listnewconfig(self, dot_config=None):
|
||||||
|
"""Run listnewconfig.
|
||||||
|
|
||||||
|
dot_config: .config file to use for configuration base (optional)
|
||||||
|
returncode: exit status of the Kconfig executable
|
||||||
|
"""
|
||||||
|
return self._run_conf('--listnewconfig', dot_config=dot_config,
|
||||||
|
out_file=None)
|
||||||
|
|
||||||
|
# checkers
|
||||||
|
def _read_and_compare(self, compare, expected):
|
||||||
|
"""Compare the result with expectation.
|
||||||
|
|
||||||
|
compare: function to compare the result with expectation
|
||||||
|
expected: file that contains the expected data
|
||||||
|
"""
|
||||||
|
with open(os.path.join(self._test_dir, expected)) as f:
|
||||||
|
expected_data = f.read()
|
||||||
|
return compare(self, expected_data)
|
||||||
|
|
||||||
|
def _contains(self, attr, expected):
|
||||||
|
return self._read_and_compare(
|
||||||
|
lambda s, e: getattr(s, attr).find(e) >= 0,
|
||||||
|
expected)
|
||||||
|
|
||||||
|
def _matches(self, attr, expected):
|
||||||
|
return self._read_and_compare(lambda s, e: getattr(s, attr) == e,
|
||||||
|
expected)
|
||||||
|
|
||||||
|
def config_contains(self, expected):
|
||||||
|
"""Check if resulted configuration contains expected data.
|
||||||
|
|
||||||
|
expected: file that contains the expected data
|
||||||
|
returncode: True if result contains the expected data, False otherwise
|
||||||
|
"""
|
||||||
|
return self._contains('config', expected)
|
||||||
|
|
||||||
|
def config_matches(self, expected):
|
||||||
|
"""Check if resulted configuration exactly matches expected data.
|
||||||
|
|
||||||
|
expected: file that contains the expected data
|
||||||
|
returncode: True if result matches the expected data, False otherwise
|
||||||
|
"""
|
||||||
|
return self._matches('config', expected)
|
||||||
|
|
||||||
|
def stdout_contains(self, expected):
|
||||||
|
"""Check if resulted stdout contains expected data.
|
||||||
|
|
||||||
|
expected: file that contains the expected data
|
||||||
|
returncode: True if result contains the expected data, False otherwise
|
||||||
|
"""
|
||||||
|
return self._contains('stdout', expected)
|
||||||
|
|
||||||
|
def stdout_matches(self, expected):
|
||||||
|
"""Check if resulted stdout exactly matches expected data.
|
||||||
|
|
||||||
|
expected: file that contains the expected data
|
||||||
|
returncode: True if result matches the expected data, False otherwise
|
||||||
|
"""
|
||||||
|
return self._matches('stdout', expected)
|
||||||
|
|
||||||
|
def stderr_contains(self, expected):
|
||||||
|
"""Check if resulted stderr contains expected data.
|
||||||
|
|
||||||
|
expected: file that contains the expected data
|
||||||
|
returncode: True if result contains the expected data, False otherwise
|
||||||
|
"""
|
||||||
|
return self._contains('stderr', expected)
|
||||||
|
|
||||||
|
def stderr_matches(self, expected):
|
||||||
|
"""Check if resulted stderr exactly matches expected data.
|
||||||
|
|
||||||
|
expected: file that contains the expected data
|
||||||
|
returncode: True if result matches the expected data, False otherwise
|
||||||
|
"""
|
||||||
|
return self._matches('stderr', expected)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def conf(request):
|
||||||
|
"""Create a Conf instance and provide it to test functions."""
|
||||||
|
return Conf(request)
|
1
scripts/kconfig/tests/err_recursive_inc/Kconfig
Normal file
1
scripts/kconfig/tests/err_recursive_inc/Kconfig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
source "Kconfig.inc1"
|
4
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1
Normal file
4
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
source "Kconfig.inc2"
|
3
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2
Normal file
3
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
|
source "Kconfig.inc3"
|
1
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3
Normal file
1
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3
Normal file
|
@ -0,0 +1 @@
|
||||||
|
source "Kconfig.inc1"
|
10
scripts/kconfig/tests/err_recursive_inc/__init__.py
Normal file
10
scripts/kconfig/tests/err_recursive_inc/__init__.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
"""
|
||||||
|
Detect recursive inclusion error.
|
||||||
|
|
||||||
|
If recursive inclusion is detected, it should fail with error messages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test(conf):
|
||||||
|
assert conf.oldaskconfig() != 0
|
||||||
|
assert conf.stderr_contains('expected_stderr')
|
6
scripts/kconfig/tests/err_recursive_inc/expected_stderr
Normal file
6
scripts/kconfig/tests/err_recursive_inc/expected_stderr
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Recursive inclusion detected.
|
||||||
|
Inclusion path:
|
||||||
|
current file : Kconfig.inc1
|
||||||
|
included from: Kconfig.inc3:1
|
||||||
|
included from: Kconfig.inc2:3
|
||||||
|
included from: Kconfig.inc1:4
|
23
scripts/kconfig/tests/inter_choice/Kconfig
Normal file
23
scripts/kconfig/tests/inter_choice/Kconfig
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
config MODULES
|
||||||
|
def_bool y
|
||||||
|
option modules
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Choice"
|
||||||
|
|
||||||
|
config CHOICE_VAL0
|
||||||
|
tristate "Choice 0"
|
||||||
|
|
||||||
|
config CHOIVE_VAL1
|
||||||
|
tristate "Choice 1"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Another choice"
|
||||||
|
depends on CHOICE_VAL0
|
||||||
|
|
||||||
|
config DUMMY
|
||||||
|
bool "dummy"
|
||||||
|
|
||||||
|
endchoice
|
14
scripts/kconfig/tests/inter_choice/__init__.py
Normal file
14
scripts/kconfig/tests/inter_choice/__init__.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""
|
||||||
|
Do not affect user-assigned choice value by another choice.
|
||||||
|
|
||||||
|
Handling of state flags for choices is complecated. In old days,
|
||||||
|
the defconfig result of a choice could be affected by another choice
|
||||||
|
if those choices interact by 'depends on', 'select', etc.
|
||||||
|
|
||||||
|
Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test(conf):
|
||||||
|
assert conf.defconfig('defconfig') == 0
|
||||||
|
assert conf.config_contains('expected_config')
|
1
scripts/kconfig/tests/inter_choice/defconfig
Normal file
1
scripts/kconfig/tests/inter_choice/defconfig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CONFIG_CHOICE_VAL0=y
|
4
scripts/kconfig/tests/inter_choice/expected_config
Normal file
4
scripts/kconfig/tests/inter_choice/expected_config
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
CONFIG_MODULES=y
|
||||||
|
CONFIG_CHOICE_VAL0=y
|
||||||
|
# CONFIG_CHOIVE_VAL1 is not set
|
||||||
|
CONFIG_DUMMY=y
|
37
scripts/kconfig/tests/new_choice_with_dep/Kconfig
Normal file
37
scripts/kconfig/tests/new_choice_with_dep/Kconfig
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
config A
|
||||||
|
bool "A"
|
||||||
|
help
|
||||||
|
This is a new symbol.
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Choice ?"
|
||||||
|
depends on A
|
||||||
|
help
|
||||||
|
"depends on A" has been newly added.
|
||||||
|
|
||||||
|
config CHOICE_B
|
||||||
|
bool "Choice B"
|
||||||
|
|
||||||
|
config CHOICE_C
|
||||||
|
bool "Choice C"
|
||||||
|
help
|
||||||
|
This is a new symbol, so should be asked.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Choice2 ?"
|
||||||
|
|
||||||
|
config CHOICE_D
|
||||||
|
bool "Choice D"
|
||||||
|
|
||||||
|
config CHOICE_E
|
||||||
|
bool "Choice E"
|
||||||
|
|
||||||
|
config CHOICE_F
|
||||||
|
bool "Choice F"
|
||||||
|
depends on A
|
||||||
|
help
|
||||||
|
This is a new symbol, so should be asked.
|
||||||
|
|
||||||
|
endchoice
|
14
scripts/kconfig/tests/new_choice_with_dep/__init__.py
Normal file
14
scripts/kconfig/tests/new_choice_with_dep/__init__.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""
|
||||||
|
Ask new choice values when they become visible.
|
||||||
|
|
||||||
|
If new choice values are added with new dependency, and they become
|
||||||
|
visible during user configuration, oldconfig should recognize them
|
||||||
|
as (NEW), and ask the user for choice.
|
||||||
|
|
||||||
|
Related Linux commit: 5d09598d488f081e3be23f885ed65cbbe2d073b5
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test(conf):
|
||||||
|
assert conf.oldconfig('config', 'y') == 0
|
||||||
|
assert conf.stdout_contains('expected_stdout')
|
3
scripts/kconfig/tests/new_choice_with_dep/config
Normal file
3
scripts/kconfig/tests/new_choice_with_dep/config
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_CHOICE_B=y
|
||||||
|
# CONFIG_CHOICE_D is not set
|
||||||
|
CONFIG_CHOICE_E=y
|
10
scripts/kconfig/tests/new_choice_with_dep/expected_stdout
Normal file
10
scripts/kconfig/tests/new_choice_with_dep/expected_stdout
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
A (A) [N/y/?] (NEW) y
|
||||||
|
Choice ?
|
||||||
|
> 1. Choice B (CHOICE_B)
|
||||||
|
2. Choice C (CHOICE_C) (NEW)
|
||||||
|
choice[1-2?]:
|
||||||
|
Choice2 ?
|
||||||
|
1. Choice D (CHOICE_D)
|
||||||
|
> 2. Choice E (CHOICE_E)
|
||||||
|
3. Choice F (CHOICE_F) (NEW)
|
||||||
|
choice[1-3?]:
|
14
scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig
Normal file
14
scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
config A
|
||||||
|
bool "A"
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Choice ?"
|
||||||
|
depends on A
|
||||||
|
|
||||||
|
config CHOICE_B
|
||||||
|
bool "Choice B"
|
||||||
|
|
||||||
|
config CHOICE_C
|
||||||
|
bool "Choice C"
|
||||||
|
|
||||||
|
endchoice
|
19
scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
Normal file
19
scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
"""
|
||||||
|
Do not write choice values to .config if the dependency is unmet.
|
||||||
|
|
||||||
|
"# CONFIG_... is not set" should not be written into the .config file
|
||||||
|
for symbols with unmet dependency.
|
||||||
|
|
||||||
|
This was not working correctly for choice values because choice needs
|
||||||
|
a bit different symbol computation.
|
||||||
|
|
||||||
|
This checks that no unneeded "# COFIG_... is not set" is contained in
|
||||||
|
the .config file.
|
||||||
|
|
||||||
|
Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test(conf):
|
||||||
|
assert conf.oldaskconfig('config', 'n') == 0
|
||||||
|
assert conf.config_matches('expected_config')
|
1
scripts/kconfig/tests/no_write_if_dep_unmet/config
Normal file
1
scripts/kconfig/tests/no_write_if_dep_unmet/config
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CONFIG_A=y
|
|
@ -0,0 +1,5 @@
|
||||||
|
#
|
||||||
|
# Automatically generated file; DO NOT EDIT.
|
||||||
|
# Linux Kernel Configuration
|
||||||
|
#
|
||||||
|
# CONFIG_A is not set
|
7
scripts/kconfig/tests/pytest.ini
Normal file
7
scripts/kconfig/tests/pytest.ini
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[pytest]
|
||||||
|
addopts = --verbose
|
||||||
|
|
||||||
|
# Pytest requires that test files have unique names, because pytest imports
|
||||||
|
# them as top-level modules. It is silly to prefix or suffix a test file with
|
||||||
|
# the directory name that contains it. Use __init__.py for all test files.
|
||||||
|
python_files = __init__.py
|
33
scripts/kconfig/tests/rand_nested_choice/Kconfig
Normal file
33
scripts/kconfig/tests/rand_nested_choice/Kconfig
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
choice
|
||||||
|
prompt "choice"
|
||||||
|
|
||||||
|
config A
|
||||||
|
bool "A"
|
||||||
|
|
||||||
|
config B
|
||||||
|
bool "B"
|
||||||
|
|
||||||
|
if B
|
||||||
|
choice
|
||||||
|
prompt "sub choice"
|
||||||
|
|
||||||
|
config C
|
||||||
|
bool "C"
|
||||||
|
|
||||||
|
config D
|
||||||
|
bool "D"
|
||||||
|
|
||||||
|
if D
|
||||||
|
choice
|
||||||
|
prompt "subsub choice"
|
||||||
|
|
||||||
|
config E
|
||||||
|
bool "E"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
endif # D
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
endif # B
|
||||||
|
|
||||||
|
endchoice
|
16
scripts/kconfig/tests/rand_nested_choice/__init__.py
Normal file
16
scripts/kconfig/tests/rand_nested_choice/__init__.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
"""
|
||||||
|
Set random values recursively in nested choices.
|
||||||
|
|
||||||
|
Kconfig can create a choice-in-choice structure by using 'if' statement.
|
||||||
|
randconfig should correctly set random choice values.
|
||||||
|
|
||||||
|
Related Linux commit: 3b9a19e08960e5cdad5253998637653e592a3c29
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test(conf):
|
||||||
|
for i in range(20):
|
||||||
|
assert conf.randconfig() == 0
|
||||||
|
assert (conf.config_contains('expected_stdout0') or
|
||||||
|
conf.config_contains('expected_stdout1') or
|
||||||
|
conf.config_contains('expected_stdout2'))
|
|
@ -0,0 +1,2 @@
|
||||||
|
CONFIG_A=y
|
||||||
|
# CONFIG_B is not set
|
|
@ -0,0 +1,4 @@
|
||||||
|
# CONFIG_A is not set
|
||||||
|
CONFIG_B=y
|
||||||
|
CONFIG_C=y
|
||||||
|
# CONFIG_D is not set
|
|
@ -0,0 +1,5 @@
|
||||||
|
# CONFIG_A is not set
|
||||||
|
CONFIG_B=y
|
||||||
|
# CONFIG_C is not set
|
||||||
|
CONFIG_D=y
|
||||||
|
CONFIG_E=y
|
62
scripts/kconfig/tests/warn_recursive_dep/Kconfig
Normal file
62
scripts/kconfig/tests/warn_recursive_dep/Kconfig
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
# depends on itself
|
||||||
|
|
||||||
|
config A
|
||||||
|
bool "A"
|
||||||
|
depends on A
|
||||||
|
|
||||||
|
# select itself
|
||||||
|
|
||||||
|
config B
|
||||||
|
bool
|
||||||
|
select B
|
||||||
|
|
||||||
|
# depends on each other
|
||||||
|
|
||||||
|
config C1
|
||||||
|
bool "C1"
|
||||||
|
depends on C2
|
||||||
|
|
||||||
|
config C2
|
||||||
|
bool "C2"
|
||||||
|
depends on C1
|
||||||
|
|
||||||
|
# depends on and select
|
||||||
|
|
||||||
|
config D1
|
||||||
|
bool "D1"
|
||||||
|
depends on D2
|
||||||
|
select D2
|
||||||
|
|
||||||
|
config D2
|
||||||
|
bool
|
||||||
|
|
||||||
|
# depends on and imply
|
||||||
|
# This is not recursive dependency
|
||||||
|
|
||||||
|
config E1
|
||||||
|
bool "E1"
|
||||||
|
depends on E2
|
||||||
|
imply E2
|
||||||
|
|
||||||
|
config E2
|
||||||
|
bool "E2"
|
||||||
|
|
||||||
|
# property
|
||||||
|
|
||||||
|
config F1
|
||||||
|
bool "F1"
|
||||||
|
default F2
|
||||||
|
|
||||||
|
config F2
|
||||||
|
bool "F2"
|
||||||
|
depends on F1
|
||||||
|
|
||||||
|
# menu
|
||||||
|
|
||||||
|
menu "menu depending on its content"
|
||||||
|
depends on G
|
||||||
|
|
||||||
|
config G
|
||||||
|
bool "G"
|
||||||
|
|
||||||
|
endmenu
|
9
scripts/kconfig/tests/warn_recursive_dep/__init__.py
Normal file
9
scripts/kconfig/tests/warn_recursive_dep/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
"""
|
||||||
|
Warn recursive inclusion.
|
||||||
|
|
||||||
|
Recursive dependency should be warned.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test(conf):
|
||||||
|
assert conf.oldaskconfig() == 0
|
||||||
|
assert conf.stderr_contains('expected_stderr')
|
30
scripts/kconfig/tests/warn_recursive_dep/expected_stderr
Normal file
30
scripts/kconfig/tests/warn_recursive_dep/expected_stderr
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Kconfig:9:error: recursive dependency detected!
|
||||||
|
Kconfig:9: symbol B is selected by B
|
||||||
|
For a resolution refer to Documentation/kbuild/kconfig-language.txt
|
||||||
|
subsection "Kconfig recursive dependency limitations"
|
||||||
|
|
||||||
|
Kconfig:3:error: recursive dependency detected!
|
||||||
|
Kconfig:3: symbol A depends on A
|
||||||
|
For a resolution refer to Documentation/kbuild/kconfig-language.txt
|
||||||
|
subsection "Kconfig recursive dependency limitations"
|
||||||
|
|
||||||
|
Kconfig:15:error: recursive dependency detected!
|
||||||
|
Kconfig:15: symbol C1 depends on C2
|
||||||
|
Kconfig:19: symbol C2 depends on C1
|
||||||
|
For a resolution refer to Documentation/kbuild/kconfig-language.txt
|
||||||
|
subsection "Kconfig recursive dependency limitations"
|
||||||
|
|
||||||
|
Kconfig:30:error: recursive dependency detected!
|
||||||
|
Kconfig:30: symbol D2 is selected by D1
|
||||||
|
Kconfig:25: symbol D1 depends on D2
|
||||||
|
For a resolution refer to Documentation/kbuild/kconfig-language.txt
|
||||||
|
subsection "Kconfig recursive dependency limitations"
|
||||||
|
|
||||||
|
Kconfig:59:error: recursive dependency detected!
|
||||||
|
Kconfig:59: symbol G depends on G
|
||||||
|
For a resolution refer to Documentation/kbuild/kconfig-language.txt
|
||||||
|
subsection "Kconfig recursive dependency limitations"
|
||||||
|
|
||||||
|
Kconfig:50:error: recursive dependency detected!
|
||||||
|
Kconfig:50: symbol F2 depends on F1
|
||||||
|
Kconfig:48: symbol F1 default value contains F2
|
|
@ -1,5 +1,5 @@
|
||||||
%option nostdinit noyywrap never-interactive full ecs
|
%option nostdinit noyywrap never-interactive full ecs
|
||||||
%option 8bit nodefault perf-report perf-report
|
%option 8bit nodefault yylineno
|
||||||
%option noinput
|
%option noinput
|
||||||
%x COMMAND HELP STRING PARAM
|
%x COMMAND HELP STRING PARAM
|
||||||
%{
|
%{
|
||||||
|
@ -83,7 +83,6 @@ n [A-Za-z0-9_-]
|
||||||
|
|
||||||
[ \t]*#.*\n |
|
[ \t]*#.*\n |
|
||||||
[ \t]*\n {
|
[ \t]*\n {
|
||||||
current_file->lineno++;
|
|
||||||
return T_EOL;
|
return T_EOL;
|
||||||
}
|
}
|
||||||
[ \t]*#.*
|
[ \t]*#.*
|
||||||
|
@ -104,7 +103,7 @@ n [A-Za-z0-9_-]
|
||||||
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
|
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
|
||||||
BEGIN(PARAM);
|
BEGIN(PARAM);
|
||||||
current_pos.file = current_file;
|
current_pos.file = current_file;
|
||||||
current_pos.lineno = current_file->lineno;
|
current_pos.lineno = yylineno;
|
||||||
if (id && id->flags & TF_COMMAND) {
|
if (id && id->flags & TF_COMMAND) {
|
||||||
yylval.id = id;
|
yylval.id = id;
|
||||||
return id->token;
|
return id->token;
|
||||||
|
@ -116,7 +115,6 @@ n [A-Za-z0-9_-]
|
||||||
. warn_ignored_character(*yytext);
|
. warn_ignored_character(*yytext);
|
||||||
\n {
|
\n {
|
||||||
BEGIN(INITIAL);
|
BEGIN(INITIAL);
|
||||||
current_file->lineno++;
|
|
||||||
return T_EOL;
|
return T_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +136,7 @@ n [A-Za-z0-9_-]
|
||||||
new_string();
|
new_string();
|
||||||
BEGIN(STRING);
|
BEGIN(STRING);
|
||||||
}
|
}
|
||||||
\n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
|
\n BEGIN(INITIAL); return T_EOL;
|
||||||
({n}|[/.])+ {
|
({n}|[/.])+ {
|
||||||
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
|
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
|
||||||
if (id && id->flags & TF_PARAM) {
|
if (id && id->flags & TF_PARAM) {
|
||||||
|
@ -150,7 +148,7 @@ n [A-Za-z0-9_-]
|
||||||
return T_WORD;
|
return T_WORD;
|
||||||
}
|
}
|
||||||
#.* /* comment */
|
#.* /* comment */
|
||||||
\\\n current_file->lineno++;
|
\\\n ;
|
||||||
[[:blank:]]+
|
[[:blank:]]+
|
||||||
. warn_ignored_character(*yytext);
|
. warn_ignored_character(*yytext);
|
||||||
<<EOF>> {
|
<<EOF>> {
|
||||||
|
@ -187,7 +185,6 @@ n [A-Za-z0-9_-]
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s:%d:warning: multi-line strings not supported\n",
|
"%s:%d:warning: multi-line strings not supported\n",
|
||||||
zconf_curname(), zconf_lineno());
|
zconf_curname(), zconf_lineno());
|
||||||
current_file->lineno++;
|
|
||||||
BEGIN(INITIAL);
|
BEGIN(INITIAL);
|
||||||
return T_EOL;
|
return T_EOL;
|
||||||
}
|
}
|
||||||
|
@ -220,12 +217,10 @@ n [A-Za-z0-9_-]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[ \t]*\n/[^ \t\n] {
|
[ \t]*\n/[^ \t\n] {
|
||||||
current_file->lineno++;
|
|
||||||
zconf_endhelp();
|
zconf_endhelp();
|
||||||
return T_HELPTEXT;
|
return T_HELPTEXT;
|
||||||
}
|
}
|
||||||
[ \t]*\n {
|
[ \t]*\n {
|
||||||
current_file->lineno++;
|
|
||||||
append_string("\n", 1);
|
append_string("\n", 1);
|
||||||
}
|
}
|
||||||
[^ \t\n].* {
|
[^ \t\n].* {
|
||||||
|
@ -304,7 +299,7 @@ void zconf_initscan(const char *name)
|
||||||
memset(current_buf, 0, sizeof(*current_buf));
|
memset(current_buf, 0, sizeof(*current_buf));
|
||||||
|
|
||||||
current_file = file_lookup(name);
|
current_file = file_lookup(name);
|
||||||
current_file->lineno = 1;
|
yylineno = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zconf_nextfile(const char *name)
|
void zconf_nextfile(const char *name)
|
||||||
|
@ -325,24 +320,26 @@ void zconf_nextfile(const char *name)
|
||||||
buf->parent = current_buf;
|
buf->parent = current_buf;
|
||||||
current_buf = buf;
|
current_buf = buf;
|
||||||
|
|
||||||
for (iter = current_file->parent; iter; iter = iter->parent ) {
|
current_file->lineno = yylineno;
|
||||||
if (!strcmp(current_file->name,iter->name) ) {
|
file->parent = current_file;
|
||||||
|
|
||||||
|
for (iter = current_file; iter; iter = iter->parent) {
|
||||||
|
if (!strcmp(iter->name, file->name)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s:%d: recursive inclusion detected. "
|
"Recursive inclusion detected.\n"
|
||||||
"Inclusion path:\n current file : '%s'\n",
|
"Inclusion path:\n"
|
||||||
zconf_curname(), zconf_lineno(),
|
" current file : %s\n", file->name);
|
||||||
zconf_curname());
|
iter = file;
|
||||||
iter = current_file;
|
|
||||||
do {
|
do {
|
||||||
iter = iter->parent;
|
iter = iter->parent;
|
||||||
fprintf(stderr, " included from: '%s:%d'\n",
|
fprintf(stderr, " included from: %s:%d\n",
|
||||||
iter->name, iter->lineno - 1);
|
iter->name, iter->lineno - 1);
|
||||||
} while (strcmp(iter->name, current_file->name));
|
} while (strcmp(iter->name, file->name));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file->lineno = 1;
|
|
||||||
file->parent = current_file;
|
yylineno = 1;
|
||||||
current_file = file;
|
current_file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,6 +348,8 @@ static void zconf_endfile(void)
|
||||||
struct buffer *parent;
|
struct buffer *parent;
|
||||||
|
|
||||||
current_file = current_file->parent;
|
current_file = current_file->parent;
|
||||||
|
if (current_file)
|
||||||
|
yylineno = current_file->lineno;
|
||||||
|
|
||||||
parent = current_buf->parent;
|
parent = current_buf->parent;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue