From d1957c96f2825d849f9715c07f2b12d00b8b1b8f Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Sun, 13 Apr 2025 18:07:21 +0100 Subject: [PATCH] feat(cargo): Set rustc-check-cfg for all config options This squashes lint warnings for config options which are not currently enabled. See https://doc.rust-lang.org/cargo/reference/build-scripts.html\#rustc-check-cfg Signed-off-by: Hayden Ball --- CMakeLists.txt | 15 ++++++++ samples/async-philosophers/src/lib.rs | 4 --- samples/bench/src/lib.rs | 4 --- samples/philosophers/src/lib.rs | 4 --- scripts/kconfig-bool-options.py | 50 +++++++++++++++++++++++++++ zephyr-build/src/lib.rs | 28 +++++++++------ 6 files changed, 83 insertions(+), 22 deletions(-) create mode 100755 scripts/kconfig-bool-options.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d4f417..c1e675e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,20 @@ DT_AUGMENTS = \"${DT_AUGMENTS}\" ${config_paths} ") + set(RUST_KCONFIG_BOOL_OPTIONS_FILE "${CMAKE_CURRENT_BINARY_DIR}/rust-kconfig-bool-options.json") + + add_custom_command( + OUTPUT ${RUST_KCONFIG_BOOL_OPTIONS_FILE} + COMMAND + ${CMAKE_COMMAND} -E + env ${COMMON_KCONFIG_ENV_SETTINGS} + ${RUST_MODULE_DIR}/scripts/kconfig-bool-options.py ${KCONFIG_ROOT} ${DOTCONFIG} + ${RUST_KCONFIG_BOOL_OPTIONS_FILE} + DEPENDS ${DOTCONFIG} + COMMENT "Finding valid kconfig boolean options" + WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR} + ) + # The block of environment variables below could theoretically be captured in a variable, but this # seems "challenging" in CMake (to be polite), as many of these contain spaces, and the quoting # rules in CMake are inconsistent, at best. @@ -161,6 +175,7 @@ ${config_paths} add_custom_command( OUTPUT ${DUMMY_FILE} BYPRODUCTS ${RUST_LIBRARY} ${WRAPPER_FILE} + DEPENDS ${RUST_KCONFIG_BOOL_OPTIONS_FILE} USES_TERMINAL COMMAND ${CMAKE_COMMAND} -E diff --git a/samples/async-philosophers/src/lib.rs b/samples/async-philosophers/src/lib.rs index 0cf4b3b..c26677e 100644 --- a/samples/async-philosophers/src/lib.rs +++ b/samples/async-philosophers/src/lib.rs @@ -2,10 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #![no_std] -// Cargo tries to detect configs that have typos in them. Unfortunately, the Zephyr Kconfig system -// uses a large number of Kconfigs and there is no easy way to know which ones might conceivably be -// valid. This prevents a warning about each cfg that is used. -#![allow(unexpected_cfgs)] extern crate alloc; diff --git a/samples/bench/src/lib.rs b/samples/bench/src/lib.rs index 432384f..462786a 100644 --- a/samples/bench/src/lib.rs +++ b/samples/bench/src/lib.rs @@ -2,10 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #![no_std] -// Cargo tries to detect configs that have typos in them. Unfortunately, the Zephyr Kconfig system -// uses a large number of Kconfigs and there is no easy way to know which ones might conceivably be -// valid. This prevents a warning about each cfg that is used. -#![allow(unexpected_cfgs)] extern crate alloc; diff --git a/samples/philosophers/src/lib.rs b/samples/philosophers/src/lib.rs index 473e84b..3668828 100644 --- a/samples/philosophers/src/lib.rs +++ b/samples/philosophers/src/lib.rs @@ -2,10 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #![no_std] -// Cargo tries to detect configs that have typos in them. Unfortunately, the Zephyr Kconfig system -// uses a large number of Kconfigs and there is no easy way to know which ones might conceivably be -// valid. This prevents a warning about each cfg that is used. -#![allow(unexpected_cfgs)] extern crate alloc; diff --git a/scripts/kconfig-bool-options.py b/scripts/kconfig-bool-options.py new file mode 100755 index 0000000..807f288 --- /dev/null +++ b/scripts/kconfig-bool-options.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: Apache-2.0 + +import os +import sys +import argparse +import json + +from itertools import chain + +sys.path.insert(0, str(os.path.join(os.environ["ZEPHYR_BASE"], "scripts", "kconfig"))) +from kconfiglib import Kconfig, _T_BOOL, _T_CHOICE + + +def main(): + args = parse_args() + + kconf = Kconfig(args.kconfig_file) + kconf.load_config(args.dotconfig) + + options = {} + + for sym in chain(kconf.unique_defined_syms, kconf.unique_choices): + if not sym.name: + continue + + if "-" in sym.name: + # Rust does not allow hyphens in cfg options. + continue + + if sym.type in [_T_BOOL, _T_CHOICE]: + options[f"CONFIG_{sym.name}"] = sym.str_value + + with open(args.outfile, "w") as f: + json.dump(options, f, indent=2, sort_keys=True) + + +def parse_args(): + parser = argparse.ArgumentParser(allow_abbrev=False) + + parser.add_argument("kconfig_file", help="Top-level Kconfig file") + parser.add_argument("dotconfig", help="Path to dotconfig file") + parser.add_argument("outfile", help="Path to output file") + + return parser.parse_args() + + +if __name__ == "__main__": + main() diff --git a/zephyr-build/src/lib.rs b/zephyr-build/src/lib.rs index 4c24812..1c5cbdc 100644 --- a/zephyr-build/src/lib.rs +++ b/zephyr-build/src/lib.rs @@ -11,6 +11,7 @@ // This builds a program that is run on the compilation host before the code is compiled. It can // output configuration settings that affect the compilation. +use std::collections::BTreeMap; use std::env; use std::fs::File; use std::io::{BufRead, BufReader, Write}; @@ -27,19 +28,26 @@ mod devicetree; /// Export boolean Kconfig entries. This must happen in any crate that wishes to access the /// configuration settings. pub fn export_bool_kconfig() { - let dotconfig = env::var("DOTCONFIG").expect("DOTCONFIG must be set by wrapper"); + let build_dir = env::var("BUILD_DIR").expect("BUILD_DIR must be set by wrapper"); - // Ensure the build script is rerun when the dotconfig changes. - println!("cargo:rerun-if-env-changed=DOTCONFIG"); - println!("cargo-rerun-if-changed={}", dotconfig); + let bool_options_path = Path::new(&build_dir) + .join("rust-kconfig-bool-options.json") + .to_str() + .unwrap() + .to_string(); - let config_y = Regex::new(r"^(CONFIG_.*)=y$").unwrap(); + // Ensure the build script is rerun when kconfig bool options change. + println!("cargo:rerun-if-changed={}", bool_options_path); - let file = File::open(&dotconfig).expect("Unable to open dotconfig"); - for line in BufReader::new(file).lines() { - let line = line.expect("reading line from dotconfig"); - if let Some(caps) = config_y.captures(&line) { - println!("cargo:rustc-cfg={}", &caps[1]); + let bool_options = File::open(&bool_options_path).expect("Unable to open bool options"); + let bool_options: BTreeMap = + serde_yaml_ng::from_reader(bool_options).expect("Unable to parse bool options"); + + for (key, value) in bool_options.iter() { + println!("cargo:rustc-check-cfg=cfg({})", key); + + if value == "y" { + println!("cargo:rustc-cfg={}", key); } } }