Skip to content

Commit 31f0cfc

Browse files
committed
Suppress transitional symbols
Linux v6.18 introduced the 'transitional' keyword for Kconfig symbols (commit 23ef9d439769d5) enabling clean option renaming: old symbols marked transitional are read from existing .config files to populate new symbol defaults, but must never appear in generated output. The parser already sets is_transitional but the flag had no behavioral impact. Add four guards to suppress transitional symbols from: - _autoconf_contents() (write_autoconf / autoconf.h) - _min_config_contents() (write_min_config) - sync_deps() (dep-file touches / auto.conf) - Symbol.config_string (write_config, _old_vals_contents) This rewrites 'makefile.patch' for Linux v6.x Makefile layout where config targets are generated by a $(foreach ...) / config_rule macro rather than individual rules.
1 parent 5e6a971 commit 31f0cfc

6 files changed

Lines changed: 179 additions & 12 deletions

File tree

‎.github/workflows/test.yml‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ jobs:
2222
# shell). Linux/macOS run selftests, compatibility tests, and
2323
# example scripts.
2424
target:
25-
# Python 3.12
2625
- python: '3.12'
2726
os: Linux
2827
builder: ubuntu-24.04
@@ -65,7 +64,7 @@ jobs:
6564
uses: actions/checkout@v6
6665
with:
6766
repository: torvalds/linux
68-
ref: v5.4
67+
ref: v6.18
6968

7069
- name: Check out Kconfiglib source code
7170
uses: actions/checkout@v6

‎kconfiglib.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,9 @@ def _autoconf_contents(self, header):
15731573
if not sym._write_to_conf:
15741574
continue
15751575

1576+
if sym.is_transitional:
1577+
continue
1578+
15761579
if sym.orig_type in _BOOL_TRISTATE:
15771580
if val == "y":
15781581
add("#define {}{} 1\n".format(self.config_prefix, sym.name))
@@ -1799,6 +1802,9 @@ def _min_config_contents(self, header):
17991802
add = chunks.append
18001803

18011804
for sym in self.unique_defined_syms:
1805+
if sym.is_transitional:
1806+
continue
1807+
18021808
# Skip symbols that cannot be changed. Only check
18031809
# non-choice symbols, as selects don't affect choice
18041810
# symbols.
@@ -1903,6 +1909,9 @@ def sync_deps(self, path):
19031909
# (though it's likely to keep working).
19041910
val = sym.str_value
19051911

1912+
if sym.is_transitional:
1913+
continue
1914+
19061915
# n tristate values do not get written to auto.conf and autoconf.h,
19071916
# making a missing symbol logically equivalent to n
19081917

@@ -4815,6 +4824,9 @@ def config_string(self):
48154824
if not self._write_to_conf:
48164825
return ""
48174826

