History

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 ...

Linus Torvalds committed 8 years ago

Commit 147a89b2 parents 3b24b83 184926858 files · +1043 −139Browse files

Showing the changes to scripts (55 of 58 files). Show all

Unified · Split

55 files
  1. scripts/checkpatch.pl +17 −4
  2. scripts/kconfig/Makefile +22 −7
  3. scripts/kconfig/conf.c +21 −20
  4. scripts/kconfig/expr.c +28 −58
  5. scripts/kconfig/expr.h +2 −2
  6. scripts/kconfig/lkc.h +1 −0
  7. scripts/kconfig/menu.c +6 −6
  8. scripts/kconfig/nconf.h +1 −3
  9. scripts/kconfig/symbol.c +26 −14
  10. scripts/kconfig/tests/auto_submenu/Kconfig +50 −0
  11. scripts/kconfig/tests/auto_submenu/__init__.py +12 −0
  12. scripts/kconfig/tests/auto_submenu/expected_stdout +10 −0
  13. scripts/kconfig/tests/choice/Kconfig +54 −0
  14. scripts/kconfig/tests/choice/__init__.py +40 −0
  15. scripts/kconfig/tests/choice/alldef_expected_config +5 −0
  16. scripts/kconfig/tests/choice/allmod_expected_config +9 −0
  17. scripts/kconfig/tests/choice/allno_expected_config +5 −0
  18. scripts/kconfig/tests/choice/allyes_expected_config +9 −0
  19. scripts/kconfig/tests/choice/oldask0_expected_stdout +10 −0
  20. scripts/kconfig/tests/choice/oldask1_config +2 −0
  21. scripts/kconfig/tests/choice/oldask1_expected_stdout +15 −0
  22. scripts/kconfig/tests/choice_value_with_m_dep/Kconfig +19 −0
  23. scripts/kconfig/tests/choice_value_with_m_dep/__init__.py +15 −0
  24. scripts/kconfig/tests/choice_value_with_m_dep/config +2 −0
  25. scripts/kconfig/tests/choice_value_with_m_dep/expected_config +3 −0
  26. scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout +4 −0
  27. scripts/kconfig/tests/conftest.py +291 −0
  28. scripts/kconfig/tests/err_recursive_inc/Kconfig +1 −0
  29. scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1 +4 −0
  30. scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2 +3 −0
  31. scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3 +1 −0
  32. scripts/kconfig/tests/err_recursive_inc/__init__.py +10 −0
  33. scripts/kconfig/tests/err_recursive_inc/expected_stderr +6 −0
  34. scripts/kconfig/tests/inter_choice/Kconfig +23 −0
  35. scripts/kconfig/tests/inter_choice/__init__.py +14 −0
  36. scripts/kconfig/tests/inter_choice/defconfig +1 −0
  37. scripts/kconfig/tests/inter_choice/expected_config +4 −0
  38. scripts/kconfig/tests/new_choice_with_dep/Kconfig +37 −0
  39. scripts/kconfig/tests/new_choice_with_dep/__init__.py +14 −0
  40. scripts/kconfig/tests/new_choice_with_dep/config +3 −0
  41. scripts/kconfig/tests/new_choice_with_dep/expected_stdout +10 −0
  42. scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig +14 −0
  43. scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py +19 −0
  44. scripts/kconfig/tests/no_write_if_dep_unmet/config +1 −0
  45. scripts/kconfig/tests/no_write_if_dep_unmet/expected_config +5 −0
  46. scripts/kconfig/tests/pytest.ini +7 −0
  47. scripts/kconfig/tests/rand_nested_choice/Kconfig +33 −0
  48. scripts/kconfig/tests/rand_nested_choice/__init__.py +16 −0
  49. scripts/kconfig/tests/rand_nested_choice/expected_stdout0 +2 −0
  50. scripts/kconfig/tests/rand_nested_choice/expected_stdout1 +4 −0
  51. scripts/kconfig/tests/rand_nested_choice/expected_stdout2 +5 −0
  52. scripts/kconfig/tests/warn_recursive_dep/Kconfig +62 −0
  53. scripts/kconfig/tests/warn_recursive_dep/__init__.py +9 −0
  54. scripts/kconfig/tests/warn_recursive_dep/expected_stderr +30 −0
  55. scripts/kconfig/zconf.l +20 −21
