diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-03 19:28:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-03 19:28:01 -0400 |
commit | 147a89bc71e7db40f011454a40add7ff2d10f8d8 (patch) | |
tree | 72f2f1355c6121c40124206c7d4ac82632f1690d | |
parent | 3b24b83763e72a6c1e728100104fd99aa83a7b3b (diff) | |
parent | 18492685e479fd4d8e1dca836f57c11b6800f083 (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
...
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 | ______________________________________________________________________ |
122 | Environment variables for 'silentoldconfig' | 122 | Environment variables for 'syncconfig' |
123 | 123 | ||
124 | KCONFIG_NOSILENTUPDATE | 124 | KCONFIG_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 | |||
32 | The driver is enabled via the standard kernel configuration system, | 32 | The driver is enabled via the standard kernel configuration system, |
33 | using the make command: | 33 | using the make command: |
34 | 34 | ||
35 | Make oldconfig/silentoldconfig/menuconfig/etc. | 35 | make config/oldconfig/menuconfig/etc. |
36 | 36 | ||
37 | The driver is located in the menu structure at: | 37 | The driver is located in the menu structure at: |
38 | 38 | ||
@@ -386,6 +386,8 @@ INSTALLKERNEL := installkernel | |||
386 | DEPMOD = /sbin/depmod | 386 | DEPMOD = /sbin/depmod |
387 | PERL = perl | 387 | PERL = perl |
388 | PYTHON = python | 388 | PYTHON = python |
389 | PYTHON2 = python2 | ||
390 | PYTHON3 = python3 | ||
389 | CHECK = sparse | 391 | CHECK = sparse |
390 | 392 | ||
391 | CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ | 393 | CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ |
@@ -432,7 +434,7 @@ GCC_PLUGINS_CFLAGS := | |||
432 | 434 | ||
433 | export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC | 435 | export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC |
434 | export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES | 436 | export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES |
435 | export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE | 437 | export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE |
436 | export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS | 438 | export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS |
437 | 439 | ||
438 | export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS | 440 | export 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). |
593 | include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd | 595 | include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd |
594 | $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig | 596 | $(Q)$(MAKE) -f $(srctree)/Makefile syncconfig |
595 | else | 597 | else |
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 | ||
6 | PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \ | 6 | PHONY += xconfig gconfig menuconfig config syncconfig update-po-config \ |
7 | localmodconfig localyesconfig | 7 | localmodconfig localyesconfig |
8 | 8 | ||
9 | ifdef KBUILD_KCONFIG | 9 | ifdef 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. |
39 | silentoldconfig: $(obj)/conf | 39 | syncconfig: $(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 | ||
43 | localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf | 43 | localyesconfig 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 | ||
89 | PHONY += oldnoconfig savedefconfig defconfig | 89 | PHONY += 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"). | ||
99 | silentoldconfig: 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 | |||
98 | savedefconfig: $(obj)/conf | 105 | savedefconfig: $(obj)/conf |
99 | $< $(silent) --$@=defconfig $(Kconfig) | 106 | $< $(silent) --$@=defconfig $(Kconfig) |
100 | 107 | ||
@@ -133,6 +140,14 @@ PHONY += tinyconfig | |||
133 | tinyconfig: | 140 | tinyconfig: |
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? | ||
144 | PHONY += testconfig | ||
145 | testconfig: $(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) | ||
149 | clean-dirs += tests/.cache | ||
150 | |||
136 | # Help text used by make help | 151 | # Help text used by make help |
137 | help: | 152 | help: |
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 | ||
24 | enum input_mode { | 24 | enum 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) | |||
440 | static struct option long_opts[] = { | 441 | static 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 | ||
1140 | static inline struct expr * | 1140 | void expr_print(struct expr *e, |
1141 | expr_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 | */ | ||
1157 | struct 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 | |||
1182 | static 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 | ||
1277 | void 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 | |||
1282 | static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) | 1232 | static 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 | */ |
1332 | void expr_gstr_print_revdep(struct expr *e, struct gstr *gs) | 1282 | static 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 | |||
1301 | void 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); | |||
305 | int expr_contains_symbol(struct expr *dep, struct symbol *sym); | 305 | int expr_contains_symbol(struct expr *dep, struct symbol *sym); |
306 | bool expr_depends_symbol(struct expr *dep, struct symbol *sym); | 306 | bool expr_depends_symbol(struct expr *dep, struct symbol *sym); |
307 | struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); | 307 | struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); |
308 | struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); | ||
309 | 308 | ||
310 | void expr_fprint(struct expr *e, FILE *out); | 309 | void expr_fprint(struct expr *e, FILE *out); |
311 | struct gstr; /* forward */ | 310 | struct gstr; /* forward */ |
312 | void expr_gstr_print(struct expr *e, struct gstr *gs); | 311 | void expr_gstr_print(struct expr *e, struct gstr *gs); |
313 | void expr_gstr_print_revdep(struct expr *e, struct gstr *gs); | 312 | void expr_gstr_print_revdep(struct expr *e, struct gstr *gs, |
313 | tristate pr_type, const char *title); | ||
314 | 314 | ||
315 | static inline int expr_is_yes(struct expr *e) | 315 | static 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 | ||
71 | extern int yylineno; | ||
71 | void zconfdump(FILE *out); | 72 | void zconfdump(FILE *out); |
72 | void zconf_starthelp(void); | 73 | void zconf_starthelp(void); |
73 | FILE *zconf_fopen(const char *name); | 74 | FILE *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 | ||
336 | static 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 | |||
336 | void sym_calc_value(struct symbol *sym) | 357 | void 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 @@ | |||
1 | config A | ||
2 | bool "A" | ||
3 | default y | ||
4 | |||
5 | config 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 | |||
12 | config 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 | |||
19 | config A1 | ||
20 | bool "A1" | ||
21 | depends on A | ||
22 | default y | ||
23 | help | ||
24 | This should line up with A0. | ||
25 | |||
26 | choice | ||
27 | prompt "choice" | ||
28 | depends on A1 | ||
29 | help | ||
30 | Choice should become a submenu as well. | ||
31 | |||
32 | config A1_0 | ||
33 | bool "A1_0" | ||
34 | |||
35 | config A1_1 | ||
36 | bool "A1_1" | ||
37 | |||
38 | endchoice | ||
39 | |||
40 | config B | ||
41 | bool "B" | ||
42 | help | ||
43 | This is independent of A. | ||
44 | |||
45 | config 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 | """ | ||
2 | Create submenu for symbols that depend on the preceding one. | ||
3 | |||
4 | If a symbols has dependency on the preceding symbol, the menu entry | ||
5 | should become the submenu of the preceding one, and displayed with | ||
6 | deeper indentation. | ||
7 | """ | ||
8 | |||
9 | |||
10 | def 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 @@ | |||
1 | A (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?]: | ||
9 | B (B) [N/y/?] (NEW) | ||
10 | C (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 @@ | |||
1 | config MODULES | ||
2 | bool "Enable loadable module support" | ||
3 | option modules | ||
4 | default y | ||
5 | |||
6 | choice | ||
7 | prompt "boolean choice" | ||
8 | default BOOL_CHOICE1 | ||
9 | |||
10 | config BOOL_CHOICE0 | ||
11 | bool "choice 0" | ||
12 | |||
13 | config BOOL_CHOICE1 | ||
14 | bool "choice 1" | ||
15 | |||
16 | endchoice | ||
17 | |||
18 | choice | ||
19 | prompt "optional boolean choice" | ||
20 | optional | ||
21 | default OPT_BOOL_CHOICE1 | ||
22 | |||
23 | config OPT_BOOL_CHOICE0 | ||
24 | bool "choice 0" | ||
25 | |||
26 | config OPT_BOOL_CHOICE1 | ||
27 | bool "choice 1" | ||
28 | |||
29 | endchoice | ||
30 | |||
31 | choice | ||
32 | prompt "tristate choice" | ||
33 | default TRI_CHOICE1 | ||
34 | |||
35 | config TRI_CHOICE0 | ||
36 | tristate "choice 0" | ||
37 | |||
38 | config TRI_CHOICE1 | ||
39 | tristate "choice 1" | ||
40 | |||
41 | endchoice | ||
42 | |||
43 | choice | ||
44 | prompt "optional tristate choice" | ||
45 | optional | ||
46 | default OPT_TRI_CHOICE1 | ||
47 | |||
48 | config OPT_TRI_CHOICE0 | ||
49 | tristate "choice 0" | ||
50 | |||
51 | config OPT_TRI_CHOICE1 | ||
52 | tristate "choice 1" | ||
53 | |||
54 | endchoice | ||
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 | """ | ||
2 | Basic choice tests. | ||
3 | |||
4 | The handling of 'choice' is a bit complicated part in Kconfig. | ||
5 | |||
6 | The behavior of 'y' choice is intuitive. If choice values are tristate, | ||
7 | the choice can be 'm' where each value can be enabled independently. | ||
8 | Also, if a choice is marked as 'optional', the whole choice can be | ||
9 | invisible. | ||
10 | """ | ||
11 | |||
12 | |||
13 | def test_oldask0(conf): | ||
14 | assert conf.oldaskconfig() == 0 | ||
15 | assert conf.stdout_contains('oldask0_expected_stdout') | ||
16 | |||
17 | |||
18 | def test_oldask1(conf): | ||
19 | assert conf.oldaskconfig('oldask1_config') == 0 | ||
20 | assert conf.stdout_contains('oldask1_expected_stdout') | ||
21 | |||
22 | |||
23 | def test_allyes(conf): | ||
24 | assert conf.allyesconfig() == 0 | ||
25 | assert conf.config_contains('allyes_expected_config') | ||
26 | |||
27 | |||
28 | def test_allmod(conf): | ||
29 | assert conf.allmodconfig() == 0 | ||
30 | assert conf.config_contains('allmod_expected_config') | ||
31 | |||
32 | |||
33 | def test_allno(conf): | ||
34 | assert conf.allnoconfig() == 0 | ||
35 | assert conf.config_contains('allno_expected_config') | ||
36 | |||
37 | |||
38 | def 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 @@ | |||
1 | CONFIG_MODULES=y | ||
2 | # CONFIG_BOOL_CHOICE0 is not set | ||
3 | CONFIG_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 @@ | |||
1 | CONFIG_MODULES=y | ||
2 | # CONFIG_BOOL_CHOICE0 is not set | ||
3 | CONFIG_BOOL_CHOICE1=y | ||
4 | # CONFIG_OPT_BOOL_CHOICE0 is not set | ||
5 | CONFIG_OPT_BOOL_CHOICE1=y | ||
6 | CONFIG_TRI_CHOICE0=m | ||
7 | CONFIG_TRI_CHOICE1=m | ||
8 | CONFIG_OPT_TRI_CHOICE0=m | ||
9 | CONFIG_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 | ||
3 | CONFIG_BOOL_CHOICE1=y | ||
4 | # CONFIG_TRI_CHOICE0 is not set | ||
5 | CONFIG_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 @@ | |||
1 | CONFIG_MODULES=y | ||
2 | # CONFIG_BOOL_CHOICE0 is not set | ||
3 | CONFIG_BOOL_CHOICE1=y | ||
4 | # CONFIG_OPT_BOOL_CHOICE0 is not set | ||
5 | CONFIG_OPT_BOOL_CHOICE1=y | ||
6 | # CONFIG_TRI_CHOICE0 is not set | ||
7 | CONFIG_TRI_CHOICE1=y | ||
8 | # CONFIG_OPT_TRI_CHOICE0 is not set | ||
9 | CONFIG_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 @@ | |||
1 | Enable loadable module support (MODULES) [Y/n/?] (NEW) | ||
2 | boolean choice | ||
3 | 1. choice 0 (BOOL_CHOICE0) (NEW) | ||
4 | > 2. choice 1 (BOOL_CHOICE1) (NEW) | ||
5 | choice[1-2?]: | ||
6 | optional boolean choice [N/y/?] (NEW) | ||
7 | tristate choice [M/y/?] (NEW) | ||
8 | choice 0 (TRI_CHOICE0) [N/m/?] (NEW) | ||
9 | choice 1 (TRI_CHOICE1) [N/m/?] (NEW) | ||
10 | optional 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 | ||
2 | CONFIG_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 @@ | |||
1 | Enable loadable module support (MODULES) [N/y/?] | ||
2 | boolean choice | ||
3 | 1. choice 0 (BOOL_CHOICE0) (NEW) | ||
4 | > 2. choice 1 (BOOL_CHOICE1) (NEW) | ||
5 | choice[1-2?]: | ||
6 | optional boolean choice [Y/n/?] (NEW) | ||
7 | optional boolean choice | ||
8 | > 1. choice 0 (OPT_BOOL_CHOICE0) | ||
9 | 2. choice 1 (OPT_BOOL_CHOICE1) (NEW) | ||
10 | choice[1-2?]: | ||
11 | tristate choice | ||
12 | 1. choice 0 (TRI_CHOICE0) (NEW) | ||
13 | > 2. choice 1 (TRI_CHOICE1) (NEW) | ||
14 | choice[1-2?]: | ||
15 | optional 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 @@ | |||
1 | config MODULES | ||
2 | def_bool y | ||
3 | option modules | ||
4 | |||
5 | config DEP | ||
6 | tristate | ||
7 | default m | ||
8 | |||
9 | choice | ||
10 | prompt "Tristate Choice" | ||
11 | |||
12 | config CHOICE0 | ||
13 | tristate "Choice 0" | ||
14 | |||
15 | config CHOICE1 | ||
16 | tristate "Choice 1" | ||
17 | depends on DEP | ||
18 | |||
19 | endchoice | ||
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 | """ | ||
2 | Hide tristate choice values with mod dependency in y choice. | ||
3 | |||
4 | If tristate choice values depend on symbols set to 'm', they should be | ||
5 | hidden when the choice containing them is changed from 'm' to 'y' | ||
6 | (i.e. exclusive choice). | ||
7 | |||
8 | Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074 | ||
9 | """ | ||
10 | |||
11 | |||
12 | def 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 @@ | |||
1 | CONFIG_CHOICE0=m | ||
2 | CONFIG_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 @@ | |||
1 | CONFIG_MODULES=y | ||
2 | CONFIG_DEP=m | ||
3 | CONFIG_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 @@ | |||
1 | Tristate Choice [M/y/?] y | ||
2 | Tristate Choice | ||
3 | > 1. Choice 0 (CHOICE0) | ||
4 | choice[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 | """ | ||
7 | Kconfig unit testing framework. | ||
8 | |||
9 | This provides fixture functions commonly used from test files. | ||
10 | """ | ||
11 | |||
12 | import os | ||
13 | import pytest | ||
14 | import shutil | ||
15 | import subprocess | ||
16 | import tempfile | ||
17 | |||
18 | CONF_PATH = os.path.abspath(os.path.join('scripts', 'kconfig', 'conf')) | ||
19 | |||
20 | |||
21 | class 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") | ||
289 | def 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 | |||
4 | source "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 | |||
3 | source "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 | """ | ||
2 | Detect recursive inclusion error. | ||
3 | |||
4 | If recursive inclusion is detected, it should fail with error messages. | ||
5 | """ | ||
6 | |||
7 | |||
8 | def 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 @@ | |||
1 | Recursive inclusion detected. | ||
2 | Inclusion 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 @@ | |||
1 | config MODULES | ||
2 | def_bool y | ||
3 | option modules | ||
4 | |||
5 | choice | ||
6 | prompt "Choice" | ||
7 | |||
8 | config CHOICE_VAL0 | ||
9 | tristate "Choice 0" | ||
10 | |||
11 | config CHOIVE_VAL1 | ||
12 | tristate "Choice 1" | ||
13 | |||
14 | endchoice | ||
15 | |||
16 | choice | ||
17 | prompt "Another choice" | ||
18 | depends on CHOICE_VAL0 | ||
19 | |||
20 | config DUMMY | ||
21 | bool "dummy" | ||
22 | |||
23 | endchoice | ||
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 | """ | ||
2 | Do not affect user-assigned choice value by another choice. | ||
3 | |||
4 | Handling of state flags for choices is complecated. In old days, | ||
5 | the defconfig result of a choice could be affected by another choice | ||
6 | if those choices interact by 'depends on', 'select', etc. | ||
7 | |||
8 | Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a | ||
9 | """ | ||
10 | |||
11 | |||
12 | def 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 @@ | |||
1 | CONFIG_MODULES=y | ||
2 | CONFIG_CHOICE_VAL0=y | ||
3 | # CONFIG_CHOIVE_VAL1 is not set | ||
4 | CONFIG_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 @@ | |||
1 | config A | ||
2 | bool "A" | ||
3 | help | ||
4 | This is a new symbol. | ||
5 | |||
6 | choice | ||
7 | prompt "Choice ?" | ||
8 | depends on A | ||
9 | help | ||
10 | "depends on A" has been newly added. | ||
11 | |||
12 | config CHOICE_B | ||
13 | bool "Choice B" | ||
14 | |||
15 | config CHOICE_C | ||
16 | bool "Choice C" | ||
17 | help | ||
18 | This is a new symbol, so should be asked. | ||
19 | |||
20 | endchoice | ||
21 | |||
22 | choice | ||
23 | prompt "Choice2 ?" | ||
24 | |||
25 | config CHOICE_D | ||
26 | bool "Choice D" | ||
27 | |||
28 | config CHOICE_E | ||
29 | bool "Choice E" | ||
30 | |||
31 | config CHOICE_F | ||
32 | bool "Choice F" | ||
33 | depends on A | ||
34 | help | ||
35 | This is a new symbol, so should be asked. | ||
36 | |||
37 | endchoice | ||
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 | """ | ||
2 | Ask new choice values when they become visible. | ||
3 | |||
4 | If new choice values are added with new dependency, and they become | ||
5 | visible during user configuration, oldconfig should recognize them | ||
6 | as (NEW), and ask the user for choice. | ||
7 | |||
8 | Related Linux commit: 5d09598d488f081e3be23f885ed65cbbe2d073b5 | ||
9 | """ | ||
10 | |||
11 | |||
12 | def 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 @@ | |||
1 | CONFIG_CHOICE_B=y | ||
2 | # CONFIG_CHOICE_D is not set | ||
3 | CONFIG_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 @@ | |||
1 | A (A) [N/y/?] (NEW) y | ||
2 | Choice ? | ||
3 | > 1. Choice B (CHOICE_B) | ||
4 | 2. Choice C (CHOICE_C) (NEW) | ||
5 | choice[1-2?]: | ||
6 | Choice2 ? | ||
7 | 1. Choice D (CHOICE_D) | ||
8 | > 2. Choice E (CHOICE_E) | ||
9 | 3. Choice F (CHOICE_F) (NEW) | ||
10 | choice[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 @@ | |||
1 | config A | ||
2 | bool "A" | ||
3 | |||
4 | choice | ||
5 | prompt "Choice ?" | ||
6 | depends on A | ||
7 | |||
8 | config CHOICE_B | ||
9 | bool "Choice B" | ||
10 | |||
11 | config CHOICE_C | ||
12 | bool "Choice C" | ||
13 | |||
14 | endchoice | ||
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 | """ | ||
2 | Do 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 | ||
5 | for symbols with unmet dependency. | ||
6 | |||
7 | This was not working correctly for choice values because choice needs | ||
8 | a bit different symbol computation. | ||
9 | |||
10 | This checks that no unneeded "# COFIG_... is not set" is contained in | ||
11 | the .config file. | ||
12 | |||
13 | Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59 | ||
14 | """ | ||
15 | |||
16 | |||
17 | def 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] | ||
2 | addopts = --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. | ||
7 | python_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 @@ | |||
1 | choice | ||
2 | prompt "choice" | ||
3 | |||
4 | config A | ||
5 | bool "A" | ||
6 | |||
7 | config B | ||
8 | bool "B" | ||
9 | |||
10 | if B | ||
11 | choice | ||
12 | prompt "sub choice" | ||
13 | |||
14 | config C | ||
15 | bool "C" | ||
16 | |||
17 | config D | ||
18 | bool "D" | ||
19 | |||
20 | if D | ||
21 | choice | ||
22 | prompt "subsub choice" | ||
23 | |||
24 | config E | ||
25 | bool "E" | ||
26 | |||
27 | endchoice | ||
28 | endif # D | ||
29 | |||
30 | endchoice | ||
31 | endif # B | ||
32 | |||
33 | endchoice | ||
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 | """ | ||
2 | Set random values recursively in nested choices. | ||
3 | |||
4 | Kconfig can create a choice-in-choice structure by using 'if' statement. | ||
5 | randconfig should correctly set random choice values. | ||
6 | |||
7 | Related Linux commit: 3b9a19e08960e5cdad5253998637653e592a3c29 | ||
8 | """ | ||
9 | |||
10 | |||
11 | def 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 @@ | |||
1 | CONFIG_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 | ||
2 | CONFIG_B=y | ||
3 | CONFIG_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 | ||
2 | CONFIG_B=y | ||
3 | # CONFIG_C is not set | ||
4 | CONFIG_D=y | ||
5 | CONFIG_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 | |||
3 | config A | ||
4 | bool "A" | ||
5 | depends on A | ||
6 | |||
7 | # select itself | ||
8 | |||
9 | config B | ||
10 | bool | ||
11 | select B | ||
12 | |||
13 | # depends on each other | ||
14 | |||
15 | config C1 | ||
16 | bool "C1" | ||
17 | depends on C2 | ||
18 | |||
19 | config C2 | ||
20 | bool "C2" | ||
21 | depends on C1 | ||
22 | |||
23 | # depends on and select | ||
24 | |||
25 | config D1 | ||
26 | bool "D1" | ||
27 | depends on D2 | ||
28 | select D2 | ||
29 | |||
30 | config D2 | ||
31 | bool | ||
32 | |||
33 | # depends on and imply | ||
34 | # This is not recursive dependency | ||
35 | |||
36 | config E1 | ||
37 | bool "E1" | ||
38 | depends on E2 | ||
39 | imply E2 | ||
40 | |||
41 | config E2 | ||
42 | bool "E2" | ||
43 | |||
44 | # property | ||
45 | |||
46 | config F1 | ||
47 | bool "F1" | ||
48 | default F2 | ||
49 | |||
50 | config F2 | ||
51 | bool "F2" | ||
52 | depends on F1 | ||
53 | |||
54 | # menu | ||
55 | |||
56 | menu "menu depending on its content" | ||
57 | depends on G | ||
58 | |||
59 | config G | ||
60 | bool "G" | ||
61 | |||
62 | endmenu | ||
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 | """ | ||
2 | Warn recursive inclusion. | ||
3 | |||
4 | Recursive dependency should be warned. | ||
5 | """ | ||
6 | |||
7 | def 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 @@ | |||
1 | Kconfig:9:error: recursive dependency detected! | ||
2 | Kconfig:9: symbol B is selected by B | ||
3 | For a resolution refer to Documentation/kbuild/kconfig-language.txt | ||
4 | subsection "Kconfig recursive dependency limitations" | ||
5 | |||
6 | Kconfig:3:error: recursive dependency detected! | ||
7 | Kconfig:3: symbol A depends on A | ||
8 | For a resolution refer to Documentation/kbuild/kconfig-language.txt | ||
9 | subsection "Kconfig recursive dependency limitations" | ||
10 | |||
11 | Kconfig:15:error: recursive dependency detected! | ||
12 | Kconfig:15: symbol C1 depends on C2 | ||
13 | Kconfig:19: symbol C2 depends on C1 | ||
14 | For a resolution refer to Documentation/kbuild/kconfig-language.txt | ||
15 | subsection "Kconfig recursive dependency limitations" | ||
16 | |||
17 | Kconfig:30:error: recursive dependency detected! | ||
18 | Kconfig:30: symbol D2 is selected by D1 | ||
19 | Kconfig:25: symbol D1 depends on D2 | ||
20 | For a resolution refer to Documentation/kbuild/kconfig-language.txt | ||
21 | subsection "Kconfig recursive dependency limitations" | ||
22 | |||
23 | Kconfig:59:error: recursive dependency detected! | ||
24 | Kconfig:59: symbol G depends on G | ||
25 | For a resolution refer to Documentation/kbuild/kconfig-language.txt | ||
26 | subsection "Kconfig recursive dependency limitations" | ||
27 | |||
28 | Kconfig:50:error: recursive dependency detected! | ||
29 | Kconfig:50: symbol F2 depends on F1 | ||
30 | Kconfig: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 | ||
310 | void zconf_nextfile(const char *name) | 305 | void 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) { |