Skip to content

Commit f9afce4

Browse files
committed
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. Added positive and negative testing via "testconfig" make target. Co-developed-by: Vegard Nossum <vegard.nossum@oracle.com> Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com> Reviewed-by: Nathan Chancellor <nathan@kernel.org> Tested-by: Nathan Chancellor <nathan@kernel.org> Link: https://lore.kernel.org/r/20250923213422.1105654-2-kees@kernel.org Signed-off-by: Kees Cook <kees@kernel.org>
1 parent 64f4ea2 commit f9afce4

12 files changed

Lines changed: 306 additions & 1 deletion

File tree

Documentation/kbuild/kconfig-language.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,38 @@ applicable everywhere (see syntax).
232232
enables the third modular state for all config symbols.
233233
At most one symbol may have the "modules" option set.
234234

235+
- transitional attribute: "transitional"
236+
This declares the symbol as transitional, meaning it should be processed
237+
during configuration but omitted from newly written .config files.
238+
Transitional symbols are useful for backward compatibility during config
239+
option migrations - they allow olddefconfig to process existing .config
240+
files while ensuring the old option doesn't appear in new configurations.
241+
242+
A transitional symbol:
243+
- Has no prompt (is not visible to users in menus)
244+
- Is processed normally during configuration (values are read and used)
245+
- Can be referenced in default expressions of other symbols
246+
- Is not written to new .config files
247+
- Cannot have any other properties (it is a pass-through option)
248+
249+
Example migration from OLD_NAME to NEW_NAME::
250+
251+
config NEW_NAME
252+
bool "New option name"
253+
default OLD_NAME
254+
help
255+
This replaces the old CONFIG_OLD_NAME option.
256+
257+
config OLD_NAME
258+
bool
259+
transitional
260+
help
261+
Transitional config for OLD_NAME to NEW_NAME migration.
262+
263+
With this setup, existing .config files with "CONFIG_OLD_NAME=y" will
264+
result in "CONFIG_NEW_NAME=y" being set, while CONFIG_OLD_NAME will be
265+
omitted from newly written .config files.
266+
235267
Menu dependencies
236268
-----------------
237269

scripts/kconfig/expr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ struct symbol {
145145
#define SYMBOL_CONST 0x0001 /* symbol is const */
146146
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
147147
#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
148+
#define SYMBOL_TRANS 0x0100 /* symbol is transitional only (not visible)*/
148149
#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
149150
#define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */
150151
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */

scripts/kconfig/lexer.l

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ n [A-Za-z0-9_-]
126126
"select" return T_SELECT;
127127
"source" return T_SOURCE;
128128
"string" return T_STRING;
129+
"transitional" return T_TRANSITIONAL;
129130
"tristate" return T_TRISTATE;
130131
"visible" return T_VISIBLE;
131132
"||" return T_OR;

scripts/kconfig/parser.y

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct menu *current_menu, *current_entry, *current_choice;
7575
%token T_SELECT
7676
%token T_SOURCE
7777
%token T_STRING
78+
%token T_TRANSITIONAL
7879
%token T_TRISTATE
7980
%token T_VISIBLE
8081
%token T_EOL
@@ -205,6 +206,12 @@ config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
205206
printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
206207
};
207208

