public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
@ 2026-01-22 10:57 Mikko Rapeli
  2026-01-22 10:57 ` [PATCH v3 2/3] scripts: kconfig: merge_config.sh: use awk in checks too Mikko Rapeli
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Mikko Rapeli @ 2026-01-22 10:57 UTC (permalink / raw)
  To: Nathan Chancellor, Nicolas Schier, Anders Roxell, linux-kbuild,
	linux-kernel
  Cc: Mikko Rapeli

From: Anders Roxell <anders.roxell@linaro.org>

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>
---
 scripts/kconfig/merge_config.sh | 168 ++++++++++++++++++++++++--------
 1 file changed, 128 insertions(+), 40 deletions(-)

v3: use shell variables with plain $VAR syntax, don't convert to =n
    syntax and use " is not set" instead, reverted warning output to
    same as before in the shell script implementation, changed warning
    output from stderr to stdout as in the shell script implementation,
    tested that output from
    make ARCH=arm64 CROSS_COMPILE=aarch64-linux- clean defconfig hardening.config
    and
    make -s ARCH=arm64 CROSS_COMPILE=aarch64-linux- clean defconfig hardening.config
    is the same with and without this change

v2: remove unused sed variables, awk from ${AWK} variable,
    curly brace syntax fix after rebase, triple check that
    correct revision of patches are used in testing with
    yocto/bitbake
    https://lore.kernel.org/linux-kbuild/20251229114447.45236-1-mikko.rapeli@linaro.org/T/#me07dcaaa205b608d56003aeb56a240e5eca1ad52

v1: https://lore.kernel.org/linux-kbuild/20251229114447.45236-1-mikko.rapeli@linaro.org/T/#t

diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 79c09b378be8..de217771b78c 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"
 
@@ -136,42 +137,129 @@ 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
+	# 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"
+done
 if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
 	echo "The fragment redefined a value and strict mode had been passed."
 	exit 1
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 2/3] scripts: kconfig: merge_config.sh: use awk in checks too
  2026-01-22 10:57 [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk Mikko Rapeli
@ 2026-01-22 10:57 ` Mikko Rapeli
  2026-01-22 10:57 ` [PATCH v3 3/3] scripts: kconfig: merge_config.sh: warn on duplicate input files Mikko Rapeli
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Mikko Rapeli @ 2026-01-22 10:57 UTC (permalink / raw)
  To: Nathan Chancellor, Nicolas Schier, Anders Roxell, linux-kbuild,
	linux-kernel
  Cc: Mikko Rapeli

Converting from shell/sed/grep loop to awk improves runtime
checks of Yocto genericarm64 kernel config from 20 seconds
to under 1 second. The checks catch this kind of issues:

WARNING: CONFIG_BLK_DEV_DM differs:
Requested value: CONFIG_BLK_DEV_DM=y
Actual value:    CONFIG_BLK_DEV_DM=m
WARNING: CONFIG_SECURITY_NETWORK differs:
Requested value: CONFIG_SECURITY_NETWORK=n
Actual value:    CONFIG_SECURITY_NETWORK=y
WARNING: Value requested for CONFIG_ARM64_BTI_KERNEL not in final .config
Requested value: CONFIG_ARM64_BTI_KERNEL=y
Actual value:

Cc: Anders Roxell <anders.roxell@linaro.org>
Signed-off-by: Mikko Rapeli <mikko.rapeli@linaro.org>
---
 scripts/kconfig/merge_config.sh | 97 +++++++++++++++++++++++++++++----
 1 file changed, 86 insertions(+), 11 deletions(-)

v3: use $VAR syntax for shell variables, changed output to be a bit more
    similar to the shell script version before

v2: awk from ${AWK}
    https://lore.kernel.org/linux-kbuild/20251229114447.45236-1-mikko.rapeli@linaro.org/T/#md557a7746d96920ff270448738adf96b9fa993ca

v1: https://lore.kernel.org/linux-kbuild/20251229114447.45236-1-mikko.rapeli@linaro.org/T/#t

diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index de217771b78c..9eda9dbd4542 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -286,16 +286,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
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 3/3] scripts: kconfig: merge_config.sh: warn on duplicate input files
  2026-01-22 10:57 [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk Mikko Rapeli
  2026-01-22 10:57 ` [PATCH v3 2/3] scripts: kconfig: merge_config.sh: use awk in checks too Mikko Rapeli
