kconfig: Add transitional symbol attribute for migration support
Subsystems (3)
PATCH v3 1/1 kconfig: Add transitional symbol attribute for migration support
During kernel option migrations (e.g. CONFIG_CFI_CLANG to CONFIG_CFI), existing .config files need to maintain backward compatibility while preventing deprecated options from appearing in newly generated configurations. This is challenging with existing Kconfig mechanisms because:
1. Simply removing old options breaks existing .config files.
2. Manually listing an option as "deprecated" leaves it needlessly visible and still writes them to new .config files.
3. Using any method to remove visibility (.e.g no 'prompt', 'if n', etc) prevents the option from being processed at all.
Add a "transitional" attribute that creates symbols which are:
- Processed during configuration (can influence other symbols' defaults)
- Hidden from user menus (no prompts appear)
- Omitted from newly written .config files (gets migrated)
- Restricted to only having help sections (no defaults, selects, etc) making it truly just a "prior value pass-through" option.
The transitional syntax requires a type argument and prevents type redefinition:
config NEW_OPTION
bool "New option"
default OLD_OPTION
config OLD_OPTION
bool
transitional
help
Transitional config for OLD_OPTION migration.
This allows seamless migration: olddefconfig processes existing CONFIG_OLD_OPTION=y settings to enable CONFIG_NEW_OPTION=y, while CONFIG_OLD_OPTION is omitted from newly generated .config files.
Implementation details:
- Parser validates transitional symbols can only have help sections
- Symbol visibility logic updated: usable = (visible != no || transitional)
- Transitional symbols preserve user values during configuration
- Documentation added to show the usage
- Added positive and negative testing via "testconfig" target
---
With help from Claude Code to show me how to navigate the kconfig parser.
v3: use existing type parsing, add tests, fix up booleans (vegard)
--- .../kconfig/tests/err_transitional/Kconfig | 52 +++++++++ scripts/kconfig/tests/transitional/Kconfig | 100 ++++++++++++++++++ scripts/kconfig/expr.h | 1 + scripts/kconfig/lexer.l | 1 + scripts/kconfig/parser.y | 47 ++++++++ scripts/kconfig/symbol.c | 16 ++- .../tests/err_transitional/__init__.py | 14 +++ .../tests/err_transitional/expected_stderr | 7 ++ .../kconfig/tests/transitional/__init__.py | 18 ++++ .../tests/transitional/expected_config | 12 +++ .../kconfig/tests/transitional/initial_config | 16 +++ Documentation/kbuild/kconfig-language.rst | 32 ++++++ 12 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 scripts/kconfig/tests/err_transitional/Kconfig create mode 100644 scripts/kconfig/tests/transitional/Kconfig create mode 100644 scripts/kconfig/tests/err_transitional/__init__.py create mode 100644 scripts/kconfig/tests/err_transitional/expected_stderr create mode 100644 scripts/kconfig/tests/transitional/__init__.py create mode 100644 scripts/kconfig/tests/transitional/expected_config create mode 100644 scripts/kconfig/tests/transitional/initial_config
scripts/kconfig/tests/err_transitional/Kconfig new file +52 -0
@@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0 +# Test that transitional symbols cannot have properties other than help + +config BAD_DEFAULT + bool + transitional + default y + help + This transitional symbol illegally has a default property. + +config BAD_PROMPT + bool + transitional + prompt "Bad prompt" + help + This transitional symbol illegally has a prompt. + +config BAD_SELECT + bool + transitional + select OTHER_SYMBOL + help + This transitional symbol illegally has a select. + +config BAD_IMPLY + bool + transitional + imply OTHER_SYMBOL + help + This transitional symbol illegally has an imply. + +config BAD_DEPENDS + bool + transitional + depends on OTHER_SYMBOL + help + This transitional symbol illegally has a depends. + +config BAD_RANGE + int + transitional + range 1 10 + help + This transitional symbol illegally has a range. + +config BAD_NO_TYPE + transitional + help + This transitional symbol illegally has no type specified. + +config OTHER_SYMBOL + bool
scripts/kconfig/tests/transitional/Kconfig new file +100 -0
100 lines not on this page · raw message
scripts/kconfig/expr.h +1 -0
@@ -145,6 +145,7 @@ struct symbol {#define SYMBOL_CONST 0x0001/* symbol is const */ #define SYMBOL_CHECK 0x0008/* used during dependency checking */ #define SYMBOL_VALID 0x0080/* set when symbol.curr is calculated */ +#define SYMBOL_HIDDEN 0x0100/* symbol is hidden (usable but invisible) */ #define SYMBOL_WRITE 0x0200/* write symbol to file (KCONFIG_CONFIG) */ #define SYMBOL_WRITTEN 0x0800/* track info to avoid double-write to .config */ #define SYMBOL_CHECKED 0x2000/* used during dependency checking */
scripts/kconfig/lexer.l +1 -0
@@ -126,6 +126,7 @@ n [A-Za-z0-9_-] "select" return T_SELECT; "source" return T_SOURCE; "string" return T_STRING; +"transitional" return T_TRANSITIONAL; "tristate" return T_TRISTATE; "visible" return T_VISIBLE; "||" return T_OR;
scripts/kconfig/parser.y +47 -0
71 lines not on this page · raw message
scripts/kconfig/symbol.c +13 -3
@@ -408,6 +408,7 @@ void sym_calc_value(struct symbol *sym)struct symbol_value newval, oldval;struct property *prop;struct menu *choice_menu; +bool usable;if (!sym)return ;
@@ -447,6 +448,13 @@ void sym_calc_value(struct symbol *sym)if (sym->visible != no) sym->flags |=SYMBOL_WRITE ; +/* +* For a symbol to be processed during configuration it needs to +* be either visible or a transitional symbol that is hidden from +* menus and omitted from newly written .config files. +*/ + usable = (sym->visible != no || (sym->flags &SYMBOL_HIDDEN )); +/* set default if recursively called */ sym->curr = newval;
@@ -459,13 +467,15 @@ void sym_calc_value(struct symbol *sym)sym_calc_choice (choice_menu); newval.tri = sym->curr.tri; }else { -if (sym->visible != no) { +if (usable) {/* if the symbol is visible use the user value * if available, otherwise try the default value */ if (sym_has_value (sym)) { +tristate value = (sym->flags &SYMBOL_HIDDEN ) ? + sym->def[S_DEF_USER ].tri : sym->visible; newval.tri =EXPR_AND (sym->def[S_DEF_USER ].tri, - sym->visible); + value); goto calc_newval; } }
@@ -497,7 +507,7 @@ void sym_calc_value(struct symbol *sym)case S_STRING :case S_HEX :case S_INT : -if (sym->visible != no &&sym_has_value (sym)) { +if (usable &&sym_has_value (sym)) { newval.val = sym->def[S_DEF_USER ].val;break ; }
scripts/kconfig/tests/err_transitional/__init__.py new file +14 -0
@@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Test that transitional symbols with invalid properties are rejected. + +Transitional symbols can only have help sections. Any other properties +(default, select, depends, etc.) should cause a parser error. +""" + +def test(conf): + # This should fail with exit code 1 due to invalid transitional symbol + assert conf.olddefconfig() == 1 + + # Check that the error message is about transitional symbols + assert conf.stderr_contains('expected_stderr')
scripts/kconfig/tests/err_transitional/expected_stderr new file +7 -0
@@ -0,0 +1,7 @@ +Kconfig:46:warning: config symbol defined without type +Kconfig:7: error: transitional symbols can only have help sections +Kconfig:14: error: transitional symbols can only have help sections +Kconfig:21: error: transitional symbols can only have help sections +Kconfig:28: error: transitional symbols can only have help sections +Kconfig:32: error: transitional symbols can only have help sections +Kconfig:42: error: transitional symbols can only have help sections
scripts/kconfig/tests/transitional/__init__.py new file +18 -0
@@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Test transitional symbol migration functionality for all Kconfig types. + +This tests that: +1. OLD_* options in existing .config cause NEW_* options to be set +2. OLD_* options are not written to the new .config file +3. NEW_* options appear in the new .config file with correct values +4. All Kconfig types work correctly: bool, tristate, string, hex, int +5. User-set NEW values take precedence over conflicting OLD transitional values +""" + +def test(conf): + # Run olddefconfig to process the migration with the initial config + assert conf.olddefconfig(dot_config='initial_config') == 0 + + # Check that the configuration matches expected output + assert conf.config_contains('expected_config')
scripts/kconfig/tests/transitional/expected_config new file +12 -0
@@ -0,0 +1,12 @@ +CONFIG_MODULES=y +CONFIG_NEW_BOOL=y +CONFIG_NEW_TRISTATE=m +CONFIG_NEW_STRING="test string" +CONFIG_NEW_HEX=0x1234 +CONFIG_NEW_INT=42 +# CONFIG_NEW_BOOL_PRECEDENCE is not set +CONFIG_NEW_STRING_PRECEDENCE="user value" +CONFIG_NEW_TRISTATE_PRECEDENCE=y +CONFIG_NEW_HEX_PRECEDENCE=0xABCD +CONFIG_NEW_INT_PRECEDENCE=100 +# CONFIG_REGULAR_OPTION is not set
scripts/kconfig/tests/transitional/initial_config new file +16 -0
@@ -0,0 +1,16 @@ +CONFIG_MODULES=y +CONFIG_OLD_BOOL=y +CONFIG_OLD_TRISTATE=m +CONFIG_OLD_STRING="test string" +CONFIG_OLD_HEX=0x1234 +CONFIG_OLD_INT=42 +# CONFIG_NEW_BOOL_PRECEDENCE is not set +CONFIG_OLD_BOOL_PRECEDENCE=y +CONFIG_NEW_STRING_PRECEDENCE="user value" +CONFIG_OLD_STRING_PRECEDENCE="old value" +CONFIG_NEW_TRISTATE_PRECEDENCE=y +CONFIG_OLD_TRISTATE_PRECEDENCE=m +CONFIG_NEW_HEX_PRECEDENCE=0xABCD +CONFIG_OLD_HEX_PRECEDENCE=0x5678 +CONFIG_NEW_INT_PRECEDENCE=100 +CONFIG_OLD_INT_PRECEDENCE=200
Documentation/kbuild/kconfig-language.rst +32 -0
@@ -232,6 +232,38 @@ applicable everywhere (see syntax). enables the third modular state for all config symbols. At most one symbol may have the "modules" option set. +- transitional attribute: "transitional" + This declares the symbol as transitional, meaning it should be processed + during configuration but omitted from newly written .config files. + Transitional symbols are useful for backward compatibility during config + option migrations - they allow olddefconfig to process existing .config + files while ensuring the old option doesn't appear in new configurations. + + A transitional symbol: + - Has no prompt (is not visible to users in menus) + - Is processed normally during configuration (values are read and used) + - Can be referenced in default expressions of other symbols + - Is not written to new .config files + - Cannot have any other properties (it is a pass-through option) + + Example migration from OLD_NAME to NEW_NAME:: + + config NEW_NAME + bool "New option name" + default OLD_NAME + help + This replaces the old CONFIG_OLD_NAME option. + + config OLD_NAME + bool + transitional + help + Transitional config for OLD_NAME to NEW_NAME migration. + + With this setup, existing .config files with "CONFIG_OLD_NAME=y" will + result in "CONFIG_NEW_NAME=y" being set, while CONFIG_OLD_NAME will be + omitted from newly written .config files. + Menu dependencies -----------------
Signature · 1 line
2.34.1