209+
config_option: T_TRANSITIONAL T_EOL
210+
{
211+
current_entry->sym->flags |= SYMBOL_TRANS;
212+
printd(DEBUG_PARSE, "%s:%d:transitional\n", cur_filename, cur_lineno);
213+
};
214+
208215
config_option: default expr if_expr T_EOL
209216
{
210217
menu_add_expr(P_DEFAULT, $2, $3);
@@ -482,6 +489,43 @@ assign_val:
482489

483490
%%
484491

492+
/**
493+
* transitional_check_sanity - check transitional symbols have no other
494+
* properties
495+
*
496+
* @menu: menu of the potentially transitional symbol
497+
*
498+
* Return: -1 if an error is found, 0 otherwise.
499+
*/
500+
static int transitional_check_sanity(const struct menu *menu)
501+
{
502+
struct property *prop;
503+
504+
if (!menu->sym || !(menu->sym->flags & SYMBOL_TRANS))
505+
return 0;
506+
507+
/* Check for depends and visible conditions. */
508+
if ((menu->dep && !expr_is_yes(menu->dep)) ||
509+
(menu->visibility && !expr_is_yes(menu->visibility))) {
510+
fprintf(stderr, "%s:%d: error: %s",
511+
menu->filename, menu->lineno,
512+
"transitional symbols can only have help sections\n");
513+
return -1;
514+
}
515+
516+
/* Check for any property other than "help". */
517+
for (prop = menu->sym->prop; prop; prop = prop->next) {
518+
if (prop->type != P_COMMENT) {
519+
fprintf(stderr, "%s:%d: error: %s",
520+
prop->filename, prop->lineno,
521+
"transitional symbols can only have help sections\n");
522+
return -1;
523+
}
524+
}
525+
526+
return 0;
527+
}
528+
485529
/**
486530
* choice_check_sanity - check sanity of a choice member
487531
*
@@ -558,6 +602,9 @@ void conf_parse(const char *name)
558602
if (menu->sym && sym_check_deps(menu->sym))
559603
yynerrs++;
560604

605+
if (transitional_check_sanity(menu))
606+
yynerrs++;
607+
561608
if (menu->sym && sym_is_choice(menu->sym)) {
562609
menu_for_each_sub_entry(child, menu)
563610
if (child->sym && choice_check_sanity(child))

scripts/kconfig/symbol.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ static void sym_calc_visibility(struct symbol *sym)
214214
struct property *prop;
215215
tristate tri;
216216

217+
if (sym->flags & SYMBOL_TRANS) {
218+
sym->visible = yes;
219+
return;
220+
}
221+
217222
/* any prompt visible? */
218223
tri = no;
219224
for_all_prompts(sym, prop) {
@@ -526,7 +531,7 @@ void sym_calc_value(struct symbol *sym)
526531
}
527532
}
528533

