mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
merge_config.sh shell/sed/grep loop scales poorly and is slow. With Yocto genericarm64 kernel and around 190 config fragments the script takes more than 20 minutes to run on a fast build machine. Re-implementation with awk does the same job in 10 seconds. Using awk since it is likely available in the build environments and using perl, python etc would introduce more complex runtime dependencies. awk is good enough and lot better than shell/sed/grep. Output stays the same but changed execution time means that parallel job output may be ordered differently. Signed-off-by: Anders Roxell <anders.roxell@linaro.org> Signed-off-by: Mikko Rapeli <mikko.rapeli@linaro.org> Link: https://patch.msgid.link/20260122105751.2186609-1-mikko.rapeli@linaro.org Signed-off-by: Nathan Chancellor <nathan@kernel.org>
This commit is contained in:
parent
a081b57892
commit
5fa9b82cbc
|
|
@ -16,8 +16,8 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
clean_up() {
|
clean_up() {
|
||||||
rm -f $TMP_FILE
|
rm -f "$TMP_FILE"
|
||||||
rm -f $MERGE_FILE
|
rm -f "$TMP_FILE.new"
|
||||||
}
|
}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
|
|
@ -43,6 +43,10 @@ STRICT=false
|
||||||
CONFIG_PREFIX=${CONFIG_-CONFIG_}
|
CONFIG_PREFIX=${CONFIG_-CONFIG_}
|
||||||
WARNOVERRIDE=echo
|
WARNOVERRIDE=echo
|
||||||
|
|
||||||
|
if [ -z "$AWK" ]; then
|
||||||
|
AWK=awk
|
||||||
|
fi
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
case $1 in
|
case $1 in
|
||||||
"-n")
|
"-n")
|
||||||
|
|
@ -117,11 +121,8 @@ if [ ! -r "$INITFILE" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MERGE_LIST=$*
|
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)
|
TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
|
||||||
MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX)
|
|
||||||
|
|
||||||
echo "Using $INITFILE as base"
|
echo "Using $INITFILE as base"
|
||||||
|
|
||||||
|
|
@ -136,42 +137,129 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
|
||||||
echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2
|
echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
cat $ORIG_MERGE_FILE > $MERGE_FILE
|
# Use awk for single-pass processing instead of per-symbol grep/sed
|
||||||
CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE)
|
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$"
|
||||||
|
}
|
||||||
|
|
||||||
for CFG in $CFG_LIST ; do
|
# Extract config name from a line, returns "" if not a config line
|
||||||
grep -q -w $CFG $TMP_FILE || continue
|
function get_cfg(line) {
|
||||||
PREV_VAL=$(grep -w $CFG $TMP_FILE)
|
if (match(line, cfg_regex)) {
|
||||||
NEW_VAL=$(grep -w $CFG $MERGE_FILE)
|
return substr(line, RSTART, RLENGTH)
|
||||||
BUILTIN_FLAG=false
|
} else if (match(line, notset_regex)) {
|
||||||
if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then
|
# Extract CONFIG_FOO from "# CONFIG_FOO is not set"
|
||||||
${WARNOVERRIDE} Previous value: $PREV_VAL
|
sub(/^# /, "", line)
|
||||||
${WARNOVERRIDE} New value: $NEW_VAL
|
sub(/ is not set$/, "", line)
|
||||||
${WARNOVERRIDE} -y passed, will not demote y to m
|
return line
|
||||||
${WARNOVERRIDE}
|
}
|
||||||
BUILTIN_FLAG=true
|
return ""
|
||||||
elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
|
}
|
||||||
${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE:
|
|
||||||
${WARNOVERRIDE} Previous value: $PREV_VAL
|
function warn_builtin(cfg, prev, new) {
|
||||||
${WARNOVERRIDE} New value: $NEW_VAL
|
if (warnoverride == "true") return
|
||||||
${WARNOVERRIDE}
|
print cfg ": -y passed, will not demote y to m"
|
||||||
if [ "$STRICT" = "true" ]; then
|
print "Previous value: " prev
|
||||||
STRICT_MODE_VIOLATED=true
|
print "New value: " new
|
||||||
fi
|
print ""
|
||||||
elif [ "$WARNREDUN" = "true" ]; then
|
}
|
||||||
${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE:
|
|
||||||
fi
|
function warn_redefined(cfg, prev, new) {
|
||||||
if [ "$BUILTIN_FLAG" = "false" ]; then
|
if (warnoverride == "true") return
|
||||||
sed -i "/$CFG[ =]/d" $TMP_FILE
|
print "Value of " cfg " is redefined by fragment " mergefile ":"
|
||||||
else
|
print "Previous value: " prev
|
||||||
sed -i "/$CFG[ =]/d" $MERGE_FILE
|
print "New value: " new
|
||||||
fi
|
print ""
|
||||||
done
|
}
|
||||||
# In case the previous file lacks a new line at the end
|
|
||||||
echo >> $TMP_FILE
|
function warn_redundant(cfg) {
|
||||||
cat $MERGE_FILE >> $TMP_FILE
|
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"
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
|
if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
|
||||||
echo "The fragment redefined a value and strict mode had been passed."
|
echo "The fragment redefined a value and strict mode had been passed."
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user