summaryrefslogtreecommitdiff
path: root/scripts/kconfig/merge_config.sh
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/kconfig/merge_config.sh')
-rwxr-xr-xscripts/kconfig/merge_config.sh276
1 files changed, 225 insertions, 51 deletions
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 79c09b378be8..735e1de450c6 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -16,8 +16,8 @@
set -e
clean_up() {
- rm -f $TMP_FILE
- rm -f $MERGE_FILE
+ rm -f "$TMP_FILE"
+ rm -f "$TMP_FILE.new"
}
usage() {
@@ -43,6 +43,10 @@ STRICT=false
CONFIG_PREFIX=${CONFIG_-CONFIG_}
WARNOVERRIDE=echo
+if [ -z "$AWK" ]; then
+ AWK=awk
+fi
+
while true; do
case $1 in
"-n")
@@ -117,11 +121,8 @@ if [ ! -r "$INITFILE" ]; then
fi
MERGE_LIST=$*
-SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p"
-SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p"
TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
-MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX)
echo "Using $INITFILE as base"
@@ -129,6 +130,8 @@ trap clean_up EXIT
cat $INITFILE > $TMP_FILE
+PROCESSED_FILES=""
+
# Merge files, printing warnings on overridden values
for ORIG_MERGE_FILE in $MERGE_LIST ; do
echo "Merging $ORIG_MERGE_FILE"
@@ -136,42 +139,138 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2
exit 1
fi
- cat $ORIG_MERGE_FILE > $MERGE_FILE
- CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE)
-
- for CFG in $CFG_LIST ; do
- grep -q -w $CFG $TMP_FILE || continue
- PREV_VAL=$(grep -w $CFG $TMP_FILE)
- NEW_VAL=$(grep -w $CFG $MERGE_FILE)
- BUILTIN_FLAG=false
- if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then
- ${WARNOVERRIDE} Previous value: $PREV_VAL
- ${WARNOVERRIDE} New value: $NEW_VAL
- ${WARNOVERRIDE} -y passed, will not demote y to m
- ${WARNOVERRIDE}
- BUILTIN_FLAG=true
- elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
- ${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE:
- ${WARNOVERRIDE} Previous value: $PREV_VAL
- ${WARNOVERRIDE} New value: $NEW_VAL
- ${WARNOVERRIDE}
- if [ "$STRICT" = "true" ]; then
- STRICT_MODE_VIOLATED=true
- fi
- elif [ "$WARNREDUN" = "true" ]; then
- ${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE:
- fi
- if [ "$BUILTIN_FLAG" = "false" ]; then
- sed -i "/$CFG[ =]/d" $TMP_FILE
- else
- sed -i "/$CFG[ =]/d" $MERGE_FILE
- fi
- done
- # In case the previous file lacks a new line at the end
- echo >> $TMP_FILE
- cat $MERGE_FILE >> $TMP_FILE
-done
+ # Check for duplicate input files
+ case " $PROCESSED_FILES " in
+ *" $ORIG_MERGE_FILE "*)
+ ${WARNOVERRIDE} "WARNING: Input file provided multiple times: $ORIG_MERGE_FILE"
+ ;;
+ esac
+
+ # Use awk for single-pass processing instead of per-symbol grep/sed
+ if ! "$AWK" -v prefix="$CONFIG_PREFIX" \
+ -v warnoverride="$WARNOVERRIDE" \
+ -v strict="$STRICT" \
+ -v builtin="$BUILTIN" \
+ -v warnredun="$WARNREDUN" '
+ BEGIN {
+ strict_violated = 0
+ cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
+ notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
+ }
+
+ # Extract config name from a line, returns "" if not a config line
+ function get_cfg(line) {
+ if (match(line, cfg_regex)) {
+ return substr(line, RSTART, RLENGTH)
+ } else if (match(line, notset_regex)) {
+ # Extract CONFIG_FOO from "# CONFIG_FOO is not set"
+ sub(/^# /, "", line)
+ sub(/ is not set$/, "", line)
+ return line
+ }
+ return ""
+ }
+
+ function warn_builtin(cfg, prev, new) {
+ if (warnoverride == "true") return
+ print cfg ": -y passed, will not demote y to m"
+ print "Previous value: " prev
+ print "New value: " new
+ print ""
+ }
+
+ function warn_redefined(cfg, prev, new) {
+ if (warnoverride == "true") return
+ print "Value of " cfg " is redefined by fragment " mergefile ":"
+ print "Previous value: " prev
+ print "New value: " new
+ print ""
+ }
+
+ function warn_redundant(cfg) {
+ if (warnredun != "true" || warnoverride == "true") return
+ print "Value of " cfg " is redundant by fragment " mergefile ":"
+ }
+
+ # First pass: read merge file, store all lines and index
+ FILENAME == ARGV[1] {
+ mergefile = FILENAME
+ merge_lines[FNR] = $0
+ merge_total = FNR
+ cfg = get_cfg($0)
+ if (cfg != "") {
+ merge_cfg[cfg] = $0
+ merge_cfg_line[cfg] = FNR
+ }
+ next
+ }
+
+ # Second pass: process base file (TMP_FILE)
+ FILENAME == ARGV[2] {
+ cfg = get_cfg($0)
+
+ # Not a config or not in merge file - keep it
+ if (cfg == "" || !(cfg in merge_cfg)) {
+ print $0 >> ARGV[3]
+ next
+ }
+
+ prev_val = $0
+ new_val = merge_cfg[cfg]
+
+ # BUILTIN: do not demote y to m
+ if (builtin == "true" && new_val ~ /=m$/ && prev_val ~ /=y$/) {
+ warn_builtin(cfg, prev_val, new_val)
+ print $0 >> ARGV[3]
+ skip_merge[merge_cfg_line[cfg]] = 1
+ next
+ }
+
+ # Values equal - redundant
+ if (prev_val == new_val) {
+ warn_redundant(cfg)
+ next
+ }
+
+ # "=n" is the same as "is not set"
+ if (prev_val ~ /=n$/ && new_val ~ / is not set$/) {
+ print $0 >> ARGV[3]
+ next
+ }
+
+ # Values differ - redefined
+ warn_redefined(cfg, prev_val, new_val)
+ if (strict == "true") {
+ strict_violated = 1
+ }
+ }
+
+ # output file, skip all lines
+ FILENAME == ARGV[3] {
+ nextfile
+ }
+
+ END {
+ # Newline in case base file lacks trailing newline
+ print "" >> ARGV[3]
+ # Append merge file, skipping lines marked for builtin preservation
+ for (i = 1; i <= merge_total; i++) {
+ if (!(i in skip_merge)) {
+ print merge_lines[i] >> ARGV[3]
+ }
+ }
+ if (strict_violated) {
+ exit 1
+ }
+ }' \
+ "$ORIG_MERGE_FILE" "$TMP_FILE" "$TMP_FILE.new"; then
+ # awk exited non-zero, strict mode was violated
+ STRICT_MODE_VIOLATED=true
+ fi
+ mv "$TMP_FILE.new" "$TMP_FILE"
+ PROCESSED_FILES="$PROCESSED_FILES $ORIG_MERGE_FILE"
+done
if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
echo "The fragment redefined a value and strict mode had been passed."
exit 1
@@ -198,16 +297,91 @@ fi
# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
+# Check all specified config values took effect (might have missed-dependency issues)
+if ! "$AWK" -v prefix="$CONFIG_PREFIX" \
+ -v warnoverride="$WARNOVERRIDE" \
+ -v strict="$STRICT" \
+ -v warnredun="$WARNREDUN" '
+BEGIN {
+ strict_violated = 0
+ cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
+ notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
+}
-# Check all specified config values took (might have missed-dependency issues)
-for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do
+# Extract config name from a line, returns "" if not a config line
+function get_cfg(line) {
+ if (match(line, cfg_regex)) {
+ return substr(line, RSTART, RLENGTH)
+ } else if (match(line, notset_regex)) {
+ # Extract CONFIG_FOO from "# CONFIG_FOO is not set"
+ sub(/^# /, "", line)
+ sub(/ is not set$/, "", line)
+ return line
+ }
+ return ""
+}
- REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
- ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG" || true)
- if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
- echo "Value requested for $CFG not in final .config"
- echo "Requested value: $REQUESTED_VAL"
- echo "Actual value: $ACTUAL_VAL"
- echo ""
- fi
-done
+function warn_mismatch(cfg, merged, final) {
+ if (warnredun == "true") return
+ if (final == "" && !(merged ~ / is not set$/ || merged ~ /=n$/)) {
+ print "WARNING: Value requested for " cfg " not in final .config"
+ print "Requested value: " merged
+ print "Actual value: " final
+ } else if (final == "" && merged ~ / is not set$/) {
+ # not set, pass
+ } else if (merged == "" && final != "") {
+ print "WARNING: " cfg " not in merged config but added in final .config:"
+ print "Requested value: " merged
+ print "Actual value: " final
+ } else {
+ print "WARNING: " cfg " differs:"
+ print "Requested value: " merged
+ print "Actual value: " final
+ }
+}
+
+# First pass: read effective config file, store all lines
+FILENAME == ARGV[1] {
+ cfg = get_cfg($0)
+ if (cfg != "") {
+ config_cfg[cfg] = $0
+ }
+ next
+}
+
+# Second pass: process merged config and compare against effective config
+{
+ cfg = get_cfg($0)
+ if (cfg == "") next
+
+ # strip trailing comment
+ sub(/[[:space:]]+#.*/, "", $0)
+ merged_val = $0
+ final_val = config_cfg[cfg]
+
+ if (merged_val == final_val) next
+
+ if (merged_val ~ /=n$/ && final_val ~ / is not set$/) next
+ if (merged_val ~ /=n$/ && final_val == "") next
+
+ warn_mismatch(cfg, merged_val, final_val)
+
+ if (strict == "true") {
+ strict_violated = 1
+ }
+}
+
+END {
+ if (strict_violated) {
+ exit 1
+ }
+}' \
+"$KCONFIG_CONFIG" "$TMP_FILE"; then
+ # awk exited non-zero, strict mode was violated
+ STRICT_MODE_VIOLATED=true
+fi
+
+if [ "$STRICT" == "true" ] && [ "$STRICT_MODE_VIOLATED" == "true" ]; then
+ echo "Requested and effective config differ"
+ exit 1
+fi