#!/bin/bash # # kconfig-new-symbols.sh # # Non-interactive "what would oldconfig have prompted me for" report. # Never touches .config — it's a true dry run. # # What it does: # 1. Runs `make listnewconfig` (the read-only Kconfig target that lists # exactly the symbols oldconfig would ask you about — auto-resolvable # ones as CONFIG_X=value, genuinely undecided ones as bare CONFIG_X — # without writing .config). Prints the count and the symbol list. # 2. For each new symbol, looks it up in a reference .config # (--ref-config) and prints its value there (or NOT SET), then # greps the Kconfig files in this tree for that symbol's help text. # The value is colorized when stdout is a terminal: red = NOT SET, # light blue = m, bright green = y (see --color to force on/off). # # Must be run from the root of a kernel source tree, with whatever # ARCH / CROSS_COMPILE / O environment you'd normally build with already # exported (this script just calls `make listnewconfig`, it inherits your # env exactly like a normal build would). # # Example: # ./kconfig-new-symbols.sh --ref-config /tmp/ref.config > new-options.txt # set -euo pipefail CONFIG=".config" REF_CONFIG="" COLOR_MODE="auto" usage() { cat <<'EOF' Usage: kconfig-new-symbols.sh [options] --ref-config PATH Reference .config to cross-check new symbols against. Optional: without it, only step 1 (count + list) runs. --config PATH Path to the working .config (default: ./.config) --color WHEN Colorize the reference-config value: auto (default, on when stdout is a terminal), always, or never. -h, --help Show this help EOF exit 1 } while [[ $# -gt 0 ]]; do case "$1" in --ref-config) REF_CONFIG="$2"; shift 2 ;; --config) CONFIG="$2"; shift 2 ;; --color) COLOR_MODE="$2"; shift 2 ;; -h|--help) usage ;; *) echo "Unknown argument: $1" >&2; usage ;; esac done case "$COLOR_MODE" in auto) [[ -t 1 ]] && USE_COLOR=1 || USE_COLOR=0 ;; always) USE_COLOR=1 ;; never) USE_COLOR=0 ;; *) echo "error: --color must be auto, always, or never" >&2; exit 1 ;; esac if [[ "$USE_COLOR" -eq 1 ]]; then C_RED=$'\033[0;31m' # NOT SET C_LBLUE=$'\033[0;94m' # m C_GREEN=$'\033[0;92m' # y C_RESET=$'\033[0m' else C_RED='' C_LBLUE='' C_GREEN='' C_RESET='' fi [[ -f "$CONFIG" ]] || { echo "error: config not found: $CONFIG" >&2; exit 1; } [[ -f "Kconfig" && -f "Makefile" ]] || { echo "error: run this from the root of a kernel source tree" >&2 exit 1 } if [[ -n "$REF_CONFIG" && ! -f "$REF_CONFIG" ]]; then echo "error: reference config not found: $REF_CONFIG" >&2 exit 1 fi # --- Step 1: list the new symbols (read-only, .config is never written) - echo "Running: make listnewconfig ..." >&2 LISTNEWCONFIG_OUT=$(make listnewconfig 2>&1) # listnewconfig emits "CONFIG_FOO=y" for symbols it can auto-resolve and # bare "CONFIG_FOO" for symbols that genuinely need a decision, interleaved # with the usual Kconfig warnings on stray/obsolete .config lines — filter # down to just the CONFIG_ lines and drop any trailing "=value". No sort: # listnewconfig walks the same menu tree in the same order oldconfig # prompts you in, so preserving that order (just deduped) is the point. NEW_ONLY=$(printf '%s\n' "$LISTNEWCONFIG_OUT" \ | grep -oE '^CONFIG_[A-Za-z0-9_]+' \ | awk '!seen[$0]++' || true) COUNT=$(printf '%s\n' "$NEW_ONLY" | grep -c . || true) echo "New CONFIG options introduced: $COUNT" echo if [[ "$COUNT" -eq 0 ]]; then exit 0 fi printf '%s\n' "$NEW_ONLY" echo if [[ -z "$REF_CONFIG" ]]; then echo "(pass --ref-config to also see reference values and Kconfig help)" exit 0 fi # --- Step 2: cross-reference against --ref-config, plus help text ------- # Collect the Kconfig file list once, not once per symbol. mapfile -t KCONFIG_FILES < <(find . -name 'Kconfig*' -not -path './.git/*') get_ref_value() { local sym="$1" line value line=$(grep -E "^${sym}=|^# ${sym} is not set" "$REF_CONFIG" || true) if [[ -z "$line" ]]; then value="NOT SET" elif [[ "$line" == "#"* ]]; then value="NOT SET" else value="${line#${sym}=}" fi case "$value" in "NOT SET") printf '%s%s%s' "$C_RED" "$value" "$C_RESET" ;; y) printf '%s%s%s' "$C_GREEN" "$value" "$C_RESET" ;; m) printf '%s%s%s' "$C_LBLUE" "$value" "$C_RESET" ;; *) printf '%s' "$value" ;; esac } # Pull the help text for a bare symbol name (no CONFIG_ prefix) out of the # Kconfig tree. Relies on standard kernel Kconfig indentation conventions: # "config FOO" at column 0, properties indented one tab, help text at # tab + further whitespace. get_help() { local sym="$1" awk -v sym="$sym" ' $1 ~ /^(menuconfig|config)$/ && $2 == sym { capture=1; inhelp=0 next } capture && /^(config|menuconfig|choice|endchoice|menu|endmenu|if|endif|comment|source)([ \t]|$)/ { capture=0; inhelp=0 } capture && /^\t(help|---help---)$/ { inhelp=1 next } capture && inhelp { if ($0 ~ /^\t[ \t]/) { line=$0 sub(/^[ \t]+/, "", line) print line } else if ($0 == "") { print "" } else { inhelp=0 } } ' "${KCONFIG_FILES[@]}" 2>/dev/null } for sym in $NEW_ONLY; do bare="${sym#CONFIG_}" echo "=== $sym ===" echo "Reference config: $(get_ref_value "$sym")" echo "--- Help ---" help_text=$(get_help "$bare") if [[ -z "$help_text" ]]; then echo "(no help text found in this tree)" else echo "$help_text" fi echo done