Subject: Re: [PATCH] meson: regenerate config-list.h when Documentation changes

From: Patrick Steinhardt <[email-masked]>
Date: Wed, 11 Feb 2026 08:42:58 +0100

On Mon, Feb 09, 2026 at 04:50:06PM -0500, D. Ben Knoble wrote:
> > On Sat, Feb 07, 2026 at 04:59:17PM -0500, D. Ben Knoble wrote:
[snip]
> Only, things are behaving oddly. For example:
> 
>     λ meson setup build2
>     λ ninja -C build2
> 
> works fine, but
> 
>     λ ls -l build2/config*
>     -rw-r--r-- 1 benknoble benknoble 17169  9 févr. 16:39 build2/config-list.h
> 
> I don't see the dependency file.

> Further, re-building seems to get stuck (I get
> similar symptoms if I add or remove a relevant config.adoc file, but let's keep
> it simple for now):
> 
>     λ ninja -C build2
>     ninja: Entering directory `build2'
>     [1/28] Generating GIT-VERSION-FILE with a custom command (wrapped by meson to set env)

With "stuck" you mean that it doesn't do anything, or that it doesn't
actually rebuild?

I guess it kind of makes sense that a new file wouldn't trigger a
rebuild, even though I would have expected a removed one to trigger one.
After all, the dependency file only tracks the set of _existing_ files
so that we know when to rebuild, and of course the dependency file only
gets regenerated in case any of those files changes.

The thing is that build systems like Meson really want to know the list
of files ahead of time so that they can have an optimal build graph. So
we could of course list all the files that we actually depend on. But I
guess that's something we want to avoid?

There's another, alternative approach: you can have a separate build
step that's marked as `build_always_stale: true` that lists all the
config files. This step would then always run, and it would only update
its target file in case any of the files has changed.

Combined with the depfile we'd then rebuild in all cases:

  - When a file gets added or removed, as that would cause the
    `build_always_stale` target to be rewritten.

  - When any of the files changes, because that would cause the
    dependencies in the depfile to change.

Something like the attached patch (note that I don't perform the
necessary changes for the Makefile). I confirmed that it works for all
of the above cases.

Thanks!

Patrick

--- >8 ---

diff --git a/generate-configlist.sh b/generate-configlist.sh
index 75c39ade20..17605e6f77 100755
--- a/generate-configlist.sh
+++ b/generate-configlist.sh
@@ -1,13 +1,6 @@
 #!/bin/sh
 
-SOURCE_DIR="$1"
-OUTPUT="$2"
-
-if test -z "$SOURCE_DIR" || ! test -d "$SOURCE_DIR" || test -z "$OUTPUT"
-then
-	echo >&2 "USAGE: $0 <SOURCE_DIR> <OUTPUT>"
-	exit 1
-fi
+set -e
 
 print_config_list () {
 	cat <<EOF
@@ -30,9 +23,50 @@ EOF
 EOF
 }
 
-{
-	echo "/* Automatically generated by generate-configlist.sh */"
-	echo
-	echo
-	print_config_list
-} >"$OUTPUT"
+case "$1" in
+generate)
+	SOURCE_DIR="$2"
+	OUTPUT="$3"
+	DEPFILE="$4"
+
+	if test -z "$SOURCE_DIR" || ! test -d "$SOURCE_DIR" || test -z "$OUTPUT"
+	then
+		echo >&2 "USAGE: $0 generate <SOURCE_DIR> <OUTPUT>"
+		exit 1
+	fi
+
+	if test -n "$DEPFILE"
+	then
+		printf "$OUTPUT: %s\n" "$SOURCE_DIR"/Documentation/*config.adoc \
+			"$SOURCE_DIR"/Documentation/config/*.adoc >"$DEPFILE"
+	fi
+
+	{
+		echo "/* Automatically generated by generate-configlist.sh */"
+		echo
+		echo
+		print_config_list
+	} >"$OUTPUT"
+	;;
+deps)
+	SOURCE_DIR="$2"
+	OUTPUT="$3"
+
+	if test -z "$SOURCE_DIR" || ! test -d "$SOURCE_DIR" || test -z "$OUTPUT"
+	then
+		echo >&2 "USAGE: $0 deps <SOURCE_DIR> <OUTPUT>"
+		exit 1
+	fi
+
+	TMPFILE=$(mktemp "$OUTPUT".XXXXXX)
+	printf "%s\n" "$SOURCE_DIR"/Documentation/*config.adoc \
+		"$SOURCE_DIR"/Documentation/config/*.adoc | sort >"$TMPFILE"
+
+	if ! test -f "$OUTPUT" || ! cmp "$TMPFILE" "$OUTPUT" >/dev/null
+	then
+		mv "$TMPFILE" "$OUTPUT"
+	else
+		rm "$TMPFILE"
+	fi
+	;;
+esac
diff --git a/meson.build b/meson.build
index dd52efd1c8..6b9147a39a 100644
--- a/meson.build
+++ b/meson.build
@@ -716,14 +716,29 @@ if not get_option('breaking_changes')
   builtin_sources += 'builtin/pack-redundant.c'
 endif
 
+configlist_deps = custom_target(
+  output: 'config-list.h.deps',
+  command: [
+    meson.current_source_dir() + '/generate-configlist.sh',
+    'deps',
+    meson.current_source_dir(),
+    '@OUTPUT@',
+  ],
+  build_always_stale: true,
+)
+
 builtin_sources += custom_target(
   output: 'config-list.h',
   command: [
     shell,
     meson.current_source_dir() + '/generate-configlist.sh',
+    'generate',
     meson.current_source_dir(),
     '@OUTPUT@',
+    '@OUTPUT@.d',
   ],
+  depends: [ configlist_deps, ],
+  depfile: 'config-list.h.d',
   env: script_environment,
 )