Skip to content

Commit 2a635b4

Browse files
committed
Use portable $(python,...) preprocessor for Kconfig detection
Replace all $(shell,...) calls with the portable $(python,...) preprocessor function from Kconfiglib. The $(python,...) built-in evaluates Python code in-process and returns "y"/"n" without spawning a shell, eliminating POSIX shell dependencies (2>/dev/null, ||, echo) for cross-platform portability. Simple checks (SDL2, SDL2_mixer) are inlined directly using the run() and shutil.which() helpers available in the $(python,...) namespace. Complex checks (compiler type, LLVM 18, RISC-V toolchain) delegate to detect-env.py via run(sys.executable, ...) with exit-code signaling. COMPILER_TYPE is derived from the CC_IS_CLANG/CC_IS_GCC/CC_IS_EMCC booleans using pure Kconfig conditionals, eliminating the last $(shell,...) call. detect-env.py changes: - Boolean flags now use exit codes (0/1) via bool_exit() instead of printing "y"/"n", matching the run() convention in $(python,...). - Compiler probing is lazy: --have-sdl2, --have-llvm18, etc. no longer pay the cost of running CC --version when they don't need it. - get_compiler_version() captures both stdout and stderr to handle emcc variants that emit version info on stderr. Reference: sysprog21/Kconfiglib#47
1 parent 47cf03d commit 2a635b4

2 files changed

Lines changed: 59 additions & 35 deletions

File tree

configs/Kconfig

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,31 @@
44

55
mainmenu "rv32emu Configuration"
66

7-
# Environment Detection (read-only, set by tools/detect-env.py)
7+
# Environment Detection (read-only)
8+
#
9+
# Boolean checks use the portable $(python,...) preprocessor function
10+
# with run() for shell-free subprocess execution.
11+
#
12+
# See: https://github.com/sysprog21/Kconfiglib/pull/47
813

914
menu "Toolchain Detection"
1015

1116
config COMPILER_TYPE
1217
string
13-
default "$(shell,tools/detect-env.py --compiler 2>/dev/null || echo Unknown)"
18+
default "Emscripten" if CC_IS_EMCC
19+
default "Clang" if CC_IS_CLANG
20+
default "GCC" if CC_IS_GCC
21+
default "Unknown"
1422

1523
config HAVE_EMCC
1624
bool
17-
default $(shell,tools/detect-env.py --have-emcc 2>/dev/null)
25+
default $(python,assert run(sys.executable, 'tools/detect-env.py', '--have-emcc'))
1826

1927
config CC_IS_CLANG
20-
def_bool $(shell,tools/detect-env.py --is-clang 2>/dev/null)
28+
def_bool $(python,assert run(sys.executable, 'tools/detect-env.py', '--is-clang'))
2129

2230
config CC_IS_GCC
23-
def_bool $(shell,tools/detect-env.py --is-gcc 2>/dev/null)
31+
def_bool $(python,assert run(sys.executable, 'tools/detect-env.py', '--is-gcc'))
2432

2533
comment "Emscripten detected - WebAssembly build available"
2634
depends on HAVE_EMCC
@@ -76,20 +84,20 @@ endmenu
7684
config HAVE_SDL2
7785
bool
7886
default n if CC_IS_EMCC
79-
default $(shell,tools/detect-env.py --have-sdl2 2>/dev/null)
87+
default $(python,assert shutil.which('sdl2-config') or run('pkg-config', '--exists', 'sdl2'))
8088

8189
config HAVE_SDL2_MIXER
8290
bool
8391
default n if CC_IS_EMCC
84-
default $(shell,tools/detect-env.py --have-sdl2-mixer 2>/dev/null)
92+
default $(python,assert run('pkg-config', '--exists', 'SDL2_mixer'))
8593

8694
config HAVE_LLVM18
8795
bool
88-
default $(shell,tools/detect-env.py --have-llvm18 2>/dev/null)
96+
default $(python,assert run(sys.executable, 'tools/detect-env.py', '--have-llvm18'))
8997

9098
config HAVE_RISCV_TOOLCHAIN
9199
bool
92-
default $(shell,tools/detect-env.py --have-riscv-toolchain 2>/dev/null)
100+
default $(python,assert run(sys.executable, 'tools/detect-env.py', '--have-riscv-toolchain'))
93101

94102
# RISC-V ISA Extensions
95103

