Skip to content

Commit 237e3ad

Browse files
Nicolas PitreKAGA-KOKO
Nicolas Pitre
authored andcommitted
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 <[email protected]> Acked-by: Richard Cochran <[email protected]> Acked-by: Thomas Gleixner <[email protected]> Acked-by: John Stultz <[email protected]> Reviewed-by: Josh Triplett <[email protected]> Cc: Paul Bolle <[email protected]> Cc: [email protected] Cc: [email protected] Cc: Michal Marek <[email protected]> Cc: Edward Cree <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 4b7e9cf commit 237e3ad

File tree

6 files changed

+108
-19
lines changed

6 files changed

+108
-19
lines changed

Documentation/kbuild/kconfig-language.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,34 @@ applicable everywhere (see syntax).
113113
That will limit the usefulness but on the other hand avoid
114114
the illegal configurations all over.
115115

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+
116144
- limiting menu display: "visible if" <expr>
117145
This attribute is only applicable to menu blocks, if the condition is
118146
false, the menu block is not displayed to the user (the symbols
@@ -481,6 +509,7 @@ historical issues resolved through these different solutions.
481509
b) Match dependency semantics:
482510
b1) Swap all "select FOO" to "depends on FOO" or,
483511
b2) Swap all "depends on FOO" to "select FOO"
512+
c) Consider the use of "imply" instead of "select"
484513

485514
The resolution to a) can be tested with the sample Kconfig file
486515
Documentation/kbuild/Kconfig.recursion-issue-01 through the removal

scripts/kconfig/expr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct symbol {
8585
struct property *prop;
8686
struct expr_value dir_dep;
8787
struct expr_value rev_dep;
88+
struct expr_value implied;
8889
};
8990

9091
#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 {
136137
P_DEFAULT, /* default y */
137138
P_CHOICE, /* choice value */
138139
P_SELECT, /* select BAR */
140+
P_IMPLY, /* imply BAR */
139141
P_RANGE, /* range 7..100 (for a symbol) */
140142
P_ENV, /* value from environment variable */
141143
P_SYMBOL, /* where a symbol is defined */

scripts/kconfig/menu.c

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ static void sym_check_prop(struct symbol *sym)
233233
{
234234
struct property *prop;
235235
struct symbol *sym2;
236+
char *use;
237+
236238
for (prop = sym->prop; prop; prop = prop->next) {
237239
switch (prop->type) {
238240
case P_DEFAULT:
@@ -252,18 +254,20 @@ static void sym_check_prop(struct symbol *sym)
252254
}
253255
break;
254256
case P_SELECT:
257+
case P_IMPLY:
258+
use = prop->type == P_SELECT ? "select" : "imply";
255259
sym2 = prop_get_symbol(prop);
256260
if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
257261
prop_warn(prop,
258-
"config symbol '%s' uses select, but is "
259-
"not boolean or tristate", sym->name);
262+
"config symbol '%s' uses %s, but is "
263+
"not boolean or tristate", sym->name, use);
260264
else if (sym2->type != S_UNKNOWN &&
261265
sym2->type != S_BOOLEAN &&
262266
sym2->type != S_TRISTATE)
263267
prop_warn(prop,
264-
"'%s' has wrong type. 'select' only "
268+
"'%s' has wrong type. '%s' only "
265269
"accept arguments of boolean and "
266-
"tristate type", sym2->name);
270+
"tristate type", sym2->name, use);
267271
break;
268272
case P_RANGE:
269273
if (sym->type != S_INT && sym->type != S_HEX)
@@ -333,6 +337,10 @@ void menu_finalize(struct menu *parent)
333337
struct symbol *es = prop_get_symbol(prop);
334338
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
335339
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)));
336344
}
337345
}
338346
}
@@ -612,13 +620,30 @@ static struct property *get_symbol_prop(struct symbol *sym)
612620
return prop;
613621
}
614622

623+
static 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+
615641
/*
616642
* head is optional and may be NULL
617643
*/
618644
static void get_symbol_str(struct gstr *r, struct symbol *sym,
619645
struct list_head *head)
620646
{
621-
bool hit;
622647
struct property *prop;
623648

624649
if (sym && sym->name) {
@@ -648,22 +673,20 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
648673
}
649674
}
650675