529-
if (sym_is_choice(sym))
534+
if (sym_is_choice(sym) || sym->flags & SYMBOL_TRANS)
530535
sym->flags &= ~SYMBOL_WRITE;
531536
}
532537

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Test that transitional symbols cannot have properties other than help
3+
4+
config BAD_DEFAULT
5+
bool
6+
transitional
7+
default y
8+
help
9+
This transitional symbol illegally has a default property.
10+
11+
config BAD_PROMPT
12+
bool
13+
transitional
14+
prompt "Bad prompt"
15+
help
16+
This transitional symbol illegally has a prompt.
17+
18+
config BAD_SELECT
19+
bool
20+
transitional
21+
select OTHER_SYMBOL
22+
help
23+
This transitional symbol illegally has a select.
24+
25+
config BAD_IMPLY
26+
bool
27+
transitional
28+
imply OTHER_SYMBOL
29+
help
30+
This transitional symbol illegally has an imply.
31+
32+
config BAD_DEPENDS
33+
bool
34+
transitional
35+
depends on OTHER_SYMBOL
36+
help
37+
This transitional symbol illegally has a depends.
38+
39+
config BAD_RANGE
40+
int
41+
transitional
42+
range 1 10
43+
help
44+
This transitional symbol illegally has a range.
45+
46+
config BAD_NO_TYPE
47+
transitional
48+
help
49+
This transitional symbol illegally has no type specified.
50+
51+
config OTHER_SYMBOL
52+
bool
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
"""
3+
Test that transitional symbols with invalid properties are rejected.
4+
5+
Transitional symbols can only have help sections. Any other properties
6+
(default, select, depends, etc.) should cause a parser error.
7+
"""
8+
9+
def test(conf):
10+
# This should fail with exit code 1 due to invalid transitional symbol
11+
assert conf.olddefconfig() == 1
12+
13+
# Check that the error message is about transitional symbols
14+
assert conf.stderr_contains('expected_stderr')
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Kconfig:46:warning: config symbol defined without type
2+
Kconfig:7: error: transitional symbols can only have help sections
3+
Kconfig:14: error: transitional symbols can only have help sections
4+
Kconfig:21: error: transitional symbols can only have help sections
5+
Kconfig:28: error: transitional symbols can only have help sections
6+
Kconfig:32: error: transitional symbols can only have help sections
7+
Kconfig:42: error: transitional symbols can only have help sections
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Test transitional symbols for config migration with all Kconfig types
3+
4+
# Enable module support for tristate testing
5+
config MODULES
6+
bool "Enable loadable module support"
7+
modules
8+
default y
9+
10+
# Basic migration tests for all types
11+
config NEW_BOOL
12+
bool "New bool option"
13+
default OLD_BOOL
14+
15+
config OLD_BOOL
16+
bool
17+
transitional
18+
19+
config NEW_TRISTATE
20+
tristate "New tristate option"
21+
default OLD_TRISTATE
22+
23+
config OLD_TRISTATE
24+
tristate
25+
transitional
26+
27+
config NEW_STRING
28+
string "New string option"
29+
default OLD_STRING
30+
31+
config OLD_STRING
32+
string
33+
transitional
34+
35+
config NEW_HEX
36+
hex "New hex option"
37+
default OLD_HEX
38+
39+
config OLD_HEX
40+
hex
41+
transitional
42+
43+
config NEW_INT
44+
int "New int option"
45+
default OLD_INT
46+
47+
config OLD_INT
48+
int
49+
transitional
50+
51+
# Precedence tests for all types
52+
config NEW_BOOL_PRECEDENCE
53+
bool "New bool option with precedence"
54+
default OLD_BOOL_PRECEDENCE
55+
56+
config OLD_BOOL_PRECEDENCE
57+
bool
58+
transitional
59+
60+
config NEW_STRING_PRECEDENCE
61+
string "New string option with precedence"
62+
default OLD_STRING_PRECEDENCE
63+
64+
config OLD_STRING_PRECEDENCE
65+
string
66+
transitional
67+
68+
config NEW_TRISTATE_PRECEDENCE
69+
tristate "New tristate option with precedence"
70+
default OLD_TRISTATE_PRECEDENCE
71+
72+
config OLD_TRISTATE_PRECEDENCE
73+
tristate
74+
transitional
75+
76+
config NEW_HEX_PRECEDENCE
77+
hex "New hex option with precedence"
78+
default OLD_HEX_PRECEDENCE
79+
80+
config OLD_HEX_PRECEDENCE
81+
hex
82+
transitional
83+
84+
config NEW_INT_PRECEDENCE
85+
int "New int option with precedence"
86+
default OLD_INT_PRECEDENCE
87+
88+
config OLD_INT_PRECEDENCE
89+
int
90+
transitional
91+
92+
# Test that help sections are allowed for transitional symbols
93+
config OLD_WITH_HELP
94+
bool
95+
transitional
96+
help
97+
This transitional symbol has a help section to validate that help is allowed.
98+
99+
config REGULAR_OPTION
100+
bool "Regular option"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
"""
3+
Test transitional symbol migration functionality for all Kconfig types.
4+
5+
This tests that:
6+
- OLD_* options in existing .config cause NEW_* options to be set
7+
- OLD_* options are not written to the new .config file
8+
- NEW_* options appear in the new .config file with correct values
9+
- All Kconfig types work correctly: bool, tristate, string, hex, int
10+
- User-set NEW values take precedence over conflicting OLD transitional values
11+
"""
12+
13+
def test(conf):
14+
# Run olddefconfig to process the migration with the initial config
15+
assert conf.olddefconfig(dot_config='initial_config') == 0
16+
17+
# Check that the configuration matches expected output
18+
assert conf.config_contains('expected_config')

0 commit comments

Comments
 (0)