When a prompt is followed by "if <expr>", the symbol is configurable when the if-conditional evaluates to true. A typical usage is as follows: menuconfig BLOCK bool "Enable the block layer" if EXPERT default y When EXPERT=n, the prompt is hidden, but this config entry is still active, and BLOCK is set to its default value 'y'. When EXPERT=y, the prompt is shown, making BLOCK a user-configurable option. This usage is common throughout the kernel tree, but it has never worked within a choice block. [Test Code] config EXPERT bool "Allow expert users to modify more options" choice prompt "Choose" if EXPERT config A bool "A" config B bool "B" endchoice [Result] # CONFIG_EXPERT is not set When the prompt is hidden, the choice block should produce the default without asking for the user's preference. Hence, the output should be: # CONFIG_EXPERT is not set CONFIG_A=y # CONFIG_B is not set Removing unnecessary hacks fixes the issue. This commit also changes the behavior of 'select' by choice members. [Test Code 2] config MODULES def_bool y modules config DEP def_tristate m if DEP choice prompt "choose" config A bool "A" select C endchoice config B def_bool y select D endif config C tristate config D tristate The current output is as follows: CONFIG_MODULES=y CONFIG_DEP=m CONFIG_A=y CONFIG_B=y CONFIG_C=y CONFIG_D=m With this commit, the output will be changed as follows: CONFIG_MODULES=y CONFIG_DEP=m CONFIG_A=y CONFIG_B=y CONFIG_C=m CONFIG_D=m CONFIG_C will be changed to 'm' because 'select C' will inherit the dependency on DEP, which is 'm'. This change is aligned with the behavior of 'select' outside a choice block; 'select D' depends on DEP, therefore D is selected by (B && DEP). Note: With this commit, allmodconfig will set CONFIG_USB_ROLE_SWITCH to 'm' instead of 'y'. I did not see any build regression with this change.
Showing the changes to scripts (2 of 2 files). Show all
Unified · Split
| @@ -306,7 +306,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) · 305 unmodified lines | |||
| 306 | struct menu *menu, *last_menu; | 306 | struct menu *menu, *last_menu; |
| 307 | struct symbol *sym; | 307 | struct symbol *sym; |
| 308 | struct property *prop; | 308 | struct property *prop; |
| 309 | struct expr *parentdep, *basedep, *dep, *dep2; | 309 | struct expr *basedep, *dep, *dep2; |
| 310 | 310 | ||
| 311 | sym = parent->sym; | 311 | sym = parent->sym; |
| 312 | if (parent->list) { | 312 | if (parent->list) { |
| @@ -315,24 +315,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) · 2 unmodified lines | |||
| 315 | * and propagate parent dependencies before moving on. | 315 | * and propagate parent dependencies before moving on. |
| 316 | */ | 316 | */ |
| 317 | 317 | ||
| 318 | bool is_choice = false; | ||
| 319 | |||
| 320 | if (sym && sym_is_choice(sym)) | ||
| 321 | is_choice = true; | ||
| 322 | |||
| 323 | if (is_choice) { | ||
| 324 | /* | ||
| 325 | * Use the choice itself as the parent dependency of | ||
| 326 | * the contained items. This turns the mode of the | ||
| 327 | * choice into an upper bound on the visibility of the | ||
| 328 | * choice value symbols. | ||
| 329 | */ | ||
| 330 | parentdep = expr_alloc_symbol(sym); | ||
| 331 | } else { | ||
| 332 | /* Menu node for 'menu', 'if' */ | ||
| 333 | parentdep = parent->dep; | ||
| 334 | } | ||
| 335 | |||
| 336 | /* For each child menu node... */ | 318 | /* For each child menu node... */ |
| 337 | for (menu = parent->list; menu; menu = menu->next) { | 319 | for (menu = parent->list; menu; menu = menu->next) { |
| 338 | /* | 320 | /* |
| @@ -341,7 +323,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) · 2 unmodified lines | |||
| 341 | */ | 323 | */ |
| 342 | basedep = rewrite_m(menu->dep); | 324 | basedep = rewrite_m(menu->dep); |
| 343 | basedep = expr_transform(basedep); | 325 | basedep = expr_transform(basedep); |
| 344 | basedep = expr_alloc_and(expr_copy(parentdep), basedep); | 326 | basedep = expr_alloc_and(expr_copy(parent->dep), basedep); |
| 345 | basedep = expr_eliminate_dups(basedep); | 327 | basedep = expr_eliminate_dups(basedep); |
| 346 | menu->dep = basedep; | 328 | menu->dep = basedep; |
| 347 | 329 | ||
| @@ -405,15 +387,12 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) · 57 unmodified lines | |||
| 405 | } | 387 | } |
| 406 | } | 388 | } |
| 407 | 389 | ||
| 408 | if (is_choice) | ||
| 409 | expr_free(parentdep); | ||
| 410 | |||
| 411 | /* | 390 | /* |
| 412 | * Recursively process children in the same fashion before | 391 | * Recursively process children in the same fashion before |
| 413 | * moving on | 392 | * moving on |
| 414 | */ | 393 | */ |
| 415 | for (menu = parent->list; menu; menu = menu->next) | 394 | for (menu = parent->list; menu; menu = menu->next) |
| 416 | _menu_finalize(menu, is_choice); | 395 | _menu_finalize(menu, sym && sym_is_choice(sym)); |
| 417 | } else if (!inside_choice && sym) { | 396 | } else if (!inside_choice && sym) { |
| 418 | /* | 397 | /* |
| 419 | * Automatic submenu creation. If sym is a symbol and A, B, C, | 398 | * Automatic submenu creation. If sym is a symbol and A, B, C, |
| @@ -541,17 +520,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) · 121 unmodified lines | |||
| 541 | sym_check_prop(sym); | 520 | sym_check_prop(sym); |
| 542 | sym->flags |= SYMBOL_WARNED; | 521 | sym->flags |= SYMBOL_WARNED; |
| 543 | } | 522 | } |
| 544 | |||
| 545 | /* | ||
| 546 | * For choices, add a reverse dependency (corresponding to a select) of | ||
| 547 | * '<visibility> && y'. This prevents the user from setting the choice | ||
| 548 | * mode to 'n' when the choice is visible. | ||
| 549 | */ | ||
| 550 | if (sym && sym_is_choice(sym) && parent->prompt) { | ||
| 551 | sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, | ||
| 552 | expr_alloc_and(parent->prompt->visible.expr, | ||
| 553 | expr_alloc_symbol(&symbol_yes))); | ||
| 554 | } | ||
| 555 | } | 523 | } |
| 556 | 524 | ||
| 557 | void menu_finalize(void) | 525 | void menu_finalize(void) |
| @@ -868,7 +868,7 @@ const char *sym_get_string_value(struct symbol *sym) · 867 unmodified lines | |||
| 868 | 868 | ||
| 869 | bool sym_is_changeable(struct symbol *sym) | 869 | bool sym_is_changeable(struct symbol *sym) |
| 870 | { | 870 | { |
| 871 | return sym->visible > sym->rev_dep.tri; | 871 | return !sym_is_choice(sym) && sym->visible > sym->rev_dep.tri; |
| 872 | } | 872 | } |
| 873 | 873 | ||
| 874 | HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE); | 874 | HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE); |