651-
hit = false;
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");
676+
get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
662677
if (sym->rev_dep.expr) {
663678
str_append(r, _(" Selected by: "));
664679
expr_gstr_print(sym->rev_dep.expr, r);
665680
str_append(r, "\n");
666681
}
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+
667690
str_append(r, "\n\n");
668691
}
669692

scripts/kconfig/symbol.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,15 @@ static void sym_calc_visibility(struct symbol *sym)
258258
sym->rev_dep.tri = tri;
259259
sym_set_changed(sym);
260260
}
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+
}
261270
}
262271

263272
/*
@@ -397,6 +406,10 @@ void sym_calc_value(struct symbol *sym)
397406
newval.tri = EXPR_AND(expr_calc_value(prop->expr),
398407
prop->visible.tri);
399408
}
409+
if (sym->implied.tri != no) {
410+
sym->flags |= SYMBOL_WRITE;
411+
newval.tri = EXPR_OR(newval.tri, sym->implied.tri);
412+
}
400413
}
401414
calc_newval:
402415
if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
@@ -413,7 +426,8 @@ void sym_calc_value(struct symbol *sym)
413426
}
414427
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
415428
}
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))
417431
newval.tri = yes;
418432
break;
419433
case S_STRING:
@@ -498,6 +512,8 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
498512
return false;
499513
if (sym->visible <= sym->rev_dep.tri)
500514
return false;
515+
if (sym->implied.tri == yes && val == mod)
516+
return false;
501517
if (sym_is_choice_value(sym) && sym->visible == yes)
502518
return val == yes;
503519
return val >= sym->rev_dep.tri && val <= sym->visible;
@@ -750,6 +766,10 @@ const char *sym_get_string_default(struct symbol *sym)
750766
if (sym->type == S_BOOLEAN && val == mod)
751767
val = yes;
752768

769+
/* adjust the default value if this symbol is implied by another */
770+
if (val < sym->implied.tri)
771+
val = sym->implied.tri;
772+
753773
switch (sym->type) {
754774
case S_BOOLEAN:
755775
case S_TRISTATE:
@@ -1352,6 +1372,8 @@ const char *prop_get_type_name(enum prop_type type)
13521372
return "choice";
13531373
case P_SELECT:
13541374
return "select";
1375+
case P_IMPLY:
1376+
return "imply";
13551377
case P_RANGE:
13561378
return "range";
13571379
case P_SYMBOL:

scripts/kconfig/zconf.gperf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ int, T_TYPE, TF_COMMAND, S_INT
3838
hex, T_TYPE, TF_COMMAND, S_HEX
3939
string, T_TYPE, TF_COMMAND, S_STRING
4040
select, T_SELECT, TF_COMMAND
41+
imply, T_IMPLY, TF_COMMAND
4142
range, T_RANGE, TF_COMMAND
4243
visible, T_VISIBLE, TF_COMMAND
4344
option, T_OPTION, TF_COMMAND

scripts/kconfig/zconf.y

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct symbol *symbol_hash[SYMBOL_HASHSIZE];
3131
static struct menu *current_menu, *current_entry;
3232

3333
%}
34-
%expect 30
34+
%expect 32
3535

3636
%union
3737
{
@@ -62,6 +62,7 @@ static struct menu *current_menu, *current_entry;
6262
%token <id>T_TYPE
6363
%token <id>T_DEFAULT
6464
%token <id>T_SELECT
65+
%token <id>T_IMPLY
6566
%token <id>T_RANGE
6667
%token <id>T_VISIBLE
6768
%token <id>T_OPTION
@@ -124,7 +125,7 @@ stmt_list:
124125
;
125126

126127
option_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
128129
;
129130

130131
common_stmt:
@@ -216,6 +217,12 @@ config_option: T_SELECT T_WORD if_expr T_EOL
216217
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
217218
};
218219

220+
config_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+
219226
config_option: T_RANGE symbol symbol if_expr T_EOL
220227
{
221228
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)
664671
expr_fprint(prop->expr, out);
665672
fputc('\n', out);
666673
break;
674+
case P_IMPLY:
675+
fputs( " imply ", out);
676+
expr_fprint(prop->expr, out);
677+
fputc('\n', out);
678+
break;
667679
case P_RANGE:
668680
fputs( " range ", out);
669681
expr_fprint(prop->expr, out);

0 commit comments

Comments
 (0)