aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2016-11-11 00:10:05 -0500
committerThomas Gleixner <tglx@linutronix.de>2016-11-16 03:26:33 -0500
commit237e3ad0f195d8fd34f1299e45f04793832a16fc (patch)
tree3c3a7fd7442cf28789ed878c918ed018701c343d
parent4b7e9cf9c84b09adc428e0433cd376b91f9c52a7 (diff)
Kconfig: Introduce the "imply" keyword
The "imply" keyword is a weak version of "select" where the target config symbol can still be turned off, avoiding those pitfalls that come with the "select" keyword. This is useful e.g. with multiple drivers that want to indicate their ability to hook into a secondary subsystem while allowing the user to configure that subsystem out without also having to unset these drivers. Currently, the same effect can almost be achieved with: config DRIVER_A tristate config DRIVER_B tristate config DRIVER_C tristate config DRIVER_D tristate [...] config SUBSYSTEM_X tristate default DRIVER_A || DRIVER_B || DRIVER_C || DRIVER_D || [...] This is unwieldy to maintain especially with a large number of drivers. Furthermore, there is no easy way to restrict the choice for SUBSYSTEM_X to y or n, excluding m, when some drivers are built-in. The "select" keyword allows for excluding m, but it excludes n as well. Hence this "imply" keyword. The above becomes: config DRIVER_A tristate imply SUBSYSTEM_X config DRIVER_B tristate imply SUBSYSTEM_X [...] config SUBSYSTEM_X tristate This is much cleaner, and way more flexible than "select". SUBSYSTEM_X can still be configured out, and it can be set as a module when none of the drivers are configured in or all of them are modular. Signed-off-by: Nicolas Pitre <nico@linaro.org> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: linux-kbuild@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Michal Marek <mmarek@suse.com> Cc: Edward Cree <ecree@solarflare.com> Link: http://lkml.kernel.org/r/1478841010-28605-2-git-send-email-nicolas.pitre@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--Documentation/kbuild/kconfig-language.txt29
-rw-r--r--scripts/kconfig/expr.h2
-rw-r--r--scripts/kconfig/menu.c55
-rw-r--r--scripts/kconfig/symbol.c24
-rw-r--r--scripts/kconfig/zconf.gperf1
-rw-r--r--scripts/kconfig/zconf.y16
6 files changed, 108 insertions, 19 deletions
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index 069fcb3eef6e..262722d8867b 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -113,6 +113,34 @@ applicable everywhere (see syntax).
113 That will limit the usefulness but on the other hand avoid 113 That will limit the usefulness but on the other hand avoid
114 the illegal configurations all over. 114 the illegal configurations all over.
115 115
116- weak reverse dependencies: "imply" <symbol> ["if" <expr>]
117 This is similar to "select" as it enforces a lower limit on another
118 symbol except that the "implied" symbol's value may still be set to n
119 from a direct dependency or with a visible prompt.
120
121 Given the following example:
122
123 config FOO
124 tristate
125 imply BAZ
126
127 config BAZ
128 tristate
129 depends on BAR
130
131 The following values are possible:
132
133 FOO BAR BAZ's default choice for BAZ
134 --- --- ------------- --------------
135 n y n N/m/y
136 m y m M/y/n
137 y y y Y/n
138 y n * N
139
140 This is useful e.g. with multiple drivers that want to indicate their
141 ability to hook into a secondary subsystem while allowing the user to
142 configure that subsystem out without also having to unset these drivers.
143
116- limiting menu display: "visible if" <expr> 144- limiting menu display: "visible if" <expr>
117 This attribute is only applicable to menu blocks, if the condition is 145 This attribute is only applicable to menu blocks, if the condition is
118 false, the menu block is not displayed to the user (the symbols 146 false, the menu block is not displayed to the user (the symbols
@@ -481,6 +509,7 @@ historical issues resolved through these different solutions.
481 b) Match dependency semantics: 509 b) Match dependency semantics:
482 b1) Swap all "select FOO" to "depends on FOO" or, 510 b1) Swap all "select FOO" to "depends on FOO" or,
483 b2) Swap all "depends on FOO" to "select FOO" 511 b2) Swap all "depends on FOO" to "select FOO"
512 c) Consider the use of "imply" instead of "select"
484 513
485The resolution to a) can be tested with the sample Kconfig file 514The resolution to a) can be tested with the sample Kconfig file
486Documentation/kbuild/Kconfig.recursion-issue-01 through the removal 515Documentation/kbuild/Kconfig.recursion-issue-01 through the removal
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 973b6f733368..a73f762c48d6 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -85,6 +85,7 @@ struct symbol {
85 struct property *prop; 85 struct property *prop;
86 struct expr_value dir_dep; 86 struct expr_value dir_dep;
87 struct expr_value rev_dep; 87 struct expr_value rev_dep;
88 struct expr_value implied;
88}; 89};
89 90
90#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) 91#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
@@ -136,6 +137,7 @@ enum prop_type {
136 P_DEFAULT, /* default y */ 137 P_DEFAULT, /* default y */
137 P_CHOICE, /* choice value */ 138 P_CHOICE, /* choice value */
138 P_SELECT, /* select BAR */ 139 P_SELECT, /* select BAR */
140 P_IMPLY, /* imply BAR */
139 P_RANGE, /* range 7..100 (for a symbol) */ 141 P_RANGE, /* range 7..100 (for a symbol) */
140 P_ENV, /* value from environment variable */ 142 P_ENV, /* value from environment variable */
141 P_SYMBOL, /* where a symbol is defined */ 143 P_SYMBOL, /* where a symbol is defined */
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index aed678e8a777..e9357931b47d 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -233,6 +233,8 @@ static void sym_check_prop(struct symbol *sym)
233{ 233{
234 struct property *prop; 234 struct property *prop;
235 struct symbol *sym2; 235 struct symbol *sym2;
236 char *use;
237
236 for (prop = sym->prop; prop; prop = prop->next) { 238 for (prop = sym->prop; prop; prop = prop->next) {
237 switch (prop->type) { 239 switch (prop->type) {
238 case P_DEFAULT: 240 case P_DEFAULT:
@@ -252,18 +254,20 @@ static void sym_check_prop(struct symbol *sym)
252 } 254 }
253 break; 255 break;
254 case P_SELECT: 256 case P_SELECT:
257 case P_IMPLY:
258 use = prop->type == P_SELECT ? "select" : "imply";
255 sym2 = prop_get_symbol(prop); 259 sym2 = prop_get_symbol(prop);
256 if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) 260 if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
257 prop_warn(prop, 261 prop_warn(prop,
258 "config symbol '%s' uses select, but is " 262 "config symbol '%s' uses %s, but is "
259 "not boolean or tristate", sym->name); 263 "not boolean or tristate", sym->name, use);
260 else if (sym2->type != S_UNKNOWN && 264 else if (sym2->type != S_UNKNOWN &&
261 sym2->type != S_BOOLEAN && 265 sym2->type != S_BOOLEAN &&
262 sym2->type != S_TRISTATE) 266 sym2->type != S_TRISTATE)
263 prop_warn(prop, 267 prop_warn(prop,
264 "'%s' has wrong type. 'select' only " 268 "'%s' has wrong type. '%s' only "
265 "accept arguments of boolean and " 269 "accept arguments of boolean and "
266 "tristate type", sym2->name); 270 "tristate type", sym2->name, use);
267 break; 271 break;
268 case P_RANGE: 272 case P_RANGE:
269 if (sym->type != S_INT && sym->type != S_HEX) 273 if (sym->type != S_INT && sym->type != S_HEX)
@@ -333,6 +337,10 @@ void menu_finalize(struct menu *parent)
333 struct symbol *es = prop_get_symbol(prop); 337 struct symbol *es = prop_get_symbol(prop);
334 es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, 338 es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
335 expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); 339 expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
340 } else if (prop->type == P_IMPLY) {
341 struct symbol *es = prop_get_symbol(prop);
342 es->implied.expr = expr_alloc_or(es->implied.expr,
343 expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
336 } 344 }
337 } 345 }
338 } 346 }
@@ -612,13 +620,30 @@ static struct property *get_symbol_prop(struct symbol *sym)
612 return prop; 620 return prop;
613} 621}
614 622
623static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
624 enum prop_type tok, const char *prefix)
625{
626 bool hit = false;
627 struct property *prop;
628
629 for_all_properties(sym, prop, tok) {
630 if (!hit) {
631 str_append(r, prefix);
632 hit = true;
633 } else
634 str_printf(r, " && ");
635 expr_gstr_print(prop->expr, r);
636 }
637 if (hit)
638 str_append(r, "\n");
639}
640
615/* 641/*
616 * head is optional and may be NULL 642 * head is optional and may be NULL
617 */ 643 */
618static void get_symbol_str(struct gstr *r, struct symbol *sym, 644static void get_symbol_str(struct gstr *r, struct symbol *sym,
619 struct list_head *head) 645 struct list_head *head)
620{ 646{
621 bool hit;
622 struct property *prop; 647 struct property *prop;
623 648
624 if (sym && sym->name) { 649 if (sym && sym->name) {
@@ -648,22 +673,20 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
648 } 673 }
649 } 674 }
650 675
651 hit = false; 676 get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
652 for_all_properties(sym, prop, P_SELECT) {
653 if (!hit) {
654 str_append(r, " Selects: ");
655 hit = true;
656 } else
657 str_printf(r, " && ");
658 expr_gstr_print(prop->expr, r);
659 }
660 if (hit)
661 str_append(r, "\n");
662 if (sym->rev_dep.expr) { 677 if (sym->rev_dep.expr) {
663 str_append(r, _(" Selected by: ")); 678 str_append(r, _(" Selected by: "));
664 expr_gstr_print(sym->rev_dep.expr, r); 679 expr_gstr_print(sym->rev_dep.expr, r);
665 str_append(r, "\n"); 680 str_append(r, "\n");
666 } 681 }
682
683 get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: "));
684 if (sym->implied.expr) {
685 str_append(r, _(" Implied by: "));
686 expr_gstr_print(sym->implied.expr, r);
687 str_append(r, "\n");
688 }
689
667 str_append(r, "\n\n"); 690 str_append(r, "\n\n");
668} 691}
669 692
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 2432298487fb..20136ffefb23 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -258,6 +258,15 @@ static void sym_calc_visibility(struct symbol *sym)
258 sym->rev_dep.tri = tri; 258 sym->rev_dep.tri = tri;
259 sym_set_changed(sym); 259 sym_set_changed(sym);
260 } 260 }
261 tri = no;
262 if (sym->implied.expr && sym->dir_dep.tri != no)
263 tri = expr_calc_value(sym->implied.expr);
264 if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
265 tri = yes;
266 if (sym->implied.tri != tri) {
267 sym->implied.tri = tri;
268 sym_set_changed(sym);
269 }
261} 270}
262 271
263/* 272/*
@@ -397,6 +406,10 @@ void sym_calc_value(struct symbol *sym)
397 newval.tri = EXPR_AND(expr_calc_value(prop->expr), 406 newval.tri = EXPR_AND(expr_calc_value(prop->expr),
398 prop->visible.tri); 407 prop->visible.tri);
399 } 408 }
409 if (sym->implied.tri != no) {
410 sym->flags |= SYMBOL_WRITE;
411 newval.tri = EXPR_OR(newval.tri, sym->implied.tri);
412 }
400 } 413 }
401 calc_newval: 414 calc_newval:
402 if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { 415 if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
@@ -413,7 +426,8 @@ void sym_calc_value(struct symbol *sym)
413 } 426 }
414 newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); 427 newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
415 } 428 }
416 if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) 429 if (newval.tri == mod &&
430 (sym_get_type(sym) == S_BOOLEAN || sym->implied.tri == yes))
417 newval.tri = yes; 431 newval.tri = yes;
418 break; 432 break;
419 case S_STRING: 433 case S_STRING:
@@ -498,6 +512,8 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
498 return false; 512 return false;
499 if (sym->visible <= sym->rev_dep.tri) 513 if (sym->visible <= sym->rev_dep.tri)
500 return false; 514 return false;
515 if (sym->implied.tri == yes && val == mod)
516 return false;
501 if (sym_is_choice_value(sym) && sym->visible == yes) 517 if (sym_is_choice_value(sym) && sym->visible == yes)
502 return val == yes; 518 return val == yes;
503 return val >= sym->rev_dep.tri && val <= sym->visible; 519 return val >= sym->rev_dep.tri && val <= sym->visible;
@@ -750,6 +766,10 @@ const char *sym_get_string_default(struct symbol *sym)
750 if (sym->type == S_BOOLEAN && val == mod) 766 if (sym->type == S_BOOLEAN && val == mod)
751 val = yes; 767 val = yes;
752 768
769 /* adjust the default value if this symbol is implied by another */
770 if (val < sym->implied.tri)
771 val = sym->implied.tri;
772
753 switch (sym->type) { 773 switch (sym->type) {
754 case S_BOOLEAN: 774 case S_BOOLEAN:
755 case S_TRISTATE: 775 case S_TRISTATE:
@@ -1352,6 +1372,8 @@ const char *prop_get_type_name(enum prop_type type)
1352 return "choice"; 1372 return "choice";
1353 case P_SELECT: 1373 case P_SELECT:
1354 return "select"; 1374 return "select";
1375 case P_IMPLY:
1376 return "imply";
1355 case P_RANGE: 1377 case P_RANGE:
1356 return "range"; 1378 return "range";
1357 case P_SYMBOL: 1379 case P_SYMBOL:
diff --git a/scripts/kconfig/zconf.gperf b/scripts/kconfig/zconf.gperf
index ac498f01b449..ead02edec936 100644
--- a/scripts/kconfig/zconf.gperf
+++ b/scripts/kconfig/zconf.gperf
@@ -38,6 +38,7 @@ int, T_TYPE, TF_COMMAND, S_INT
38hex, T_TYPE, TF_COMMAND, S_HEX 38hex, T_TYPE, TF_COMMAND, S_HEX
39string, T_TYPE, TF_COMMAND, S_STRING 39string, T_TYPE, TF_COMMAND, S_STRING
40select, T_SELECT, TF_COMMAND 40select, T_SELECT, TF_COMMAND
41imply, T_IMPLY, TF_COMMAND
41range, T_RANGE, TF_COMMAND 42range, T_RANGE, TF_COMMAND
42visible, T_VISIBLE, TF_COMMAND 43visible, T_VISIBLE, TF_COMMAND
43option, T_OPTION, TF_COMMAND 44option, T_OPTION, TF_COMMAND
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index 71bf8bff696a..001305fa080b 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -31,7 +31,7 @@ struct symbol *symbol_hash[SYMBOL_HASHSIZE];
31static struct menu *current_menu, *current_entry; 31static struct menu *current_menu, *current_entry;
32 32
33%} 33%}
34%expect 30 34%expect 32
35 35
36%union 36%union
37{ 37{
@@ -62,6 +62,7 @@ static struct menu *current_menu, *current_entry;
62%token <id>T_TYPE 62%token <id>T_TYPE
63%token <id>T_DEFAULT 63%token <id>T_DEFAULT
64%token <id>T_SELECT 64%token <id>T_SELECT
65%token <id>T_IMPLY
65%token <id>T_RANGE 66%token <id>T_RANGE
66%token <id>T_VISIBLE 67%token <id>T_VISIBLE
67%token <id>T_OPTION 68%token <id>T_OPTION
@@ -124,7 +125,7 @@ stmt_list:
124; 125;
125 126
126option_name: 127option_name:
127 T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE 128 T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_IMPLY | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
128; 129;
129 130
130common_stmt: 131common_stmt:
@@ -216,6 +217,12 @@ config_option: T_SELECT T_WORD if_expr T_EOL
216 printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); 217 printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
217}; 218};
218 219
220config_option: T_IMPLY T_WORD if_expr T_EOL
221{
222 menu_add_symbol(P_IMPLY, sym_lookup($2, 0), $3);
223 printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
224};
225
219config_option: T_RANGE symbol symbol if_expr T_EOL 226config_option: T_RANGE symbol symbol if_expr T_EOL
220{ 227{
221 menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); 228 menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
@@ -664,6 +671,11 @@ static void print_symbol(FILE *out, struct menu *menu)
664 expr_fprint(prop->expr, out); 671 expr_fprint(prop->expr, out);
665 fputc('\n', out); 672 fputc('\n', out);
666 break; 673 break;
674 case P_IMPLY:
675 fputs( " imply ", out);
676 expr_fprint(prop->expr, out);
677 fputc('\n', out);
678 break;
667 case P_RANGE: 679 case P_RANGE:
668 fputs( " range ", out); 680 fputs( " range ", out);
669 expr_fprint(prop->expr, out); 681 expr_fprint(prop->expr, out);