scripts/checkpatch.pl+17−4
@@ -2797,7 +2797,10 @@ sub process { · 2796 unmodified lines
27972797 # Only applies when adding the entry originally, after that we do not have
27982798 # sufficient context to determine whether it is indeed long enough.
27992799 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/) {
28012804 my $length = 0;
28022805 my $cnt = $realcnt;
28032806 my $ln = $linenr + 1;
@@ -2812,9 +2815,13 @@ sub process { · 8 unmodified lines
28122815 next if ($f =~ /^-/);
28132816 last if (!$file && $f =~ /^\@\@/);
28142817
2815− if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) {
2818+ if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) {
28162819 $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+ }
28182825 $length = -1;
28192826 }
28202827
@@ -2822,7 +2829,13 @@ sub process { · 1 unmodified line
28222829 $f =~ s/#.*//;
28232830 $f =~ s/^\s+//;
28242831 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) {
28262839 $is_end = 1;
28272840 last;
28282841 }
scripts/kconfig/Makefile+22−7
@@ -3,7 +3,7 @@ · 2 unmodified lines
33 # Kernel configuration targets
44 # These targets are used from top-level makefile
55
6−PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \
6+PHONY += xconfig gconfig menuconfig config syncconfig update-po-config \
77 localmodconfig localyesconfig
88
99 ifdef KBUILD_KCONFIG
@@ -36,22 +36,22 @@ nconfig: $(obj)/nconf · 26 unmodified lines
3636
3737 # This has become an internal implementation detail and is now deprecated
3838 # for external use.
39−silentoldconfig: $(obj)/conf
39+syncconfig: $(obj)/conf
4040 $(Q)mkdir -p include/config include/generated
4141 $< $(silent) --$@ $(Kconfig)
4242
43−localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
43+localyesconfig localmodconfig: $(obj)/conf
4444 $(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
4646 $(Q)if [ -f .config ]; then \
4747 cmp -s .tmp.config .config || \
4848 (mv -f .config .config.old.1; \
4949 mv -f .tmp.config .config; \
50− $(obj)/conf $(silent) --silentoldconfig $(Kconfig); \
50+ $< $(silent) --oldconfig $(Kconfig); \
5151 mv -f .config.old.1 .config.old) \
5252 else \
5353 mv -f .tmp.config .config; \
54− $(obj)/conf $(silent) --silentoldconfig $(Kconfig); \
54+ $< $(silent) --oldconfig $(Kconfig); \
5555 fi
5656 $(Q)rm -f .tmp.config
5757
@@ -86,7 +86,7 @@ PHONY += $(simple-targets) · 28 unmodified lines
8686 $(simple-targets): $(obj)/conf
8787 $< $(silent) --$@ $(Kconfig)
8888
89−PHONY += oldnoconfig savedefconfig defconfig
89+PHONY += oldnoconfig silentoldconfig savedefconfig defconfig
9090
9191 # oldnoconfig is an alias of olddefconfig, because people already are dependent
9292 # on its behavior (sets new symbols to their default value but not 'n') with the
@@ -95,6 +95,13 @@ oldnoconfig: olddefconfig · 2 unmodified lines
9595 @echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19"
9696 @echo " Please use \"olddefconfig\" instead, which is an alias."
9797
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+
98105 savedefconfig: $(obj)/conf
99106 $< $(silent) --$@=defconfig $(Kconfig)
100107
@@ -133,6 +140,14 @@ PHONY += tinyconfig · 32 unmodified lines
133140 tinyconfig:
134141 $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
135142
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+
136151 # Help text used by make help
137152 help:
138153 @echo ' config - Update current config utilising a line-oriented program'
scripts/kconfig/conf.c+21−20
@@ -23,7 +23,7 @@ static void check_conf(struct menu *menu); · 22 unmodified lines
2323
2424 enum input_mode {
2525 oldaskconfig,
26− silentoldconfig,
26+ syncconfig,
2727 oldconfig,
2828 allnoconfig,
2929 allyesconfig,
@@ -100,7 +100,7 @@ static int conf_askvalue(struct symbol *sym, const char *def) · 70 unmodified lines
100100
101101 switch (input_mode) {
102102 case oldconfig:
103− case silentoldconfig:
103+ case syncconfig:
104104 if (sym_has_value(sym)) {
105105 printf("%s\n", def);
106106 return 0;
@@ -293,7 +293,7 @@ static int conf_choice(struct menu *menu) · 186 unmodified lines
293293 printf("[1-%d?]: ", cnt);
294294 switch (input_mode) {
295295 case oldconfig:
296− case silentoldconfig:
296+ case syncconfig:
297297 if (!is_new) {
298298 cnt = def;
299299 printf("%d\n", cnt);
@@ -358,10 +358,11 @@ static void conf(struct menu *menu) · 58 unmodified lines
358358
359359 switch (prop->type) {
360360 case P_MENU:
361− if ((input_mode == silentoldconfig ||
362− input_mode == listnewconfig ||
363− input_mode == olddefconfig) &&
364− rootEntry != menu) {
361+ /*
362+ * Except in oldaskconfig mode, we show only menus that
363+ * contain new symbols.
364+ */
365+ if (input_mode != oldaskconfig && rootEntry != menu) {
365366 check_conf(menu);
366367 return;
367368 }
@@ -424,7 +425,7 @@ static void check_conf(struct menu *menu) · 56 unmodified lines
424425 if (sym->name && !sym_is_choice_value(sym)) {
425426 printf("%s%s\n", CONFIG_, sym->name);
426427 }
427− } else if (input_mode != olddefconfig) {
428+ } else {
428429 if (!conf_cnt++)
429430 printf(_("*\n* Restart config...\n*\n"));
430431 rootEntry = menu_get_parent_menu(menu);
@@ -440,7 +441,7 @@ static void check_conf(struct menu *menu) · 9 unmodified lines
440441 static struct option long_opts[] = {
441442 {"oldaskconfig", no_argument, NULL, oldaskconfig},
442443 {"oldconfig", no_argument, NULL, oldconfig},
443− {"silentoldconfig", no_argument, NULL, silentoldconfig},
444+ {"syncconfig", no_argument, NULL, syncconfig},
444445 {"defconfig", optional_argument, NULL, defconfig},
445446 {"savedefconfig", required_argument, NULL, savedefconfig},
446447 {"allnoconfig", no_argument, NULL, allnoconfig},
@@ -467,8 +468,8 @@ static void conf_usage(const char *progname) · 20 unmodified lines
467468 printf(" --listnewconfig List new options\n");
468469 printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
469470 printf(" --oldconfig Update a configuration using a provided .config as base\n");
470− printf(" --silentoldconfig Similar to oldconfig but generates configuration in\n"
471− " include/{generated/,config/} (oldconfig used to be more verbose)\n");
471+ printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
472+ " include/{generated/,config/}\n");
472473 printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
473474 printf(" --oldnoconfig An alias of olddefconfig\n");
474475 printf(" --defconfig <file> New config with default defined in <file>\n");
@@ -500,7 +501,7 @@ int main(int ac, char **av) · 25 unmodified lines
500501 }
501502 input_mode = (enum input_mode)opt;
502503 switch (opt) {
503− case silentoldconfig:
504+ case syncconfig:
504505 sync_kconfig = 1;
505506 break;
506507 case defconfig:
@@ -582,7 +583,7 @@ int main(int ac, char **av) · 75 unmodified lines
582583 }
583584 break;
584585 case savedefconfig:
585− case silentoldconfig:
586+ case syncconfig:
586587 case oldaskconfig:
587588 case oldconfig:
588589 case listnewconfig:
@@ -662,24 +663,24 @@ int main(int ac, char **av) · 73 unmodified lines
662663 case oldaskconfig:
663664 rootEntry = &rootmenu;
664665 conf(&rootmenu);
665− input_mode = silentoldconfig;
666+ input_mode = oldconfig;
666667 /* fall through */
667668 case oldconfig:
668669 case listnewconfig:
669− case olddefconfig:
670− case silentoldconfig:
670+ case syncconfig:
671671 /* Update until a loop caused no more changes */
672672 do {
673673 conf_cnt = 0;
674674 check_conf(&rootmenu);
675− } while (conf_cnt &&
676− (input_mode != listnewconfig &&
677− input_mode != olddefconfig));
675+ } while (conf_cnt);
676+ break;
677+ case olddefconfig:
678+ default:
678679 break;
679680 }
680681
681682 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.
683684 * All other commands are only used to generate a config.
684685 */
685686 if (conf_get_changed() && conf_write(NULL)) {
scripts/kconfig/expr.c+28−58
@@ -1137,49 +1137,9 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2) · 1136 unmodified lines
11371137 return 0;
11381138 }
11391139
1140−static inline struct expr *
1141−expr_get_leftmost_symbol(const struct expr *e)
1142−{
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)
1140+void expr_print(struct expr *e,
1141+ void (*fn)(void *, struct symbol *, const char *),
1142+ void *data, int prevtoken)
11831143 {
11841144 if (!e) {
11851145 fn(data, NULL, "y");
@@ -1234,14 +1194,9 @@ static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, con · 48 unmodified lines
12341194 fn(data, e->right.sym, e->right.sym->name);
12351195 break;
12361196 case E_OR:
1237− if (revdep && e->left.expr->type != E_OR)
1238− fn(data, NULL, "\n - ");
1239− __expr_print(e->left.expr, fn, data, E_OR, revdep);
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);
1197+ expr_print(e->left.expr, fn, data, E_OR);
1198+ fn(data, NULL, " || ");
1199+ expr_print(e->right.expr, fn, data, E_OR);
12451200 break;
12461201 case E_AND:
12471202 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 · 26 unmodified lines
12741229 fn(data, NULL, ")");
12751230 }
12761231
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−
12821232 static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
12831233 {
12841234 xfwrite(str, strlen(str), 1, data);
@@ -1329,7 +1279,27 @@ void expr_gstr_print(struct expr *e, struct gstr *gs) · 44 unmodified lines
13291279 * line with a minus. This makes expressions much easier to read.
13301280 * Suitable for reverse dependency expressions.
13311281 */
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)
13331303 {
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);
13351305 }
scripts/kconfig/expr.h+2−2
@@ -305,12 +305,12 @@ struct expr *expr_transform(struct expr *e); · 304 unmodified lines
305305 int expr_contains_symbol(struct expr *dep, struct symbol *sym);
306306 bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
307307 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);
309308
310309 void expr_fprint(struct expr *e, FILE *out);
311310 struct gstr; /* forward */
312311 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);
314314
315315 static inline int expr_is_yes(struct expr *e)
316316 {
scripts/kconfig/lkc.h+1−0
@@ -68,6 +68,7 @@ struct kconf_id { · 67 unmodified lines
6868 enum symbol_type stype;
6969 };
7070
71+extern int yylineno;
7172 void zconfdump(FILE *out);
7273 void zconf_starthelp(void);
7374 FILE *zconf_fopen(const char *name);
scripts/kconfig/menu.c+6−6
@@ -828,16 +828,16 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, · 827 unmodified lines
828828
829829 get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
830830 if (sym->rev_dep.expr) {
831− str_append(r, _(" Selected by: "));
832− expr_gstr_print_revdep(sym->rev_dep.expr, r);
833− str_append(r, "\n");
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, mod, " Selected by [m]:\n");
833+ expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n");
834834 }
835835
836836 get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: "));
837837 if (sym->implied.expr) {
838− str_append(r, _(" Implied by: "));
839− expr_gstr_print_revdep(sym->implied.expr, r);
840− str_append(r, "\n");
838+ expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n");
839+ expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n");
840+ expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n");
841841 }
842842
843843 str_append(r, "\n\n");
scripts/kconfig/nconf.h+1−3
@@ -15,7 +15,7 @@ · 14 unmodified lines
1515 #include <string.h>
1616 #include <unistd.h>
1717 #include <locale.h>
18−#include <curses.h>
18+#include <ncurses.h>
1919 #include <menu.h>
2020 #include <panel.h>
2121 #include <form.h>
@@ -24,8 +24,6 @@ · 2 unmodified lines
2424 #include <time.h>
2525 #include <sys/time.h>
2626
27−#include "ncurses.h"
28−
2927 #define max(a, b) ({\
3028 typeof(a) _a = a;\
3129 typeof(b) _b = b;\
scripts/kconfig/symbol.c+26−14
@@ -243,7 +243,7 @@ static void sym_calc_visibility(struct symbol *sym) · 242 unmodified lines
243243 tri = yes;
244244 if (sym->dir_dep.expr)
245245 tri = expr_calc_value(sym->dir_dep.expr);
246− if (tri == mod)
246+ if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
247247 tri = yes;
248248 if (sym->dir_dep.tri != tri) {
249249 sym->dir_dep.tri = tri;
@@ -333,6 +333,27 @@ static struct symbol *sym_calc_choice(struct symbol *sym) · 83 unmodified lines
333333 return def_sym;
334334 }
335335
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+
336357 void sym_calc_value(struct symbol *sym)
337358 {
338359 struct symbol_value newval, oldval;
@@ -403,9 +424,10 @@ void sym_calc_value(struct symbol *sym) · 64 unmodified lines
403424 if (!sym_is_choice(sym)) {
404425 prop = sym_get_default_prop(sym);
405426 if (prop) {
406− sym->flags |= SYMBOL_WRITE;
407427 newval.tri = EXPR_AND(expr_calc_value(prop->expr),
408428 prop->visible.tri);
429+ if (newval.tri != no)
430+ sym->flags |= SYMBOL_WRITE;
409431 }
410432 if (sym->implied.tri != no) {
411433 sym->flags |= SYMBOL_WRITE;
@@ -413,18 +435,8 @@ void sym_calc_value(struct symbol *sym) · 1 unmodified line
413435 }
414436 }
415437 calc_newval:
416− if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
417− struct expr *e;
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− }
438+ if (sym->dir_dep.tri < sym->rev_dep.tri)
439+ sym_warn_unmet_dep(sym);
428440 newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
429441 }
430442 if (newval.tri == mod &&
scripts/kconfig/tests/auto_submenu/Kconfig+50−0
@@ -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.
scripts/kconfig/tests/auto_submenu/__init__.py+12−0
@@ -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')
scripts/kconfig/tests/auto_submenu/expected_stdout+10−0
@@ -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)
scripts/kconfig/tests/choice/Kconfig+54−0
@@ -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
scripts/kconfig/tests/choice/__init__.py+40−0
@@ -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')
scripts/kconfig/tests/choice/alldef_expected_config+5−0
@@ -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
scripts/kconfig/tests/choice/allmod_expected_config+9−0
@@ -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
scripts/kconfig/tests/choice/allno_expected_config+5−0
@@ -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
scripts/kconfig/tests/choice/allyes_expected_config+9−0
@@ -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
scripts/kconfig/tests/choice/oldask0_expected_stdout+10−0
@@ -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)
scripts/kconfig/tests/choice/oldask1_config+2−0
@@ -0,0 +1,2 @@
1+# CONFIG_MODULES is not set
2+CONFIG_OPT_BOOL_CHOICE0=y
scripts/kconfig/tests/choice/oldask1_expected_stdout+15−0
@@ -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/?]
scripts/kconfig/tests/choice_value_with_m_dep/Kconfig+19−0
@@ -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
scripts/kconfig/tests/choice_value_with_m_dep/__init__.py+15−0
@@ -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')
scripts/kconfig/tests/choice_value_with_m_dep/config+2−0
@@ -0,0 +1,2 @@
1+CONFIG_CHOICE0=m
2+CONFIG_CHOICE1=m
scripts/kconfig/tests/choice_value_with_m_dep/expected_config+3−0
@@ -0,0 +1,3 @@
1+CONFIG_MODULES=y
2+CONFIG_DEP=m
3+CONFIG_CHOICE0=y
scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout+4−0
@@ -0,0 +1,4 @@
1+Tristate Choice [M/y/?] y
2+Tristate Choice
3+> 1. Choice 0 (CHOICE0)
4+choice[1]: 1
scripts/kconfig/tests/conftest.py+291−0
@@ -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)
scripts/kconfig/tests/err_recursive_inc/Kconfig+1−0
@@ -0,0 +1 @@
1+source "Kconfig.inc1"
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1+4−0
@@ -0,0 +1,4 @@
1+
2+
3+
4+source "Kconfig.inc2"
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2+3−0
@@ -0,0 +1,3 @@
1+
2+
3+source "Kconfig.inc3"
scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3+1−0
@@ -0,0 +1 @@
1+source "Kconfig.inc1"
scripts/kconfig/tests/err_recursive_inc/__init__.py+10−0
@@ -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')
scripts/kconfig/tests/err_recursive_inc/expected_stderr+6−0
@@ -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
scripts/kconfig/tests/inter_choice/Kconfig+23−0
@@ -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
scripts/kconfig/tests/inter_choice/__init__.py+14−0
@@ -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')
scripts/kconfig/tests/inter_choice/defconfig+1−0
@@ -0,0 +1 @@
1+CONFIG_CHOICE_VAL0=y
scripts/kconfig/tests/inter_choice/expected_config+4−0
@@ -0,0 +1,4 @@
1+CONFIG_MODULES=y
2+CONFIG_CHOICE_VAL0=y
3+# CONFIG_CHOIVE_VAL1 is not set
4+CONFIG_DUMMY=y
scripts/kconfig/tests/new_choice_with_dep/Kconfig+37−0
@@ -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
scripts/kconfig/tests/new_choice_with_dep/__init__.py+14−0
@@ -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')
scripts/kconfig/tests/new_choice_with_dep/config+3−0
@@ -0,0 +1,3 @@
1+CONFIG_CHOICE_B=y
2+# CONFIG_CHOICE_D is not set
3+CONFIG_CHOICE_E=y
scripts/kconfig/tests/new_choice_with_dep/expected_stdout+10−0
@@ -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?]:
scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig+14−0
@@ -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
scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py+19−0
@@ -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')
scripts/kconfig/tests/no_write_if_dep_unmet/config+1−0
@@ -0,0 +1 @@
1+CONFIG_A=y
scripts/kconfig/tests/no_write_if_dep_unmet/expected_config+5−0
@@ -0,0 +1,5 @@
1+#
2+# Automatically generated file; DO NOT EDIT.
3+# Linux Kernel Configuration
4+#
5+# CONFIG_A is not set
scripts/kconfig/tests/pytest.ini+7−0
@@ -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
scripts/kconfig/tests/rand_nested_choice/Kconfig+33−0
@@ -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
scripts/kconfig/tests/rand_nested_choice/__init__.py+16−0
@@ -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'))
scripts/kconfig/tests/rand_nested_choice/expected_stdout0+2−0
@@ -0,0 +1,2 @@
1+CONFIG_A=y
2+# CONFIG_B is not set
scripts/kconfig/tests/rand_nested_choice/expected_stdout1+4−0
@@ -0,0 +1,4 @@
1+# CONFIG_A is not set
2+CONFIG_B=y
3+CONFIG_C=y
4+# CONFIG_D is not set
scripts/kconfig/tests/rand_nested_choice/expected_stdout2+5−0
@@ -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
scripts/kconfig/tests/warn_recursive_dep/Kconfig+62−0
@@ -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
scripts/kconfig/tests/warn_recursive_dep/__init__.py+9−0
@@ -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')
scripts/kconfig/tests/warn_recursive_dep/expected_stderr+30−0
@@ -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
scripts/kconfig/zconf.l+20−21
@@ -1,5 +1,5 @@
11 %option nostdinit noyywrap never-interactive full ecs
2−%option 8bit nodefault perf-report perf-report
2+%option 8bit nodefault yylineno
33 %option noinput
44 %x COMMAND HELP STRING PARAM
55 %{
@@ -83,7 +83,6 @@ n [A-Za-z0-9_-] · 77 unmodified lines
8383
8484 [ \t]*#.*\n |
8585 [ \t]*\n {
86− current_file->lineno++;
8786 return T_EOL;
8887 }
8988 [ \t]*#.*
@@ -104,7 +103,7 @@ n [A-Za-z0-9_-] · 14 unmodified lines
104103 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
105104 BEGIN(PARAM);
106105 current_pos.file = current_file;
107− current_pos.lineno = current_file->lineno;
106+ current_pos.lineno = yylineno;
108107 if (id && id->flags & TF_COMMAND) {
109108 yylval.id = id;
110109 return id->token;
@@ -116,7 +115,6 @@ n [A-Za-z0-9_-] · 5 unmodified lines
116115 . warn_ignored_character(*yytext);
117116 \n {
118117 BEGIN(INITIAL);
119− current_file->lineno++;
120118 return T_EOL;
121119 }
122120 }
@@ -138,7 +136,7 @@ n [A-Za-z0-9_-] · 15 unmodified lines
138136 new_string();
139137 BEGIN(STRING);
140138 }
141− \n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
139+ \n BEGIN(INITIAL); return T_EOL;
142140 ({n}|[/.])+ {
143141 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
144142 if (id && id->flags & TF_PARAM) {
@@ -150,7 +148,7 @@ n [A-Za-z0-9_-] · 5 unmodified lines
150148 return T_WORD;
151149 }
152150 #.* /* comment */
153− \\\n current_file->lineno++;
151+ \\\n ;
154152 [[:blank:]]+
155153 . warn_ignored_character(*yytext);
156154 <<EOF>> {
@@ -187,7 +185,6 @@ n [A-Za-z0-9_-] · 30 unmodified lines
187185 fprintf(stderr,
188186 "%s:%d:warning: multi-line strings not supported\n",
189187 zconf_curname(), zconf_lineno());
190− current_file->lineno++;
191188 BEGIN(INITIAL);
192189 return T_EOL;
193190 }
@@ -220,12 +217,10 @@ n [A-Za-z0-9_-] · 26 unmodified lines
220217 }
221218 }
222219 [ \t]*\n/[^ \t\n] {
223− current_file->lineno++;
224220 zconf_endhelp();
225221 return T_HELPTEXT;
226222 }
227223 [ \t]*\n {
228− current_file->lineno++;
229224 append_string("\n", 1);
230225 }
231226 [^ \t\n].* {
@@ -304,7 +299,7 @@ void zconf_initscan(const char *name) · 72 unmodified lines
304299 memset(current_buf, 0, sizeof(*current_buf));
305300
306301 current_file = file_lookup(name);
307− current_file->lineno = 1;
302+ yylineno = 1;
308303 }
309304
310305 void zconf_nextfile(const char *name)
@@ -325,24 +320,26 @@ void zconf_nextfile(const char *name) · 14 unmodified lines
325320 buf->parent = current_buf;
326321 current_buf = buf;
327322
328− for (iter = current_file->parent; iter; iter = iter->parent ) {
329− if (!strcmp(current_file->name,iter->name) ) {
323+ current_file->lineno = yylineno;
324+ file->parent = current_file;
325+
326+ for (iter = current_file; iter; iter = iter->parent) {
327+ if (!strcmp(iter->name, file->name)) {
330328 fprintf(stderr,
331− "%s:%d: recursive inclusion detected. "
332− "Inclusion path:\n current file : '%s'\n",
333− zconf_curname(), zconf_lineno(),
334− zconf_curname());
335− iter = current_file;
329+ "Recursive inclusion detected.\n"
330+ "Inclusion path:\n"
331+ " current file : %s\n", file->name);
332+ iter = file;
336333 do {
337334 iter = iter->parent;
338− fprintf(stderr, " included from: '%s:%d'\n",
335+ fprintf(stderr, " included from: %s:%d\n",
339336 iter->name, iter->lineno - 1);
340− } while (strcmp(iter->name, current_file->name));
337+ } while (strcmp(iter->name, file->name));
341338 exit(1);
342339 }
343340 }
344− file->lineno = 1;
345− file->parent = current_file;
341+
342+ yylineno = 1;
346343 current_file = file;
347344 }
348345
@@ -351,6 +348,8 @@ static void zconf_endfile(void) · 2 unmodified lines
351348 struct buffer *parent;
352349
353350 current_file = current_file->parent;
351+ if (current_file)
352+ yylineno = current_file->lineno;
354353
355354 parent = current_buf->parent;
356355 if (parent) {