diff options
Diffstat (limited to 'scripts')
55 files changed, 1037 insertions, 135 deletions
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) { |