4827+
if self.is_transitional:
4828+
return ""
4829+
48184830
if self.orig_type in _BOOL_TRISTATE:
48194831
return (
48204832
"{}{}={}\n".format(self.kconfig.config_prefix, self.name, val)

‎makefile.patch‎

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
1-
From 93daf46f309b0c8f86149ef58c4906387d054c22 Mon Sep 17 00:00:00 2001
2-
From: Ulf Magnusson <ulfalizer@gmail.com>
3-
Date: Tue, 9 Jun 2015 13:01:34 +0200
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: Kconfiglib <kconfiglib@example.com>
3+
Date: Wed, 19 Feb 2026 00:00:00 +0000
44
Subject: [PATCH] Kconfiglib scripts/kconfig/Makefile patch
55

6+
Adds scriptconfig, iscriptconfig, kmenuconfig, guiconfig, and
7+
dumpvarsconfig targets to the kernel's scripts/kconfig/Makefile,
8+
allowing Kconfiglib scripts to be run via 'make scriptconfig'.
9+
10+
Targets the v6.x kernel Makefile layout where config targets are
11+
generated by a $(foreach ...) / config_rule macro. Tested against
12+
v6.18.
613
---
714
scripts/kconfig/Makefile | 29 +++++++++++++++++++++++++++++
815
1 file changed, 29 insertions(+)
916

1017
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
11-
index 3f327e21f60e..8b7dd1292005 100644
18+
index 1ad1c35..0000000 100644
1219
--- a/scripts/kconfig/Makefile
1320
+++ b/scripts/kconfig/Makefile
14-
@@ -27,2 +27,31 @@ gconfig: $(obj)/gconf
15-
21+
@@ -70,6 +70,35 @@ endef
22+
$(foreach c, config menuconfig nconfig gconfig xconfig, $(eval $(call config_rule,$(c))))
23+
1624
+PHONY += scriptconfig iscriptconfig kmenuconfig guiconfig dumpvarsconfig
1725
+
18-
+PYTHONCMD ?= python
26+
+PYTHONCMD ?= python3
1927
+kpython := PYTHONPATH=$(srctree)/Kconfiglib:$$PYTHONPATH $(PYTHONCMD)
2028
+
2129
+ifneq ($(filter scriptconfig,$(MAKECMDGOALS)),)
@@ -42,7 +50,8 @@ index 3f327e21f60e..8b7dd1292005 100644
4250
+dumpvarsconfig:
4351
+ $(Q)$(kpython) $(srctree)/Kconfiglib/examples/dumpvars.py $(Kconfig)
4452
+
45-
menuconfig: $(obj)/mconf
46-
--
47-
2.20.1
53+
PHONY += localmodconfig localyesconfig
54+
localyesconfig localmodconfig: $(obj)/conf
55+
--
56+
2.47.0
4857

‎tests/Ktransitional‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
config NEW_BOOL
2+
bool "new bool option"
3+
default LEGACY_BOOL
4+
5+
config LEGACY_BOOL
6+
bool "legacy bool (deprecated)"
7+
transitional
8+
9+
config NEW_INT
10+
int "new int option"
11+
default LEGACY_INT
12+
13+
config LEGACY_INT
14+
int "legacy int (deprecated)"
15+
transitional
16+
17+
config NORMAL_BOOL
18+
bool "normal bool"
19+
default y
20+
21+
config NORMAL_INT
22+
int "normal int"
23+
default 42

‎tests/config_transitional‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CONFIG_LEGACY_BOOL=y
2+
CONFIG_LEGACY_INT=99

‎tests/test_transitional.py‎

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
"""Tests for the 'transitional' keyword (Linux >= 6.18).
2+
3+
Transitional symbols are read from old .config files to populate new symbol
4+
defaults, but must never appear in generated .config, autoconf.h, or
5+
min-config output.
6+
"""
7+
8+
import os
9+
import tempfile
10+
11+
import kconfiglib
12+
13+
KCONFIG_PATH = "tests/Ktransitional"
14+
CONFIG_PATH = "tests/config_transitional"
15+
16+
17+
def _load(config_path=None):
18+
"""Load the transitional test Kconfig, optionally with a .config."""
19+
kconf = kconfiglib.Kconfig(KCONFIG_PATH, warn=False)
20+
if config_path:
21+
kconf.load_config(config_path)
22+
return kconf
23+
24+
25+
def test_transitional_flag():
26+
"""is_transitional is True for transitional syms, False for normal."""
27+
kconf = _load()
28+
29+
assert kconf.syms["LEGACY_BOOL"].is_transitional is True
30+
assert kconf.syms["LEGACY_INT"].is_transitional is True
31+
assert kconf.syms["NEW_BOOL"].is_transitional is False
32+
assert kconf.syms["NEW_INT"].is_transitional is False
33+
assert kconf.syms["NORMAL_BOOL"].is_transitional is False
34+
assert kconf.syms["NORMAL_INT"].is_transitional is False
35+
36+
37+
def test_transitional_migration():
38+
"""Loading old .config with LEGACY_BOOL=y causes NEW_BOOL to default to y."""
39+
kconf = _load(CONFIG_PATH)
40+
41+
# LEGACY_BOOL=y was loaded, so NEW_BOOL (default LEGACY_BOOL) should be y
42+
assert kconf.syms["NEW_BOOL"].str_value == "y"
43+
# LEGACY_INT=99 was loaded, so NEW_INT (default LEGACY_INT) should be 99
44+
assert kconf.syms["NEW_INT"].str_value == "99"
45+
46+
47+
def test_transitional_write_config():
48+
"""Transitional symbols absent from write_config output; normal symbols present."""
49+
kconf = _load(CONFIG_PATH)
50+
51+
with tempfile.NamedTemporaryFile(mode="r", suffix=".config", delete=False) as f:
52+
tmppath = f.name
53+
try:
54+
kconf.write_config(tmppath)
55+
with open(tmppath) as f:
56+
content = f.read()
57+
finally:
58+
os.unlink(tmppath)
59+
60+
assert "LEGACY_BOOL" not in content
61+
assert "LEGACY_INT" not in content
62+
assert "NEW_BOOL" in content
63+
assert "NORMAL_BOOL" in content
64+
assert "NORMAL_INT" in content
65+
66+
67+
def test_transitional_write_autoconf():
68+
"""Transitional symbols absent from write_autoconf output."""
69+
kconf = _load(CONFIG_PATH)
70+
71+
with tempfile.NamedTemporaryFile(mode="r", suffix=".h", delete=False) as f:
72+
tmppath = f.name
73+
try:
74+
kconf.write_autoconf(tmppath)
75+
with open(tmppath) as f:
76+
content = f.read()
77+
finally:
78+
os.unlink(tmppath)
79+
80+
assert "LEGACY_BOOL" not in content
81+
assert "LEGACY_INT" not in content
82+
# NEW_BOOL=y should produce a #define
83+
assert "NEW_BOOL" in content
84+
85+
86+
def test_transitional_write_min_config():
87+
"""Transitional symbols absent from write_min_config output."""
88+
kconf = _load(CONFIG_PATH)
89+
90+
with tempfile.NamedTemporaryFile(mode="r", suffix=".config", delete=False) as f:
91+
tmppath = f.name
92+
try:
93+
kconf.write_min_config(tmppath)
94+
with open(tmppath) as f:
95+
content = f.read()
96+
finally:
97+
os.unlink(tmppath)
98+
99+
assert "LEGACY_BOOL" not in content
100+
assert "LEGACY_INT" not in content
101+
102+
103+
def test_transitional_config_string():
104+
"""config_string returns '' for transitional symbols."""
105+
kconf = _load(CONFIG_PATH)
106+
107+
assert kconf.syms["LEGACY_BOOL"].config_string == ""
108+
assert kconf.syms["LEGACY_INT"].config_string == ""
109+
# Normal symbols should have non-empty config_string
110+
assert kconf.syms["NORMAL_BOOL"].config_string != ""
111+
assert kconf.syms["NORMAL_INT"].config_string != ""
112+
113+
114+
def test_transitional_repr():
115+
"""repr() includes 'transitional' for flagged symbols."""
116+
kconf = _load()
117+
118+
# Use ", transitional," to avoid false-matching the filename Ktransitional
119+
assert ", transitional," in repr(kconf.syms["LEGACY_BOOL"])
120+
assert ", transitional," in repr(kconf.syms["LEGACY_INT"])
121+
assert ", transitional," not in repr(kconf.syms["NEW_BOOL"])
122+
assert ", transitional," not in repr(kconf.syms["NORMAL_BOOL"])

0 commit comments

Comments
 (0)