@ 2026-01-22 10:57 ` Mikko Rapeli
  2026-01-30  0:10 ` [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk Nathan Chancellor
  2026-03-09 16:38 ` Andreas Larsson
  3 siblings, 0 replies; 10+ messages in thread
From: Mikko Rapeli @ 2026-01-22 10:57 UTC (permalink / raw)
  To: Nathan Chancellor, Nicolas Schier, Anders Roxell, linux-kbuild,
	linux-kernel
  Cc: Mikko Rapeli

External scripts like yocto kernel scc may provide
same input config fragment multiple times. This may
be a bug since processing same fragments multiple times
can be time consuming.

Cc: Anders Roxell <anders.roxell@linaro.org>
Signed-off-by: Mikko Rapeli <mikko.rapeli@linaro.org>
---
 scripts/kconfig/merge_config.sh | 11 +++++++++++
 1 file changed, 11 insertions(+)

v3: no changes

v2: no changes
    https://lore.kernel.org/linux-kbuild/20251229114447.45236-1-mikko.rapeli@linaro.org/T/#me2023dbfef124059bd906d44c60ffaa7cd83732c

v1: https://lore.kernel.org/linux-kbuild/20251229114447.45236-1-mikko.rapeli@linaro.org/T/#t

diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 9eda9dbd4542..735e1de450c6 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -130,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"
@@ -137,6 +139,14 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
 		echo "The merge file '$ORIG_MERGE_FILE' does not exist.  Exit." >&2
 		exit 1
 	fi
+
+	# 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" \
@@ -259,6 +269,7 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
 		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."
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
  2026-01-22 10:57 [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk Mikko Rapeli
  2026-01-22 10:57 ` [PATCH v3 2/3] scripts: kconfig: merge_config.sh: use awk in checks too Mikko Rapeli
  2026-01-22 10:57 ` [PATCH v3 3/3] scripts: kconfig: merge_config.sh: warn on duplicate input files Mikko Rapeli
@ 2026-01-30  0:10 ` Nathan Chancellor
  2026-03-09 16:38 ` Andreas Larsson
  3 siblings, 0 replies; 10+ messages in thread
From: Nathan Chancellor @ 2026-01-30  0:10 UTC (permalink / raw)
  To: Nathan Chancellor, Nicolas Schier, Anders Roxell, linux-kbuild,
	linux-kernel, Mikko Rapeli

On Thu, 22 Jan 2026 12:57:49 +0200, Mikko Rapeli wrote:
> 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.
> 
> [...]

Applied to

  https://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git kbuild-next

Thanks!

[1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
      (no commit info)
[2/3] scripts: kconfig: merge_config.sh: use awk in checks too
      (no commit info)
[3/3] scripts: kconfig: merge_config.sh: warn on duplicate input files
      (no commit info)

Please look out for regression or issue reports or other follow up
comments, as they may result in the patch/series getting dropped or
reverted. Patches applied to an "unstable" branch are accepted pending
wider testing in -next and any post-commit review; they will generally
be moved to the main branch in a week if no issues are found.

Best regards,
-- 
Nathan Chancellor <nathan@kernel.org>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
  2026-01-22 10:57 [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk Mikko Rapeli
                   ` (2 preceding siblings ...)
  2026-01-30  0:10 ` [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk Nathan Chancellor
@ 2026-03-09 16:38 ` Andreas Larsson
  2026-03-09 17:09   ` Nathan Chancellor
  3 siblings, 1 reply; 10+ messages in thread
From: Andreas Larsson @ 2026-03-09 16:38 UTC (permalink / raw)
  To: Mikko Rapeli, Nathan Chancellor, Nicolas Schier, Anders Roxell,
	linux-kbuild, linux-kernel

On 2026-01-22 11:57, Mikko Rapeli wrote:
> From: Anders Roxell <anders.roxell@linaro.org>
> 
> 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>
> ---
>  scripts/kconfig/merge_config.sh | 168 ++++++++++++++++++++++++--------
>  1 file changed, 128 insertions(+), 40 deletions(-)

Hi,

Commit 5fa9b82cbcfc ("scripts: kconfig: merge_config.sh: refactor from
shell/sed/grep to awk") breaks merge_config.sh for me:

---------->%----------
$ make tiny.config
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/confdata.o
  HOSTCC  scripts/kconfig/expr.o
  LEX     scripts/kconfig/lexer.lex.c
  YACC    scripts/kconfig/parser.tab.[ch]
  HOSTCC  scripts/kconfig/lexer.lex.o
  HOSTCC  scripts/kconfig/menu.o
  HOSTCC  scripts/kconfig/parser.tab.o
  HOSTCC  scripts/kconfig/preprocess.o
  HOSTCC  scripts/kconfig/symbol.o
  HOSTCC  scripts/kconfig/util.o
  HOSTLD  scripts/kconfig/conf
The base file '.config' does not exist. Creating one...
Using .config as base
Merging ./kernel/configs/tiny.config
awk: cannot open ./.tmp.config.U9SROCKTBj.new (No such file or directory)
mv: cannot stat './.tmp.config.U9SROCKTBj.new': No such file or directory
make[2]: *** [scripts/kconfig/Makefile:112: tiny.config] Error 1
make[1]: *** [<kernel-source-top-dir>/Makefile:744: tiny.config] Error 2
make: *** [Makefile:248: __sub-make] Error 2
---------->%----------

with this underlying call to merge_config.sh, an empty .config and where
my awk is GNU Awk 5.1.0:

---------->%----------
$ make tiny.config V=1
make --no-print-directory -C <kernel-source-top-dir> \
-f <kernel-source-top-dir>/Makefile tiny.config
make -f ./scripts/Makefile.build obj=scripts/basic
make -f ./scripts/Makefile.build obj=scripts/kconfig tiny.config
# cmd_merge_fragments tiny.config
  ./scripts/kconfig/merge_config.sh -m .config ./kernel/configs/tiny.config ./arch/x86/configs/tiny.config
...

$ awk --version
GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
---------->%----------

At 5fa9b82cbcfc~ things works as expected.

Cheers,
Andreas


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
  2026-03-09 16:38 ` Andreas Larsson
@ 2026-03-09 17:09   ` Nathan Chancellor
  2026-03-10  7:50     ` Mikko Rapeli
  0 siblings, 1 reply; 10+ messages in thread
From: Nathan Chancellor @ 2026-03-09 17:09 UTC (permalink / raw)
  To: Andreas Larsson
  Cc: Mikko Rapeli, Nicolas Schier, Anders Roxell, linux-kbuild,
	linux-kernel

On Mon, Mar 09, 2026 at 05:38:58PM +0100, Andreas Larsson wrote:
> On 2026-01-22 11:57, Mikko Rapeli wrote:
> > From: Anders Roxell <anders.roxell@linaro.org>
> > 
> > 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>
> > ---
> >  scripts/kconfig/merge_config.sh | 168 ++++++++++++++++++++++++--------
> >  1 file changed, 128 insertions(+), 40 deletions(-)
> 
> Hi,
> 
> Commit 5fa9b82cbcfc ("scripts: kconfig: merge_config.sh: refactor from
> shell/sed/grep to awk") breaks merge_config.sh for me:
> 
> ---------->%----------
> $ make tiny.config
>   HOSTCC  scripts/basic/fixdep
>   HOSTCC  scripts/kconfig/conf.o
>   HOSTCC  scripts/kconfig/confdata.o
>   HOSTCC  scripts/kconfig/expr.o
>   LEX     scripts/kconfig/lexer.lex.c
>   YACC    scripts/kconfig/parser.tab.[ch]
>   HOSTCC  scripts/kconfig/lexer.lex.o
>   HOSTCC  scripts/kconfig/menu.o
>   HOSTCC  scripts/kconfig/parser.tab.o
>   HOSTCC  scripts/kconfig/preprocess.o
>   HOSTCC  scripts/kconfig/symbol.o
>   HOSTCC  scripts/kconfig/util.o
>   HOSTLD  scripts/kconfig/conf
> The base file '.config' does not exist. Creating one...
> Using .config as base
> Merging ./kernel/configs/tiny.config
> awk: cannot open ./.tmp.config.U9SROCKTBj.new (No such file or directory)
> mv: cannot stat './.tmp.config.U9SROCKTBj.new': No such file or directory
> make[2]: *** [scripts/kconfig/Makefile:112: tiny.config] Error 1
> make[1]: *** [<kernel-source-top-dir>/Makefile:744: tiny.config] Error 2
> make: *** [Makefile:248: __sub-make] Error 2
> ---------->%----------
> 
> with this underlying call to merge_config.sh, an empty .config and where
> my awk is GNU Awk 5.1.0:
> 
> ---------->%----------
> $ make tiny.config V=1
> make --no-print-directory -C <kernel-source-top-dir> \
> -f <kernel-source-top-dir>/Makefile tiny.config
> make -f ./scripts/Makefile.build obj=scripts/basic
> make -f ./scripts/Makefile.build obj=scripts/kconfig tiny.config
> # cmd_merge_fragments tiny.config
>   ./scripts/kconfig/merge_config.sh -m .config ./kernel/configs/tiny.config ./arch/x86/configs/tiny.config
> ...
> 
> $ awk --version
> GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
> ---------->%----------
> 
> At 5fa9b82cbcfc~ things works as expected.

Hmmm, not sure how I have not seen this error myself since I test
tiny.config but I can reproduce with a clean output directory. Something
like this seems like a simple fix but the only instances of ARGV[3] in
the awk script that I can see use '>>', which should create the file if
it does not exist. Mikko, any ideas?

diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 735e1de450c6..070ecae87a1c 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -123,6 +123,7 @@ fi
 MERGE_LIST=$*
 
 TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
+touch "$TMP_FILE.new"
 
 echo "Using $INITFILE as base"
 

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
  2026-03-09 17:09   ` Nathan Chancellor
@ 2026-03-10  7:50     ` Mikko Rapeli
  2026-03-10  9:55       ` Andreas Larsson
  0 siblings, 1 reply; 10+ messages in thread
From: Mikko Rapeli @ 2026-03-10  7:50 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Andreas Larsson, Nicolas Schier, Anders Roxell, linux-kbuild,
	linux-kernel

Hi,

On Mon, Mar 09, 2026 at 10:09:04AM -0700, Nathan Chancellor wrote:
> On Mon, Mar 09, 2026 at 05:38:58PM +0100, Andreas Larsson wrote:
> > On 2026-01-22 11:57, Mikko Rapeli wrote:
> > > From: Anders Roxell <anders.roxell@linaro.org>
> > > 
> > > 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>
> > > ---
> > >  scripts/kconfig/merge_config.sh | 168 ++++++++++++++++++++++++--------
> > >  1 file changed, 128 insertions(+), 40 deletions(-)
> > 
> > Hi,
> > 
> > Commit 5fa9b82cbcfc ("scripts: kconfig: merge_config.sh: refactor from
> > shell/sed/grep to awk") breaks merge_config.sh for me:
> > 
> > ---------->%----------
> > $ make tiny.config
> >   HOSTCC  scripts/basic/fixdep
> >   HOSTCC  scripts/kconfig/conf.o
> >   HOSTCC  scripts/kconfig/confdata.o
> >   HOSTCC  scripts/kconfig/expr.o
> >   LEX     scripts/kconfig/lexer.lex.c
> >   YACC    scripts/kconfig/parser.tab.[ch]
> >   HOSTCC  scripts/kconfig/lexer.lex.o
> >   HOSTCC  scripts/kconfig/menu.o
> >   HOSTCC  scripts/kconfig/parser.tab.o
> >   HOSTCC  scripts/kconfig/preprocess.o
> >   HOSTCC  scripts/kconfig/symbol.o
> >   HOSTCC  scripts/kconfig/util.o
> >   HOSTLD  scripts/kconfig/conf
> > The base file '.config' does not exist. Creating one...
> > Using .config as base
> > Merging ./kernel/configs/tiny.config
> > awk: cannot open ./.tmp.config.U9SROCKTBj.new (No such file or directory)
> > mv: cannot stat './.tmp.config.U9SROCKTBj.new': No such file or directory
> > make[2]: *** [scripts/kconfig/Makefile:112: tiny.config] Error 1
> > make[1]: *** [<kernel-source-top-dir>/Makefile:744: tiny.config] Error 2
> > make: *** [Makefile:248: __sub-make] Error 2
> > ---------->%----------
> > 
> > with this underlying call to merge_config.sh, an empty .config and where
> > my awk is GNU Awk 5.1.0:
> > 
> > ---------->%----------
> > $ make tiny.config V=1
> > make --no-print-directory -C <kernel-source-top-dir> \
> > -f <kernel-source-top-dir>/Makefile tiny.config
> > make -f ./scripts/Makefile.build obj=scripts/basic
> > make -f ./scripts/Makefile.build obj=scripts/kconfig tiny.config
> > # cmd_merge_fragments tiny.config
> >   ./scripts/kconfig/merge_config.sh -m .config ./kernel/configs/tiny.config ./arch/x86/configs/tiny.config
> > ...
> > 
> > $ awk --version
> > GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
> > ---------->%----------
> > 
> > At 5fa9b82cbcfc~ things works as expected.

Hmm, all these steps work for me with GNU awk 5.1.0 so something else
is different here. On line 267 awk is given input file args
"$ORIG_MERGE_FILE" "$TMP_FILE" "$TMP_FILE.new" and it fails to
create the output file "$TMP_FILE.new" with >> and plain print statement.

> Hmmm, not sure how I have not seen this error myself since I test
> tiny.config but I can reproduce with a clean output directory. Something
> like this seems like a simple fix but the only instances of ARGV[3] in
> the awk script that I can see use '>>', which should create the file if
> it does not exist. Mikko, any ideas?
> 
> diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
> index 735e1de450c6..070ecae87a1c 100755
> --- a/scripts/kconfig/merge_config.sh
> +++ b/scripts/kconfig/merge_config.sh
> @@ -123,6 +123,7 @@ fi
>  MERGE_LIST=$*
>  
>  TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
> +touch "$TMP_FILE.new"
>  
>  echo "Using $INITFILE as base"

This could help but I fail to understand why this would be needed. Why is awk
not able to create this file on line 256?

awk manual says:

https://www.gnu.org/software/gawk/manual/html_node/Redirection.html

    print items >> output-file

    This redirection prints the items into the preexisting output file named
    output-file. The difference between this and the single-‘>’ redirection
    is that the old contents (if any) of output-file are not erased. Instead,
    the awk output is appended to the file. If output-file does not exist,
    then it is created.

And in all my testing this works. Which distro is this? Is something else like
file system setup in some way unusual?

Cheers,

-Mikko

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
  2026-03-10  7:50     ` Mikko Rapeli
@ 2026-03-10  9:55       ` Andreas Larsson
  2026-03-10 10:01         ` Mikko Rapeli
  0 siblings, 1 reply; 10+ messages in thread
From: Andreas Larsson @ 2026-03-10  9:55 UTC (permalink / raw)
  To: Mikko Rapeli, Nathan Chancellor
  Cc: Nicolas Schier, Anders Roxell, linux-kbuild, linux-kernel

On 2026-03-10 08:50, Mikko Rapeli wrote:
> Hi,
> 
> On Mon, Mar 09, 2026 at 10:09:04AM -0700, Nathan Chancellor wrote:
>> On Mon, Mar 09, 2026 at 05:38:58PM +0100, Andreas Larsson wrote:
>>> On 2026-01-22 11:57, Mikko Rapeli wrote:
>>>> From: Anders Roxell <anders.roxell@linaro.org>
>>>>
>>>> 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>
>>>> ---
>>>>  scripts/kconfig/merge_config.sh | 168 ++++++++++++++++++++++++--------
>>>>  1 file changed, 128 insertions(+), 40 deletions(-)
>>>
>>> Hi,
>>>
>>> Commit 5fa9b82cbcfc ("scripts: kconfig: merge_config.sh: refactor from
>>> shell/sed/grep to awk") breaks merge_config.sh for me:
>>>
>>> ---------->%----------
>>> $ make tiny.config
>>>   HOSTCC  scripts/basic/fixdep
>>>   HOSTCC  scripts/kconfig/conf.o
>>>   HOSTCC  scripts/kconfig/confdata.o
>>>   HOSTCC  scripts/kconfig/expr.o
>>>   LEX     scripts/kconfig/lexer.lex.c
>>>   YACC    scripts/kconfig/parser.tab.[ch]
>>>   HOSTCC  scripts/kconfig/lexer.lex.o
>>>   HOSTCC  scripts/kconfig/menu.o
>>>   HOSTCC  scripts/kconfig/parser.tab.o
>>>   HOSTCC  scripts/kconfig/preprocess.o
>>>   HOSTCC  scripts/kconfig/symbol.o
>>>   HOSTCC  scripts/kconfig/util.o
>>>   HOSTLD  scripts/kconfig/conf
>>> The base file '.config' does not exist. Creating one...
>>> Using .config as base
>>> Merging ./kernel/configs/tiny.config
>>> awk: cannot open ./.tmp.config.U9SROCKTBj.new (No such file or directory)
>>> mv: cannot stat './.tmp.config.U9SROCKTBj.new': No such file or directory
>>> make[2]: *** [scripts/kconfig/Makefile:112: tiny.config] Error 1
>>> make[1]: *** [<kernel-source-top-dir>/Makefile:744: tiny.config] Error 2
>>> make: *** [Makefile:248: __sub-make] Error 2
>>> ---------->%----------
>>>
>>> with this underlying call to merge_config.sh, an empty .config and where
>>> my awk is GNU Awk 5.1.0:
>>>
>>> ---------->%----------
>>> $ make tiny.config V=1
>>> make --no-print-directory -C <kernel-source-top-dir> \
>>> -f <kernel-source-top-dir>/Makefile tiny.config
>>> make -f ./scripts/Makefile.build obj=scripts/basic
>>> make -f ./scripts/Makefile.build obj=scripts/kconfig tiny.config
>>> # cmd_merge_fragments tiny.config
>>>   ./scripts/kconfig/merge_config.sh -m .config ./kernel/configs/tiny.config ./arch/x86/configs/tiny.config
>>> ...
>>>
>>> $ awk --version
>>> GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
>>> ---------->%----------
>>>
>>> At 5fa9b82cbcfc~ things works as expected.
> 
> Hmm, all these steps work for me with GNU awk 5.1.0 so something else
> is different here. On line 267 awk is given input file args
> "$ORIG_MERGE_FILE" "$TMP_FILE" "$TMP_FILE.new" and it fails to
> create the output file "$TMP_FILE.new" with >> and plain print statement.
> 
>> Hmmm, not sure how I have not seen this error myself since I test
>> tiny.config but I can reproduce with a clean output directory. Something
>> like this seems like a simple fix but the only instances of ARGV[3] in
>> the awk script that I can see use '>>', which should create the file if
>> it does not exist. Mikko, any ideas?
>>
>> diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
>> index 735e1de450c6..070ecae87a1c 100755
>> --- a/scripts/kconfig/merge_config.sh
>> +++ b/scripts/kconfig/merge_config.sh
>> @@ -123,6 +123,7 @@ fi
>>  MERGE_LIST=$*
>>  
>>  TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
>> +touch "$TMP_FILE.new"
>>  
>>  echo "Using $INITFILE as base"
> 
> This could help but I fail to understand why this would be needed. Why is awk
> not able to create this file on line 256?
> 
> awk manual says:
> 
> https://www.gnu.org/software/gawk/manual/html_node/Redirection.html
> 
>     print items >> output-file
> 
>     This redirection prints the items into the preexisting output file named
>     output-file. The difference between this and the single-‘>’ redirection
>     is that the old contents (if any) of output-file are not erased. Instead,
>     the awk output is appended to the file. If output-file does not exist,
>     then it is created.

Awk is opening the file for reading and fails before any prints with >>
to it, much like this one does:

$ awk 'FILENAME == "non-existent" {nextfile}' non-existent
awk: fatal: cannot open file `non-existent' for reading: No such file or directory

$ strace awk 'FILENAME == "non-existent" {nextfile}' non-existent |& grep non-existent
execve("/usr/bin/awk", ["awk", "FILENAME == \"non-existent\" {next"..., "non-existent"], 0x7ffd32bda2e8 /* 66 vars */) = 0
openat(AT_FDCWD, "non-existent", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, "cannot open file `non-existent' "..., 70cannot open file `non-existent' for reading: No such file or directory) = 70


> And in all my testing this works. Which distro is this? Is something else like
> file system setup in some way unusual?
Ubuntu 22.04.5 and a regular ext4 file system.

Cheers,
Andreas


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
  2026-03-10  9:55       ` Andreas Larsson
@ 2026-03-10 10:01         ` Mikko Rapeli
  2026-03-10 10:25           ` Andreas Larsson
  0 siblings, 1 reply; 10+ messages in thread
From: Mikko Rapeli @ 2026-03-10 10:01 UTC (permalink / raw)
  To: Andreas Larsson
  Cc: Nathan Chancellor, Nicolas Schier, Anders Roxell, linux-kbuild,
	linux-kernel

Hi,

On Tue, Mar 10, 2026 at 10:55:46AM +0100, Andreas Larsson wrote:
> On 2026-03-10 08:50, Mikko Rapeli wrote:
> > On Mon, Mar 09, 2026 at 10:09:04AM -0700, Nathan Chancellor wrote:
> >> On Mon, Mar 09, 2026 at 05:38:58PM +0100, Andreas Larsson wrote:
> >>> On 2026-01-22 11:57, Mikko Rapeli wrote:
> >>>> From: Anders Roxell <anders.roxell@linaro.org>
> >>>>
> >>>> 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>
> >>>> ---
> >>>>  scripts/kconfig/merge_config.sh | 168 ++++++++++++++++++++++++--------
> >>>>  1 file changed, 128 insertions(+), 40 deletions(-)
> >>>
> >>> Hi,
> >>>
> >>> Commit 5fa9b82cbcfc ("scripts: kconfig: merge_config.sh: refactor from
> >>> shell/sed/grep to awk") breaks merge_config.sh for me:
> >>>
> >>> ---------->%----------
> >>> $ make tiny.config
> >>>   HOSTCC  scripts/basic/fixdep
> >>>   HOSTCC  scripts/kconfig/conf.o
> >>>   HOSTCC  scripts/kconfig/confdata.o
> >>>   HOSTCC  scripts/kconfig/expr.o
> >>>   LEX     scripts/kconfig/lexer.lex.c
> >>>   YACC    scripts/kconfig/parser.tab.[ch]
> >>>   HOSTCC  scripts/kconfig/lexer.lex.o
> >>>   HOSTCC  scripts/kconfig/menu.o
> >>>   HOSTCC  scripts/kconfig/parser.tab.o
> >>>   HOSTCC  scripts/kconfig/preprocess.o
> >>>   HOSTCC  scripts/kconfig/symbol.o
> >>>   HOSTCC  scripts/kconfig/util.o
> >>>   HOSTLD  scripts/kconfig/conf
> >>> The base file '.config' does not exist. Creating one...
> >>> Using .config as base
> >>> Merging ./kernel/configs/tiny.config
> >>> awk: cannot open ./.tmp.config.U9SROCKTBj.new (No such file or directory)
> >>> mv: cannot stat './.tmp.config.U9SROCKTBj.new': No such file or directory
> >>> make[2]: *** [scripts/kconfig/Makefile:112: tiny.config] Error 1
> >>> make[1]: *** [<kernel-source-top-dir>/Makefile:744: tiny.config] Error 2
> >>> make: *** [Makefile:248: __sub-make] Error 2
> >>> ---------->%----------
> >>>
> >>> with this underlying call to merge_config.sh, an empty .config and where
> >>> my awk is GNU Awk 5.1.0:
> >>>
> >>> ---------->%----------
> >>> $ make tiny.config V=1
> >>> make --no-print-directory -C <kernel-source-top-dir> \
> >>> -f <kernel-source-top-dir>/Makefile tiny.config
> >>> make -f ./scripts/Makefile.build obj=scripts/basic
> >>> make -f ./scripts/Makefile.build obj=scripts/kconfig tiny.config
> >>> # cmd_merge_fragments tiny.config
> >>>   ./scripts/kconfig/merge_config.sh -m .config ./kernel/configs/tiny.config ./arch/x86/configs/tiny.config
> >>> ...
> >>>
> >>> $ awk --version
> >>> GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
> >>> ---------->%----------
> >>>
> >>> At 5fa9b82cbcfc~ things works as expected.
> > 
> > Hmm, all these steps work for me with GNU awk 5.1.0 so something else
> > is different here. On line 267 awk is given input file args
> > "$ORIG_MERGE_FILE" "$TMP_FILE" "$TMP_FILE.new" and it fails to
> > create the output file "$TMP_FILE.new" with >> and plain print statement.
> > 
> >> Hmmm, not sure how I have not seen this error myself since I test
> >> tiny.config but I can reproduce with a clean output directory. Something
> >> like this seems like a simple fix but the only instances of ARGV[3] in
> >> the awk script that I can see use '>>', which should create the file if
> >> it does not exist. Mikko, any ideas?
> >>
> >> diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
> >> index 735e1de450c6..070ecae87a1c 100755
> >> --- a/scripts/kconfig/merge_config.sh
> >> +++ b/scripts/kconfig/merge_config.sh
> >> @@ -123,6 +123,7 @@ fi
> >>  MERGE_LIST=$*
> >>  
> >>  TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
> >> +touch "$TMP_FILE.new"
> >>  
> >>  echo "Using $INITFILE as base"
> > 
> > This could help but I fail to understand why this would be needed. Why is awk
> > not able to create this file on line 256?
> > 
> > awk manual says:
> > 
> > https://www.gnu.org/software/gawk/manual/html_node/Redirection.html
> > 
> >     print items >> output-file
> > 
> >     This redirection prints the items into the preexisting output file named
> >     output-file. The difference between this and the single-‘>’ redirection
> >     is that the old contents (if any) of output-file are not erased. Instead,
> >     the awk output is appended to the file. If output-file does not exist,
> >     then it is created.
> 
> Awk is opening the file for reading and fails before any prints with >>
> to it, much like this one does:
> 
> $ awk 'FILENAME == "non-existent" {nextfile}' non-existent
> awk: fatal: cannot open file `non-existent' for reading: No such file or directory
> 
> $ strace awk 'FILENAME == "non-existent" {nextfile}' non-existent |& grep non-existent
> execve("/usr/bin/awk", ["awk", "FILENAME == \"non-existent\" {next"..., "non-existent"], 0x7ffd32bda2e8 /* 66 vars */) = 0
> openat(AT_FDCWD, "non-existent", O_RDONLY) = -1 ENOENT (No such file or directory)
> write(2, "cannot open file `non-existent' "..., 70cannot open file `non-existent' for reading: No such file or directory) = 70
> 
> 
> > And in all my testing this works. Which distro is this? Is something else like
> > file system setup in some way unusual?
> Ubuntu 22.04.5 and a regular ext4 file system.

Right, so some awk versions behave differently. For the record in my testing on
Ubuntu 22.04.5 LTS (Jammy Jellyfish) this script works :/

Can you try if the touch fix from Nathan works?

Cheers,

-Mikko

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk
  2026-03-10 10:01         ` Mikko Rapeli
@ 2026-03-10 10:25           ` Andreas Larsson
  0 siblings, 0 replies; 10+ messages in thread
From: Andreas Larsson @ 2026-03-10 10:25 UTC (permalink / raw)
  To: Mikko Rapeli
  Cc: Nathan Chancellor, Nicolas Schier, Anders Roxell, linux-kbuild,
	linux-kernel

On 2026-03-10 11:01, Mikko Rapeli wrote:
> Hi,
> 
> On Tue, Mar 10, 2026 at 10:55:46AM +0100, Andreas Larsson wrote:
>> On 2026-03-10 08:50, Mikko Rapeli wrote:
>>> On Mon, Mar 09, 2026 at 10:09:04AM -0700, Nathan Chancellor wrote:
>>>> On Mon, Mar 09, 2026 at 05:38:58PM +0100, Andreas Larsson wrote:
>>>>> On 2026-01-22 11:57, Mikko Rapeli wrote:
>>>>>> From: Anders Roxell <anders.roxell@linaro.org>
>>>>>>
>>>>>> 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>
>>>>>> ---
>>>>>>  scripts/kconfig/merge_config.sh | 168 ++++++++++++++++++++++++--------
>>>>>>  1 file changed, 128 insertions(+), 40 deletions(-)
>>>>>
>>>>> Hi,
>>>>>
>>>>> Commit 5fa9b82cbcfc ("scripts: kconfig: merge_config.sh: refactor from
>>>>> shell/sed/grep to awk") breaks merge_config.sh for me:
>>>>>
>>>>> ---------->%----------
>>>>> $ make tiny.config
>>>>>   HOSTCC  scripts/basic/fixdep
>>>>>   HOSTCC  scripts/kconfig/conf.o
>>>>>   HOSTCC  scripts/kconfig/confdata.o
>>>>>   HOSTCC  scripts/kconfig/expr.o
>>>>>   LEX     scripts/kconfig/lexer.lex.c
>>>>>   YACC    scripts/kconfig/parser.tab.[ch]
>>>>>   HOSTCC  scripts/kconfig/lexer.lex.o
>>>>>   HOSTCC  scripts/kconfig/menu.o
>>>>>   HOSTCC  scripts/kconfig/parser.tab.o
>>>>>   HOSTCC  scripts/kconfig/preprocess.o
>>>>>   HOSTCC  scripts/kconfig/symbol.o
>>>>>   HOSTCC  scripts/kconfig/util.o
>>>>>   HOSTLD  scripts/kconfig/conf
>>>>> The base file '.config' does not exist. Creating one...
>>>>> Using .config as base
>>>>> Merging ./kernel/configs/tiny.config
>>>>> awk: cannot open ./.tmp.config.U9SROCKTBj.new (No such file or directory)
>>>>> mv: cannot stat './.tmp.config.U9SROCKTBj.new': No such file or directory
>>>>> make[2]: *** [scripts/kconfig/Makefile:112: tiny.config] Error 1
>>>>> make[1]: *** [<kernel-source-top-dir>/Makefile:744: tiny.config] Error 2
>>>>> make: *** [Makefile:248: __sub-make] Error 2
>>>>> ---------->%----------
>>>>>
>>>>> with this underlying call to merge_config.sh, an empty .config and where
>>>>> my awk is GNU Awk 5.1.0:
>>>>>
>>>>> ---------->%----------
>>>>> $ make tiny.config V=1
>>>>> make --no-print-directory -C <kernel-source-top-dir> \
>>>>> -f <kernel-source-top-dir>/Makefile tiny.config
>>>>> make -f ./scripts/Makefile.build obj=scripts/basic
>>>>> make -f ./scripts/Makefile.build obj=scripts/kconfig tiny.config
>>>>> # cmd_merge_fragments tiny.config
>>>>>   ./scripts/kconfig/merge_config.sh -m .config ./kernel/configs/tiny.config ./arch/x86/configs/tiny.config
>>>>> ...
>>>>>
>>>>> $ awk --version
>>>>> GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
>>>>> ---------->%----------
>>>>>
>>>>> At 5fa9b82cbcfc~ things works as expected.
>>>
>>> Hmm, all these steps work for me with GNU awk 5.1.0 so something else
>>> is different here. On line 267 awk is given input file args
>>> "$ORIG_MERGE_FILE" "$TMP_FILE" "$TMP_FILE.new" and it fails to
>>> create the output file "$TMP_FILE.new" with >> and plain print statement.
>>>
>>>> Hmmm, not sure how I have not seen this error myself since I test
>>>> tiny.config but I can reproduce with a clean output directory. Something
>>>> like this seems like a simple fix but the only instances of ARGV[3] in
>>>> the awk script that I can see use '>>', which should create the file if
>>>> it does not exist. Mikko, any ideas?
>>>>
>>>> diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
>>>> index 735e1de450c6..070ecae87a1c 100755
>>>> --- a/scripts/kconfig/merge_config.sh
>>>> +++ b/scripts/kconfig/merge_config.sh
>>>> @@ -123,6 +123,7 @@ fi
>>>>  MERGE_LIST=$*
>>>>  
>>>>  TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
>>>> +touch "$TMP_FILE.new"
>>>>  
>>>>  echo "Using $INITFILE as base"
>>>
>>> This could help but I fail to understand why this would be needed. Why is awk
>>> not able to create this file on line 256?
>>>
>>> awk manual says:
>>>
>>> https://www.gnu.org/software/gawk/manual/html_node/Redirection.html
>>>
>>>     print items >> output-file
>>>
>>>     This redirection prints the items into the preexisting output file named
>>>     output-file. The difference between this and the single-‘>’ redirection
>>>     is that the old contents (if any) of output-file are not erased. Instead,
>>>     the awk output is appended to the file. If output-file does not exist,
>>>     then it is created.
>>
>> Awk is opening the file for reading and fails before any prints with >>
>> to it, much like this one does:
>>
>> $ awk 'FILENAME == "non-existent" {nextfile}' non-existent
>> awk: fatal: cannot open file `non-existent' for reading: No such file or directory
>>
>> $ strace awk 'FILENAME == "non-existent" {nextfile}' non-existent |& grep non-existent
>> execve("/usr/bin/awk", ["awk", "FILENAME == \"non-existent\" {next"..., "non-existent"], 0x7ffd32bda2e8 /* 66 vars */) = 0
>> openat(AT_FDCWD, "non-existent", O_RDONLY) = -1 ENOENT (No such file or directory)
>> write(2, "cannot open file `non-existent' "..., 70cannot open file `non-existent' for reading: No such file or directory) = 70
>>
>>
>>> And in all my testing this works. Which distro is this? Is something else like
>>> file system setup in some way unusual?
>> Ubuntu 22.04.5 and a regular ext4 file system.
> 
> Right, so some awk versions behave differently. For the record in my testing on
> Ubuntu 22.04.5 LTS (Jammy Jellyfish) this script works :/
> 
> Can you try if the touch fix from Nathan works?

Yes, with that fix it works fine.

Cheers,
Andreas


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-03-10 10:25 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-22 10:57 [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk Mikko Rapeli
2026-01-22 10:57 ` [PATCH v3 2/3] scripts: kconfig: merge_config.sh: use awk in checks too Mikko Rapeli
2026-01-22 10:57 ` [PATCH v3 3/3] scripts: kconfig: merge_config.sh: warn on duplicate input files Mikko Rapeli
2026-01-30  0:10 ` [PATCH v3 1/3] scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk Nathan Chancellor
2026-03-09 16:38 ` Andreas Larsson
2026-03-09 17:09   ` Nathan Chancellor
2026-03-10  7:50     ` Mikko Rapeli
2026-03-10  9:55       ` Andreas Larsson
2026-03-10 10:01         ` Mikko Rapeli
2026-03-10 10:25           ` Andreas Larsson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox