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 | 306 | struct menu *menu, *last_menu; |
| 307 | 307 | struct symbol *sym; |
| 308 | 308 | struct property *prop; |
| 309 | − struct expr *parentdep, *basedep, *dep, *dep2; | |
| 309 | + struct expr *basedep, *dep, *dep2; | |
| 310 | 310 | |
| 311 | 311 | sym = parent->sym; |
| 312 | 312 | if (parent->list) { |
| @@ -315,24 +315,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) · 2 unmodified lines | ||
| 315 | 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 | 318 | /* For each child menu node... */ |
| 337 | 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 | 324 | basedep = rewrite_m(menu->dep); |
| 343 | 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 | 327 | basedep = expr_eliminate_dups(basedep); |
| 346 | 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 | 391 | * Recursively process children in the same fashion before |
| 413 | 392 | * moving on |
| 414 | 393 | */ |
| 415 | 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 | 396 | } else if (!inside_choice && sym) { |
| 418 | 397 | /* |
| 419 | 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 | 520 | sym_check_prop(sym); |
| 542 | 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 | 525 | void menu_finalize(void) |
| @@ -868,7 +868,7 @@ const char *sym_get_string_value(struct symbol *sym) · 867 unmodified lines | ||
| 868 | 868 | |
| 869 | 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 | 874 | HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE); |