aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 19:28:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 19:28:01 -0400
commit147a89bc71e7db40f011454a40add7ff2d10f8d8 (patch)
tree72f2f1355c6121c40124206c7d4ac82632f1690d
parent3b24b83763e72a6c1e728100104fd99aa83a7b3b (diff)
parent18492685e479fd4d8e1dca836f57c11b6800f083 (diff)
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 ...
-rw-r--r--Documentation/kbuild/kconfig.txt2
-rw-r--r--Documentation/networking/i40e.txt2
-rw-r--r--Makefile6
-rwxr-xr-xscripts/checkpatch.pl21
-rw-r--r--scripts/kconfig/Makefile29
-rw-r--r--scripts/kconfig/conf.c41
-rw-r--r--scripts/kconfig/expr.c86
-rw-r--r--scripts/kconfig/expr.h4
-rw-r--r--scripts/kconfig/lkc.h1
-rw-r--r--scripts/kconfig/menu.c12
-rw-r--r--scripts/kconfig/nconf.h4
-rw-r--r--scripts/kconfig/symbol.c40
-rw-r--r--scripts/kconfig/tests/auto_submenu/Kconfig50
-rw-r--r--scripts/kconfig/tests/auto_submenu/__init__.py12
-rw-r--r--scripts/kconfig/tests/auto_submenu/expected_stdout10
-rw-r--r--scripts/kconfig/tests/choice/Kconfig54
-rw-r--r--scripts/kconfig/tests/choice/__init__.py40
-rw-r--r--scripts/kconfig/tests/choice/alldef_expected_config5
-rw-r--r--scripts/kconfig/tests/choice/allmod_expected_config9
-rw-r--r--scripts/kconfig/tests/choice/allno_expected_config5
-rw-r--r--scripts/kconfig/tests/choice/allyes_expected_config9
-rw-r--r--scripts/kconfig/tests/choice/oldask0_expected_stdout10
-rw-r--r--scripts/kconfig/tests/choice/oldask1_config2
-rw-r--r--scripts/kconfig/tests/choice/oldask1_expected_stdout15
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/Kconfig19
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/__init__.py15
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/config2
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/expected_config3
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout4
-rw-r--r--scripts/kconfig/tests/conftest.py291
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/Kconfig1
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/Kconfig.inc14
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/Kconfig.inc23
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/Kconfig.inc31
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/__init__.py10
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/expected_stderr6
-rw-r--r--scripts/kconfig/tests/inter_choice/Kconfig23
-rw-r--r--scripts/kconfig/tests/inter_choice/__init__.py14
-rw-r--r--scripts/kconfig/tests/inter_choice/defconfig1
-rw-r--r--scripts/kconfig/tests/inter_choice/expected_config4
-rw-r--r--scripts/kconfig/tests/new_choice_with_dep/Kconfig37
-rw-r--r--scripts/kconfig/tests/new_choice_with_dep/__init__.py14
-rw-r--r--scripts/kconfig/tests/new_choice_with_dep/config3
-rw-r--r--scripts/kconfig/tests/new_choice_with_dep/expected_stdout10
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig14
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py19
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/config1
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/expected_config5
-rw-r--r--scripts/kconfig/tests/pytest.ini7
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/Kconfig33
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/__init__.py16
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/expected_stdout02
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/expected_stdout14
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/expected_stdout25
-rw-r--r--scripts/kconfig/tests/warn_recursive_dep/Kconfig62
-rw-r--r--scripts/kconfig/tests/warn_recursive_dep/__init__.py9
-rw-r--r--scripts/kconfig/tests/warn_recursive_dep/expected_stderr30
-rw-r--r--scripts/kconfig/zconf.l41
58 files changed, 1043 insertions, 139 deletions
diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt
index bbc99c0c1094..7233118f3a05 100644
--- a/Documentation/kbuild/kconfig.txt
+++ b/Documentation/kbuild/kconfig.txt
@@ -119,7 +119,7 @@ Examples:
119 15% of tristates will be set to 'y', 15% to 'm', 70% to 'n' 119 15% of tristates will be set to 'y', 15% to 'm', 70% to 'n'
120 120
121______________________________________________________________________ 121______________________________________________________________________
122Environment variables for 'silentoldconfig' 122Environment variables for 'syncconfig'
123 123
124KCONFIG_NOSILENTUPDATE 124KCONFIG_NOSILENTUPDATE
125-------------------------------------------------- 125--------------------------------------------------
diff --git a/Documentation/networking/i40e.txt b/Documentation/networking/i40e.txt
index 57e616ed10b0..c2d6e1824b29 100644
--- a/Documentation/networking/i40e.txt
+++ b/Documentation/networking/i40e.txt
@@ -32,7 +32,7 @@ Enabling the driver
32The driver is enabled via the standard kernel configuration system, 32The driver is enabled via the standard kernel configuration system,
33using the make command: 33using the make command:
34 34
35 Make oldconfig/silentoldconfig/menuconfig/etc. 35 make config/oldconfig/menuconfig/etc.
36 36
37The driver is located in the menu structure at: 37The driver is located in the menu structure at:
38 38
diff --git a/Makefile b/Makefile
index 65b61599b513..c1a608a1bc4c 100644
--- a/Makefile
+++ b/Makefile
@@ -386,6 +386,8 @@ INSTALLKERNEL := installkernel
386DEPMOD = /sbin/depmod 386DEPMOD = /sbin/depmod
387PERL = perl 387PERL = perl
388PYTHON = python 388PYTHON = python
389PYTHON2 = python2
390PYTHON3 = python3
389CHECK = sparse 391CHECK = sparse
390 392
391CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ 393CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
@@ -432,7 +434,7 @@ GCC_PLUGINS_CFLAGS :=
432 434
433export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC 435export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
434export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES 436export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES
435export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE 437export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE
436export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS 438export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
437 439
438export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS 440export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
@@ -591,7 +593,7 @@ $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
591# include/generated/ and include/config/. Update them if .config is newer than 593# include/generated/ and include/config/. Update them if .config is newer than
592# include/config/auto.conf (which mirrors .config). 594# include/config/auto.conf (which mirrors .config).
593include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd 595include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
594 $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig 596 $(Q)$(MAKE) -f $(srctree)/Makefile syncconfig
595else 597else
596# external modules needs include/generated/autoconf.h and include/config/auto.conf 598# external modules needs include/generated/autoconf.h and include/config/auto.conf
597# but do not care if they are up-to-date. Use auto.conf to trigger the test 599# but do not care if they are up-to-date. Use auto.conf to trigger the test
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 949842e8c97e..764ffd1bb1c5 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2797,7 +2797,10 @@ sub process {
2797# Only applies when adding the entry originally, after that we do not have 2797# Only applies when adding the entry originally, after that we do not have
2798# sufficient context to determine whether it is indeed long enough. 2798# sufficient context to determine whether it is indeed long enough.
2799 if ($realfile =~ /Kconfig/ && 2799 if ($realfile =~ /Kconfig/ &&
2800 $line =~ /^\+\s*config\s+/) { 2800 # 'choice' is usually the last thing on the line (though
2801 # Kconfig supports named choices), so use a word boundary
2802 # (\b) rather than a whitespace character (\s)
2803 $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) {
2801 my $length = 0; 2804 my $length = 0;
2802 my $cnt = $realcnt; 2805 my $cnt = $realcnt;
2803 my $ln = $linenr + 1; 2806 my $ln = $linenr + 1;
@@ -2812,9 +2815,13 @@ sub process {
2812 next if ($f =~ /^-/); 2815 next if ($f =~ /^-/);
2813 last if (!$file && $f =~ /^\@\@/); 2816 last if (!$file && $f =~ /^\@\@/);
2814 2817
2815 if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) { 2818 if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) {
2816 $is_start = 1; 2819 $is_start = 1;
2817 } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) { 2820 } elsif ($lines[$ln - 1] =~ /^\+\s*(?:help|---help---)\s*$/) {
2821 if ($lines[$ln - 1] =~ "---help---") {
2822 WARN("CONFIG_DESCRIPTION",
2823 "prefer 'help' over '---help---' for new help texts\n" . $herecurr);
2824 }
2818 $length = -1; 2825 $length = -1;
2819 } 2826 }
2820 2827
@@ -2822,7 +2829,13 @@ sub process {
2822 $f =~ s/#.*//; 2829 $f =~ s/#.*//;
2823 $f =~ s/^\s+//; 2830 $f =~ s/^\s+//;
2824 next if ($f =~ /^$/); 2831 next if ($f =~ /^$/);
2825 if ($f =~ /^\s*config\s/) { 2832
2833 # This only checks context lines in the patch
2834 # and so hopefully shouldn't trigger false
2835 # positives, even though some of these are
2836 # common words in help texts
2837 if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice|
2838 if|endif|menu|endmenu|source)\b/x) {
2826 $is_end = 1; 2839 $is_end = 1;
2827 last; 2840 last;
2828 } 2841 }
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index eb139a17383c..f9bdd02c06a2 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -3,7 +3,7 @@
3# Kernel configuration targets 3# Kernel configuration targets
4# These targets are used from top-level makefile 4# These targets are used from top-level makefile
5 5
6PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \ 6PHONY += xconfig gconfig menuconfig config syncconfig update-po-config \
7 localmodconfig localyesconfig 7 localmodconfig localyesconfig
8 8
9ifdef KBUILD_KCONFIG 9ifdef KBUILD_KCONFIG
@@ -36,22 +36,22 @@ nconfig: $(obj)/nconf
36 36
37# This has become an internal implementation detail and is now deprecated 37# This has become an internal implementation detail and is now deprecated
38# for external use. 38# for external use.
39silentoldconfig: $(obj)/conf 39syncconfig: $(obj)/conf
40 $(Q)mkdir -p include/config include/generated 40 $(Q)mkdir -p include/config include/generated
41 $< $(silent) --$@ $(Kconfig) 41 $< $(silent) --$@ $(Kconfig)
42 42
43localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf 43localyesconfig localmodconfig: $(obj)/conf
44 $(Q)mkdir -p include/config include/generated 44 $(Q)mkdir -p include/config include/generated
45 $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config 45 $(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config
46 $(Q)if [ -f .config ]; then \ 46 $(Q)if [ -f .config ]; then \
47 cmp -s .tmp.config .config || \ 47 cmp -s .tmp.config .config || \
48 (mv -f .config .config.old.1; \ 48 (mv -f .config .config.old.1; \
49 mv -f .tmp.config .config; \ 49 mv -f .tmp.config .config; \
50 $(obj)/conf $(silent) --silentoldconfig $(Kconfig); \ 50 $< $(silent) --oldconfig $(Kconfig); \
51 mv -f .config.old.1 .config.old) \ 51 mv -f .config.old.1 .config.old) \
52 else \ 52 else \
53 mv -f .tmp.config .config; \ 53 mv -f .tmp.config .config; \
54 $(obj)/conf $(silent) --silentoldconfig $(Kconfig); \ 54 $< $(silent) --oldconfig $(Kconfig); \
55 fi 55 fi
56 $(Q)rm -f .tmp.config 56 $(Q)rm -f .tmp.config
57 57
@@ -86,7 +86,7 @@ PHONY += $(simple-targets)
86$(simple-targets): $(obj)/conf 86$(simple-targets): $(obj)/conf
87 $< $(silent) --$@ $(Kconfig) 87 $< $(silent) --$@ $(Kconfig)
88 88
89PHONY += oldnoconfig savedefconfig defconfig 89PHONY += oldnoconfig silentoldconfig savedefconfig defconfig
90 90
91# oldnoconfig is an alias of olddefconfig, because people already are dependent 91# oldnoconfig is an alias of olddefconfig, because people already are dependent
92# on its behavior (sets new symbols to their default value but not 'n') with the 92# on its behavior (sets new symbols to their default value but not 'n') with the
@@ -95,6 +95,13 @@ oldnoconfig: olddefconfig
95 @echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19" 95 @echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19"
96 @echo " Please use \"olddefconfig\" instead, which is an alias." 96 @echo " Please use \"olddefconfig\" instead, which is an alias."
97 97
98# We do not expect manual invokcation of "silentoldcofig" (or "syncconfig").
99silentoldconfig: syncconfig
100 @echo " WARNING: \"silentoldconfig\" has been renamed to \"syncconfig\""
101 @echo " and is now an internal implementation detail."
102 @echo " What you want is probably \"oldconfig\"."
103 @echo " \"silentoldconfig\" will be removed after Linux 4.19"
104
98savedefconfig: $(obj)/conf 105savedefconfig: $(obj)/conf
99 $< $(silent) --$@=defconfig $(Kconfig) 106 $< $(silent) --$@=defconfig $(Kconfig)
100 107
@@ -133,6 +140,14 @@ PHONY += tinyconfig
133tinyconfig: 140tinyconfig:
134 $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config 141 $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
135 142
143# CHECK: -o cache_dir=<path> working?
144PHONY += testconfig
145testconfig: $(obj)/conf
146 $(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
147 -o cache_dir=$(abspath $(obj)/tests/.cache) \
148 $(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no)
149clean-dirs += tests/.cache
150
136# Help text used by make help 151# Help text used by make help
137help: 152help:
138 @echo ' config - Update current config utilising a line-oriented program' 153 @echo ' config - Update current config utilising a line-oriented program'
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 822dc51923d6..4e08121a35fb 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -23,7 +23,7 @@ static void check_conf(struct menu *menu);
23 23
24enum input_mode { 24enum input_mode {
25 oldaskconfig, 25 oldaskconfig,
26 silentoldconfig, 26 syncconfig,
27 oldconfig, 27 oldconfig,
28 allnoconfig, 28 allnoconfig,
29 allyesconfig, 29 allyesconfig,
@@ -100,7 +100,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
100 100
101 switch (input_mode) { 101 switch (input_mode) {
102 case oldconfig: 102 case oldconfig:
103 case silentoldconfig: 103 case syncconfig:
104 if (sym_has_value(sym)) { 104 if (sym_has_value(sym)) {
105 printf("%s\n", def); 105 printf("%s\n", def);
106 return 0; 106 return 0;
@@ -293,7 +293,7 @@ static int conf_choice(struct menu *menu)
293 printf("[1-%d?]: ", cnt); 293 printf("[1-%d?]: ", cnt);
294 switch (input_mode) { 294 switch (input_mode) {
295 case oldconfig: 295 case oldconfig:
296 case silentoldconfig: 296 case syncconfig:
297 if (!is_new) { 297 if (!is_new) {
298 cnt = def; 298 cnt = def;
299 printf("%d\n", cnt); 299 printf("%d\n", cnt);
@@ -358,10 +358,11 @@ static void conf(struct menu *menu)
358 358
359 switch (prop->type) { 359 switch (prop->type) {
360 case P_MENU: 360 case P_MENU:
361 if ((input_mode == silentoldconfig || 361 /*
362 input_mode == listnewconfig || 362 * Except in oldaskconfig mode, we show only menus that
363 input_mode == olddefconfig) && 363 * contain new symbols.
364 rootEntry != menu) { 364 */
365 if (input_mode != oldaskconfig && rootEntry != menu) {
365 check_conf(menu); 366 check_conf(menu);
366 return; 367 return;
367 } 368 }
@@ -424,7 +425,7 @@ static void check_conf(struct menu *menu)
424 if (sym->name && !sym_is_choice_value(sym)) { 425 if (sym->name && !sym_is_choice_value(sym)) {
425 printf("%s%s\n", CONFIG_, sym->name); 426 printf("%s%s\n", CONFIG_, sym->name);
426 } 427 }
427 } else if (input_mode != olddefconfig) { 428 } else {
428 if (!conf_cnt++) 429 if (!conf_cnt++)
429 printf(_("*\n* Restart config...\n*\n")); 430 printf(_("*\n* Restart config...\n*\n"));
430 rootEntry = menu_get_parent_menu(menu); 431 rootEntry = menu_get_parent_menu(menu);
@@ -440,7 +441,7 @@ static void check_conf(struct menu *menu)
440static struct option long_opts[] = { 441static struct option long_opts[] = {
441 {"oldaskconfig", no_argument, NULL, oldaskconfig}, 442 {"oldaskconfig", no_argument, NULL, oldaskconfig},
442 {"oldconfig", no_argument, NULL, oldconfig}, 443 {"oldconfig", no_argument, NULL, oldconfig},
443 {"silentoldconfig", no_argument, NULL, silentoldconfig}, 444 {"syncconfig", no_argument, NULL, syncconfig},
444 {"defconfig", optional_argument, NULL, defconfig}, 445 {"defconfig", optional_argument, NULL, defconfig},
445 {"savedefconfig", required_argument, NULL, savedefconfig}, 446 {"savedefconfig", required_argument, NULL, savedefconfig},
446 {"allnoconfig", no_argument, NULL, allnoconfig}, 447 {"allnoconfig", no_argument, NULL, allnoconfig},
@@ -467,8 +468,8 @@ static void conf_usage(const char *progname)
467 printf(" --listnewconfig List new options\n"); 468 printf(" --listnewconfig List new options\n");
468 printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); 469 printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
469 printf(" --oldconfig Update a configuration using a provided .config as base\n"); 470 printf(" --oldconfig Update a configuration using a provided .config as base\n");
470 printf(" --silentoldconfig Similar to oldconfig but generates configuration in\n" 471 printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
471 " include/{generated/,config/} (oldconfig used to be more verbose)\n"); 472 " include/{generated/,config/}\n");
472 printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n"); 473 printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
473 printf(" --oldnoconfig An alias of olddefconfig\n"); 474 printf(" --oldnoconfig An alias of olddefconfig\n");
474 printf(" --defconfig <file> New config with default defined in <file>\n"); 475 printf(" --defconfig <file> New config with default defined in <file>\n");
@@ -500,7 +501,7 @@ int main(int ac, char **av)
500 } 501 }
501 input_mode = (enum input_mode)opt; 502 input_mode = (enum input_mode)opt;
502 switch (opt) { 503 switch (opt) {
503 case silentoldconfig: 504 case syncconfig:
504 sync_kconfig = 1; 505 sync_kconfig = 1;
505 break; 506 break;
506 case defconfig: 507 case defconfig:
@@ -582,7 +583,7 @@ int main(int ac, char **av)
582 } 583 }
583 break; 584 break;
584 case savedefconfig: 585 case savedefconfig:
585 case silentoldconfig: 586 case syncconfig:
586 case oldaskconfig: 587 case oldaskconfig:
587 case oldconfig: 588 case oldconfig:
588 case listnewconfig: 589 case listnewconfig:
@@ -662,24 +663,24 @@ int main(int ac, char **av)
662 case oldaskconfig: 663 case oldaskconfig:
663 rootEntry = &rootmenu; 664 rootEntry = &rootmenu;
664 conf(&rootmenu); 665 conf(&rootmenu);
665 input_mode = silentoldconfig; 666 input_mode = oldconfig;
666 /* fall through */ 667 /* fall through */
667 case oldconfig: 668 case oldconfig:
668 case listnewconfig: 669 case listnewconfig:
669 case olddefconfig: 670 case syncconfig:
670 case silentoldconfig:
671 /* Update until a loop caused no more changes */ 671 /* Update until a loop caused no more changes */
672 do { 672 do {
673 conf_cnt = 0; 673 conf_cnt = 0;
674 check_conf(&rootmenu); 674 check_conf(&rootmenu);
675 } while (conf_cnt && 675 } while (conf_cnt);
676 (input_mode != listnewconfig && 676 break;
677 input_mode != olddefconfig)); 677 case olddefconfig:
678 default:
678 break; 679 break;
679 } 680 }
680 681
681 if (sync_kconfig) { 682 if (sync_kconfig) {
682 /* silentoldconfig is used during the build so we shall update autoconf. 683 /* syncconfig is used during the build so we shall update autoconf.
683 * All other commands are only used to generate a config. 684 * All other commands are only used to generate a config.
684 */ 685 */
685 if (conf_get_changed() && conf_write(NULL)) { 686 if (conf_get_changed() && conf_write(NULL)) {
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index d45381986ac7..e1a39e90841d 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -1137,49 +1137,9 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
1137 return 0; 1137 return 0;
1138} 1138}
1139 1139
1140static inline struct expr * 1140void expr_print(struct expr *e,
1141expr_get_leftmost_symbol(const struct expr *e) 1141 void (*fn)(void *, struct symbol *, const char *),
1142{ 1142 void *data, int prevtoken)
1143
1144 if (e == NULL)
1145 return NULL;
1146
1147 while (e->type != E_SYMBOL)
1148 e = e->left.expr;
1149
1150 return expr_copy(e);
1151}
1152
1153/*
1154 * Given expression `e1' and `e2', returns the leaf of the longest
1155 * sub-expression of `e1' not containing 'e2.
1156 */
1157struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
1158{
1159 struct expr *ret;
1160
1161 switch (e1->type) {
1162 case E_OR:
1163 return expr_alloc_and(
1164 expr_simplify_unmet_dep(e1->left.expr, e2),
1165 expr_simplify_unmet_dep(e1->right.expr, e2));
1166 case E_AND: {
1167 struct expr *e;
1168 e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
1169 e = expr_eliminate_dups(e);
1170 ret = (!expr_eq(e, e1)) ? e1 : NULL;
1171 expr_free(e);
1172 break;
1173 }
1174 default:
1175 ret = e1;
1176 break;
1177 }
1178
1179 return expr_get_leftmost_symbol(ret);
1180}
1181
1182static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken, bool revdep)
1183{ 1143{
1184 if (!e) { 1144 if (!e) {
1185 fn(data, NULL, "y"); 1145 fn(data, NULL, "y");
@@ -1234,14 +1194,9 @@ static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, con
1234 fn(data, e->right.sym, e->right.sym->name); 1194 fn(data, e->right.sym, e->right.sym->name);
1235 break; 1195 break;
1236 case E_OR: 1196 case E_OR:
1237 if (revdep && e->left.expr->type != E_OR) 1197 expr_print(e->left.expr, fn, data, E_OR);
1238 fn(data, NULL, "\n - "); 1198 fn(data, NULL, " || ");
1239 __expr_print(e->left.expr, fn, data, E_OR, revdep); 1199 expr_print(e->right.expr, fn, data, E_OR);
1240 if (revdep)
1241 fn(data, NULL, "\n - ");
1242 else
1243 fn(data, NULL, " || ");
1244 __expr_print(e->right.expr, fn, data, E_OR, revdep);
1245 break; 1200 break;
1246 case E_AND: 1201 case E_AND:
1247 expr_print(e->left.expr, fn, data, E_AND); 1202 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
1274 fn(data, NULL, ")"); 1229 fn(data, NULL, ")");
1275} 1230}
1276 1231
1277void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
1278{
1279 __expr_print(e, fn, data, prevtoken, false);
1280}
1281
1282static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) 1232static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
1283{ 1233{
1284 xfwrite(str, strlen(str), 1, data); 1234 xfwrite(str, strlen(str), 1, data);
@@ -1329,7 +1279,27 @@ void expr_gstr_print(struct expr *e, struct gstr *gs)
1329 * line with a minus. This makes expressions much easier to read. 1279 * line with a minus. This makes expressions much easier to read.
1330 * Suitable for reverse dependency expressions. 1280 * Suitable for reverse dependency expressions.
1331 */ 1281 */
1332void expr_gstr_print_revdep(struct expr *e, struct gstr *gs) 1282static void expr_print_revdep(struct expr *e,
1283 void (*fn)(void *, struct symbol *, const char *),
1284 void *data, tristate pr_type, const char **title)
1285{
1286 if (e->type == E_OR) {
1287 expr_print_revdep(e->left.expr, fn, data, pr_type, title);
1288 expr_print_revdep(e->right.expr, fn, data, pr_type, title);
1289 } else if (expr_calc_value(e) == pr_type) {
1290 if (*title) {
1291 fn(data, NULL, *title);
1292 *title = NULL;
1293 }
1294
1295 fn(data, NULL, " - ");
1296 expr_print(e, fn, data, E_NONE);
1297 fn(data, NULL, "\n");
1298 }
1299}
1300
1301void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
1302 tristate pr_type, const char *title)
1333{ 1303{
1334 __expr_print(e, expr_print_gstr_helper, gs, E_NONE, true); 1304 expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title);
1335} 1305}
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index c16e82e302a2..94a383b21df6 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -305,12 +305,12 @@ struct expr *expr_transform(struct expr *e);
305int expr_contains_symbol(struct expr *dep, struct symbol *sym); 305int expr_contains_symbol(struct expr *dep, struct symbol *sym);
306bool expr_depends_symbol(struct expr *dep, struct symbol *sym); 306bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
307struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); 307struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
308struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
309 308
310void expr_fprint(struct expr *e, FILE *out); 309void expr_fprint(struct expr *e, FILE *out);
311struct gstr; /* forward */ 310struct gstr; /* forward */
312void expr_gstr_print(struct expr *e, struct gstr *gs); 311void expr_gstr_print(struct expr *e, struct gstr *gs);
313void expr_gstr_print_revdep(struct expr *e, struct gstr *gs); 312void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
313 tristate pr_type, const char *title);
314 314
315static inline int expr_is_yes(struct expr *e) 315static inline int expr_is_yes(struct expr *e)
316{ 316{
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 2d5ec2d0e952..f4394af6e4b8 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -68,6 +68,7 @@ struct kconf_id {
68 enum symbol_type stype; 68 enum symbol_type stype;
69}; 69};
70 70
71extern int yylineno;
71void zconfdump(FILE *out); 72void zconfdump(FILE *out);
72void zconf_starthelp(void); 73void zconf_starthelp(void);
73FILE *zconf_fopen(const char *name); 74FILE *zconf_fopen(const char *name);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 36cd3e1f1c28..5c5c1374b151 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -828,16 +828,16 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
828 828
829 get_symbol_props_str(r, sym, P_SELECT, _(" Selects: ")); 829 get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
830 if (sym->rev_dep.expr) { 830 if (sym->rev_dep.expr) {
831 str_append(r, _(" Selected by: ")); 831 expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n");
832 expr_gstr_print_revdep(sym->rev_dep.expr, r); 832 expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n");
833 str_append(r, "\n"); 833 expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n");
834 } 834 }
835 835
836 get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: ")); 836 get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: "));
837 if (sym->implied.expr) { 837 if (sym->implied.expr) {
838 str_append(r, _(" Implied by: ")); 838 expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n");
839 expr_gstr_print_revdep(sym->implied.expr, r); 839 expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n");
840 str_append(r, "\n"); 840 expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n");
841 } 841 }
842 842
843 str_append(r, "\n\n"); 843 str_append(r, "\n\n");
diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h
index 0d5261705ef5..9f6f21d3b0d4 100644
--- a/scripts/kconfig/nconf.h
+++ b/scripts/kconfig/nconf.h
@@ -15,7 +15,7 @@
15#include <string.h> 15#include <string.h>
16#include <unistd.h> 16#include <unistd.h>
17#include <locale.h> 17#include <locale.h>
18#include <curses.h> 18#include <ncurses.h>
19#include <menu.h> 19#include <menu.h>
20#include <panel.h> 20#include <panel.h>
21#include <form.h> 21#include <form.h>
@@ -24,8 +24,6 @@
24#include <time.h> 24#include <time.h>
25#include <sys/time.h> 25#include <sys/time.h>
26 26
27#include "ncurses.h"
28
29#define max(a, b) ({\ 27#define max(a, b) ({\
30 typeof(a) _a = a;\ 28 typeof(a) _a = a;\
31 typeof(b) _b = b;\ 29 typeof(b) _b = b;\
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 2220bc4b051b..f0b2e3b3102d 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -243,7 +243,7 @@ static void sym_calc_visibility(struct symbol *sym)
243 tri = yes; 243 tri = yes;
244 if (sym->dir_dep.expr) 244 if (sym->dir_dep.expr)
245 tri = expr_calc_value(sym->dir_dep.expr); 245 tri = expr_calc_value(sym->dir_dep.expr);
246 if (tri == mod) 246 if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
247 tri = yes; 247 tri = yes;
248 if (sym->dir_dep.tri != tri) { 248 if (sym->dir_dep.tri != tri) {
249 sym->dir_dep.tri = tri; 249 sym->dir_dep.tri = tri;
@@ -333,6 +333,27 @@ static struct symbol *sym_calc_choice(struct symbol *sym)
333 return def_sym; 333 return def_sym;
334} 334}
335 335
336static void sym_warn_unmet_dep(struct symbol *sym)
337{
338 struct gstr gs = str_new();
339
340 str_printf(&gs,
341 "\nWARNING: unmet direct dependencies detected for %s\n",
342 sym->name);
343 str_printf(&gs,
344 " Depends on [%c]: ",
345 sym->dir_dep.tri == mod ? 'm' : 'n');
346 expr_gstr_print(sym->dir_dep.expr, &gs);
347 str_printf(&gs, "\n");
348
349 expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes,
350 " Selected by [y]:\n");
351 expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod,
352 " Selected by [m]:\n");
353
354 fputs(str_get(&gs), stderr);
355}
356
336void sym_calc_value(struct symbol *sym) 357void sym_calc_value(struct symbol *sym)
337{ 358{
338 struct symbol_value newval, oldval; 359 struct symbol_value newval, oldval;
@@ -403,9 +424,10 @@ void sym_calc_value(struct symbol *sym)
403 if (!sym_is_choice(sym)) { 424 if (!sym_is_choice(sym)) {
404 prop = sym_get_default_prop(sym); 425 prop = sym_get_default_prop(sym);
405 if (prop) { 426 if (prop) {
406 sym->flags |= SYMBOL_WRITE;
407 newval.tri = EXPR_AND(expr_calc_value(prop->expr), 427 newval.tri = EXPR_AND(expr_calc_value(prop->expr),
408 prop->visible.tri); 428 prop->visible.tri);
429 if (newval.tri != no)
430 sym->flags |= SYMBOL_WRITE;
409 } 431 }
410 if (sym->implied.tri != no) { 432 if (sym->implied.tri != no) {
411 sym->flags |= SYMBOL_WRITE; 433 sym->flags |= SYMBOL_WRITE;
@@ -413,18 +435,8 @@ void sym_calc_value(struct symbol *sym)
413 } 435 }
414 } 436 }
415 calc_newval: 437 calc_newval:
416 if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { 438 if (sym->dir_dep.tri < sym->rev_dep.tri)
417 struct expr *e; 439 sym_warn_unmet_dep(sym);
418 e = expr_simplify_unmet_dep(sym->rev_dep.expr,
419 sym->dir_dep.expr);
420 fprintf(stderr, "warning: (");
421 expr_fprint(e, stderr);
422 fprintf(stderr, ") selects %s which has unmet direct dependencies (",
423 sym->name);
424 expr_fprint(sym->dir_dep.expr, stderr);
425 fprintf(stderr, ")\n");
426 expr_free(e);
427 }
428 newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); 440 newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
429 } 441 }
430 if (newval.tri == mod && 442 if (newval.tri == mod &&
diff --git a/scripts/kconfig/tests/auto_submenu/Kconfig b/scripts/kconfig/tests/auto_submenu/Kconfig
new file mode 100644
index 000000000000..c17bf2caa7e6
--- /dev/null
+++ b/scripts/kconfig/tests/auto_submenu/Kconfig
@@ -0,0 +1,50 @@
1config A
2 bool "A"
3 default y
4
5config A0
6 bool "A0"
7 depends on A
8 default y
9 help
10 This depends on A, so should be a submenu of A.
11
12config A0_0
13 bool "A1_0"
14 depends on A0
15 help
16 Submenus are created recursively.
17 This should be a submenu of A0.
18
19config A1
20 bool "A1"
21 depends on A
22 default y
23 help
24 This should line up with A0.
25
26choice
27 prompt "choice"
28 depends on A1
29 help
30 Choice should become a submenu as well.
31
32config A1_0
33 bool "A1_0"
34
35config A1_1
36 bool "A1_1"
37
38endchoice
39
40config B
41 bool "B"
42 help
43 This is independent of A.
44
45config C
46 bool "C"
47 depends on A
48 help
49 This depends on A, but not a consecutive item, so can/should not
50 be a submenu.
diff --git a/scripts/kconfig/tests/auto_submenu/__init__.py b/scripts/kconfig/tests/auto_submenu/__init__.py
new file mode 100644
index 000000000000..32e79b85faeb
--- /dev/null
+++ b/scripts/kconfig/tests/auto_submenu/__init__.py
@@ -0,0 +1,12 @@
1"""
2Create submenu for symbols that depend on the preceding one.
3
4If a symbols has dependency on the preceding symbol, the menu entry
5should become the submenu of the preceding one, and displayed with
6deeper indentation.
7"""
8
9
10def test(conf):
11 assert conf.oldaskconfig() == 0
12 assert conf.stdout_contains('expected_stdout')
diff --git a/scripts/kconfig/tests/auto_submenu/expected_stdout b/scripts/kconfig/tests/auto_submenu/expected_stdout
new file mode 100644
index 000000000000..bf5236f39a56
--- /dev/null
+++ b/scripts/kconfig/tests/auto_submenu/expected_stdout
@@ -0,0 +1,10 @@
1A (A) [Y/n/?] (NEW)
2 A0 (A0) [Y/n/?] (NEW)
3 A1_0 (A0_0) [N/y/?] (NEW)
4 A1 (A1) [Y/n/?] (NEW)
5 choice
6 > 1. A1_0 (A1_0) (NEW)
7 2. A1_1 (A1_1) (NEW)
8 choice[1-2?]:
9B (B) [N/y/?] (NEW)
10C (C) [N/y/?] (NEW)
diff --git a/scripts/kconfig/tests/choice/Kconfig b/scripts/kconfig/tests/choice/Kconfig
new file mode 100644
index 000000000000..cc60e9ce2c03
--- /dev/null
+++ b/scripts/kconfig/tests/choice/Kconfig
@@ -0,0 +1,54 @@
1config MODULES
2 bool "Enable loadable module support"
3 option modules
4 default y
5
6choice
7 prompt "boolean choice"
8 default BOOL_CHOICE1
9
10config BOOL_CHOICE0
11 bool "choice 0"
12
13config BOOL_CHOICE1
14 bool "choice 1"
15
16endchoice
17
18choice
19 prompt "optional boolean choice"
20 optional
21 default OPT_BOOL_CHOICE1
22
23config OPT_BOOL_CHOICE0
24 bool "choice 0"
25
26config OPT_BOOL_CHOICE1
27 bool "choice 1"
28
29endchoice
30
31choice
32 prompt "tristate choice"
33 default TRI_CHOICE1
34
35config TRI_CHOICE0
36 tristate "choice 0"
37
38config TRI_CHOICE1
39 tristate "choice 1"
40
41endchoice
42
43choice
44 prompt "optional tristate choice"
45 optional
46 default OPT_TRI_CHOICE1
47
48config OPT_TRI_CHOICE0
49 tristate "choice 0"
50
51config OPT_TRI_CHOICE1
52 tristate "choice 1"
53
54endchoice
diff --git a/scripts/kconfig/tests/choice/__init__.py b/scripts/kconfig/tests/choice/__init__.py
new file mode 100644
index 000000000000..9edcc5262134
--- /dev/null
+++ b/scripts/kconfig/tests/choice/__init__.py
@@ -0,0 +1,40 @@
1"""
2Basic choice tests.
3
4The handling of 'choice' is a bit complicated part in Kconfig.
5
6The behavior of 'y' choice is intuitive. If choice values are tristate,
7the choice can be 'm' where each value can be enabled independently.
8Also, if a choice is marked as 'optional', the whole choice can be
9invisible.
10"""
11
12
13def test_oldask0(conf):
14 assert conf.oldaskconfig() == 0
15 assert conf.stdout_contains('oldask0_expected_stdout')
16
17
18def test_oldask1(conf):
19 assert conf.oldaskconfig('oldask1_config') == 0
20 assert conf.stdout_contains('oldask1_expected_stdout')
21
22
23def test_allyes(conf):
24 assert conf.allyesconfig() == 0
25 assert conf.config_contains('allyes_expected_config')
26
27
28def test_allmod(conf):
29 assert conf.allmodconfig() == 0
30 assert conf.config_contains('allmod_expected_config')
31
32
33def test_allno(conf):
34 assert conf.allnoconfig() == 0
35 assert conf.config_contains('allno_expected_config')
36
37
38def test_alldef(conf):
39 assert conf.alldefconfig() == 0
40 assert conf.config_contains('alldef_expected_config')
diff --git a/scripts/kconfig/tests/choice/alldef_expected_config b/scripts/kconfig/tests/choice/alldef_expected_config
new file mode 100644
index 000000000000..7a754bf4be94
--- /dev/null
+++ b/scripts/kconfig/tests/choice/alldef_expected_config
@@ -0,0 +1,5 @@
1CONFIG_MODULES=y
2# CONFIG_BOOL_CHOICE0 is not set
3CONFIG_BOOL_CHOICE1=y
4# CONFIG_TRI_CHOICE0 is not set
5# CONFIG_TRI_CHOICE1 is not set
diff --git a/scripts/kconfig/tests/choice/allmod_expected_config b/scripts/kconfig/tests/choice/allmod_expected_config
new file mode 100644
index 000000000000..f1f5dcdb7923
--- /dev/null
+++ b/scripts/kconfig/tests/choice/allmod_expected_config
@@ -0,0 +1,9 @@
1CONFIG_MODULES=y
2# CONFIG_BOOL_CHOICE0 is not set
3CONFIG_BOOL_CHOICE1=y
4# CONFIG_OPT_BOOL_CHOICE0 is not set
5CONFIG_OPT_BOOL_CHOICE1=y
6CONFIG_TRI_CHOICE0=m
7CONFIG_TRI_CHOICE1=m
8CONFIG_OPT_TRI_CHOICE0=m
9CONFIG_OPT_TRI_CHOICE1=m
diff --git a/scripts/kconfig/tests/choice/allno_expected_config b/scripts/kconfig/tests/choice/allno_expected_config
new file mode 100644
index 000000000000..b88ee7a43136
--- /dev/null
+++ b/scripts/kconfig/tests/choice/allno_expected_config
@@ -0,0 +1,5 @@
1# CONFIG_MODULES is not set
2# CONFIG_BOOL_CHOICE0 is not set
3CONFIG_BOOL_CHOICE1=y
4# CONFIG_TRI_CHOICE0 is not set
5CONFIG_TRI_CHOICE1=y
diff --git a/scripts/kconfig/tests/choice/allyes_expected_config b/scripts/kconfig/tests/choice/allyes_expected_config
new file mode 100644
index 000000000000..e5a062a1157c
--- /dev/null
+++ b/scripts/kconfig/tests/choice/allyes_expected_config
@@ -0,0 +1,9 @@
1CONFIG_MODULES=y
2# CONFIG_BOOL_CHOICE0 is not set
3CONFIG_BOOL_CHOICE1=y
4# CONFIG_OPT_BOOL_CHOICE0 is not set
5CONFIG_OPT_BOOL_CHOICE1=y
6# CONFIG_TRI_CHOICE0 is not set
7CONFIG_TRI_CHOICE1=y
8# CONFIG_OPT_TRI_CHOICE0 is not set
9CONFIG_OPT_TRI_CHOICE1=y
diff --git a/scripts/kconfig/tests/choice/oldask0_expected_stdout b/scripts/kconfig/tests/choice/oldask0_expected_stdout
new file mode 100644
index 000000000000..b251bba9698b
--- /dev/null
+++ b/scripts/kconfig/tests/choice/oldask0_expected_stdout
@@ -0,0 +1,10 @@
1Enable loadable module support (MODULES) [Y/n/?] (NEW)
2boolean choice
3 1. choice 0 (BOOL_CHOICE0) (NEW)
4> 2. choice 1 (BOOL_CHOICE1) (NEW)
5choice[1-2?]:
6optional boolean choice [N/y/?] (NEW)
7tristate choice [M/y/?] (NEW)
8 choice 0 (TRI_CHOICE0) [N/m/?] (NEW)
9 choice 1 (TRI_CHOICE1) [N/m/?] (NEW)
10optional tristate choice [N/m/y/?] (NEW)
diff --git a/scripts/kconfig/tests/choice/oldask1_config b/scripts/kconfig/tests/choice/oldask1_config
new file mode 100644
index 000000000000..b67bfe3c641f
--- /dev/null
+++ b/scripts/kconfig/tests/choice/oldask1_config
@@ -0,0 +1,2 @@
1# CONFIG_MODULES is not set
2CONFIG_OPT_BOOL_CHOICE0=y
diff --git a/scripts/kconfig/tests/choice/oldask1_expected_stdout b/scripts/kconfig/tests/choice/oldask1_expected_stdout
new file mode 100644
index 000000000000..c2125e9bf96a
--- /dev/null
+++ b/scripts/kconfig/tests/choice/oldask1_expected_stdout
@@ -0,0 +1,15 @@
1Enable loadable module support (MODULES) [N/y/?]
2boolean choice
3 1. choice 0 (BOOL_CHOICE0) (NEW)
4> 2. choice 1 (BOOL_CHOICE1) (NEW)
5choice[1-2?]:
6optional boolean choice [Y/n/?] (NEW)
7optional boolean choice
8> 1. choice 0 (OPT_BOOL_CHOICE0)
9 2. choice 1 (OPT_BOOL_CHOICE1) (NEW)
10choice[1-2?]:
11tristate choice
12 1. choice 0 (TRI_CHOICE0) (NEW)
13> 2. choice 1 (TRI_CHOICE1) (NEW)
14choice[1-2?]:
15optional tristate choice [N/y/?]
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
new file mode 100644
index 000000000000..11ac25c26040
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
@@ -0,0 +1,19 @@
1config MODULES
2 def_bool y
3 option modules
4
5config DEP
6 tristate
7 default m
8
9choice
10 prompt "Tristate Choice"
11
12config CHOICE0
13 tristate "Choice 0"
14
15config CHOICE1
16 tristate "Choice 1"
17 depends on DEP
18
19endchoice
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py b/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py
new file mode 100644
index 000000000000..f8d728c7b101
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py
@@ -0,0 +1,15 @@
1"""
2Hide tristate choice values with mod dependency in y choice.
3
4If tristate choice values depend on symbols set to 'm', they should be
5hidden when the choice containing them is changed from 'm' to 'y'
6(i.e. exclusive choice).
7
8Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074
9"""
10
11
12def test(conf):
13 assert conf.oldaskconfig('config', 'y') == 0
14 assert conf.config_contains('expected_config')
15 assert conf.stdout_contains('expected_stdout')
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/config b/scripts/kconfig/tests/choice_value_with_m_dep/config
new file mode 100644
index 000000000000..3a126b7a2546
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/config
@@ -0,0 +1,2 @@
1CONFIG_CHOICE0=m
2CONFIG_CHOICE1=m
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/expected_config b/scripts/kconfig/tests/choice_value_with_m_dep/expected_config
new file mode 100644
index 000000000000..4d07b449540e
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/expected_config
@@ -0,0 +1,3 @@
1CONFIG_MODULES=y
2CONFIG_DEP=m
3CONFIG_CHOICE0=y
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout b/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout
new file mode 100644
index 000000000000..2b50ab65c86a
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout
@@ -0,0 +1,4 @@
1Tristate Choice [M/y/?] y
2Tristate Choice
3> 1. Choice 0 (CHOICE0)
4choice[1]: 1
diff --git a/scripts/kconfig/tests/conftest.py b/scripts/kconfig/tests/conftest.py
new file mode 100644
index 000000000000..0345ef6e3273
--- /dev/null
+++ b/scripts/kconfig/tests/conftest.py
@@ -0,0 +1,291 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
4#
5
6"""
7Kconfig unit testing framework.
8
9This provides fixture functions commonly used from test files.
10"""
11
12import os
13import pytest
14import shutil
15import subprocess
16import tempfile
17
18CONF_PATH = os.path.abspath(os.path.join('scripts', 'kconfig', 'conf'))
19
20
21class Conf:
22 """Kconfig runner and result checker.
23
24 This class provides methods to run text-based interface of Kconfig
25 (scripts/kconfig/conf) and retrieve the resulted configuration,
26 stdout, and stderr. It also provides methods to compare those
27 results with expectations.
28 """
29
30 def __init__(self, request):
31 """Create a new Conf instance.
32
33 request: object to introspect the requesting test module
34 """
35 # the directory of the test being run
36 self._test_dir = os.path.dirname(str(request.fspath))
37
38 # runners
39 def _run_conf(self, mode, dot_config=None, out_file='.config',
40 interactive=False, in_keys=None, extra_env={}):
41 """Run text-based Kconfig executable and save the result.
42
43 mode: input mode option (--oldaskconfig, --defconfig=<file> etc.)
44 dot_config: .config file to use for configuration base
45 out_file: file name to contain the output config data
46 interactive: flag to specify the interactive mode
47 in_keys: key inputs for interactive modes
48 extra_env: additional environments
49 returncode: exit status of the Kconfig executable
50 """
51 command = [CONF_PATH, mode, 'Kconfig']
52
53 # Override 'srctree' environment to make the test as the top directory
54 extra_env['srctree'] = self._test_dir
55
56 # Run Kconfig in a temporary directory.
57 # This directory is automatically removed when done.
58 with tempfile.TemporaryDirectory() as temp_dir:
59
60 # if .config is given, copy it to the working directory
61 if dot_config:
62 shutil.copyfile(os.path.join(self._test_dir, dot_config),
63 os.path.join(temp_dir, '.config'))
64
65 ps = subprocess.Popen(command,
66 stdin=subprocess.PIPE,
67 stdout=subprocess.PIPE,
68 stderr=subprocess.PIPE,
69 cwd=temp_dir,
70 env=dict(os.environ, **extra_env))
71
72 # If input key sequence is given, feed it to stdin.
73 if in_keys:
74 ps.stdin.write(in_keys.encode('utf-8'))
75
76 while ps.poll() is None:
77 # For interactive modes such as oldaskconfig, oldconfig,
78 # send 'Enter' key until the program finishes.
79 if interactive:
80 ps.stdin.write(b'\n')
81
82 self.retcode = ps.returncode
83 self.stdout = ps.stdout.read().decode()
84 self.stderr = ps.stderr.read().decode()
85
86 # Retrieve the resulted config data only when .config is supposed
87 # to exist. If the command fails, the .config does not exist.
88 # 'listnewconfig' does not produce .config in the first place.
89 if self.retcode == 0 and out_file:
90 with open(os.path.join(temp_dir, out_file)) as f:
91 self.config = f.read()
92 else:
93 self.config = None
94
95 # Logging:
96 # Pytest captures the following information by default. In failure
97 # of tests, the captured log will be displayed. This will be useful to
98 # figure out what has happened.
99
100 print("[command]\n{}\n".format(' '.join(command)))
101
102 print("[retcode]\n{}\n".format(self.retcode))
103
104 print("[stdout]")
105 print(self.stdout)
106
107 print("[stderr]")
108 print(self.stderr)
109
110 if self.config is not None:
111 print("[output for '{}']".format(out_file))
112 print(self.config)
113
114 return self.retcode
115
116 def oldaskconfig(self, dot_config=None, in_keys=None):
117 """Run oldaskconfig.
118
119 dot_config: .config file to use for configuration base (optional)
120 in_key: key inputs (optional)
121 returncode: exit status of the Kconfig executable
122 """
123 return self._run_conf('--oldaskconfig', dot_config=dot_config,
124 interactive=True, in_keys=in_keys)
125
126 def oldconfig(self, dot_config=None, in_keys=None):
127 """Run oldconfig.
128
129 dot_config: .config file to use for configuration base (optional)
130 in_key: key inputs (optional)
131 returncode: exit status of the Kconfig executable
132 """
133 return self._run_conf('--oldconfig', dot_config=dot_config,
134 interactive=True, in_keys=in_keys)
135
136 def olddefconfig(self, dot_config=None):
137 """Run olddefconfig.
138
139 dot_config: .config file to use for configuration base (optional)
140 returncode: exit status of the Kconfig executable
141 """
142 return self._run_conf('--olddefconfig', dot_config=dot_config)
143
144 def defconfig(self, defconfig):
145 """Run defconfig.
146
147 defconfig: defconfig file for input
148 returncode: exit status of the Kconfig executable
149 """
150 defconfig_path = os.path.join(self._test_dir, defconfig)
151 return self._run_conf('--defconfig={}'.format(defconfig_path))
152
153 def _allconfig(self, mode, all_config):
154 if all_config:
155 all_config_path = os.path.join(self._test_dir, all_config)
156 extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
157 else:
158 extra_env = {}
159
160 return self._run_conf('--{}config'.format(mode), extra_env=extra_env)
161
162 def allyesconfig(self, all_config=None):
163 """Run allyesconfig.
164
165 all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
166 returncode: exit status of the Kconfig executable
167 """
168 return self._allconfig('allyes', all_config)
169
170 def allmodconfig(self, all_config=None):
171 """Run allmodconfig.
172
173 all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
174 returncode: exit status of the Kconfig executable
175 """
176 return self._allconfig('allmod', all_config)
177
178 def allnoconfig(self, all_config=None):
179 """Run allnoconfig.
180
181 all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
182 returncode: exit status of the Kconfig executable
183 """
184 return self._allconfig('allno', all_config)
185
186 def alldefconfig(self, all_config=None):
187 """Run alldefconfig.
188
189 all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
190 returncode: exit status of the Kconfig executable
191 """
192 return self._allconfig('alldef', all_config)
193
194 def randconfig(self, all_config=None):
195 """Run randconfig.
196
197 all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
198 returncode: exit status of the Kconfig executable
199 """
200 return self._allconfig('rand', all_config)
201
202 def savedefconfig(self, dot_config):
203 """Run savedefconfig.
204
205 dot_config: .config file for input
206 returncode: exit status of the Kconfig executable
207 """
208 return self._run_conf('--savedefconfig', out_file='defconfig')
209
210 def listnewconfig(self, dot_config=None):
211 """Run listnewconfig.
212
213 dot_config: .config file to use for configuration base (optional)
214 returncode: exit status of the Kconfig executable
215 """
216 return self._run_conf('--listnewconfig', dot_config=dot_config,
217 out_file=None)
218
219 # checkers
220 def _read_and_compare(self, compare, expected):
221 """Compare the result with expectation.
222
223 compare: function to compare the result with expectation
224 expected: file that contains the expected data
225 """
226 with open(os.path.join(self._test_dir, expected)) as f:
227 expected_data = f.read()
228 return compare(self, expected_data)
229
230 def _contains(self, attr, expected):
231 return self._read_and_compare(
232 lambda s, e: getattr(s, attr).find(e) >= 0,
233 expected)
234
235 def _matches(self, attr, expected):
236 return self._read_and_compare(lambda s, e: getattr(s, attr) == e,
237 expected)
238
239 def config_contains(self, expected):
240 """Check if resulted configuration contains expected data.
241
242 expected: file that contains the expected data
243 returncode: True if result contains the expected data, False otherwise
244 """
245 return self._contains('config', expected)
246
247 def config_matches(self, expected):
248 """Check if resulted configuration exactly matches expected data.
249
250 expected: file that contains the expected data
251 returncode: True if result matches the expected data, False otherwise
252 """
253 return self._matches('config', expected)
254
255 def stdout_contains(self, expected):
256 """Check if resulted stdout contains expected data.
257
258 expected: file that contains the expected data
259 returncode: True if result contains the expected data, False otherwise
260 """
261 return self._contains('stdout', expected)
262
263 def stdout_matches(self, expected):
264 """Check if resulted stdout exactly matches expected data.
265
266 expected: file that contains the expected data
267 returncode: True if result matches the expected data, False otherwise
268 """
269 return self._matches('stdout', expected)
270
271 def stderr_contains(self, expected):
272 """Check if resulted stderr contains expected data.
273
274 expected: file that contains the expected data
275 returncode: True if result contains the expected data, False otherwise
276 """
277 return self._contains('stderr', expected)
278
279 def stderr_matches(self, expected):
280 """Check if resulted stderr exactly matches expected data.
281
282 expected: file that contains the expected data
283 returncode: True if result matches the expected data, False otherwise
284 """
285 return self._matches('stderr', expected)
286
287
288@pytest.fixture(scope="module")
289def conf(request):
290 """Create a Conf instance and provide it to test functions."""
291 return Conf(request)
diff --git a/scripts/kconfig/tests/err_recursive_inc/Kconfig b/scripts/kconfig/tests/err_recursive_inc/Kconfig
new file mode 100644
index 000000000000..0e4c8750ab65
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/Kconfig
@@ -0,0 +1 @@
source "Kconfig.inc1"
diff --git a/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1 b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1
new file mode 100644
index 000000000000..00e408d653fc
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1
@@ -0,0 +1,4 @@
1
2
3
4source "Kconfig.inc2"
diff --git a/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2 b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2
new file mode 100644
index 000000000000..349ea2db15dc
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2
@@ -0,0 +1,3 @@
1
2
3source "Kconfig.inc3"
diff --git a/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3 b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3
new file mode 100644
index 000000000000..0e4c8750ab65
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3
@@ -0,0 +1 @@
source "Kconfig.inc1"
diff --git a/scripts/kconfig/tests/err_recursive_inc/__init__.py b/scripts/kconfig/tests/err_recursive_inc/__init__.py
new file mode 100644
index 000000000000..0e4c839c54aa
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/__init__.py
@@ -0,0 +1,10 @@
1"""
2Detect recursive inclusion error.
3
4If recursive inclusion is detected, it should fail with error messages.
5"""
6
7
8def test(conf):
9 assert conf.oldaskconfig() != 0
10 assert conf.stderr_contains('expected_stderr')
diff --git a/scripts/kconfig/tests/err_recursive_inc/expected_stderr b/scripts/kconfig/tests/err_recursive_inc/expected_stderr
new file mode 100644
index 000000000000..6b582eee2176
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/expected_stderr
@@ -0,0 +1,6 @@
1Recursive inclusion detected.
2Inclusion path:
3 current file : Kconfig.inc1
4 included from: Kconfig.inc3:1
5 included from: Kconfig.inc2:3
6 included from: Kconfig.inc1:4
diff --git a/scripts/kconfig/tests/inter_choice/Kconfig b/scripts/kconfig/tests/inter_choice/Kconfig
new file mode 100644
index 000000000000..e44449f075df
--- /dev/null
+++ b/scripts/kconfig/tests/inter_choice/Kconfig
@@ -0,0 +1,23 @@
1config MODULES
2 def_bool y
3 option modules
4
5choice
6 prompt "Choice"
7
8config CHOICE_VAL0
9 tristate "Choice 0"
10
11config CHOIVE_VAL1
12 tristate "Choice 1"
13
14endchoice
15
16choice
17 prompt "Another choice"
18 depends on CHOICE_VAL0
19
20config DUMMY
21 bool "dummy"
22
23endchoice
diff --git a/scripts/kconfig/tests/inter_choice/__init__.py b/scripts/kconfig/tests/inter_choice/__init__.py
new file mode 100644
index 000000000000..5c7fc365ed40
--- /dev/null
+++ b/scripts/kconfig/tests/inter_choice/__init__.py
@@ -0,0 +1,14 @@
1"""
2Do not affect user-assigned choice value by another choice.
3
4Handling of state flags for choices is complecated. In old days,
5the defconfig result of a choice could be affected by another choice
6if those choices interact by 'depends on', 'select', etc.
7
8Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a
9"""
10
11
12def test(conf):
13 assert conf.defconfig('defconfig') == 0
14 assert conf.config_contains('expected_config')
diff --git a/scripts/kconfig/tests/inter_choice/defconfig b/scripts/kconfig/tests/inter_choice/defconfig
new file mode 100644
index 000000000000..162c4148e2a5
--- /dev/null
+++ b/scripts/kconfig/tests/inter_choice/defconfig
@@ -0,0 +1 @@
CONFIG_CHOICE_VAL0=y
diff --git a/scripts/kconfig/tests/inter_choice/expected_config b/scripts/kconfig/tests/inter_choice/expected_config
new file mode 100644
index 000000000000..5dceefb054e3
--- /dev/null
+++ b/scripts/kconfig/tests/inter_choice/expected_config
@@ -0,0 +1,4 @@
1CONFIG_MODULES=y
2CONFIG_CHOICE_VAL0=y
3# CONFIG_CHOIVE_VAL1 is not set
4CONFIG_DUMMY=y
diff --git a/scripts/kconfig/tests/new_choice_with_dep/Kconfig b/scripts/kconfig/tests/new_choice_with_dep/Kconfig
new file mode 100644
index 000000000000..53ef1b86e7bf
--- /dev/null
+++ b/scripts/kconfig/tests/new_choice_with_dep/Kconfig
@@ -0,0 +1,37 @@
1config A
2 bool "A"
3 help
4 This is a new symbol.
5
6choice
7 prompt "Choice ?"
8 depends on A
9 help
10 "depends on A" has been newly added.
11
12config CHOICE_B
13 bool "Choice B"
14
15config CHOICE_C
16 bool "Choice C"
17 help
18 This is a new symbol, so should be asked.
19
20endchoice
21
22choice
23 prompt "Choice2 ?"
24
25config CHOICE_D
26 bool "Choice D"
27
28config CHOICE_E
29 bool "Choice E"
30
31config CHOICE_F
32 bool "Choice F"
33 depends on A
34 help
35 This is a new symbol, so should be asked.
36
37endchoice
diff --git a/scripts/kconfig/tests/new_choice_with_dep/__init__.py b/scripts/kconfig/tests/new_choice_with_dep/__init__.py
new file mode 100644
index 000000000000..f0e0ead0f32f
--- /dev/null
+++ b/scripts/kconfig/tests/new_choice_with_dep/__init__.py
@@ -0,0 +1,14 @@
1"""
2Ask new choice values when they become visible.
3
4If new choice values are added with new dependency, and they become
5visible during user configuration, oldconfig should recognize them
6as (NEW), and ask the user for choice.
7
8Related Linux commit: 5d09598d488f081e3be23f885ed65cbbe2d073b5
9"""
10
11
12def test(conf):
13 assert conf.oldconfig('config', 'y') == 0
14 assert conf.stdout_contains('expected_stdout')
diff --git a/scripts/kconfig/tests/new_choice_with_dep/config b/scripts/kconfig/tests/new_choice_with_dep/config
new file mode 100644
index 000000000000..47ef95d567fd
--- /dev/null
+++ b/scripts/kconfig/tests/new_choice_with_dep/config
@@ -0,0 +1,3 @@
1CONFIG_CHOICE_B=y
2# CONFIG_CHOICE_D is not set
3CONFIG_CHOICE_E=y
diff --git a/scripts/kconfig/tests/new_choice_with_dep/expected_stdout b/scripts/kconfig/tests/new_choice_with_dep/expected_stdout
new file mode 100644
index 000000000000..74dc0bcb22bc
--- /dev/null
+++ b/scripts/kconfig/tests/new_choice_with_dep/expected_stdout
@@ -0,0 +1,10 @@
1A (A) [N/y/?] (NEW) y
2 Choice ?
3 > 1. Choice B (CHOICE_B)
4 2. Choice C (CHOICE_C) (NEW)
5 choice[1-2?]:
6Choice2 ?
7 1. Choice D (CHOICE_D)
8> 2. Choice E (CHOICE_E)
9 3. Choice F (CHOICE_F) (NEW)
10choice[1-3?]:
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig b/scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig
new file mode 100644
index 000000000000..c00b8fe54f45
--- /dev/null
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig
@@ -0,0 +1,14 @@
1config A
2 bool "A"
3
4choice
5 prompt "Choice ?"
6 depends on A
7
8config CHOICE_B
9 bool "Choice B"
10
11config CHOICE_C
12 bool "Choice C"
13
14endchoice
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py b/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
new file mode 100644
index 000000000000..207261b0fe00
--- /dev/null
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
@@ -0,0 +1,19 @@
1"""
2Do not write choice values to .config if the dependency is unmet.
3
4"# CONFIG_... is not set" should not be written into the .config file
5for symbols with unmet dependency.
6
7This was not working correctly for choice values because choice needs
8a bit different symbol computation.
9
10This checks that no unneeded "# COFIG_... is not set" is contained in
11the .config file.
12
13Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59
14"""
15
16
17def test(conf):
18 assert conf.oldaskconfig('config', 'n') == 0
19 assert conf.config_matches('expected_config')
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/config b/scripts/kconfig/tests/no_write_if_dep_unmet/config
new file mode 100644
index 000000000000..abd280e2f616
--- /dev/null
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/config
@@ -0,0 +1 @@
CONFIG_A=y
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config b/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config
new file mode 100644
index 000000000000..0d15e41da475
--- /dev/null
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config
@@ -0,0 +1,5 @@
1#
2# Automatically generated file; DO NOT EDIT.
3# Linux Kernel Configuration
4#
5# CONFIG_A is not set
diff --git a/scripts/kconfig/tests/pytest.ini b/scripts/kconfig/tests/pytest.ini
new file mode 100644
index 000000000000..85d7ce8e448b
--- /dev/null
+++ b/scripts/kconfig/tests/pytest.ini
@@ -0,0 +1,7 @@
1[pytest]
2addopts = --verbose
3
4# Pytest requires that test files have unique names, because pytest imports
5# them as top-level modules. It is silly to prefix or suffix a test file with
6# the directory name that contains it. Use __init__.py for all test files.
7python_files = __init__.py
diff --git a/scripts/kconfig/tests/rand_nested_choice/Kconfig b/scripts/kconfig/tests/rand_nested_choice/Kconfig
new file mode 100644
index 000000000000..c591d512929f
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/Kconfig
@@ -0,0 +1,33 @@
1choice
2 prompt "choice"
3
4config A
5 bool "A"
6
7config B
8 bool "B"
9
10if B
11choice
12 prompt "sub choice"
13
14config C
15 bool "C"
16
17config D
18 bool "D"
19
20if D
21choice
22 prompt "subsub choice"
23
24config E
25 bool "E"
26
27endchoice
28endif # D
29
30endchoice
31endif # B
32
33endchoice
diff --git a/scripts/kconfig/tests/rand_nested_choice/__init__.py b/scripts/kconfig/tests/rand_nested_choice/__init__.py
new file mode 100644
index 000000000000..e729a4e85218
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/__init__.py
@@ -0,0 +1,16 @@
1"""
2Set random values recursively in nested choices.
3
4Kconfig can create a choice-in-choice structure by using 'if' statement.
5randconfig should correctly set random choice values.
6
7Related Linux commit: 3b9a19e08960e5cdad5253998637653e592a3c29
8"""
9
10
11def test(conf):
12 for i in range(20):
13 assert conf.randconfig() == 0
14 assert (conf.config_contains('expected_stdout0') or
15 conf.config_contains('expected_stdout1') or
16 conf.config_contains('expected_stdout2'))
diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout0 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout0
new file mode 100644
index 000000000000..05450f3d4eb5
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/expected_stdout0
@@ -0,0 +1,2 @@
1CONFIG_A=y
2# CONFIG_B is not set
diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout1 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout1
new file mode 100644
index 000000000000..37ab29584157
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/expected_stdout1
@@ -0,0 +1,4 @@
1# CONFIG_A is not set
2CONFIG_B=y
3CONFIG_C=y
4# CONFIG_D is not set
diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout2 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout2
new file mode 100644
index 000000000000..849ff47e9848
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/expected_stdout2
@@ -0,0 +1,5 @@
1# CONFIG_A is not set
2CONFIG_B=y
3# CONFIG_C is not set
4CONFIG_D=y
5CONFIG_E=y
diff --git a/scripts/kconfig/tests/warn_recursive_dep/Kconfig b/scripts/kconfig/tests/warn_recursive_dep/Kconfig
new file mode 100644
index 000000000000..a65bfcb7137e
--- /dev/null
+++ b/scripts/kconfig/tests/warn_recursive_dep/Kconfig
@@ -0,0 +1,62 @@
1# depends on itself
2
3config A
4 bool "A"
5 depends on A
6
7# select itself
8
9config B
10 bool
11 select B
12
13# depends on each other
14
15config C1
16 bool "C1"
17 depends on C2
18
19config C2
20 bool "C2"
21 depends on C1
22
23# depends on and select
24
25config D1
26 bool "D1"
27 depends on D2
28 select D2
29
30config D2
31 bool
32
33# depends on and imply
34# This is not recursive dependency
35
36config E1
37 bool "E1"
38 depends on E2
39 imply E2
40
41config E2
42 bool "E2"
43
44# property
45
46config F1
47 bool "F1"
48 default F2
49
50config F2
51 bool "F2"
52 depends on F1
53
54# menu
55
56menu "menu depending on its content"
57 depends on G
58
59config G
60 bool "G"
61
62endmenu
diff --git a/scripts/kconfig/tests/warn_recursive_dep/__init__.py b/scripts/kconfig/tests/warn_recursive_dep/__init__.py
new file mode 100644
index 000000000000..adb21951ba41
--- /dev/null
+++ b/scripts/kconfig/tests/warn_recursive_dep/__init__.py
@@ -0,0 +1,9 @@
1"""
2Warn recursive inclusion.
3
4Recursive dependency should be warned.
5"""
6
7def test(conf):
8 assert conf.oldaskconfig() == 0
9 assert conf.stderr_contains('expected_stderr')
diff --git a/scripts/kconfig/tests/warn_recursive_dep/expected_stderr b/scripts/kconfig/tests/warn_recursive_dep/expected_stderr
new file mode 100644
index 000000000000..3de807dd9cb2
--- /dev/null
+++ b/scripts/kconfig/tests/warn_recursive_dep/expected_stderr
@@ -0,0 +1,30 @@
1Kconfig:9:error: recursive dependency detected!
2Kconfig:9: symbol B is selected by B
3For a resolution refer to Documentation/kbuild/kconfig-language.txt
4subsection "Kconfig recursive dependency limitations"
5
6Kconfig:3:error: recursive dependency detected!
7Kconfig:3: symbol A depends on A
8For a resolution refer to Documentation/kbuild/kconfig-language.txt
9subsection "Kconfig recursive dependency limitations"
10
11Kconfig:15:error: recursive dependency detected!
12Kconfig:15: symbol C1 depends on C2
13Kconfig:19: symbol C2 depends on C1
14For a resolution refer to Documentation/kbuild/kconfig-language.txt
15subsection "Kconfig recursive dependency limitations"
16
17Kconfig:30:error: recursive dependency detected!
18Kconfig:30: symbol D2 is selected by D1
19Kconfig:25: symbol D1 depends on D2
20For a resolution refer to Documentation/kbuild/kconfig-language.txt
21subsection "Kconfig recursive dependency limitations"
22
23Kconfig:59:error: recursive dependency detected!
24Kconfig:59: symbol G depends on G
25For a resolution refer to Documentation/kbuild/kconfig-language.txt
26subsection "Kconfig recursive dependency limitations"
27
28Kconfig:50:error: recursive dependency detected!
29Kconfig:50: symbol F2 depends on F1
30Kconfig:48: symbol F1 default value contains F2
diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l
index 88b650eb9cc9..045093d827e1 100644
--- a/scripts/kconfig/zconf.l
+++ b/scripts/kconfig/zconf.l
@@ -1,5 +1,5 @@
1%option nostdinit noyywrap never-interactive full ecs 1%option nostdinit noyywrap never-interactive full ecs
2%option 8bit nodefault perf-report perf-report 2%option 8bit nodefault yylineno
3%option noinput 3%option noinput
4%x COMMAND HELP STRING PARAM 4%x COMMAND HELP STRING PARAM
5%{ 5%{
@@ -83,7 +83,6 @@ n [A-Za-z0-9_-]
83 83
84[ \t]*#.*\n | 84[ \t]*#.*\n |
85[ \t]*\n { 85[ \t]*\n {
86 current_file->lineno++;
87 return T_EOL; 86 return T_EOL;
88} 87}
89[ \t]*#.* 88[ \t]*#.*
@@ -104,7 +103,7 @@ n [A-Za-z0-9_-]
104 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); 103 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
105 BEGIN(PARAM); 104 BEGIN(PARAM);
106 current_pos.file = current_file; 105 current_pos.file = current_file;
107 current_pos.lineno = current_file->lineno; 106 current_pos.lineno = yylineno;
108 if (id && id->flags & TF_COMMAND) { 107 if (id && id->flags & TF_COMMAND) {
109 yylval.id = id; 108 yylval.id = id;
110 return id->token; 109 return id->token;
@@ -116,7 +115,6 @@ n [A-Za-z0-9_-]
116 . warn_ignored_character(*yytext); 115 . warn_ignored_character(*yytext);
117 \n { 116 \n {
118 BEGIN(INITIAL); 117 BEGIN(INITIAL);
119 current_file->lineno++;
120 return T_EOL; 118 return T_EOL;
121 } 119 }
122} 120}
@@ -138,7 +136,7 @@ n [A-Za-z0-9_-]
138 new_string(); 136 new_string();
139 BEGIN(STRING); 137 BEGIN(STRING);
140 } 138 }
141 \n BEGIN(INITIAL); current_file->lineno++; return T_EOL; 139 \n BEGIN(INITIAL); return T_EOL;
142 ({n}|[/.])+ { 140 ({n}|[/.])+ {
143 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); 141 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
144 if (id && id->flags & TF_PARAM) { 142 if (id && id->flags & TF_PARAM) {
@@ -150,7 +148,7 @@ n [A-Za-z0-9_-]
150 return T_WORD; 148 return T_WORD;
151 } 149 }
152 #.* /* comment */ 150 #.* /* comment */
153 \\\n current_file->lineno++; 151 \\\n ;
154 [[:blank:]]+ 152 [[:blank:]]+
155 . warn_ignored_character(*yytext); 153 . warn_ignored_character(*yytext);
156 <<EOF>> { 154 <<EOF>> {
@@ -187,7 +185,6 @@ n [A-Za-z0-9_-]
187 fprintf(stderr, 185 fprintf(stderr,
188 "%s:%d:warning: multi-line strings not supported\n", 186 "%s:%d:warning: multi-line strings not supported\n",
189 zconf_curname(), zconf_lineno()); 187 zconf_curname(), zconf_lineno());
190 current_file->lineno++;
191 BEGIN(INITIAL); 188 BEGIN(INITIAL);
192 return T_EOL; 189 return T_EOL;
193 } 190 }
@@ -220,12 +217,10 @@ n [A-Za-z0-9_-]
220 } 217 }
221 } 218 }
222 [ \t]*\n/[^ \t\n] { 219 [ \t]*\n/[^ \t\n] {
223 current_file->lineno++;
224 zconf_endhelp(); 220 zconf_endhelp();
225 return T_HELPTEXT; 221 return T_HELPTEXT;
226 } 222 }
227 [ \t]*\n { 223 [ \t]*\n {
228 current_file->lineno++;
229 append_string("\n", 1); 224 append_string("\n", 1);
230 } 225 }
231 [^ \t\n].* { 226 [^ \t\n].* {
@@ -304,7 +299,7 @@ void zconf_initscan(const char *name)
304 memset(current_buf, 0, sizeof(*current_buf)); 299 memset(current_buf, 0, sizeof(*current_buf));
305 300
306 current_file = file_lookup(name); 301 current_file = file_lookup(name);
307 current_file->lineno = 1; 302 yylineno = 1;
308} 303}
309 304
310void zconf_nextfile(const char *name) 305void zconf_nextfile(const char *name)
@@ -325,24 +320,26 @@ void zconf_nextfile(const char *name)
325 buf->parent = current_buf; 320 buf->parent = current_buf;
326 current_buf = buf; 321 current_buf = buf;
327 322
328 for (iter = current_file->parent; iter; iter = iter->parent ) { 323 current_file->lineno = yylineno;
329 if (!strcmp(current_file->name,iter->name) ) { 324 file->parent = current_file;
325
326 for (iter = current_file; iter; iter = iter->parent) {
327 if (!strcmp(iter->name, file->name)) {
330 fprintf(stderr, 328 fprintf(stderr,
331 "%s:%d: recursive inclusion detected. " 329 "Recursive inclusion detected.\n"
332 "Inclusion path:\n current file : '%s'\n", 330 "Inclusion path:\n"
333 zconf_curname(), zconf_lineno(), 331 " current file : %s\n", file->name);
334 zconf_curname()); 332 iter = file;
335 iter = current_file;
336 do { 333 do {
337 iter = iter->parent; 334 iter = iter->parent;
338 fprintf(stderr, " included from: '%s:%d'\n", 335 fprintf(stderr, " included from: %s:%d\n",
339 iter->name, iter->lineno - 1); 336 iter->name, iter->lineno - 1);
340 } while (strcmp(iter->name, current_file->name)); 337 } while (strcmp(iter->name, file->name));
341 exit(1); 338 exit(1);
342 } 339 }
343 } 340 }
344 file->lineno = 1; 341
345 file->parent = current_file; 342 yylineno = 1;
346 current_file = file; 343 current_file = file;
347} 344}
348 345
@@ -351,6 +348,8 @@ static void zconf_endfile(void)
351 struct buffer *parent; 348 struct buffer *parent;
352 349
353 current_file = current_file->parent; 350 current_file = current_file->parent;
351 if (current_file)
352 yylineno = current_file->lineno;
354 353
355 parent = current_buf->parent; 354 parent = current_buf->parent;
356 if (parent) { 355 if (parent) {