Skip to content

Commit c833850

Browse files
authored
Merge pull request #39 from sysprog21/linux-compat
Suppress transitional symbols
2 parents 5e6a971 + 7852844 commit c833850

8 files changed

Lines changed: 202 additions & 26 deletions

File tree

‎.github/workflows/test.yml‎

Lines changed: 15 additions & 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
@@ -59,13 +58,27 @@ jobs:
5958
run: |
6059
python -m pip install --user setuptools wheel pytest
6160
61+
- name: Install GNU toolchain (macOS)
62+
# v6.18 kernel Kconfig probes require GNU Make >= 4.0 and a
63+
# supported linker (GNU ld or LLD). macOS ships Make 3.81
64+
# and Apple ld, neither of which is compatible.
65+
# We add ld.lld to PATH and set LD=ld.lld; reltest forwards LD
66+
# as a make command-line variable to override the kernel
67+
# Makefile's unconditional LD=$(CROSS_COMPILE)ld assignment.
68+
if: ${{ matrix.target.os == 'macOS' }}
69+
run: |
70+
brew install make lld
71+
echo "$(brew --prefix make)/libexec/gnubin" >> $GITHUB_PATH
72+
echo "$(brew --prefix lld)/bin" >> $GITHUB_PATH
73+
echo "LD=ld.lld" >> $GITHUB_ENV
74+
6275
- name: Check out Linux source code
6376
# Skip for Windows (headless-only mode)
6477
if: ${{ matrix.target.headless-only != true }}
6578
uses: actions/checkout@v6
6679
with:
6780
repository: torvalds/linux
68-
ref: v5.4
81+
ref: v6.18
6982

7083
- name: Check out Kconfiglib source code
7184
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: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
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
4-
Subject: [PATCH] Kconfiglib scripts/kconfig/Makefile patch
5-
6-
---
7-
scripts/kconfig/Makefile | 29 +++++++++++++++++++++++++++++
8-
1 file changed, 29 insertions(+)
9-
101
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
11-
index 3f327e21f60e..8b7dd1292005 100644
2+
index fb50bd4..85f47ce 100644
123
--- a/scripts/kconfig/Makefile
134
+++ b/scripts/kconfig/Makefile
14-
@@ -27,2 +27,31 @@ gconfig: $(obj)/gconf
5+
@@ -55,6 +55,35 @@ endef
6+
7+
$(foreach c, config menuconfig nconfig gconfig xconfig, $(eval $(call config_rule,$(c))))
158

169
+PHONY += scriptconfig iscriptconfig kmenuconfig guiconfig dumpvarsconfig
1710
+
18-
+PYTHONCMD ?= python
11+
+PYTHONCMD ?= python3
1912
+kpython := PYTHONPATH=$(srctree)/Kconfiglib:$$PYTHONPATH $(PYTHONCMD)
2013
+
2114
+ifneq ($(filter scriptconfig,$(MAKECMDGOALS)),)
@@ -42,7 +35,6 @@ index 3f327e21f60e..8b7dd1292005 100644
4235
+dumpvarsconfig:
4336
+ $(Q)$(kpython) $(srctree)/Kconfiglib/examples/dumpvars.py $(Kconfig)
4437
+
45-
menuconfig: $(obj)/mconf
46-
--
47-
2.20.1
48-
38+
PHONY += localmodconfig localyesconfig
39+
localyesconfig localmodconfig: $(obj)/conf
40+
$(Q)$(PERL) $(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config

‎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/reltest‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@
1212

1313
test_script() {
1414
echo -e "\n================= $1 with $py =================\n"
15+
# Forward LD as a make command-line variable so it overrides the
16+
# kernel Makefile's unconditional LD=$(CROSS_COMPILE)ld assignment.
17+
# Environment variables alone do not override Makefile assignments.
18+
local _ld_override=""
19+
[ -n "${LD:-}" ] && _ld_override="LD=$LD"
1520
if (($# == 1)); then
16-
make scriptconfig PYTHONCMD=$py SCRIPT=$1
21+
${MAKE:-make} $_ld_override scriptconfig PYTHONCMD=$py SCRIPT=$1
1722
else
18-
make scriptconfig PYTHONCMD=$py SCRIPT=$1 SCRIPT_ARG="$2"
23+
${MAKE:-make} $_ld_override scriptconfig PYTHONCMD=$py SCRIPT=$1 SCRIPT_ARG="$2"
1924
fi
2025

2126
if (($?)); then

‎tests/test_compat.py‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,21 @@ def kernel_env():
6464
These are referenced inside the kernel Kconfig files and must be present
6565
before any Kconfig object is instantiated.
6666
"""
67+
os.environ["srctree"] = "."
68+
os.environ.setdefault("CC", "gcc")
69+
os.environ.setdefault("LD", "ld")
70+
_make = os.environ.get("MAKE", "make")
71+
_cc = os.environ["CC"]
6772
os.environ["KERNELVERSION"] = (
68-
subprocess.check_output("make kernelversion", shell=True)
73+
subprocess.check_output(f"{_make} kernelversion", shell=True)
6974
.decode("utf-8")
7075
.rstrip()
7176
)
7277
os.environ["CC_VERSION_TEXT"] = (
73-
subprocess.check_output("gcc --version | head -n1", shell=True)
78+
subprocess.check_output(f"{_cc} --version | head -n1", shell=True)
7479
.decode("utf-8")
7580
.rstrip()
7681
)
77-
os.environ["srctree"] = "."
78-
os.environ["CC"] = "gcc"
79-
os.environ["LD"] = "ld"
8082
yield
8183

8284

@@ -126,7 +128,12 @@ def run_conf_and_compare(script, conf_flag, arch):
126128
"""Run a Kconfiglib script via 'make scriptconfig', then run the C
127129
implementation with *conf_flag*, and compare the resulting .config files.
128130
"""
129-
shell(f"make scriptconfig SCRIPT={script} PYTHONCMD='{sys.executable}'")
131+
_make = os.environ.get("MAKE", "make")
132+
_ld = os.environ.get("LD")
133+
_ld_override = f"LD={_ld}" if _ld else ""
134+
shell(
135+
f"{_make} {_ld_override} scriptconfig SCRIPT={script} PYTHONCMD='{sys.executable}'"
136+
)
130137
shell("mv .config ._config")
131138
shell(f"scripts/kconfig/conf --{conf_flag} Kconfig")
132139
compare_configs(arch)

‎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)