tools/detect-env.py

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@
33
Environment Detection Script for rv32emu Build System
44
55
Detects compilers, libraries, and toolchains for Kconfig integration.
6-
Called by Kconfig with $(shell,...) to populate configuration options.
6+
Boolean checks use exit codes (0 = true, 1 = false) for portable
7+
$(python,...) preprocessor integration.
78
89
Usage:
910
python3 detect-env.py [OPTIONS]
1011
1112
Options:
1213
--compiler Print detected compiler type (GCC/Clang/Emscripten)
13-
--is-emcc Check if compiler is Emscripten (prints y/n)
14-
--is-clang Check if compiler is Clang (prints y/n)
15-
--is-gcc Check if compiler is GCC (prints y/n)
16-
--have-emcc Check if Emscripten (emcc) is available (prints y/n)
17-
--have-sdl2 Check if SDL2 is available (prints y/n)
18-
--have-sdl2-mixer Check if SDL2_mixer is available (prints y/n)
19-
--have-llvm18 Check if LLVM 18 is available (prints y/n)
20-
--have-riscv-toolchain Check if RISC-V toolchain exists (prints y/n)
14+
--is-emcc Check if compiler is Emscripten (exit 0/1)
15+
--is-clang Check if compiler is Clang (exit 0/1)
16+
--is-gcc Check if compiler is GCC (exit 0/1)
17+
--have-emcc Check if Emscripten (emcc) is available (exit 0/1)
18+
--have-sdl2 Check if SDL2 is available (exit 0/1)
19+
--have-sdl2-mixer Check if SDL2_mixer is available (exit 0/1)
20+
--have-llvm18 Check if LLVM 18 is available (exit 0/1)
21+
--have-riscv-toolchain Check if RISC-V toolchain exists (exit 0/1)
2122
--summary Print full environment summary
2223
"""
2324

@@ -55,13 +56,13 @@ def get_compiler_path():
5556

5657

5758
def get_compiler_version(compiler):
58-
"""Get compiler version string."""
59-
ret, stdout, _ = run_cmd(
59+
"""Get compiler version string (stdout + stderr for emcc compat)."""
60+
ret, stdout, stderr = run_cmd(
6061
[compiler, "--version"]
61-
if not " " in compiler
62+
if " " not in compiler
6263
else shlex.split(compiler) + ["--version"]
6364
)
64-
return stdout if ret == 0 else ""
65+
return (stdout + stderr) if ret == 0 else ""
6566

6667

6768
def detect_compiler_type(version_output):
@@ -186,35 +187,50 @@ def print_summary():
186187
print(f"RISC-V Toolchain: {'yes' if have_riscv_toolchain() else 'no'}")
187188

188189

190+
def bool_exit(result):
191+
"""Signal boolean result via exit code for $(python,...) integration.
192+
193+
Kconfig's $(python,assert run(sys.executable, 'tools/detect-env.py', ...))
194+
checks the exit code: 0 maps to 'y', non-zero maps to 'n'.
195+
"""
196+
sys.exit(0 if result else 1)
197+
198+
199+
def _compiler_type():
200+
"""Detect compiler type (lazy, avoids probing when not needed)."""
201+
compiler = get_compiler_path()
202+
version = get_compiler_version(compiler)
203+
return detect_compiler_type(version)
204+
205+
189206
def main():
190207
if len(sys.argv) < 2:
191208
print_summary()
192209
return
193210

194-
compiler = get_compiler_path()
195-
version = get_compiler_version(compiler)
196-
comp_type = detect_compiler_type(version)
197-
198211
arg = sys.argv[1]
199212

213+
# Compiler-type queries (probe CC lazily)
200214
if arg == "--compiler":
201-
print(comp_type)
215+
# String output for $(shell,...) -- not convertible to $(python,...)
216+
print(_compiler_type())
202217
elif arg == "--is-emcc":
203-
print("y" if comp_type == "Emscripten" else "n")
218+
bool_exit(_compiler_type() == "Emscripten")
204219
elif arg == "--is-clang":
205-
print("y" if comp_type == "Clang" else "n")
220+
bool_exit(_compiler_type() == "Clang")
206221
elif arg == "--is-gcc":
207-
print("y" if comp_type == "GCC" else "n")
222+
bool_exit(_compiler_type() == "GCC")
223+
# Library/toolchain availability (no compiler probing needed)
208224
elif arg == "--have-emcc":
209-
print("y" if have_emcc() else "n")
225+
bool_exit(have_emcc())
210226
elif arg == "--have-sdl2":
211-
print("y" if have_sdl2() else "n")
227+
bool_exit(have_sdl2())
212228
elif arg == "--have-sdl2-mixer":
213-
print("y" if have_sdl2_mixer() else "n")
229+
bool_exit(have_sdl2_mixer())
214230
elif arg == "--have-llvm18":
215-
print("y" if have_llvm18() else "n")
231+
bool_exit(have_llvm18())
216232
elif arg == "--have-riscv-toolchain":
217-
print("y" if have_riscv_toolchain() else "n")
233+
bool_exit(have_riscv_toolchain())
218234
elif arg == "--summary":
219235
print_summary()
220236
else:

0 commit comments

Comments
 (0)