{"thread":{"id":"65200","subject":"[PATCH 0/8] Some build system improvements","startedAt":"2026-03-10T17:52:55Z","lastAt":"2026-04-10T16:05:34Z","messageCount":53,"participants":["Patrick Steinhardt","Junio C Hamano","Phillip Wood","SZEDER Gábor","Kristoffer Haugsbakk","Toon Claes"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"538489","messageId":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":null,"subject":"[PATCH 0/8] Some build system improvements","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:33Z","receivedAt":"2026-03-10T17:52:55Z","isPatch":true,"body":"Hi,\n\nthis patch series contains a small set of build system improvements:\n\n  - The first couple patches introduce a new \"tools/\" directory that\n    contains items related to our build infrastructure and to our\n    developer tooling. This finally follows up on my promise to do this\n    back when I did the spring clean of \"contrib/\". [1]\n\n  - The last couple patches introduce precompiled headers into Meson for\n    a nice compilation speedup of ~30%. It's \n\nThe two topics are not really related with one another other than being\nrelated to build systems. I decided to throw them in the same patch\nseries though so that I can introduce \"precompiled.h\" in \"tools/\".\n\nThanks!\n\nPatrick\n\n[1]: https://lore.kernel.org/git/20250506-pks-contrib-spring-cleanup-v1-0-e6d5ddd79a72@pks.im/\n\n---\nPatrick Steinhardt (8):\n      Introduce new \"tools/\" directory\n      contrib: move \"coccinelle/\" directory into \"tools/\"\n      contrib: move \"coverage-diff.sh\" script into \"tools/\"\n      contrib: move \"update-unicode.sh\" script into \"tools/\"\n      builds: move build scripts into \"tools/\"\n      git-compat-util.h: move warning infra to prepare for PCHs\n      meson: compile compatibility sources separately\n      meson: precompile \"git-compat-util.h\"\n\n Makefile                                           | 76 ++++++++---------\n ci/run-static-analysis.sh                          |  2 +-\n config.mak.dev                                     |  2 +-\n contrib/buildsystems/CMakeLists.txt                | 18 ++--\n contrib/meson.build                                |  1 -\n contrib/subtree/meson.build                        |  2 +-\n git-compat-util.h                                  |  8 +-\n meson.build                                        | 96 +++++++++++++---------\n tools/README.md                                    |  7 ++\n check-builtins.sh => tools/check-builtins.sh       |  0\n {contrib => tools}/coccinelle/.gitignore           |  0\n {contrib => tools}/coccinelle/README               |  2 +-\n {contrib => tools}/coccinelle/array.cocci          |  0\n {contrib => tools}/coccinelle/commit.cocci         |  0\n .../coccinelle/config_fn_ctx.pending.cocci         |  0\n {contrib => tools}/coccinelle/equals-null.cocci    |  0\n {contrib => tools}/coccinelle/flex_alloc.cocci     |  0\n {contrib => tools}/coccinelle/free.cocci           |  0\n .../coccinelle/git_config_number.cocci             |  0\n {contrib => tools}/coccinelle/hashmap.cocci        |  0\n .../coccinelle/index-compatibility.cocci           |  0\n {contrib => tools}/coccinelle/meson.build          |  0\n {contrib => tools}/coccinelle/object_id.cocci      |  0\n {contrib => tools}/coccinelle/preincr.cocci        |  0\n {contrib => tools}/coccinelle/qsort.cocci          |  0\n {contrib => tools}/coccinelle/refs.cocci           |  0\n {contrib => tools}/coccinelle/spatchcache          |  6 +-\n {contrib => tools}/coccinelle/strbuf.cocci         |  0\n {contrib => tools}/coccinelle/swap.cocci           |  0\n {contrib => tools}/coccinelle/tests/free.c         |  0\n {contrib => tools}/coccinelle/tests/free.res       |  0\n {contrib => tools}/coccinelle/the_repository.cocci |  0\n {contrib => tools}/coccinelle/xcalloc.cocci        |  0\n {contrib => tools}/coccinelle/xopen.cocci          |  0\n .../coccinelle/xstrdup_or_null.cocci               |  0\n {contrib => tools}/coccinelle/xstrncmpz.cocci      |  0\n {contrib => tools}/coverage-diff.sh                |  0\n detect-compiler => tools/detect-compiler           |  0\n generate-cmdlist.sh => tools/generate-cmdlist.sh   |  0\n .../generate-configlist.sh                         |  0\n generate-hooklist.sh => tools/generate-hooklist.sh |  0\n generate-perl.sh => tools/generate-perl.sh         |  0\n generate-python.sh => tools/generate-python.sh     |  0\n generate-script.sh => tools/generate-script.sh     |  0\n tools/meson.build                                  |  1 +\n tools/precompiled.h                                |  1 +\n {contrib => tools}/update-unicode/.gitignore       |  0\n {contrib => tools}/update-unicode/README           |  0\n .../update-unicode/update_unicode.sh               |  0\n 49 files changed, 123 insertions(+), 99 deletions(-)\n\n\n---\nbase-commit: af2c8a61818d773325ef2324dd135786a03ebca0\nchange-id: 20260304-b4-pks-build-infra-improvements-cc4012c5364e\n\n"},{"id":"538490","messageId":"20260310-b4-pks-build-infra-improvements-v1-1-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH 1/8] Introduce new \"tools/\" directory","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:34Z","receivedAt":"2026-03-10T17:52:57Z","isPatch":true,"body":"According to its readme, the \"contrib/\" directory's main intent is to\ncollect stuff that is not an official part of Git, either because it is\ntoo specialized or because it is still considered experimental. The\nreality tells a bit of a different story though: while it _does_ contain\nsuch things, it also contains other things:\n\n  - Our credential helpers, which are being distributed by many\n    packagers nowadays and which can be considered \"stable\".\n\n  - A bunch of tooling that relates to our build and test\n    infrastructure.\n\nEspecially the second category is somewhat of a sore spot. You really\nwouldn't expect build-related tooling to be considered an optional part\nof Git. Quite the opposite.\n\nCreate a new top-level \"tools/\" directory to fix this discrepancy. This\ndirectory will contain all kind of tools that are related to our build\ninfrastructure and that Git developers are likely to use day to day.\n\nFor now, this directory doesn't contain anything yet except for a\nreadme and a Meson skeleton. This will change in subsequent commits.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile          | 2 ++\n meson.build       | 1 +\n tools/README.md   | 7 +++++++\n tools/meson.build | 0\n 4 files changed, 10 insertions(+)\n\ndiff --git a/Makefile b/Makefile\nindex f3264d0a37..c7cedbcd7c 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1066,11 +1066,13 @@ SOURCES_CMD = ( \\\n \t\t'*.sh' \\\n \t\t':!*[tp][0-9][0-9][0-9][0-9]*' \\\n \t\t':!contrib' \\\n+\t\t':!tools' \\\n \t\t2>/dev/null || \\\n \t$(FIND) . \\\n \t\t\\( -name .git -type d -prune \\) \\\n \t\t-o \\( -name '[tp][0-9][0-9][0-9][0-9]*' -prune \\) \\\n \t\t-o \\( -name contrib -type d -prune \\) \\\n+\t\t-o \\( -name tools -type d -prune \\) \\\n \t\t-o \\( -name build -type d -prune \\) \\\n \t\t-o \\( -name .build -type d -prune \\) \\\n \t\t-o \\( -name 'trash*' -type d -prune \\) \\\ndiff --git a/meson.build b/meson.build\nindex 4b536e0124..1d66b5181e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -2149,6 +2149,7 @@ else\n endif\n \n subdir('contrib')\n+subdir('tools')\n \n # Note that the target is intentionally configured after including the\n # 'contrib' directory, as some tool there also have their own manpages.\ndiff --git a/tools/README.md b/tools/README.md\nnew file mode 100644\nindex 0000000000..d732997136\n--- /dev/null\n+++ b/tools/README.md\n@@ -0,0 +1,7 @@\n+Developer Tooling\n+-----------------\n+\n+This directory is expected to contain all sorts of tooling that\n+relates to our build infrastructure. This includes scripts and\n+inputs required by our build systems, but also scripts that\n+developers are expected to run manually.\ndiff --git a/tools/meson.build b/tools/meson.build\nnew file mode 100644\nindex 0000000000..e69de29bb2\n\n-- \n2.53.0.880.g73c4285caa.dirty\n\n"},{"id":"538491","messageId":"20260310-b4-pks-build-infra-improvements-v1-2-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH 2/8] contrib: move \"coccinelle/\" directory into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:35Z","receivedAt":"2026-03-10T17:53:00Z","isPatch":true,"body":"The Coccinelle tool is an ingrained part of our build infrastructure. It\nis executed by our CI to detect antipatterns and is used to detect\nmisuses of certain interfaces. It's presence in \"contrib/\" is thus\nrather misleading.\n\nPromote the configuration into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile                                           | 40 +++++++++++-----------\n ci/run-static-analysis.sh                          |  2 +-\n contrib/meson.build                                |  1 -\n {contrib => tools}/coccinelle/.gitignore           |  0\n {contrib => tools}/coccinelle/README               |  2 +-\n {contrib => tools}/coccinelle/array.cocci          |  0\n {contrib => tools}/coccinelle/commit.cocci         |  0\n .../coccinelle/config_fn_ctx.pending.cocci         |  0\n {contrib => tools}/coccinelle/equals-null.cocci    |  0\n {contrib => tools}/coccinelle/flex_alloc.cocci     |  0\n {contrib => tools}/coccinelle/free.cocci           |  0\n .../coccinelle/git_config_number.cocci             |  0\n {contrib => tools}/coccinelle/hashmap.cocci        |  0\n .../coccinelle/index-compatibility.cocci           |  0\n {contrib => tools}/coccinelle/meson.build          |  0\n {contrib => tools}/coccinelle/object_id.cocci      |  0\n {contrib => tools}/coccinelle/preincr.cocci        |  0\n {contrib => tools}/coccinelle/qsort.cocci          |  0\n {contrib => tools}/coccinelle/refs.cocci           |  0\n {contrib => tools}/coccinelle/spatchcache          |  6 ++--\n {contrib => tools}/coccinelle/strbuf.cocci         |  0\n {contrib => tools}/coccinelle/swap.cocci           |  0\n {contrib => tools}/coccinelle/tests/free.c         |  0\n {contrib => tools}/coccinelle/tests/free.res       |  0\n {contrib => tools}/coccinelle/the_repository.cocci |  0\n {contrib => tools}/coccinelle/xcalloc.cocci        |  0\n {contrib => tools}/coccinelle/xopen.cocci          |  0\n .../coccinelle/xstrdup_or_null.cocci               |  0\n {contrib => tools}/coccinelle/xstrncmpz.cocci      |  0\n tools/meson.build                                  |  1 +\n 30 files changed, 26 insertions(+), 26 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex c7cedbcd7c..8564b1be36 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1005,8 +1005,8 @@ SPATCH_TEST_FLAGS =\n # COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.\n SPATCH_USE_O_DEPENDENCIES = YesPlease\n \n-# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci\n-# files into a single contrib/cocci/ALL.cocci before running\n+# Set SPATCH_CONCAT_COCCI to concatenate the tools/coccinelle/*.cocci\n+# files into a single tools/coccinelle/ALL.cocci before running\n # \"coccicheck\".\n #\n # Pros:\n@@ -1025,7 +1025,7 @@ SPATCH_USE_O_DEPENDENCIES = YesPlease\n #   generate a specific patch, e.g. this will always use strbuf.cocci,\n #   not ALL.cocci:\n #\n-#\tmake contrib/coccinelle/strbuf.cocci.patch\n+#\tmake tools/coccinelle/strbuf.cocci.patch\n SPATCH_CONCAT_COCCI = YesPlease\n \n # Rebuild 'coccicheck' if $(SPATCH), its flags etc. change\n@@ -3457,15 +3457,15 @@ check:\n \t\texit 1; \\\n \tfi\n \n-COCCI_GEN_ALL = .build/contrib/coccinelle/ALL.cocci\n-COCCI_GLOB = $(wildcard contrib/coccinelle/*.cocci)\n+COCCI_GEN_ALL = .build/tools/coccinelle/ALL.cocci\n+COCCI_GLOB = $(wildcard tools/coccinelle/*.cocci)\n COCCI_RULES_TRACKED = $(COCCI_GLOB:%=.build/%)\n COCCI_RULES_TRACKED_NO_PENDING = $(filter-out %.pending.cocci,$(COCCI_RULES_TRACKED))\n COCCI_RULES =\n COCCI_RULES += $(COCCI_GEN_ALL)\n COCCI_RULES += $(COCCI_RULES_TRACKED)\n COCCI_NAMES =\n-COCCI_NAMES += $(COCCI_RULES:.build/contrib/coccinelle/%.cocci=%)\n+COCCI_NAMES += $(COCCI_RULES:.build/tools/coccinelle/%.cocci=%)\n \n COCCICHECK_PENDING = $(filter %.pending.cocci,$(COCCI_RULES))\n COCCICHECK = $(filter-out $(COCCICHECK_PENDING),$(COCCI_RULES))\n@@ -3480,20 +3480,20 @@ COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)\n # on $(MAKECMDGOALS) that match these $(COCCI_RULES)\n COCCI_RULES_GLOB =\n COCCI_RULES_GLOB += cocci%\n-COCCI_RULES_GLOB += .build/contrib/coccinelle/%\n+COCCI_RULES_GLOB += .build/tools/coccinelle/%\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES)\n COCCI_RULES_GLOB += $(COCCICHEC_PATCHES_PENDING)\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_INTREE)\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_PENDING_INTREE)\n COCCI_GOALS = $(filter $(COCCI_RULES_GLOB),$(MAKECMDGOALS))\n \n-COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)\n+COCCI_TEST_RES = $(wildcard tools/coccinelle/tests/*.res)\n \n $(COCCI_RULES_TRACKED): .build/% : %\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_CP)cp $< $@\n \n-.build/contrib/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)\n+.build/tools/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_GEN) >$@\n \n@@ -3507,12 +3507,12 @@ endif\n define cocci-rule\n \n ## Rule for .build/$(1).patch/$(2); Params:\n-# $(1) = e.g. \".build/contrib/coccinelle/free.cocci\"\n+# $(1) = e.g. \".build/tools/coccinelle/free.cocci\"\n # $(2) = e.g. \"grep.c\"\n # $(3) = e.g. \"grep.o\"\n-COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch\n+COCCI_$(1:.build/tools/coccinelle/%.cocci=%) += $(1).d/$(2).patch\n $(1).d/$(2).patch: GIT-SPATCH-DEFINES\n-$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)\n+$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/tools/coccinelle/FOUND_H_SOURCES)\n $(1).d/$(2).patch: $(1)\n $(1).d/$(2).patch: $(1).d/%.patch : %\n \t$$(call mkdir_p_parent_template)\n@@ -3538,13 +3538,13 @@ endif\n \n define spatch-rule\n \n-.build/contrib/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))\n+.build/tools/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))\n \t$$(QUIET_SPATCH_CAT)cat $$^ >$$@ && \\\n \tif test -s $$@; \\\n \tthen \\\n \t\techo '    ' SPATCH result: $$@; \\\n \tfi\n-contrib/coccinelle/$(1).cocci.patch: .build/contrib/coccinelle/$(1).cocci.patch\n+tools/coccinelle/$(1).cocci.patch: .build/tools/coccinelle/$(1).cocci.patch\n \t$$(QUIET_CP)cp $$< $$@\n \n endef\n@@ -3558,9 +3558,9 @@ $(COCCI_TEST_RES_GEN): GIT-SPATCH-DEFINES\n $(COCCI_TEST_RES_GEN): .build/%.res : %.c\n $(COCCI_TEST_RES_GEN): .build/%.res : %.res\n ifdef SPATCH_CONCAT_COCCI\n-$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : $(COCCI_GEN_ALL)\n+$(COCCI_TEST_RES_GEN): .build/tools/coccinelle/tests/%.res : $(COCCI_GEN_ALL)\n else\n-$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci\n+$(COCCI_TEST_RES_GEN): .build/tools/coccinelle/tests/%.res : tools/coccinelle/%.cocci\n endif\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_SPATCH_TEST)$(SPATCH) $(SPATCH_TEST_FLAGS) \\\n@@ -3576,14 +3576,14 @@ coccicheck-test: $(COCCI_TEST_RES_GEN)\n coccicheck: coccicheck-test\n \n ifdef SPATCH_CONCAT_COCCI\n-COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = contrib/coccinelle/ALL.cocci.patch\n+COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = tools/coccinelle/ALL.cocci.patch\n else\n COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = $(COCCICHECK_PATCHES_INTREE)\n endif\n coccicheck: $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES)\n \t! grep ^ $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES) /dev/null\n \n-# See contrib/coccinelle/README\n+# See tools/coccinelle/README\n coccicheck-pending: coccicheck-test\n coccicheck-pending: $(COCCICHECK_PATCHES_PENDING_INTREE)\n \n@@ -3857,8 +3857,8 @@ profile-clean:\n \n cocciclean:\n \t$(RM) GIT-SPATCH-DEFINES\n-\t$(RM) -r .build/contrib/coccinelle\n-\t$(RM) contrib/coccinelle/*.cocci.patch\n+\t$(RM) -r .build/tools/coccinelle\n+\t$(RM) tools/coccinelle/*.cocci.patch\n \n clean: profile-clean coverage-clean cocciclean\n \t$(RM) -r .build $(UNIT_TEST_BIN)\ndiff --git a/ci/run-static-analysis.sh b/ci/run-static-analysis.sh\nindex 9e9c72681d..ba67e80b4d 100755\n--- a/ci/run-static-analysis.sh\n+++ b/ci/run-static-analysis.sh\n@@ -10,7 +10,7 @@ make coccicheck\n set +x\n \n fail=\n-for cocci_patch in contrib/coccinelle/*.patch\n+for cocci_patch in tools/coccinelle/*.patch\n do\n \tif test -s \"$cocci_patch\"\n \tthen\ndiff --git a/contrib/meson.build b/contrib/meson.build\nindex a88c5dfe09..569c23ee76 100644\n--- a/contrib/meson.build\n+++ b/contrib/meson.build\n@@ -2,5 +2,4 @@ foreach feature : get_option('contrib')\n   subdir(feature)\n endforeach\n \n-subdir('coccinelle')\n subdir('credential')\ndiff --git a/contrib/coccinelle/.gitignore b/tools/coccinelle/.gitignore\nsimilarity index 100%\nrename from contrib/coccinelle/.gitignore\nrename to tools/coccinelle/.gitignore\ndiff --git a/contrib/coccinelle/README b/tools/coccinelle/README\nsimilarity index 98%\nrename from contrib/coccinelle/README\nrename to tools/coccinelle/README\nindex 055ad0e06a..fd0a543cc2 100644\n--- a/contrib/coccinelle/README\n+++ b/tools/coccinelle/README\n@@ -38,7 +38,7 @@ that might be useful to developers.\n    So to aid these large scale refactorings, semantic patches can be used.\n    However we do not want to store them in the same place as the checks for\n    bad patterns, as then automated builds would fail.\n-   That is why semantic patches 'contrib/coccinelle/*.pending.cocci'\n+   That is why semantic patches 'tools/coccinelle/*.pending.cocci'\n    are ignored for checks, and can be applied using 'make coccicheck-pending'.\n \n    This allows to expose plans of pending large scale refactorings without\ndiff --git a/contrib/coccinelle/array.cocci b/tools/coccinelle/array.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/array.cocci\nrename to tools/coccinelle/array.cocci\ndiff --git a/contrib/coccinelle/commit.cocci b/tools/coccinelle/commit.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/commit.cocci\nrename to tools/coccinelle/commit.cocci\ndiff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/tools/coccinelle/config_fn_ctx.pending.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/config_fn_ctx.pending.cocci\nrename to tools/coccinelle/config_fn_ctx.pending.cocci\ndiff --git a/contrib/coccinelle/equals-null.cocci b/tools/coccinelle/equals-null.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/equals-null.cocci\nrename to tools/coccinelle/equals-null.cocci\ndiff --git a/contrib/coccinelle/flex_alloc.cocci b/tools/coccinelle/flex_alloc.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/flex_alloc.cocci\nrename to tools/coccinelle/flex_alloc.cocci\ndiff --git a/contrib/coccinelle/free.cocci b/tools/coccinelle/free.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/free.cocci\nrename to tools/coccinelle/free.cocci\ndiff --git a/contrib/coccinelle/git_config_number.cocci b/tools/coccinelle/git_config_number.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/git_config_number.cocci\nrename to tools/coccinelle/git_config_number.cocci\ndiff --git a/contrib/coccinelle/hashmap.cocci b/tools/coccinelle/hashmap.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/hashmap.cocci\nrename to tools/coccinelle/hashmap.cocci\ndiff --git a/contrib/coccinelle/index-compatibility.cocci b/tools/coccinelle/index-compatibility.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/index-compatibility.cocci\nrename to tools/coccinelle/index-compatibility.cocci\ndiff --git a/contrib/coccinelle/meson.build b/tools/coccinelle/meson.build\nsimilarity index 100%\nrename from contrib/coccinelle/meson.build\nrename to tools/coccinelle/meson.build\ndiff --git a/contrib/coccinelle/object_id.cocci b/tools/coccinelle/object_id.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/object_id.cocci\nrename to tools/coccinelle/object_id.cocci\ndiff --git a/contrib/coccinelle/preincr.cocci b/tools/coccinelle/preincr.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/preincr.cocci\nrename to tools/coccinelle/preincr.cocci\ndiff --git a/contrib/coccinelle/qsort.cocci b/tools/coccinelle/qsort.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/qsort.cocci\nrename to tools/coccinelle/qsort.cocci\ndiff --git a/contrib/coccinelle/refs.cocci b/tools/coccinelle/refs.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/refs.cocci\nrename to tools/coccinelle/refs.cocci\ndiff --git a/contrib/coccinelle/spatchcache b/tools/coccinelle/spatchcache\nsimilarity index 97%\nrename from contrib/coccinelle/spatchcache\nrename to tools/coccinelle/spatchcache\nindex 29e9352d8a..efbcbc3827 100755\n--- a/contrib/coccinelle/spatchcache\n+++ b/tools/coccinelle/spatchcache\n@@ -30,7 +30,7 @@\n #\t   out of control.\n #\n # This along with the general incremental \"make\" support for\n-# \"contrib/coccinelle\" makes it viable to (re-)run coccicheck\n+# \"tools/coccinelle\" makes it viable to (re-)run coccicheck\n # e.g. when merging integration branches.\n #\n # Note that the \"--very-quiet\" flag is currently critical. The cache\n@@ -42,7 +42,7 @@\n # to change, so just supply \"--very-quiet\" for now.\n #\n # To use this, simply set SPATCH to\n-# contrib/coccinelle/spatchcache. Then optionally set:\n+# tools/coccinelle/spatchcache. Then optionally set:\n #\n #\t[spatchCache]\n #\t\t# Optional: path to a custom spatch\n@@ -65,7 +65,7 @@\n #\n #\tredis-cli FLUSHALL\n #\t<make && make coccicheck, as above>\n-#\tgrep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/contrib/coccinelle | sort | uniq -c\n+#\tgrep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/tools/coccinelle | sort | uniq -c\n #\t    600 CANTCACHE\n #\t   7365 MISS\n #\t   7365 SET\ndiff --git a/contrib/coccinelle/strbuf.cocci b/tools/coccinelle/strbuf.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/strbuf.cocci\nrename to tools/coccinelle/strbuf.cocci\ndiff --git a/contrib/coccinelle/swap.cocci b/tools/coccinelle/swap.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/swap.cocci\nrename to tools/coccinelle/swap.cocci\ndiff --git a/contrib/coccinelle/tests/free.c b/tools/coccinelle/tests/free.c\nsimilarity index 100%\nrename from contrib/coccinelle/tests/free.c\nrename to tools/coccinelle/tests/free.c\ndiff --git a/contrib/coccinelle/tests/free.res b/tools/coccinelle/tests/free.res\nsimilarity index 100%\nrename from contrib/coccinelle/tests/free.res\nrename to tools/coccinelle/tests/free.res\ndiff --git a/contrib/coccinelle/the_repository.cocci b/tools/coccinelle/the_repository.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/the_repository.cocci\nrename to tools/coccinelle/the_repository.cocci\ndiff --git a/contrib/coccinelle/xcalloc.cocci b/tools/coccinelle/xcalloc.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xcalloc.cocci\nrename to tools/coccinelle/xcalloc.cocci\ndiff --git a/contrib/coccinelle/xopen.cocci b/tools/coccinelle/xopen.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xopen.cocci\nrename to tools/coccinelle/xopen.cocci\ndiff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/tools/coccinelle/xstrdup_or_null.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xstrdup_or_null.cocci\nrename to tools/coccinelle/xstrdup_or_null.cocci\ndiff --git a/contrib/coccinelle/xstrncmpz.cocci b/tools/coccinelle/xstrncmpz.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xstrncmpz.cocci\nrename to tools/coccinelle/xstrncmpz.cocci\ndiff --git a/tools/meson.build b/tools/meson.build\nindex e69de29bb2..f731f74312 100644\n--- a/tools/meson.build\n+++ b/tools/meson.build\n@@ -0,0 +1 @@\n+subdir('coccinelle')\n\n-- \n2.53.0.880.g73c4285caa.dirty\n\n"},{"id":"538492","messageId":"20260310-b4-pks-build-infra-improvements-v1-3-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH 3/8] contrib: move \"coverage-diff.sh\" script into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:36Z","receivedAt":"2026-03-10T17:53:02Z","isPatch":true,"body":"The \"coverage-diff.sh\" script can be used to get information about test\ncoverage fro the Git codebase. It is thus rather specific to our build\nand test infrastructure and part of the developer-facing tooling. The\nfact that this script is part of \"contrib/\" is thus rather misleading\nand a historic wart.\n\nPromote the tool into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n {contrib => tools}/coverage-diff.sh | 0\n 1 file changed, 0 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/coverage-diff.sh b/tools/coverage-diff.sh\nsimilarity index 100%\nrename from contrib/coverage-diff.sh\nrename to tools/coverage-diff.sh\n\n-- \n2.53.0.880.g73c4285caa.dirty\n\n"},{"id":"538493","messageId":"20260310-b4-pks-build-infra-improvements-v1-4-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH 4/8] contrib: move \"update-unicode.sh\" script into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:37Z","receivedAt":"2026-03-10T17:53:04Z","isPatch":true,"body":"The \"update-unicode.sh\" script is used to update the unicode data\ncompiled into Git whenever a new version of the Unicode standard has\nbeen released. As such, it is a natural part of our developer-facing\ntooling, and its presence in \"contrib/\" is misleading.\n\nPromote the script into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n {contrib => tools}/update-unicode/.gitignore        | 0\n {contrib => tools}/update-unicode/README            | 0\n {contrib => tools}/update-unicode/update_unicode.sh | 0\n 3 files changed, 0 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/update-unicode/.gitignore b/tools/update-unicode/.gitignore\nsimilarity index 100%\nrename from contrib/update-unicode/.gitignore\nrename to tools/update-unicode/.gitignore\ndiff --git a/contrib/update-unicode/README b/tools/update-unicode/README\nsimilarity index 100%\nrename from contrib/update-unicode/README\nrename to tools/update-unicode/README\ndiff --git a/contrib/update-unicode/update_unicode.sh b/tools/update-unicode/update_unicode.sh\nsimilarity index 100%\nrename from contrib/update-unicode/update_unicode.sh\nrename to tools/update-unicode/update_unicode.sh\n\n-- \n2.53.0.880.g73c4285caa.dirty\n\n"},{"id":"538494","messageId":"20260310-b4-pks-build-infra-improvements-v1-5-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH 5/8] builds: move build scripts into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:38Z","receivedAt":"2026-03-10T17:53:07Z","isPatch":true,"body":"We have a bunch of scripts used by our different build systems that are\nall located in the top-level directory. Now that we have introduced the\nnew \"tools/\" directory though we have a better home for them.\n\nMove the scripts into the \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile                                           | 34 +++++++++++-----------\n config.mak.dev                                     |  2 +-\n contrib/buildsystems/CMakeLists.txt                | 18 ++++++------\n contrib/subtree/meson.build                        |  2 +-\n meson.build                                        | 14 ++++-----\n check-builtins.sh => tools/check-builtins.sh       |  0\n detect-compiler => tools/detect-compiler           |  0\n generate-cmdlist.sh => tools/generate-cmdlist.sh   |  0\n .../generate-configlist.sh                         |  0\n generate-hooklist.sh => tools/generate-hooklist.sh |  0\n generate-perl.sh => tools/generate-perl.sh         |  0\n generate-python.sh => tools/generate-python.sh     |  0\n generate-script.sh => tools/generate-script.sh     |  0\n 13 files changed, 35 insertions(+), 35 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 8564b1be36..322f5940e3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2689,21 +2689,21 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n-config-list.h: generate-configlist.sh\n+config-list.h: tools/generate-configlist.sh\n \t@mkdir -p .depend\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh . $@ .depend/config-list.h.d\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-configlist.sh . $@ .depend/config-list.h.d\n \n -include .depend/config-list.h.d\n \n-command-list.h: generate-cmdlist.sh command-list.txt\n+command-list.h: tools/generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.adoc)\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh \\\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-cmdlist.sh \\\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\t. $@\n \n-hook-list.h: generate-hooklist.sh Documentation/githooks.adoc\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh . $@\n+hook-list.h: tools/generate-hooklist.sh Documentation/githooks.adoc\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-hooklist.sh . $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):\\\n \t$(localedir_SQ):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n@@ -2716,8 +2716,8 @@ GIT-SCRIPT-DEFINES: FORCE\n \t\techo \"$$FLAGS\" >$@; \\\n             fi\n \n-$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n-\t$(QUIET_GEN)./generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n+$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh tools/generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n+\t$(QUIET_GEN)./tools/generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n \tmv $@+ $@\n \n git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE\n@@ -2757,8 +2757,8 @@ endif\n \n PERL_DEFINES += $(gitexecdir) $(perllibdir) $(localedir)\n \n-$(SCRIPT_PERL_GEN): % : %.perl generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@+\" && \\\n+$(SCRIPT_PERL_GEN): % : %.perl tools/generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@+\" && \\\n \tmv $@+ $@\n \n PERL_DEFINES := $(subst $(space),:,$(PERL_DEFINES))\n@@ -2786,8 +2786,8 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile\n perllibdir:\n \t@echo '$(perllibdir_SQ)'\n \n-git-instaweb: git-instaweb.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n-\t$(QUIET_GEN)./generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n+git-instaweb: git-instaweb.sh tools/generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n+\t$(QUIET_GEN)./tools/generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n \tchmod +x $@+ && \\\n \tmv $@+ $@\n else # NO_PERL\n@@ -2804,9 +2804,9 @@ endif # NO_PERL\n $(SCRIPT_PYTHON_GEN): GIT-BUILD-OPTIONS\n \n ifndef NO_PYTHON\n-$(SCRIPT_PYTHON_GEN): generate-python.sh\n+$(SCRIPT_PYTHON_GEN): tools/generate-python.sh\n $(SCRIPT_PYTHON_GEN): % : %.py\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-python.sh ./GIT-BUILD-OPTIONS \"$<\" \"$@\"\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-python.sh ./GIT-BUILD-OPTIONS \"$<\" \"$@\"\n else # NO_PYTHON\n $(SCRIPT_PYTHON_GEN): % : unimplemented.sh\n \t$(QUIET_GEN) \\\n@@ -3226,9 +3226,9 @@ endif\n NO_PERL_CPAN_FALLBACKS_SQ = $(subst ','\\'',$(NO_PERL_CPAN_FALLBACKS))\n endif\n \n-perl/build/lib/%.pm: perl/%.pm generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES\n+perl/build/lib/%.pm: perl/%.pm tools/generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES\n \t$(call mkdir_p_parent_template)\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@\"\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@\"\n \n perl/build/man/man3/Git.3pm: perl/Git.pm\n \t$(call mkdir_p_parent_template)\n@@ -3936,7 +3936,7 @@ check-docs::\n ### Make sure built-ins do not have dups and listed in git.c\n #\n check-builtins::\n-\t./check-builtins.sh\n+\t./tools/check-builtins.sh\n \n ### Test suite coverage testing\n #\ndiff --git a/config.mak.dev b/config.mak.dev\nindex e86b6e1b34..c8dcf78779 100644\n--- a/config.mak.dev\n+++ b/config.mak.dev\n@@ -1,5 +1,5 @@\n ifndef COMPILER_FEATURES\n-COMPILER_FEATURES := $(shell ./detect-compiler $(CC))\n+COMPILER_FEATURES := $(shell ./tools/detect-compiler $(CC))\n endif\n \n ifeq ($(filter no-error,$(DEVOPTS)),)\ndiff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt\nindex c6cfb874ef..81b4306e72 100644\n--- a/contrib/buildsystems/CMakeLists.txt\n+++ b/contrib/buildsystems/CMakeLists.txt\n@@ -636,7 +636,7 @@ set(EXCLUSION_PROGS_CACHE ${EXCLUSION_PROGS} CACHE STRING \"Programs not built\" F\n if(NOT EXISTS ${CMAKE_BINARY_DIR}/command-list.h OR NOT EXCLUSION_PROGS_CACHE STREQUAL EXCLUSION_PROGS)\n \tlist(REMOVE_ITEM EXCLUSION_PROGS empty)\n \tmessage(\"Generating command-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-cmdlist.sh\"\n+\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-cmdlist.sh\"\n \t\t\t\t${EXCLUSION_PROGS}\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/command-list.h\")\n@@ -644,14 +644,14 @@ endif()\n \n if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)\n \tmessage(\"Generating config-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-configlist.sh\"\n+\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-configlist.sh\"\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/config-list.h\")\n endif()\n \n if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h)\n \tmessage(\"Generating hook-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" ${CMAKE_SOURCE_DIR}/generate-hooklist.sh\n+\texecute_process(COMMAND \"${SH_EXE}\" ${CMAKE_SOURCE_DIR}/tools/generate-hooklist.sh\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/hook-list.h\")\n endif()\n@@ -832,11 +832,11 @@ foreach(script ${git_shell_scripts})\n \tendif()\n \n \tadd_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/${shell_gen_path}\"\n-\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-script.sh\"\n+\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-script.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}.sh\"\n \t\t\t\"${CMAKE_BINARY_DIR}/${shell_gen_path}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n-\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-script.sh\"\n+\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-script.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}.sh\"\n \t\tVERBATIM)\n \tlist(APPEND shell_gen ${CMAKE_BINARY_DIR}/${shell_gen_path})\n@@ -875,13 +875,13 @@ foreach(script ${git_perl_scripts} ${perl_modules})\n \tfile(MAKE_DIRECTORY \"${CMAKE_BINARY_DIR}/${perl_gen_dir}\")\n \n \tadd_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/${perl_gen_path}\"\n-\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-perl.sh\"\n+\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-perl.sh\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-VERSION-FILE\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-PERL-HEADER\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/${perl_gen_path}\"\n-\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-perl.sh\"\n+\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-perl.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-VERSION-FILE\"\n@@ -892,11 +892,11 @@ add_custom_target(perl-gen ALL DEPENDS ${perl_gen})\n \n # Python script\n add_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/git-p4\"\n-\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-python.sh\"\n+\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-python.sh\"\n \t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\"${CMAKE_SOURCE_DIR}/git-p4.py\"\n \t\t\"${CMAKE_BINARY_DIR}/git-p4\"\n-\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-python.sh\"\n+\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-python.sh\"\n \t\t\"${CMAKE_SOURCE_DIR}/git-p4.py\"\n \t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \tVERBATIM)\ndiff --git a/contrib/subtree/meson.build b/contrib/subtree/meson.build\nindex 161435abeb..804c315894 100644\n--- a/contrib/subtree/meson.build\n+++ b/contrib/subtree/meson.build\n@@ -3,7 +3,7 @@ git_subtree = custom_target(\n   output: 'git-subtree',\n   command: [\n     shell,\n-    meson.project_source_root() / 'generate-script.sh',\n+    meson.project_source_root() / 'tools/generate-script.sh',\n     '@INPUT@',\n     '@OUTPUT@',\n     meson.project_build_root() / 'GIT-BUILD-OPTIONS',\ndiff --git a/meson.build b/meson.build\nindex 1d66b5181e..604fe89d2d 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -554,7 +554,7 @@ libgit_sources = [\n libgit_sources += custom_target(\n   input: 'command-list.txt',\n   output: 'command-list.h',\n-  command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],\n+  command: [shell, meson.current_source_dir() + '/tools/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],\n   env: script_environment,\n )\n \n@@ -723,10 +723,10 @@ endif\n builtin_sources += custom_target(\n   output: 'config-list.h',\n   depfile: 'config-list.h.d',\n-  depend_files: [ 'generate-configlist.sh' ],\n+  depend_files: [ 'tools/generate-configlist.sh' ],\n   command: [\n     shell,\n-    meson.current_source_dir() / 'generate-configlist.sh',\n+    meson.current_source_dir() / 'tools/generate-configlist.sh',\n     meson.current_source_dir(),\n     '@OUTPUT@',\n     '@DEPFILE@',\n@@ -739,7 +739,7 @@ builtin_sources += custom_target(\n   output: 'hook-list.h',\n   command: [\n     shell,\n-    meson.current_source_dir() + '/generate-hooklist.sh',\n+    meson.current_source_dir() + '/tools/generate-hooklist.sh',\n     meson.current_source_dir(),\n     '@OUTPUT@',\n   ],\n@@ -1959,7 +1959,7 @@ foreach script : scripts_sh\n     output: fs.stem(script),\n     command: [\n       shell,\n-      meson.project_source_root() / 'generate-script.sh',\n+      meson.project_source_root() / 'tools/generate-script.sh',\n       '@INPUT@',\n       '@OUTPUT@',\n       meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n@@ -2008,7 +2008,7 @@ if perl_features_enabled\n \n   generate_perl_command = [\n     shell,\n-    meson.project_source_root() / 'generate-perl.sh',\n+    meson.project_source_root() / 'tools/generate-perl.sh',\n     meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n     git_version_file.full_path(),\n     perl_header,\n@@ -2057,7 +2057,7 @@ if target_python.found()\n       output: fs.stem(script),\n       command: [\n         shell,\n-        meson.project_source_root() / 'generate-python.sh',\n+        meson.project_source_root() / 'tools/generate-python.sh',\n         meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n         '@INPUT@',\n         '@OUTPUT@',\ndiff --git a/check-builtins.sh b/tools/check-builtins.sh\nsimilarity index 100%\nrename from check-builtins.sh\nrename to tools/check-builtins.sh\ndiff --git a/detect-compiler b/tools/detect-compiler\nsimilarity index 100%\nrename from detect-compiler\nrename to tools/detect-compiler\ndiff --git a/generate-cmdlist.sh b/tools/generate-cmdlist.sh\nsimilarity index 100%\nrename from generate-cmdlist.sh\nrename to tools/generate-cmdlist.sh\ndiff --git a/generate-configlist.sh b/tools/generate-configlist.sh\nsimilarity index 100%\nrename from generate-configlist.sh\nrename to tools/generate-configlist.sh\ndiff --git a/generate-hooklist.sh b/tools/generate-hooklist.sh\nsimilarity index 100%\nrename from generate-hooklist.sh\nrename to tools/generate-hooklist.sh\ndiff --git a/generate-perl.sh b/tools/generate-perl.sh\nsimilarity index 100%\nrename from generate-perl.sh\nrename to tools/generate-perl.sh\ndiff --git a/generate-python.sh b/tools/generate-python.sh\nsimilarity index 100%\nrename from generate-python.sh\nrename to tools/generate-python.sh\ndiff --git a/generate-script.sh b/tools/generate-script.sh\nsimilarity index 100%\nrename from generate-script.sh\nrename to tools/generate-script.sh\n\n-- \n2.53.0.880.g73c4285caa.dirty\n\n"},{"id":"538495","messageId":"20260310-b4-pks-build-infra-improvements-v1-6-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH 6/8] git-compat-util.h: move warning infra to prepare for PCHs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:39Z","receivedAt":"2026-03-10T17:53:09Z","isPatch":true,"body":"The \"git-compat-util.h\" header is supposed to be the first header\nincluded by every code compilation unit. As such, a subsequent commit\nwill start to precompile this header to speed up compilation of Git.\n\nThis will cause an issue though with the way that we have set up the\n\"-Wsign-compare\" warnings. It is expected that any compilation unit that\nfails with that compiler warning sets `DISABLE_SIGN_COMPARE_WARNINGS`\nbefore including \"git-compat-util.h\". If so, we'll disable the warning\nright away via a compiler pragma.\n\nBut with precompiled headers we do not know ahead of time whether the\ncode unit wants to disable those warnings, and thus we'll have to\nprecompile the header without defining `DISABLE_SIGN_COMPARE_WARNINGS`.\nBut as the pragma statement is wrapped by our include guards, the second\ninclude of that file will not have the desired effect of disabling the\nwarnings anymore.\n\nWe could fix this issue by declaring a new macro that compilation units\nare expected to invoke after having included the file. In retrospect,\nthat would have been the better way to handle this as it allows for\nmore flexibility: we could for example toggle the warning for specific\ncode blocks, only. But changing this now would require a bunch of\nchanges, and the churn feels excessive for what we gain.\n\nInstead, prepare for the precompiled headers by moving the code outside\nof the include guards.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n git-compat-util.h | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex bebcf9f698..4b4ea2498f 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -34,10 +34,6 @@ struct strbuf;\n #  define DISABLE_WARNING(warning)\n #endif\n \n-#ifdef DISABLE_SIGN_COMPARE_WARNINGS\n-DISABLE_WARNING(-Wsign-compare)\n-#endif\n-\n #undef FLEX_ARRAY\n #define FLEX_ARRAY /* empty - weather balloon to require C99 FAM */\n \n@@ -1099,3 +1095,7 @@ extern int not_supposed_to_survive;\n #endif /* CHECK_ASSERTION_SIDE_EFFECTS */\n \n #endif\n+\n+#ifdef DISABLE_SIGN_COMPARE_WARNINGS\n+DISABLE_WARNING(-Wsign-compare)\n+#endif\n\n-- \n2.53.0.880.g73c4285caa.dirty\n\n"},{"id":"538496","messageId":"20260310-b4-pks-build-infra-improvements-v1-7-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH 7/8] meson: compile compatibility sources separately","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:40Z","receivedAt":"2026-03-10T17:53:11Z","isPatch":true,"body":"In the next commit we're about to introduce a precompiled header for\n\"git-compat-util.h\". The consequence of this change is that we'll\nimplicitly include that header for every compilation unit that uses the\nprecompiled headers.\n\nThis is okay for our \"normal\" library sources and our builtins. But some\nof our compatibility sources do not include the header on purpose, and\ndoing so would cause compileir errors.\n\nPrepare for this change by splitting out compatibility sources into\ntheir static library. Like this we can selectively enable precompiled\nheaders for the library sources.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 79 +++++++++++++++++++++++++++++++++++--------------------------\n 1 file changed, 45 insertions(+), 34 deletions(-)\n\ndiff --git a/meson.build b/meson.build\nindex 604fe89d2d..cd00be1c23 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -271,6 +271,13 @@ version_gen_environment.set('GIT_VERSION', get_option('version'))\n \n compiler = meson.get_compiler('c')\n \n+compat_sources = [\n+  'compat/nonblock.c',\n+  'compat/obstack.c',\n+  'compat/open.c',\n+  'compat/terminal.c',\n+]\n+\n libgit_sources = [\n   'abspath.c',\n   'add-interactive.c',\n@@ -304,10 +311,6 @@ libgit_sources = [\n   'commit.c',\n   'common-exit.c',\n   'common-init.c',\n-  'compat/nonblock.c',\n-  'compat/obstack.c',\n-  'compat/open.c',\n-  'compat/terminal.c',\n   'compiler-tricks/not-constant.c',\n   'config.c',\n   'connect.c',\n@@ -1163,7 +1166,7 @@ endif\n \n if not has_poll_h and not has_sys_poll_h\n   libgit_c_args += '-DNO_POLL'\n-  libgit_sources += 'compat/poll/poll.c'\n+  compat_sources += 'compat/poll/poll.c'\n   libgit_include_directories += 'compat/poll'\n endif\n \n@@ -1179,7 +1182,7 @@ endif\n # implementation to threat things like drive prefixes specially.\n if host_machine.system() == 'windows' or not compiler.has_header('libgen.h')\n   libgit_c_args += '-DNO_LIBGEN_H'\n-  libgit_sources += 'compat/basename.c'\n+  compat_sources += 'compat/basename.c'\n endif\n \n if compiler.has_header('paths.h')\n@@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'\n   foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']\n     if not compiler.has_function(symbol, dependencies: networking_dependencies)\n       libgit_c_args += '-DNO_' + symbol.to_upper()\n-      libgit_sources += 'compat/' + symbol + '.c'\n+      compat_sources += 'compat/' + symbol + '.c'\n     endif\n   endforeach\n endif\n@@ -1251,18 +1254,18 @@ else\n endif\n \n if host_machine.system() == 'darwin'\n-  libgit_sources += 'compat/precompose_utf8.c'\n+  compat_sources += 'compat/precompose_utf8.c'\n   libgit_c_args += '-DPRECOMPOSE_UNICODE'\n   libgit_c_args += '-DPROTECT_HFS_DEFAULT'\n endif\n \n # Configure general compatibility wrappers.\n if host_machine.system() == 'cygwin'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/win32/path-utils.c',\n   ]\n elif host_machine.system() == 'windows'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/winansi.c',\n     'compat/win32/dirent.c',\n     'compat/win32/flush.c',\n@@ -1289,20 +1292,20 @@ elif host_machine.system() == 'windows'\n   libgit_include_directories += 'compat/win32'\n   if compiler.get_id() == 'msvc'\n     libgit_include_directories += 'compat/vcbuild/include'\n-    libgit_sources += 'compat/msvc.c'\n+    compat_sources += 'compat/msvc.c'\n   else\n-    libgit_sources += 'compat/mingw.c'\n+    compat_sources += 'compat/mingw.c'\n   endif\n endif\n \n if host_machine.system() == 'linux'\n-  libgit_sources += 'compat/linux/procinfo.c'\n+  compat_sources += 'compat/linux/procinfo.c'\n elif host_machine.system() == 'windows'\n-  libgit_sources += 'compat/win32/trace2_win32_process_info.c'\n+  compat_sources += 'compat/win32/trace2_win32_process_info.c'\n elif host_machine.system() == 'darwin'\n-  libgit_sources += 'compat/darwin/procinfo.c'\n+  compat_sources += 'compat/darwin/procinfo.c'\n else\n-  libgit_sources += 'compat/stub/procinfo.c'\n+  compat_sources += 'compat/stub/procinfo.c'\n endif\n \n if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'\n@@ -1315,13 +1318,13 @@ endif\n \n # Configure the simple-ipc subsystem required fro the fsmonitor.\n if host_machine.system() == 'windows'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/simple-ipc/ipc-shared.c',\n     'compat/simple-ipc/ipc-win32.c',\n   ]\n   libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'\n else\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/simple-ipc/ipc-shared.c',\n     'compat/simple-ipc/ipc-unix-socket.c',\n   ]\n@@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''\n   libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND'\n   libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'\n \n-  libgit_sources += [\n+  compat_sources += [\n     'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',\n     'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',\n     'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',\n@@ -1355,7 +1358,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').allo\n \n   if compiler.get_define('REG_ENHANCED', prefix: '#include <regex.h>') != ''\n     libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'\n-    libgit_sources += 'compat/regcomp_enhanced.c'\n+    compat_sources += 'compat/regcomp_enhanced.c'\n   endif\n elif not get_option('regex').enabled()\n   libgit_c_args += [\n@@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()\n     '-DNO_MBSUPPORT',\n   ]\n   build_options_config.set('NO_REGEX', '1')\n-  libgit_sources += 'compat/regex/regex.c'\n+  compat_sources += 'compat/regex/regex.c'\n   libgit_include_directories += 'compat/regex'\n else\n     error('Native regex support requested but not found')\n@@ -1428,7 +1431,7 @@ else\n \n   if get_option('b_sanitize').contains('address')\n     libgit_c_args += '-DNO_MMAP'\n-    libgit_sources += 'compat/mmap.c'\n+    compat_sources += 'compat/mmap.c'\n   else\n     checkfuncs += { 'mmap': ['mmap.c'] }\n   endif\n@@ -1438,7 +1441,7 @@ foreach func, impls : checkfuncs\n   if not compiler.has_function(func)\n     libgit_c_args += '-DNO_' + func.to_upper()\n     foreach impl : impls\n-      libgit_sources += 'compat/' + impl\n+      compat_sources += 'compat/' + impl\n     endforeach\n   endif\n endforeach\n@@ -1449,13 +1452,13 @@ endif\n \n if not compiler.has_function('strdup')\n   libgit_c_args += '-DOVERRIDE_STRDUP'\n-  libgit_sources += 'compat/strdup.c'\n+  compat_sources += 'compat/strdup.c'\n endif\n \n if not compiler.has_function('qsort')\n   libgit_c_args += '-DINTERNAL_QSORT'\n endif\n-libgit_sources += 'compat/qsort_s.c'\n+compat_sources += 'compat/qsort_s.c'\n \n if compiler.has_function('getdelim')\n   libgit_c_args += '-DHAVE_GETDELIM'\n@@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and compiler.run('''\n   }\n ''', name: 'fread reads directories').returncode() == 0\n   libgit_c_args += '-DFREAD_READS_DIRECTORIES'\n-  libgit_sources += 'compat/fopen.c'\n+  compat_sources += 'compat/fopen.c'\n endif\n \n if not meson.is_cross_build() and fs.exists('/dev/tty')\n@@ -1745,14 +1748,22 @@ else\n endif\n \n libgit = declare_dependency(\n-  link_with: static_library('git',\n-    sources: libgit_sources,\n-    c_args: libgit_c_args + [\n-      '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n-    ],\n-    dependencies: libgit_dependencies,\n-    include_directories: libgit_include_directories,\n-  ),\n+  link_with: [\n+    static_library('compat',\n+      sources: compat_sources,\n+      c_args: libgit_c_args,\n+      dependencies: libgit_dependencies,\n+      include_directories: libgit_include_directories,\n+    ),\n+    static_library('git',\n+      sources: libgit_sources,\n+      c_args: libgit_c_args + [\n+        '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n+      ],\n+      dependencies: libgit_dependencies,\n+      include_directories: libgit_include_directories,\n+    ),\n+  ],\n   compile_args: libgit_c_args,\n   dependencies: libgit_dependencies,\n   include_directories: libgit_include_directories,\n\n-- \n2.53.0.880.g73c4285caa.dirty\n\n"},{"id":"538497","messageId":"20260310-b4-pks-build-infra-improvements-v1-8-ec75d0710d6a@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH 8/8] meson: precompile \"git-compat-util.h\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-10T17:52:41Z","receivedAt":"2026-03-10T17:53:14Z","isPatch":true,"body":"Every compilation unit in Git is expected to include \"git-compat-util.h\"\nfirst, either directly or indirectly via \"builtin.h\". This header papers\nover differences between platforms so that we can expect the typical\nPOSIX functions to exist. Furthermore, it provides functionality that we\nend up using everywhere.\n\nThis header is thus quite heavy as a consequence. Preprocessing it as a\nstandalone unit via `clang -E git-compat-util.h` yields over 23,000\nlines of code overall. Naturally, it takes quite some time to compile\nall of this.\n\nLuckily, this is exactly the kind of use case that precompiled headers\naim to solve: instead of recompiling it every single time, we compile it\nonce and then link the result into the executable. If include guards are\nset up properly it means that the file won't need to be reprocessed.\n\nSet up such a precompiled header for \"git-compat-util.h\" and wire it up\nvia Meson. This leads to a significant speedup when performing full\nbuilds:\n\n  Benchmark 1: ninja (rev = HEAD~)\n  Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n  Range (min … max):   14.195 s … 14.633 s    10 runs\n\n  Benchmark 2: ninja (rev = HEAD)\n    Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n    Range (min … max):   10.030 s … 10.433 s    10 runs\n\n  Summary\n    ninja (rev = HEAD) ran\n      1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build         | 2 ++\n tools/precompiled.h | 1 +\n 2 files changed, 3 insertions(+)\n\ndiff --git a/meson.build b/meson.build\nindex cd00be1c23..4b3fd47061 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1760,6 +1760,7 @@ libgit = declare_dependency(\n       c_args: libgit_c_args + [\n         '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n       ],\n+      c_pch: [ 'tools/precompiled.h' ],\n       dependencies: libgit_dependencies,\n       include_directories: libgit_include_directories,\n     ),\n@@ -1820,6 +1821,7 @@ test_dependencies = [ ]\n \n git_builtin = executable('git',\n   sources: builtin_sources + 'git.c',\n+  c_pch: [ 'tools/precompiled.h' ],\n   dependencies: [libgit_commonmain],\n   install: true,\n   install_dir: git_exec_path,\ndiff --git a/tools/precompiled.h b/tools/precompiled.h\nnew file mode 100644\nindex 0000000000..b2bec0d2b4\n--- /dev/null\n+++ b/tools/precompiled.h\n@@ -0,0 +1 @@\n+#include \"git-compat-util.h\"\n\n-- \n2.53.0.880.g73c4285caa.dirty\n\n"},{"id":"538502","messageId":"xmqqwlzjtufv.fsf@gitster.g","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"Re: [PATCH 0/8] Some build system improvements","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-10T18:23:32Z","receivedAt":"2026-03-10T18:23:34Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Patrick Steinhardt (8):\n>       Introduce new \"tools/\" directory\n>       contrib: move \"coccinelle/\" directory into \"tools/\"\n\nEven though \"make coccicheck\" may not care where the coccinelle\nstuff lives, if this step changes the location of the resulting\ncoccinelle-generated patch in the tree, it will have fallouts to\ndeveloper workflows.  The blast radius may be limited, as those\nother than Git developers will be hurt, though.\n\nI mention this to forewarn others early, but I do not have a strong\nobjection against this step; at least not yet, even though I may\nchange my mind if the fallout turns out to be greater than I\nanticipated.\n\n\n\n>       contrib: move \"coverage-diff.sh\" script into \"tools/\"\n>       contrib: move \"update-unicode.sh\" script into \"tools/\"\n>       builds: move build scripts into \"tools/\"\n>       git-compat-util.h: move warning infra to prepare for PCHs\n>       meson: compile compatibility sources separately\n>       meson: precompile \"git-compat-util.h\"\n>\n>  Makefile                                           | 76 ++++++++---------\n>  ci/run-static-analysis.sh                          |  2 +-\n>  config.mak.dev                                     |  2 +-\n>  contrib/buildsystems/CMakeLists.txt                | 18 ++--\n>  contrib/meson.build                                |  1 -\n>  contrib/subtree/meson.build                        |  2 +-\n>  git-compat-util.h                                  |  8 +-\n>  meson.build                                        | 96 +++++++++++++---------\n>  tools/README.md                                    |  7 ++\n>  check-builtins.sh => tools/check-builtins.sh       |  0\n>  {contrib => tools}/coccinelle/.gitignore           |  0\n>  {contrib => tools}/coccinelle/README               |  2 +-\n>  {contrib => tools}/coccinelle/array.cocci          |  0\n>  {contrib => tools}/coccinelle/commit.cocci         |  0\n>  .../coccinelle/config_fn_ctx.pending.cocci         |  0\n>  {contrib => tools}/coccinelle/equals-null.cocci    |  0\n>  {contrib => tools}/coccinelle/flex_alloc.cocci     |  0\n>  {contrib => tools}/coccinelle/free.cocci           |  0\n>  .../coccinelle/git_config_number.cocci             |  0\n>  {contrib => tools}/coccinelle/hashmap.cocci        |  0\n>  .../coccinelle/index-compatibility.cocci           |  0\n>  {contrib => tools}/coccinelle/meson.build          |  0\n>  {contrib => tools}/coccinelle/object_id.cocci      |  0\n>  {contrib => tools}/coccinelle/preincr.cocci        |  0\n>  {contrib => tools}/coccinelle/qsort.cocci          |  0\n>  {contrib => tools}/coccinelle/refs.cocci           |  0\n>  {contrib => tools}/coccinelle/spatchcache          |  6 +-\n>  {contrib => tools}/coccinelle/strbuf.cocci         |  0\n>  {contrib => tools}/coccinelle/swap.cocci           |  0\n>  {contrib => tools}/coccinelle/tests/free.c         |  0\n>  {contrib => tools}/coccinelle/tests/free.res       |  0\n>  {contrib => tools}/coccinelle/the_repository.cocci |  0\n>  {contrib => tools}/coccinelle/xcalloc.cocci        |  0\n>  {contrib => tools}/coccinelle/xopen.cocci          |  0\n>  .../coccinelle/xstrdup_or_null.cocci               |  0\n>  {contrib => tools}/coccinelle/xstrncmpz.cocci      |  0\n>  {contrib => tools}/coverage-diff.sh                |  0\n>  detect-compiler => tools/detect-compiler           |  0\n>  generate-cmdlist.sh => tools/generate-cmdlist.sh   |  0\n>  .../generate-configlist.sh                         |  0\n>  generate-hooklist.sh => tools/generate-hooklist.sh |  0\n>  generate-perl.sh => tools/generate-perl.sh         |  0\n>  generate-python.sh => tools/generate-python.sh     |  0\n>  generate-script.sh => tools/generate-script.sh     |  0\n>  tools/meson.build                                  |  1 +\n>  tools/precompiled.h                                |  1 +\n>  {contrib => tools}/update-unicode/.gitignore       |  0\n>  {contrib => tools}/update-unicode/README           |  0\n>  .../update-unicode/update_unicode.sh               |  0\n>  49 files changed, 123 insertions(+), 99 deletions(-)\n>\n>\n> ---\n> base-commit: af2c8a61818d773325ef2324dd135786a03ebca0\n> change-id: 20260304-b4-pks-build-infra-improvements-cc4012c5364e\n"},{"id":"538561","messageId":"abEaeC1kRsGyQYWy@pks.im","threadId":"65200","inReplyTo":"xmqqwlzjtufv.fsf@gitster.g","subject":"Re: [PATCH 0/8] Some build system improvements","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-11T07:32:08Z","receivedAt":"2026-03-11T07:32:13Z","isPatch":true,"body":"On Tue, Mar 10, 2026 at 11:23:32AM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > Patrick Steinhardt (8):\n> >       Introduce new \"tools/\" directory\n> >       contrib: move \"coccinelle/\" directory into \"tools/\"\n> \n> Even though \"make coccicheck\" may not care where the coccinelle\n> stuff lives, if this step changes the location of the resulting\n> coccinelle-generated patch in the tree, it will have fallouts to\n> developer workflows.  The blast radius may be limited, as those\n> other than Git developers will be hurt, though.\n> \n> I mention this to forewarn others early, but I do not have a strong\n> objection against this step; at least not yet, even though I may\n> change my mind if the fallout turns out to be greater than I\n> anticipated.\n\nYup, that's completely fair. Thanks!\n\nPatrick\n"},{"id":"538610","messageId":"a5d1ea70-12dd-461d-b5c5-a1127e017d01@gmail.com","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-7-ec75d0710d6a@pks.im","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-03-11T14:32:30Z","receivedAt":"2026-03-11T14:32:33Z","isPatch":true,"body":"On 10/03/2026 17:52, Patrick Steinhardt wrote:\n> In the next commit we're about to introduce a precompiled header for\n> \"git-compat-util.h\". The consequence of this change is that we'll\n> implicitly include that header for every compilation unit that uses the\n> precompiled headers.\n\nIs that a meson thing? I know it defines precompiled headers on a \nper-target basis but does it somehow force each source file to include \nthe precompiled header? Looking at the gcc documentation it seems like \nthe precompiled header is only included where the original header is \nincluded. Splitting out the sources that do not depend on \n\"git-compat-util.h\" does mean we get some additional parallelism while \nwe're precompiling the header which is probably a good thing.\n\nThanks\n\nPhillip\n\n> This is okay for our \"normal\" library sources and our builtins. But some\n> of our compatibility sources do not include the header on purpose, and\n> doing so would cause compileir errors.\n> \n> Prepare for this change by splitting out compatibility sources into\n> their static library. Like this we can selectively enable precompiled\n> headers for the library sources.\n> \n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>   meson.build | 79 +++++++++++++++++++++++++++++++++++--------------------------\n>   1 file changed, 45 insertions(+), 34 deletions(-)\n> \n> diff --git a/meson.build b/meson.build\n> index 604fe89d2d..cd00be1c23 100644\n> --- a/meson.build\n> +++ b/meson.build\n> @@ -271,6 +271,13 @@ version_gen_environment.set('GIT_VERSION', get_option('version'))\n>   \n>   compiler = meson.get_compiler('c')\n>   \n> +compat_sources = [\n> +  'compat/nonblock.c',\n> +  'compat/obstack.c',\n> +  'compat/open.c',\n> +  'compat/terminal.c',\n> +]\n> +\n>   libgit_sources = [\n>     'abspath.c',\n>     'add-interactive.c',\n> @@ -304,10 +311,6 @@ libgit_sources = [\n>     'commit.c',\n>     'common-exit.c',\n>     'common-init.c',\n> -  'compat/nonblock.c',\n> -  'compat/obstack.c',\n> -  'compat/open.c',\n> -  'compat/terminal.c',\n>     'compiler-tricks/not-constant.c',\n>     'config.c',\n>     'connect.c',\n> @@ -1163,7 +1166,7 @@ endif\n>   \n>   if not has_poll_h and not has_sys_poll_h\n>     libgit_c_args += '-DNO_POLL'\n> -  libgit_sources += 'compat/poll/poll.c'\n> +  compat_sources += 'compat/poll/poll.c'\n>     libgit_include_directories += 'compat/poll'\n>   endif\n>   \n> @@ -1179,7 +1182,7 @@ endif\n>   # implementation to threat things like drive prefixes specially.\n>   if host_machine.system() == 'windows' or not compiler.has_header('libgen.h')\n>     libgit_c_args += '-DNO_LIBGEN_H'\n> -  libgit_sources += 'compat/basename.c'\n> +  compat_sources += 'compat/basename.c'\n>   endif\n>   \n>   if compiler.has_header('paths.h')\n> @@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'\n>     foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']\n>       if not compiler.has_function(symbol, dependencies: networking_dependencies)\n>         libgit_c_args += '-DNO_' + symbol.to_upper()\n> -      libgit_sources += 'compat/' + symbol + '.c'\n> +      compat_sources += 'compat/' + symbol + '.c'\n>       endif\n>     endforeach\n>   endif\n> @@ -1251,18 +1254,18 @@ else\n>   endif\n>   \n>   if host_machine.system() == 'darwin'\n> -  libgit_sources += 'compat/precompose_utf8.c'\n> +  compat_sources += 'compat/precompose_utf8.c'\n>     libgit_c_args += '-DPRECOMPOSE_UNICODE'\n>     libgit_c_args += '-DPROTECT_HFS_DEFAULT'\n>   endif\n>   \n>   # Configure general compatibility wrappers.\n>   if host_machine.system() == 'cygwin'\n> -  libgit_sources += [\n> +  compat_sources += [\n>       'compat/win32/path-utils.c',\n>     ]\n>   elif host_machine.system() == 'windows'\n> -  libgit_sources += [\n> +  compat_sources += [\n>       'compat/winansi.c',\n>       'compat/win32/dirent.c',\n>       'compat/win32/flush.c',\n> @@ -1289,20 +1292,20 @@ elif host_machine.system() == 'windows'\n>     libgit_include_directories += 'compat/win32'\n>     if compiler.get_id() == 'msvc'\n>       libgit_include_directories += 'compat/vcbuild/include'\n> -    libgit_sources += 'compat/msvc.c'\n> +    compat_sources += 'compat/msvc.c'\n>     else\n> -    libgit_sources += 'compat/mingw.c'\n> +    compat_sources += 'compat/mingw.c'\n>     endif\n>   endif\n>   \n>   if host_machine.system() == 'linux'\n> -  libgit_sources += 'compat/linux/procinfo.c'\n> +  compat_sources += 'compat/linux/procinfo.c'\n>   elif host_machine.system() == 'windows'\n> -  libgit_sources += 'compat/win32/trace2_win32_process_info.c'\n> +  compat_sources += 'compat/win32/trace2_win32_process_info.c'\n>   elif host_machine.system() == 'darwin'\n> -  libgit_sources += 'compat/darwin/procinfo.c'\n> +  compat_sources += 'compat/darwin/procinfo.c'\n>   else\n> -  libgit_sources += 'compat/stub/procinfo.c'\n> +  compat_sources += 'compat/stub/procinfo.c'\n>   endif\n>   \n>   if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'\n> @@ -1315,13 +1318,13 @@ endif\n>   \n>   # Configure the simple-ipc subsystem required fro the fsmonitor.\n>   if host_machine.system() == 'windows'\n> -  libgit_sources += [\n> +  compat_sources += [\n>       'compat/simple-ipc/ipc-shared.c',\n>       'compat/simple-ipc/ipc-win32.c',\n>     ]\n>     libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'\n>   else\n> -  libgit_sources += [\n> +  compat_sources += [\n>       'compat/simple-ipc/ipc-shared.c',\n>       'compat/simple-ipc/ipc-unix-socket.c',\n>     ]\n> @@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''\n>     libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND'\n>     libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'\n>   \n> -  libgit_sources += [\n> +  compat_sources += [\n>       'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',\n>       'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',\n>       'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',\n> @@ -1355,7 +1358,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').allo\n>   \n>     if compiler.get_define('REG_ENHANCED', prefix: '#include <regex.h>') != ''\n>       libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'\n> -    libgit_sources += 'compat/regcomp_enhanced.c'\n> +    compat_sources += 'compat/regcomp_enhanced.c'\n>     endif\n>   elif not get_option('regex').enabled()\n>     libgit_c_args += [\n> @@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()\n>       '-DNO_MBSUPPORT',\n>     ]\n>     build_options_config.set('NO_REGEX', '1')\n> -  libgit_sources += 'compat/regex/regex.c'\n> +  compat_sources += 'compat/regex/regex.c'\n>     libgit_include_directories += 'compat/regex'\n>   else\n>       error('Native regex support requested but not found')\n> @@ -1428,7 +1431,7 @@ else\n>   \n>     if get_option('b_sanitize').contains('address')\n>       libgit_c_args += '-DNO_MMAP'\n> -    libgit_sources += 'compat/mmap.c'\n> +    compat_sources += 'compat/mmap.c'\n>     else\n>       checkfuncs += { 'mmap': ['mmap.c'] }\n>     endif\n> @@ -1438,7 +1441,7 @@ foreach func, impls : checkfuncs\n>     if not compiler.has_function(func)\n>       libgit_c_args += '-DNO_' + func.to_upper()\n>       foreach impl : impls\n> -      libgit_sources += 'compat/' + impl\n> +      compat_sources += 'compat/' + impl\n>       endforeach\n>     endif\n>   endforeach\n> @@ -1449,13 +1452,13 @@ endif\n>   \n>   if not compiler.has_function('strdup')\n>     libgit_c_args += '-DOVERRIDE_STRDUP'\n> -  libgit_sources += 'compat/strdup.c'\n> +  compat_sources += 'compat/strdup.c'\n>   endif\n>   \n>   if not compiler.has_function('qsort')\n>     libgit_c_args += '-DINTERNAL_QSORT'\n>   endif\n> -libgit_sources += 'compat/qsort_s.c'\n> +compat_sources += 'compat/qsort_s.c'\n>   \n>   if compiler.has_function('getdelim')\n>     libgit_c_args += '-DHAVE_GETDELIM'\n> @@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and compiler.run('''\n>     }\n>   ''', name: 'fread reads directories').returncode() == 0\n>     libgit_c_args += '-DFREAD_READS_DIRECTORIES'\n> -  libgit_sources += 'compat/fopen.c'\n> +  compat_sources += 'compat/fopen.c'\n>   endif\n>   \n>   if not meson.is_cross_build() and fs.exists('/dev/tty')\n> @@ -1745,14 +1748,22 @@ else\n>   endif\n>   \n>   libgit = declare_dependency(\n> -  link_with: static_library('git',\n> -    sources: libgit_sources,\n> -    c_args: libgit_c_args + [\n> -      '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n> -    ],\n> -    dependencies: libgit_dependencies,\n> -    include_directories: libgit_include_directories,\n> -  ),\n> +  link_with: [\n> +    static_library('compat',\n> +      sources: compat_sources,\n> +      c_args: libgit_c_args,\n> +      dependencies: libgit_dependencies,\n> +      include_directories: libgit_include_directories,\n> +    ),\n> +    static_library('git',\n> +      sources: libgit_sources,\n> +      c_args: libgit_c_args + [\n> +        '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n> +      ],\n> +      dependencies: libgit_dependencies,\n> +      include_directories: libgit_include_directories,\n> +    ),\n> +  ],\n>     compile_args: libgit_c_args,\n>     dependencies: libgit_dependencies,\n>     include_directories: libgit_include_directories,\n> \n\n"},{"id":"538611","messageId":"040296b2-9a69-4603-9a2a-2001c98220b7@gmail.com","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-8-ec75d0710d6a@pks.im","subject":"Re: [PATCH 8/8] meson: precompile \"git-compat-util.h\"","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-03-11T14:32:36Z","receivedAt":"2026-03-11T14:32:39Z","isPatch":true,"body":"On 10/03/2026 17:52, Patrick Steinhardt wrote:\n> Every compilation unit in Git is expected to include \"git-compat-util.h\"\n> first, either directly or indirectly via \"builtin.h\". This header papers\n> over differences between platforms so that we can expect the typical\n> POSIX functions to exist. Furthermore, it provides functionality that we\n> end up using everywhere.\n> \n> This header is thus quite heavy as a consequence. Preprocessing it as a\n> standalone unit via `clang -E git-compat-util.h` yields over 23,000\n> lines of code overall. Naturally, it takes quite some time to compile\n> all of this.\n> \n> Luckily, this is exactly the kind of use case that precompiled headers\n> aim to solve: instead of recompiling it every single time, we compile it\n> once and then link the result into the executable. If include guards are\n> set up properly it means that the file won't need to be reprocessed.\n> \n> Set up such a precompiled header for \"git-compat-util.h\" and wire it up\n> via Meson. This leads to a significant speedup when performing full\n> builds:\n> \n>    Benchmark 1: ninja (rev = HEAD~)\n>    Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n>    Range (min … max):   14.195 s … 14.633 s    10 runs\n> \n>    Benchmark 2: ninja (rev = HEAD)\n>      Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n>      Range (min … max):   10.030 s … 10.433 s    10 runs\n> \n>    Summary\n>      ninja (rev = HEAD) ran\n>        1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n\nThis is a nice speedup for a full build. I'm not sure about dumping the \nprecompiled header in tools/ though, it seems like an odd location for a \nheader file. It is a requirement of meson that the source for the \nprecompiled header lives in a separate directory to the rest of the \nsources but it might be better to adopt the suggestion in the \ndocumentation of a \"pch\" (or maybe \"precompiled\"?) directory rather than \nmixing it in with our build scripts.\n\nThanks\n\nPhillip\n\n\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>   meson.build         | 2 ++\n>   tools/precompiled.h | 1 +\n>   2 files changed, 3 insertions(+)\n> \n> diff --git a/meson.build b/meson.build\n> index cd00be1c23..4b3fd47061 100644\n> --- a/meson.build\n> +++ b/meson.build\n> @@ -1760,6 +1760,7 @@ libgit = declare_dependency(\n>         c_args: libgit_c_args + [\n>           '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n>         ],\n> +      c_pch: [ 'tools/precompiled.h' ],\n>         dependencies: libgit_dependencies,\n>         include_directories: libgit_include_directories,\n>       ),\n> @@ -1820,6 +1821,7 @@ test_dependencies = [ ]\n>   \n>   git_builtin = executable('git',\n>     sources: builtin_sources + 'git.c',\n> +  c_pch: [ 'tools/precompiled.h' ],\n>     dependencies: [libgit_commonmain],\n>     install: true,\n>     install_dir: git_exec_path,\n> diff --git a/tools/precompiled.h b/tools/precompiled.h\n> new file mode 100644\n> index 0000000000..b2bec0d2b4\n> --- /dev/null\n> +++ b/tools/precompiled.h\n> @@ -0,0 +1 @@\n> +#include \"git-compat-util.h\"\n> \n\n"},{"id":"538612","messageId":"debb89c9-2fab-4922-af1a-6048094baf9f@gmail.com","threadId":"65200","inReplyTo":"a5d1ea70-12dd-461d-b5c5-a1127e017d01@gmail.com","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-03-11T14:56:24Z","receivedAt":"2026-03-11T14:56:28Z","isPatch":true,"body":"On 11/03/2026 14:32, Phillip Wood wrote:\n> On 10/03/2026 17:52, Patrick Steinhardt wrote:\n>> In the next commit we're about to introduce a precompiled header for\n>> \"git-compat-util.h\". The consequence of this change is that we'll\n>> implicitly include that header for every compilation unit that uses the\n>> precompiled headers.\n> \n> Is that a meson thing? I know it defines precompiled headers on a per- \n> target basis but does it somehow force each source file to include the \n> precompiled header? Looking at the gcc documentation it seems like the \n> precompiled header is only included where the original header is \n> included.\n\nAnswering my own question the precompiled header is included via \n\"-include\" on the commandline. This is necessary in the general case \nbecause a precompiled header cannot be used once the first C token is seen.\n\nAs an aside in git we could probably get away without using \"-include\" \nbecause if we include \"git-compat-util.h\" it is always the first thing \nwe do, or we inculde another file like \"builtin.h\" which immediately \nincludes \"git-compat-util.h\" and so it is included before the first C \ntoken is seen. However meson cannot rely on that.\n\nI notice the reftable sources don't seem to include \"git-compat-util.h\", \ndo they need special handling here as well?\n\nThanks\n\nPhillip\n\n> Splitting out the sources that do not depend on \"git-compat- \n> util.h\" does mean we get some additional parallelism while we're \n> precompiling the header which is probably a good thing.\n> \n> Thanks\n> \n> Phillip\n> \n>> This is okay for our \"normal\" library sources and our builtins. But some\n>> of our compatibility sources do not include the header on purpose, and\n>> doing so would cause compileir errors.\n>>\n>> Prepare for this change by splitting out compatibility sources into\n>> their static library. Like this we can selectively enable precompiled\n>> headers for the library sources.\n>>\n>> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n>> ---\n>>   meson.build | 79 ++++++++++++++++++++++++++++++++++ \n>> +--------------------------\n>>   1 file changed, 45 insertions(+), 34 deletions(-)\n>>\n>> diff --git a/meson.build b/meson.build\n>> index 604fe89d2d..cd00be1c23 100644\n>> --- a/meson.build\n>> +++ b/meson.build\n>> @@ -271,6 +271,13 @@ version_gen_environment.set('GIT_VERSION', \n>> get_option('version'))\n>>   compiler = meson.get_compiler('c')\n>> +compat_sources = [\n>> +  'compat/nonblock.c',\n>> +  'compat/obstack.c',\n>> +  'compat/open.c',\n>> +  'compat/terminal.c',\n>> +]\n>> +\n>>   libgit_sources = [\n>>     'abspath.c',\n>>     'add-interactive.c',\n>> @@ -304,10 +311,6 @@ libgit_sources = [\n>>     'commit.c',\n>>     'common-exit.c',\n>>     'common-init.c',\n>> -  'compat/nonblock.c',\n>> -  'compat/obstack.c',\n>> -  'compat/open.c',\n>> -  'compat/terminal.c',\n>>     'compiler-tricks/not-constant.c',\n>>     'config.c',\n>>     'connect.c',\n>> @@ -1163,7 +1166,7 @@ endif\n>>   if not has_poll_h and not has_sys_poll_h\n>>     libgit_c_args += '-DNO_POLL'\n>> -  libgit_sources += 'compat/poll/poll.c'\n>> +  compat_sources += 'compat/poll/poll.c'\n>>     libgit_include_directories += 'compat/poll'\n>>   endif\n>> @@ -1179,7 +1182,7 @@ endif\n>>   # implementation to threat things like drive prefixes specially.\n>>   if host_machine.system() == 'windows' or not \n>> compiler.has_header('libgen.h')\n>>     libgit_c_args += '-DNO_LIBGEN_H'\n>> -  libgit_sources += 'compat/basename.c'\n>> +  compat_sources += 'compat/basename.c'\n>>   endif\n>>   if compiler.has_header('paths.h')\n>> @@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'\n>>     foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']\n>>       if not compiler.has_function(symbol, dependencies: \n>> networking_dependencies)\n>>         libgit_c_args += '-DNO_' + symbol.to_upper()\n>> -      libgit_sources += 'compat/' + symbol + '.c'\n>> +      compat_sources += 'compat/' + symbol + '.c'\n>>       endif\n>>     endforeach\n>>   endif\n>> @@ -1251,18 +1254,18 @@ else\n>>   endif\n>>   if host_machine.system() == 'darwin'\n>> -  libgit_sources += 'compat/precompose_utf8.c'\n>> +  compat_sources += 'compat/precompose_utf8.c'\n>>     libgit_c_args += '-DPRECOMPOSE_UNICODE'\n>>     libgit_c_args += '-DPROTECT_HFS_DEFAULT'\n>>   endif\n>>   # Configure general compatibility wrappers.\n>>   if host_machine.system() == 'cygwin'\n>> -  libgit_sources += [\n>> +  compat_sources += [\n>>       'compat/win32/path-utils.c',\n>>     ]\n>>   elif host_machine.system() == 'windows'\n>> -  libgit_sources += [\n>> +  compat_sources += [\n>>       'compat/winansi.c',\n>>       'compat/win32/dirent.c',\n>>       'compat/win32/flush.c',\n>> @@ -1289,20 +1292,20 @@ elif host_machine.system() == 'windows'\n>>     libgit_include_directories += 'compat/win32'\n>>     if compiler.get_id() == 'msvc'\n>>       libgit_include_directories += 'compat/vcbuild/include'\n>> -    libgit_sources += 'compat/msvc.c'\n>> +    compat_sources += 'compat/msvc.c'\n>>     else\n>> -    libgit_sources += 'compat/mingw.c'\n>> +    compat_sources += 'compat/mingw.c'\n>>     endif\n>>   endif\n>>   if host_machine.system() == 'linux'\n>> -  libgit_sources += 'compat/linux/procinfo.c'\n>> +  compat_sources += 'compat/linux/procinfo.c'\n>>   elif host_machine.system() == 'windows'\n>> -  libgit_sources += 'compat/win32/trace2_win32_process_info.c'\n>> +  compat_sources += 'compat/win32/trace2_win32_process_info.c'\n>>   elif host_machine.system() == 'darwin'\n>> -  libgit_sources += 'compat/darwin/procinfo.c'\n>> +  compat_sources += 'compat/darwin/procinfo.c'\n>>   else\n>> -  libgit_sources += 'compat/stub/procinfo.c'\n>> +  compat_sources += 'compat/stub/procinfo.c'\n>>   endif\n>>   if host_machine.system() == 'cygwin' or host_machine.system() == \n>> 'windows'\n>> @@ -1315,13 +1318,13 @@ endif\n>>   # Configure the simple-ipc subsystem required fro the fsmonitor.\n>>   if host_machine.system() == 'windows'\n>> -  libgit_sources += [\n>> +  compat_sources += [\n>>       'compat/simple-ipc/ipc-shared.c',\n>>       'compat/simple-ipc/ipc-win32.c',\n>>     ]\n>>     libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'\n>>   else\n>> -  libgit_sources += [\n>> +  compat_sources += [\n>>       'compat/simple-ipc/ipc-shared.c',\n>>       'compat/simple-ipc/ipc-unix-socket.c',\n>>     ]\n>> @@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''\n>>     libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND'\n>>     libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'\n>> -  libgit_sources += [\n>> +  compat_sources += [\n>>       'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',\n>>       'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',\n>>       'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',\n>> @@ -1355,7 +1358,7 @@ if not \n>> get_option('b_sanitize').contains('address') and get_option('regex').allo\n>>     if compiler.get_define('REG_ENHANCED', prefix: '#include \n>> <regex.h>') != ''\n>>       libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'\n>> -    libgit_sources += 'compat/regcomp_enhanced.c'\n>> +    compat_sources += 'compat/regcomp_enhanced.c'\n>>     endif\n>>   elif not get_option('regex').enabled()\n>>     libgit_c_args += [\n>> @@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()\n>>       '-DNO_MBSUPPORT',\n>>     ]\n>>     build_options_config.set('NO_REGEX', '1')\n>> -  libgit_sources += 'compat/regex/regex.c'\n>> +  compat_sources += 'compat/regex/regex.c'\n>>     libgit_include_directories += 'compat/regex'\n>>   else\n>>       error('Native regex support requested but not found')\n>> @@ -1428,7 +1431,7 @@ else\n>>     if get_option('b_sanitize').contains('address')\n>>       libgit_c_args += '-DNO_MMAP'\n>> -    libgit_sources += 'compat/mmap.c'\n>> +    compat_sources += 'compat/mmap.c'\n>>     else\n>>       checkfuncs += { 'mmap': ['mmap.c'] }\n>>     endif\n>> @@ -1438,7 +1441,7 @@ foreach func, impls : checkfuncs\n>>     if not compiler.has_function(func)\n>>       libgit_c_args += '-DNO_' + func.to_upper()\n>>       foreach impl : impls\n>> -      libgit_sources += 'compat/' + impl\n>> +      compat_sources += 'compat/' + impl\n>>       endforeach\n>>     endif\n>>   endforeach\n>> @@ -1449,13 +1452,13 @@ endif\n>>   if not compiler.has_function('strdup')\n>>     libgit_c_args += '-DOVERRIDE_STRDUP'\n>> -  libgit_sources += 'compat/strdup.c'\n>> +  compat_sources += 'compat/strdup.c'\n>>   endif\n>>   if not compiler.has_function('qsort')\n>>     libgit_c_args += '-DINTERNAL_QSORT'\n>>   endif\n>> -libgit_sources += 'compat/qsort_s.c'\n>> +compat_sources += 'compat/qsort_s.c'\n>>   if compiler.has_function('getdelim')\n>>     libgit_c_args += '-DHAVE_GETDELIM'\n>> @@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and \n>> compiler.run('''\n>>     }\n>>   ''', name: 'fread reads directories').returncode() == 0\n>>     libgit_c_args += '-DFREAD_READS_DIRECTORIES'\n>> -  libgit_sources += 'compat/fopen.c'\n>> +  compat_sources += 'compat/fopen.c'\n>>   endif\n>>   if not meson.is_cross_build() and fs.exists('/dev/tty')\n>> @@ -1745,14 +1748,22 @@ else\n>>   endif\n>>   libgit = declare_dependency(\n>> -  link_with: static_library('git',\n>> -    sources: libgit_sources,\n>> -    c_args: libgit_c_args + [\n>> -      '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n>> -    ],\n>> -    dependencies: libgit_dependencies,\n>> -    include_directories: libgit_include_directories,\n>> -  ),\n>> +  link_with: [\n>> +    static_library('compat',\n>> +      sources: compat_sources,\n>> +      c_args: libgit_c_args,\n>> +      dependencies: libgit_dependencies,\n>> +      include_directories: libgit_include_directories,\n>> +    ),\n>> +    static_library('git',\n>> +      sources: libgit_sources,\n>> +      c_args: libgit_c_args + [\n>> +        '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n>> +      ],\n>> +      dependencies: libgit_dependencies,\n>> +      include_directories: libgit_include_directories,\n>> +    ),\n>> +  ],\n>>     compile_args: libgit_c_args,\n>>     dependencies: libgit_dependencies,\n>>     include_directories: libgit_include_directories,\n>>\n> \n> \n\n"},{"id":"538700","messageId":"abH6dayn5tJBMY9p@szeder.dev","threadId":"65200","inReplyTo":"debb89c9-2fab-4922-af1a-6048094baf9f@gmail.com","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2026-03-11T23:27:49Z","receivedAt":"2026-03-11T23:28:02Z","isPatch":true,"body":"On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:\n> On 11/03/2026 14:32, Phillip Wood wrote:\n> > On 10/03/2026 17:52, Patrick Steinhardt wrote:\n> > > In the next commit we're about to introduce a precompiled header for\n> > > \"git-compat-util.h\". The consequence of this change is that we'll\n> > > implicitly include that header for every compilation unit that uses the\n> > > precompiled headers.\n> > \n> > Is that a meson thing? I know it defines precompiled headers on a per-\n> > target basis but does it somehow force each source file to include the\n> > precompiled header? Looking at the gcc documentation it seems like the\n> > precompiled header is only included where the original header is\n> > included.\n> \n> Answering my own question the precompiled header is included via \"-include\"\n> on the commandline. This is necessary in the general case because a\n> precompiled header cannot be used once the first C token is seen.\n> \n> As an aside in git we could probably get away without using \"-include\"\n> because if we include \"git-compat-util.h\" it is always the first thing we\n> do, or we inculde another file like \"builtin.h\" which immediately includes\n> \"git-compat-util.h\" and so it is included before the first C token is seen.\n\nI couldn't find this in the GCC docs, but Make's documentation states\nthat \"you cannot include a precompiled header from inside another\nheader.\" [1]\n\nThe strace of compiling a 'builtin/*.c' source file seems to confirm\nit, the compiler (gcc-12) does look for 'builtin.h.gch', but doesn't\nlook for 'git-compat-util.h.gch':\n\n  592662 newfstatat(AT_FDCWD, \"builtin/builtin.h.gch\", 0x7fff2066e610, 0) = -1 ENOENT (No such file or directory)\n  592662 openat(AT_FDCWD, \"builtin/builtin.h\", O_RDONLY|O_NOCTTY) = -1 ENOENT (No such file or directory)\n  592662 newfstatat(AT_FDCWD, \"./builtin.h.gch\", 0x7fff2066e610, 0) = -1 ENOENT (No such file or directory)\n  592662 openat(AT_FDCWD, \"./builtin.h\", O_RDONLY|O_NOCTTY) = 4\n  592662 newfstatat(4, \"\", {st_mode=S_IFREG|0664, st_size=17968, ...}, AT_EMPTY_PATH) = 0\n  592662 read(4, \"#ifndef BUILTIN_H\\n#define BUILTI\"..., 17968) = 17968\n  592662 close(4)                         = 0\n  592662 openat(AT_FDCWD, \"./git-compat-util.h\", O_RDONLY|O_NOCTTY) = 4\n\n\n[1] Second bullet point at:\n    https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n\n"},{"id":"538718","messageId":"abJbf3m-EpYmHiYG@pks.im","threadId":"65200","inReplyTo":"040296b2-9a69-4603-9a2a-2001c98220b7@gmail.com","subject":"Re: [PATCH 8/8] meson: precompile \"git-compat-util.h\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-12T06:21:51Z","receivedAt":"2026-03-12T06:21:58Z","isPatch":true,"body":"On Wed, Mar 11, 2026 at 02:32:36PM +0000, Phillip Wood wrote:\n> On 10/03/2026 17:52, Patrick Steinhardt wrote:\n> > Every compilation unit in Git is expected to include \"git-compat-util.h\"\n> > first, either directly or indirectly via \"builtin.h\". This header papers\n> > over differences between platforms so that we can expect the typical\n> > POSIX functions to exist. Furthermore, it provides functionality that we\n> > end up using everywhere.\n> > \n> > This header is thus quite heavy as a consequence. Preprocessing it as a\n> > standalone unit via `clang -E git-compat-util.h` yields over 23,000\n> > lines of code overall. Naturally, it takes quite some time to compile\n> > all of this.\n> > \n> > Luckily, this is exactly the kind of use case that precompiled headers\n> > aim to solve: instead of recompiling it every single time, we compile it\n> > once and then link the result into the executable. If include guards are\n> > set up properly it means that the file won't need to be reprocessed.\n> > \n> > Set up such a precompiled header for \"git-compat-util.h\" and wire it up\n> > via Meson. This leads to a significant speedup when performing full\n> > builds:\n> > \n> >    Benchmark 1: ninja (rev = HEAD~)\n> >    Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n> >    Range (min … max):   14.195 s … 14.633 s    10 runs\n> > \n> >    Benchmark 2: ninja (rev = HEAD)\n> >      Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n> >      Range (min … max):   10.030 s … 10.433 s    10 runs\n> > \n> >    Summary\n> >      ninja (rev = HEAD) ran\n> >        1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n> \n> This is a nice speedup for a full build. I'm not sure about dumping the\n> precompiled header in tools/ though, it seems like an odd location for a\n> header file. It is a requirement of meson that the source for the\n> precompiled header lives in a separate directory to the rest of the sources\n> but it might be better to adopt the suggestion in the documentation of a\n> \"pch\" (or maybe \"precompiled\"?) directory rather than mixing it in with our\n> build scripts.\n\nYeah, it's a bit on the odd side. The reason I decided on \"tools/\"\nthough is that it now contains our build infra and developer tooling, so\nit's an okayish fit. And I didn't feel like creating a directory for a\nsingle file, only.\n\nPatrick\n"},{"id":"538719","messageId":"abJbhQwc-X0T6S_B@pks.im","threadId":"65200","inReplyTo":"abH6dayn5tJBMY9p@szeder.dev","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-12T06:21:57Z","receivedAt":"2026-03-12T06:22:02Z","isPatch":true,"body":"On Thu, Mar 12, 2026 at 12:27:49AM +0100, SZEDER Gábor wrote:\n> On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:\n> > On 11/03/2026 14:32, Phillip Wood wrote:\n> > > On 10/03/2026 17:52, Patrick Steinhardt wrote:\n> > > > In the next commit we're about to introduce a precompiled header for\n> > > > \"git-compat-util.h\". The consequence of this change is that we'll\n> > > > implicitly include that header for every compilation unit that uses the\n> > > > precompiled headers.\n> > > \n> > > Is that a meson thing? I know it defines precompiled headers on a per-\n> > > target basis but does it somehow force each source file to include the\n> > > precompiled header? Looking at the gcc documentation it seems like the\n> > > precompiled header is only included where the original header is\n> > > included.\n> > \n> > Answering my own question the precompiled header is included via \"-include\"\n> > on the commandline. This is necessary in the general case because a\n> > precompiled header cannot be used once the first C token is seen.\n> > \n> > As an aside in git we could probably get away without using \"-include\"\n> > because if we include \"git-compat-util.h\" it is always the first thing we\n> > do, or we inculde another file like \"builtin.h\" which immediately includes\n> > \"git-compat-util.h\" and so it is included before the first C token is seen.\n> \n> I couldn't find this in the GCC docs, but Make's documentation states\n> that \"you cannot include a precompiled header from inside another\n> header.\" [1]\n\nI think you must have confused something, because the link _does_ point\nto GCC's documentation, which does contain the quote.\n\nBut yes, overall there can only be one precompiled header, and it cannot\nbe used after the first token indeed. The use of \"-include\" is also\nexplicitly noted for \"projects not designed with precompiled headers in\nmind\", which fits Git. After all, we still have the ability to compile\nwithout precompiled headers, and I don't expect that to go away.\n\nPatrick\n\n> [1] Second bullet point at:\n>     https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n"},{"id":"538720","messageId":"abJbir7NocxmBuAo@pks.im","threadId":"65200","inReplyTo":"debb89c9-2fab-4922-af1a-6048094baf9f@gmail.com","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-12T06:22:02Z","receivedAt":"2026-03-12T06:22:07Z","isPatch":true,"body":"On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:\n> On 11/03/2026 14:32, Phillip Wood wrote:\n> > On 10/03/2026 17:52, Patrick Steinhardt wrote:\n> > > In the next commit we're about to introduce a precompiled header for\n> > > \"git-compat-util.h\". The consequence of this change is that we'll\n> > > implicitly include that header for every compilation unit that uses the\n> > > precompiled headers.\n> > \n> > Is that a meson thing? I know it defines precompiled headers on a per-\n> > target basis but does it somehow force each source file to include the\n> > precompiled header? Looking at the gcc documentation it seems like the\n> > precompiled header is only included where the original header is\n> > included.\n> \n> Answering my own question the precompiled header is included via \"-include\"\n> on the commandline. This is necessary in the general case because a\n> precompiled header cannot be used once the first C token is seen.\n> \n> As an aside in git we could probably get away without using \"-include\"\n> because if we include \"git-compat-util.h\" it is always the first thing we\n> do, or we inculde another file like \"builtin.h\" which immediately includes\n> \"git-compat-util.h\" and so it is included before the first C token is seen.\n> However meson cannot rely on that.\n> \n> I notice the reftable sources don't seem to include \"git-compat-util.h\", do\n> they need special handling here as well?\n\nI don't see a strong reason to do so. The reason why we need to be\ncareful with \"compat/\" is that we redefine a bunch of standard symbols\nthere, and that requires us to play a couple of tricks with preprocessor\nmacros (see e.g. \"compat/fopen.c\").\n\nWe don't do anything like that in the reftable library, and we already\ninclude \"compat/posix.h\". So in practice, it shouldn't have much of a\nconsueqence if we start to include \"git-compat-util.h\" implicitly over\nthere.\n\nBut if it ever does we can treat it the same as the compat library.\n\nPatrick\n"},{"id":"538871","messageId":"2fe87868-dff5-4b3a-95e3-d4b6376b59ed@gmail.com","threadId":"65200","inReplyTo":"abJbir7NocxmBuAo@pks.im","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-03-13T10:33:20Z","receivedAt":"2026-03-13T10:33:23Z","isPatch":true,"body":"On 12/03/2026 06:22, Patrick Steinhardt wrote:\n> On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:\n>>\n>> I notice the reftable sources don't seem to include \"git-compat-util.h\", do\n>> they need special handling here as well?\n> \n> I don't see a strong reason to do so. The reason why we need to be\n> careful with \"compat/\" is that we redefine a bunch of standard symbols\n> there, and that requires us to play a couple of tricks with preprocessor\n> macros (see e.g. \"compat/fopen.c\").\n> \n> We don't do anything like that in the reftable library, and we already\n> include \"compat/posix.h\". So in practice, it shouldn't have much of a\n> consueqence if we start to include \"git-compat-util.h\" implicitly over\n> there.\n\nIt does mean we're using different includes when compiling with \npre-compiled headers compared to compiling without them though which \nmeans contributors using per-compiled headers could accidentally depend \non functions that are not included when compiling without them. Wasn't \nthe idea behind \"compat/posix.h\" to avoid including \"git-compat-util.h\" \nin the reftable code? The commit message for 75a044f748f \n(git-compat-util.h: split out POSIX-emulating bits, 2025-02-18) says\n\n     This intermixing is a bit of a problem for the reftable library as\n     we don't want to recreate the POSIX-like interface there. But\n     neither do we want to pull in the Git-specific functionality, as it\n     is otherwise quite easy to start depending on the Git codebase\n     again.\n\nWe could precompile \"compat/posix.h\" for the code that does not want \n\"git-compat-util.h\"\n\nThanks\n\nPhillip\n\n> But if it ever does we can treat it the same as the compat library.\n> \n> Patrick\n> \n\n"},{"id":"538872","messageId":"3be0c711-5222-4faf-bd32-117230215490@gmail.com","threadId":"65200","inReplyTo":"abJbhQwc-X0T6S_B@pks.im","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-03-13T10:33:36Z","receivedAt":"2026-03-13T10:33:39Z","isPatch":true,"body":"On 12/03/2026 06:21, Patrick Steinhardt wrote:\n> On Thu, Mar 12, 2026 at 12:27:49AM +0100, SZEDER Gábor wrote:\n>> On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:\n>>> On 11/03/2026 14:32, Phillip Wood wrote:\n>>>> On 10/03/2026 17:52, Patrick Steinhardt wrote:\n>>>>> In the next commit we're about to introduce a precompiled header for\n>>>>> \"git-compat-util.h\". The consequence of this change is that we'll\n>>>>> implicitly include that header for every compilation unit that uses the\n>>>>> precompiled headers.\n>>>>\n>>>> Is that a meson thing? I know it defines precompiled headers on a per-\n>>>> target basis but does it somehow force each source file to include the\n>>>> precompiled header? Looking at the gcc documentation it seems like the\n>>>> precompiled header is only included where the original header is\n>>>> included.\n>>>\n>>> Answering my own question the precompiled header is included via \"-include\"\n>>> on the commandline. This is necessary in the general case because a\n>>> precompiled header cannot be used once the first C token is seen.\n>>>\n>>> As an aside in git we could probably get away without using \"-include\"\n>>> because if we include \"git-compat-util.h\" it is always the first thing we\n>>> do, or we inculde another file like \"builtin.h\" which immediately includes\n>>> \"git-compat-util.h\" and so it is included before the first C token is seen.\n>>\n>> I couldn't find this in the GCC docs, but Make's documentation states\n>> that \"you cannot include a precompiled header from inside another\n>> header.\" [1]\n> \n> I think you must have confused something, because the link _does_ point\n> to GCC's documentation, which does contain the quote.\n> \n> But yes, overall there can only be one precompiled header, and it cannot\n> be used after the first token indeed. The use of \"-include\" is also\n> explicitly noted for \"projects not designed with precompiled headers in\n> mind\", which fits Git. After all, we still have the ability to compile\n> without precompiled headers, and I don't expect that to go away.\n\nThanks to you both for the explanation. Should we explain this in the \ncommit message?\n\nThanks\n\nPhillip\n\n> Patrick\n> \n>> [1] Second bullet point at:\n>>      https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n\n"},{"id":"538939","messageId":"xmqq34232wwu.fsf@gitster.g","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"Re: [PATCH 0/8] Some build system improvements","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-13T22:21:21Z","receivedAt":"2026-03-13T22:21:24Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Hi,\n>\n> this patch series contains a small set of build system improvements:\n>\n>   - The first couple patches introduce a new \"tools/\" directory that\n>     contains items related to our build infrastructure and to our\n>     developer tooling. This finally follows up on my promise to do this\n>     back when I did the spring clean of \"contrib/\". [1]\n>\n>   - The last couple patches introduce precompiled headers into Meson for\n>     a nice compilation speedup of ~30%. It's \n>\n> The two topics are not really related with one another other than being\n> related to build systems. I decided to throw them in the same patch\n> series though so that I can introduce \"precompiled.h\" in \"tools/\".\n\nWe saw a handful of exchanges a few days ago, but are there any more\ncomments?  Is the topic ready to advance?\n\nThanks.\n"},{"id":"539076","messageId":"abe6pVAzMEY60rJ8@pks.im","threadId":"65200","inReplyTo":"2fe87868-dff5-4b3a-95e3-d4b6376b59ed@gmail.com","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T08:09:09Z","receivedAt":"2026-03-16T08:09:14Z","isPatch":true,"body":"On Fri, Mar 13, 2026 at 10:33:20AM +0000, Phillip Wood wrote:\n> On 12/03/2026 06:22, Patrick Steinhardt wrote:\n> > On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:\n> > > \n> > > I notice the reftable sources don't seem to include \"git-compat-util.h\", do\n> > > they need special handling here as well?\n> > \n> > I don't see a strong reason to do so. The reason why we need to be\n> > careful with \"compat/\" is that we redefine a bunch of standard symbols\n> > there, and that requires us to play a couple of tricks with preprocessor\n> > macros (see e.g. \"compat/fopen.c\").\n> > \n> > We don't do anything like that in the reftable library, and we already\n> > include \"compat/posix.h\". So in practice, it shouldn't have much of a\n> > consueqence if we start to include \"git-compat-util.h\" implicitly over\n> > there.\n> \n> It does mean we're using different includes when compiling with pre-compiled\n> headers compared to compiling without them though which means contributors\n> using per-compiled headers could accidentally depend on functions that are\n> not included when compiling without them. Wasn't the idea behind\n> \"compat/posix.h\" to avoid including \"git-compat-util.h\" in the reftable\n> code? The commit message for 75a044f748f (git-compat-util.h: split out\n> POSIX-emulating bits, 2025-02-18) says\n> \n>     This intermixing is a bit of a problem for the reftable library as\n>     we don't want to recreate the POSIX-like interface there. But\n>     neither do we want to pull in the Git-specific functionality, as it\n>     is otherwise quite easy to start depending on the Git codebase\n>     again.\n> \n> We could precompile \"compat/posix.h\" for the code that does not want\n> \"git-compat-util.h\"\n\nIn theory, yes. But in practice we'd notice this quite fast via other CI\njobs, and it feels a bit ugly to split out so many different libraries.\nSo I'd propose to keep this as-is for now, but iterate in case we notice\nthat it _does_ become a problem.\n\nDoes that work for you?\n\nThanks!\n\nPatrick\n"},{"id":"539077","messageId":"abe6rGICliivaEqb@pks.im","threadId":"65200","inReplyTo":"3be0c711-5222-4faf-bd32-117230215490@gmail.com","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T08:09:16Z","receivedAt":"2026-03-16T08:09:20Z","isPatch":true,"body":"On Fri, Mar 13, 2026 at 10:33:36AM +0000, Phillip Wood wrote:\n> On 12/03/2026 06:21, Patrick Steinhardt wrote:\n> > On Thu, Mar 12, 2026 at 12:27:49AM +0100, SZEDER Gábor wrote:\n> > > On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:\n> > > > On 11/03/2026 14:32, Phillip Wood wrote:\n> > > > > On 10/03/2026 17:52, Patrick Steinhardt wrote:\n> > > > > > In the next commit we're about to introduce a precompiled header for\n> > > > > > \"git-compat-util.h\". The consequence of this change is that we'll\n> > > > > > implicitly include that header for every compilation unit that uses the\n> > > > > > precompiled headers.\n> > > > > \n> > > > > Is that a meson thing? I know it defines precompiled headers on a per-\n> > > > > target basis but does it somehow force each source file to include the\n> > > > > precompiled header? Looking at the gcc documentation it seems like the\n> > > > > precompiled header is only included where the original header is\n> > > > > included.\n> > > > \n> > > > Answering my own question the precompiled header is included via \"-include\"\n> > > > on the commandline. This is necessary in the general case because a\n> > > > precompiled header cannot be used once the first C token is seen.\n> > > > \n> > > > As an aside in git we could probably get away without using \"-include\"\n> > > > because if we include \"git-compat-util.h\" it is always the first thing we\n> > > > do, or we inculde another file like \"builtin.h\" which immediately includes\n> > > > \"git-compat-util.h\" and so it is included before the first C token is seen.\n> > > \n> > > I couldn't find this in the GCC docs, but Make's documentation states\n> > > that \"you cannot include a precompiled header from inside another\n> > > header.\" [1]\n> > \n> > I think you must have confused something, because the link _does_ point\n> > to GCC's documentation, which does contain the quote.\n> > \n> > But yes, overall there can only be one precompiled header, and it cannot\n> > be used after the first token indeed. The use of \"-include\" is also\n> > explicitly noted for \"projects not designed with precompiled headers in\n> > mind\", which fits Git. After all, we still have the ability to compile\n> > without precompiled headers, and I don't expect that to go away.\n> \n> Thanks to you both for the explanation. Should we explain this in the commit\n> message?\n\nYeah, let's add a note for how this works internally. Let's also\nhighlight that we typically only have a single precompiled header by not\npassing the headers as an array.\n\nPatrick\n"},{"id":"539078","messageId":"abe6sUIlk7IuV42s@pks.im","threadId":"65200","inReplyTo":"xmqq34232wwu.fsf@gitster.g","subject":"Re: [PATCH 0/8] Some build system improvements","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T08:09:21Z","receivedAt":"2026-03-16T08:09:27Z","isPatch":true,"body":"On Fri, Mar 13, 2026 at 03:21:21PM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > Hi,\n> >\n> > this patch series contains a small set of build system improvements:\n> >\n> >   - The first couple patches introduce a new \"tools/\" directory that\n> >     contains items related to our build infrastructure and to our\n> >     developer tooling. This finally follows up on my promise to do this\n> >     back when I did the spring clean of \"contrib/\". [1]\n> >\n> >   - The last couple patches introduce precompiled headers into Meson for\n> >     a nice compilation speedup of ~30%. It's \n> >\n> > The two topics are not really related with one another other than being\n> > related to build systems. I decided to throw them in the same patch\n> > series though so that I can introduce \"precompiled.h\" in \"tools/\".\n> \n> We saw a handful of exchanges a few days ago, but are there any more\n> comments?  Is the topic ready to advance?\n\nI'll send a v2 with some minor adjustments in a bit. Thanks!\n\nPatrick\n"},{"id":"539082","messageId":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH v2 0/8] Some build system improvements","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:07:55Z","receivedAt":"2026-03-16T10:08:13Z","isPatch":true,"body":"Hi,\n\nthis patch series contains a small set of build system improvements:\n\n  - The first couple patches introduce a new \"tools/\" directory that\n    contains items related to our build infrastructure and to our\n    developer tooling. This finally follows up on my promise to do this\n    back when I did the spring clean of \"contrib/\". [1]\n\n  - The last couple patches introduce precompiled headers into Meson for\n    a nice compilation speedup of ~30%. It's \n\nThe two topics are not really related with one another other than being\nrelated to build systems. I decided to throw them in the same patch\nseries though so that I can introduce \"precompiled.h\" in \"tools/\".\n\nChanges in v2:\n  - Turn array of precompiled headers into a simple string.\n  - Point out in the commit message that the precompiled header is\n    included implicitly.\n  - Link to v1: https://lore.kernel.org/r/20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im\n\nThanks!\n\nPatrick\n\n[1]: https://lore.kernel.org/git/20250506-pks-contrib-spring-cleanup-v1-0-e6d5ddd79a72@pks.im/\n\n---\nPatrick Steinhardt (8):\n      Introduce new \"tools/\" directory\n      contrib: move \"coccinelle/\" directory into \"tools/\"\n      contrib: move \"coverage-diff.sh\" script into \"tools/\"\n      contrib: move \"update-unicode.sh\" script into \"tools/\"\n      builds: move build scripts into \"tools/\"\n      git-compat-util.h: move warning infra to prepare for PCHs\n      meson: compile compatibility sources separately\n      meson: precompile \"git-compat-util.h\"\n\n Makefile                                           | 76 ++++++++---------\n ci/run-static-analysis.sh                          |  2 +-\n config.mak.dev                                     |  2 +-\n contrib/buildsystems/CMakeLists.txt                | 18 ++--\n contrib/meson.build                                |  1 -\n contrib/subtree/meson.build                        |  2 +-\n git-compat-util.h                                  |  8 +-\n meson.build                                        | 96 +++++++++++++---------\n tools/README.md                                    |  7 ++\n check-builtins.sh => tools/check-builtins.sh       |  0\n {contrib => tools}/coccinelle/.gitignore           |  0\n {contrib => tools}/coccinelle/README               |  2 +-\n {contrib => tools}/coccinelle/array.cocci          |  0\n {contrib => tools}/coccinelle/commit.cocci         |  0\n .../coccinelle/config_fn_ctx.pending.cocci         |  0\n {contrib => tools}/coccinelle/equals-null.cocci    |  0\n {contrib => tools}/coccinelle/flex_alloc.cocci     |  0\n {contrib => tools}/coccinelle/free.cocci           |  0\n .../coccinelle/git_config_number.cocci             |  0\n {contrib => tools}/coccinelle/hashmap.cocci        |  0\n .../coccinelle/index-compatibility.cocci           |  0\n {contrib => tools}/coccinelle/meson.build          |  0\n {contrib => tools}/coccinelle/object_id.cocci      |  0\n {contrib => tools}/coccinelle/preincr.cocci        |  0\n {contrib => tools}/coccinelle/qsort.cocci          |  0\n {contrib => tools}/coccinelle/refs.cocci           |  0\n {contrib => tools}/coccinelle/spatchcache          |  6 +-\n {contrib => tools}/coccinelle/strbuf.cocci         |  0\n {contrib => tools}/coccinelle/swap.cocci           |  0\n {contrib => tools}/coccinelle/tests/free.c         |  0\n {contrib => tools}/coccinelle/tests/free.res       |  0\n {contrib => tools}/coccinelle/the_repository.cocci |  0\n {contrib => tools}/coccinelle/xcalloc.cocci        |  0\n {contrib => tools}/coccinelle/xopen.cocci          |  0\n .../coccinelle/xstrdup_or_null.cocci               |  0\n {contrib => tools}/coccinelle/xstrncmpz.cocci      |  0\n {contrib => tools}/coverage-diff.sh                |  0\n detect-compiler => tools/detect-compiler           |  0\n generate-cmdlist.sh => tools/generate-cmdlist.sh   |  0\n .../generate-configlist.sh                         |  0\n generate-hooklist.sh => tools/generate-hooklist.sh |  0\n generate-perl.sh => tools/generate-perl.sh         |  0\n generate-python.sh => tools/generate-python.sh     |  0\n generate-script.sh => tools/generate-script.sh     |  0\n tools/meson.build                                  |  1 +\n tools/precompiled.h                                |  1 +\n {contrib => tools}/update-unicode/.gitignore       |  0\n {contrib => tools}/update-unicode/README           |  0\n .../update-unicode/update_unicode.sh               |  0\n 49 files changed, 123 insertions(+), 99 deletions(-)\n\nRange-diff versus v1:\n\n1:  224e28be31 = 1:  9d09d2c39a Introduce new \"tools/\" directory\n2:  b217df51e5 = 2:  1b96bfe0f4 contrib: move \"coccinelle/\" directory into \"tools/\"\n3:  e371b6c221 = 3:  ed6e90bd36 contrib: move \"coverage-diff.sh\" script into \"tools/\"\n4:  3efeda9fa0 = 4:  48d8275ed1 contrib: move \"update-unicode.sh\" script into \"tools/\"\n5:  ee074c1396 = 5:  daafeb3462 builds: move build scripts into \"tools/\"\n6:  d30d4a3119 = 6:  947fc0f7b4 git-compat-util.h: move warning infra to prepare for PCHs\n7:  ca118197a9 = 7:  6a2fb99aae meson: compile compatibility sources separately\n8:  a865a8650b ! 8:  857b478896 meson: precompile \"git-compat-util.h\"\n    @@ Commit message\n         set up properly it means that the file won't need to be reprocessed.\n     \n         Set up such a precompiled header for \"git-compat-util.h\" and wire it up\n    -    via Meson. This leads to a significant speedup when performing full\n    -    builds:\n    +    via Meson. This causes Meson to implicitly include the precompiled\n    +    header in all compilation units. With GCC and Clang for example this is\n    +    done via the \"-include\" statement [1].\n    +\n    +    This leads to a significant speedup when performing full builds:\n     \n           Benchmark 1: ninja (rev = HEAD~)\n           Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n    @@ Commit message\n             ninja (rev = HEAD) ran\n               1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n     \n    +    [1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n    +\n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n      ## meson.build ##\n    @@ meson.build: libgit = declare_dependency(\n            c_args: libgit_c_args + [\n              '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n            ],\n    -+      c_pch: [ 'tools/precompiled.h' ],\n    ++      c_pch: 'tools/precompiled.h',\n            dependencies: libgit_dependencies,\n            include_directories: libgit_include_directories,\n          ),\n    @@ meson.build: test_dependencies = [ ]\n      \n      git_builtin = executable('git',\n        sources: builtin_sources + 'git.c',\n    -+  c_pch: [ 'tools/precompiled.h' ],\n    ++  c_pch: 'tools/precompiled.h',\n        dependencies: [libgit_commonmain],\n        install: true,\n        install_dir: git_exec_path,\n\n---\nbase-commit: af2c8a61818d773325ef2324dd135786a03ebca0\nchange-id: 20260304-b4-pks-build-infra-improvements-cc4012c5364e\n\n"},{"id":"539083","messageId":"20260316-b4-pks-build-infra-improvements-v2-1-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"[PATCH v2 1/8] Introduce new \"tools/\" directory","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:07:56Z","receivedAt":"2026-03-16T10:08:14Z","isPatch":true,"body":"According to its readme, the \"contrib/\" directory's main intent is to\ncollect stuff that is not an official part of Git, either because it is\ntoo specialized or because it is still considered experimental. The\nreality tells a bit of a different story though: while it _does_ contain\nsuch things, it also contains other things:\n\n  - Our credential helpers, which are being distributed by many\n    packagers nowadays and which can be considered \"stable\".\n\n  - A bunch of tooling that relates to our build and test\n    infrastructure.\n\nEspecially the second category is somewhat of a sore spot. You really\nwouldn't expect build-related tooling to be considered an optional part\nof Git. Quite the opposite.\n\nCreate a new top-level \"tools/\" directory to fix this discrepancy. This\ndirectory will contain all kind of tools that are related to our build\ninfrastructure and that Git developers are likely to use day to day.\n\nFor now, this directory doesn't contain anything yet except for a\nreadme and a Meson skeleton. This will change in subsequent commits.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile          | 2 ++\n meson.build       | 1 +\n tools/README.md   | 7 +++++++\n tools/meson.build | 0\n 4 files changed, 10 insertions(+)\n\ndiff --git a/Makefile b/Makefile\nindex f3264d0a37..c7cedbcd7c 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1066,11 +1066,13 @@ SOURCES_CMD = ( \\\n \t\t'*.sh' \\\n \t\t':!*[tp][0-9][0-9][0-9][0-9]*' \\\n \t\t':!contrib' \\\n+\t\t':!tools' \\\n \t\t2>/dev/null || \\\n \t$(FIND) . \\\n \t\t\\( -name .git -type d -prune \\) \\\n \t\t-o \\( -name '[tp][0-9][0-9][0-9][0-9]*' -prune \\) \\\n \t\t-o \\( -name contrib -type d -prune \\) \\\n+\t\t-o \\( -name tools -type d -prune \\) \\\n \t\t-o \\( -name build -type d -prune \\) \\\n \t\t-o \\( -name .build -type d -prune \\) \\\n \t\t-o \\( -name 'trash*' -type d -prune \\) \\\ndiff --git a/meson.build b/meson.build\nindex 4b536e0124..1d66b5181e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -2149,6 +2149,7 @@ else\n endif\n \n subdir('contrib')\n+subdir('tools')\n \n # Note that the target is intentionally configured after including the\n # 'contrib' directory, as some tool there also have their own manpages.\ndiff --git a/tools/README.md b/tools/README.md\nnew file mode 100644\nindex 0000000000..d732997136\n--- /dev/null\n+++ b/tools/README.md\n@@ -0,0 +1,7 @@\n+Developer Tooling\n+-----------------\n+\n+This directory is expected to contain all sorts of tooling that\n+relates to our build infrastructure. This includes scripts and\n+inputs required by our build systems, but also scripts that\n+developers are expected to run manually.\ndiff --git a/tools/meson.build b/tools/meson.build\nnew file mode 100644\nindex 0000000000..e69de29bb2\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539084","messageId":"20260316-b4-pks-build-infra-improvements-v2-2-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"[PATCH v2 2/8] contrib: move \"coccinelle/\" directory into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:07:57Z","receivedAt":"2026-03-16T10:08:16Z","isPatch":true,"body":"The Coccinelle tool is an ingrained part of our build infrastructure. It\nis executed by our CI to detect antipatterns and is used to detect\nmisuses of certain interfaces. It's presence in \"contrib/\" is thus\nrather misleading.\n\nPromote the configuration into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile                                           | 40 +++++++++++-----------\n ci/run-static-analysis.sh                          |  2 +-\n contrib/meson.build                                |  1 -\n {contrib => tools}/coccinelle/.gitignore           |  0\n {contrib => tools}/coccinelle/README               |  2 +-\n {contrib => tools}/coccinelle/array.cocci          |  0\n {contrib => tools}/coccinelle/commit.cocci         |  0\n .../coccinelle/config_fn_ctx.pending.cocci         |  0\n {contrib => tools}/coccinelle/equals-null.cocci    |  0\n {contrib => tools}/coccinelle/flex_alloc.cocci     |  0\n {contrib => tools}/coccinelle/free.cocci           |  0\n .../coccinelle/git_config_number.cocci             |  0\n {contrib => tools}/coccinelle/hashmap.cocci        |  0\n .../coccinelle/index-compatibility.cocci           |  0\n {contrib => tools}/coccinelle/meson.build          |  0\n {contrib => tools}/coccinelle/object_id.cocci      |  0\n {contrib => tools}/coccinelle/preincr.cocci        |  0\n {contrib => tools}/coccinelle/qsort.cocci          |  0\n {contrib => tools}/coccinelle/refs.cocci           |  0\n {contrib => tools}/coccinelle/spatchcache          |  6 ++--\n {contrib => tools}/coccinelle/strbuf.cocci         |  0\n {contrib => tools}/coccinelle/swap.cocci           |  0\n {contrib => tools}/coccinelle/tests/free.c         |  0\n {contrib => tools}/coccinelle/tests/free.res       |  0\n {contrib => tools}/coccinelle/the_repository.cocci |  0\n {contrib => tools}/coccinelle/xcalloc.cocci        |  0\n {contrib => tools}/coccinelle/xopen.cocci          |  0\n .../coccinelle/xstrdup_or_null.cocci               |  0\n {contrib => tools}/coccinelle/xstrncmpz.cocci      |  0\n tools/meson.build                                  |  1 +\n 30 files changed, 26 insertions(+), 26 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex c7cedbcd7c..8564b1be36 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1005,8 +1005,8 @@ SPATCH_TEST_FLAGS =\n # COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.\n SPATCH_USE_O_DEPENDENCIES = YesPlease\n \n-# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci\n-# files into a single contrib/cocci/ALL.cocci before running\n+# Set SPATCH_CONCAT_COCCI to concatenate the tools/coccinelle/*.cocci\n+# files into a single tools/coccinelle/ALL.cocci before running\n # \"coccicheck\".\n #\n # Pros:\n@@ -1025,7 +1025,7 @@ SPATCH_USE_O_DEPENDENCIES = YesPlease\n #   generate a specific patch, e.g. this will always use strbuf.cocci,\n #   not ALL.cocci:\n #\n-#\tmake contrib/coccinelle/strbuf.cocci.patch\n+#\tmake tools/coccinelle/strbuf.cocci.patch\n SPATCH_CONCAT_COCCI = YesPlease\n \n # Rebuild 'coccicheck' if $(SPATCH), its flags etc. change\n@@ -3457,15 +3457,15 @@ check:\n \t\texit 1; \\\n \tfi\n \n-COCCI_GEN_ALL = .build/contrib/coccinelle/ALL.cocci\n-COCCI_GLOB = $(wildcard contrib/coccinelle/*.cocci)\n+COCCI_GEN_ALL = .build/tools/coccinelle/ALL.cocci\n+COCCI_GLOB = $(wildcard tools/coccinelle/*.cocci)\n COCCI_RULES_TRACKED = $(COCCI_GLOB:%=.build/%)\n COCCI_RULES_TRACKED_NO_PENDING = $(filter-out %.pending.cocci,$(COCCI_RULES_TRACKED))\n COCCI_RULES =\n COCCI_RULES += $(COCCI_GEN_ALL)\n COCCI_RULES += $(COCCI_RULES_TRACKED)\n COCCI_NAMES =\n-COCCI_NAMES += $(COCCI_RULES:.build/contrib/coccinelle/%.cocci=%)\n+COCCI_NAMES += $(COCCI_RULES:.build/tools/coccinelle/%.cocci=%)\n \n COCCICHECK_PENDING = $(filter %.pending.cocci,$(COCCI_RULES))\n COCCICHECK = $(filter-out $(COCCICHECK_PENDING),$(COCCI_RULES))\n@@ -3480,20 +3480,20 @@ COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)\n # on $(MAKECMDGOALS) that match these $(COCCI_RULES)\n COCCI_RULES_GLOB =\n COCCI_RULES_GLOB += cocci%\n-COCCI_RULES_GLOB += .build/contrib/coccinelle/%\n+COCCI_RULES_GLOB += .build/tools/coccinelle/%\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES)\n COCCI_RULES_GLOB += $(COCCICHEC_PATCHES_PENDING)\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_INTREE)\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_PENDING_INTREE)\n COCCI_GOALS = $(filter $(COCCI_RULES_GLOB),$(MAKECMDGOALS))\n \n-COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)\n+COCCI_TEST_RES = $(wildcard tools/coccinelle/tests/*.res)\n \n $(COCCI_RULES_TRACKED): .build/% : %\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_CP)cp $< $@\n \n-.build/contrib/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)\n+.build/tools/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_GEN) >$@\n \n@@ -3507,12 +3507,12 @@ endif\n define cocci-rule\n \n ## Rule for .build/$(1).patch/$(2); Params:\n-# $(1) = e.g. \".build/contrib/coccinelle/free.cocci\"\n+# $(1) = e.g. \".build/tools/coccinelle/free.cocci\"\n # $(2) = e.g. \"grep.c\"\n # $(3) = e.g. \"grep.o\"\n-COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch\n+COCCI_$(1:.build/tools/coccinelle/%.cocci=%) += $(1).d/$(2).patch\n $(1).d/$(2).patch: GIT-SPATCH-DEFINES\n-$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)\n+$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/tools/coccinelle/FOUND_H_SOURCES)\n $(1).d/$(2).patch: $(1)\n $(1).d/$(2).patch: $(1).d/%.patch : %\n \t$$(call mkdir_p_parent_template)\n@@ -3538,13 +3538,13 @@ endif\n \n define spatch-rule\n \n-.build/contrib/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))\n+.build/tools/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))\n \t$$(QUIET_SPATCH_CAT)cat $$^ >$$@ && \\\n \tif test -s $$@; \\\n \tthen \\\n \t\techo '    ' SPATCH result: $$@; \\\n \tfi\n-contrib/coccinelle/$(1).cocci.patch: .build/contrib/coccinelle/$(1).cocci.patch\n+tools/coccinelle/$(1).cocci.patch: .build/tools/coccinelle/$(1).cocci.patch\n \t$$(QUIET_CP)cp $$< $$@\n \n endef\n@@ -3558,9 +3558,9 @@ $(COCCI_TEST_RES_GEN): GIT-SPATCH-DEFINES\n $(COCCI_TEST_RES_GEN): .build/%.res : %.c\n $(COCCI_TEST_RES_GEN): .build/%.res : %.res\n ifdef SPATCH_CONCAT_COCCI\n-$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : $(COCCI_GEN_ALL)\n+$(COCCI_TEST_RES_GEN): .build/tools/coccinelle/tests/%.res : $(COCCI_GEN_ALL)\n else\n-$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci\n+$(COCCI_TEST_RES_GEN): .build/tools/coccinelle/tests/%.res : tools/coccinelle/%.cocci\n endif\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_SPATCH_TEST)$(SPATCH) $(SPATCH_TEST_FLAGS) \\\n@@ -3576,14 +3576,14 @@ coccicheck-test: $(COCCI_TEST_RES_GEN)\n coccicheck: coccicheck-test\n \n ifdef SPATCH_CONCAT_COCCI\n-COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = contrib/coccinelle/ALL.cocci.patch\n+COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = tools/coccinelle/ALL.cocci.patch\n else\n COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = $(COCCICHECK_PATCHES_INTREE)\n endif\n coccicheck: $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES)\n \t! grep ^ $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES) /dev/null\n \n-# See contrib/coccinelle/README\n+# See tools/coccinelle/README\n coccicheck-pending: coccicheck-test\n coccicheck-pending: $(COCCICHECK_PATCHES_PENDING_INTREE)\n \n@@ -3857,8 +3857,8 @@ profile-clean:\n \n cocciclean:\n \t$(RM) GIT-SPATCH-DEFINES\n-\t$(RM) -r .build/contrib/coccinelle\n-\t$(RM) contrib/coccinelle/*.cocci.patch\n+\t$(RM) -r .build/tools/coccinelle\n+\t$(RM) tools/coccinelle/*.cocci.patch\n \n clean: profile-clean coverage-clean cocciclean\n \t$(RM) -r .build $(UNIT_TEST_BIN)\ndiff --git a/ci/run-static-analysis.sh b/ci/run-static-analysis.sh\nindex 9e9c72681d..ba67e80b4d 100755\n--- a/ci/run-static-analysis.sh\n+++ b/ci/run-static-analysis.sh\n@@ -10,7 +10,7 @@ make coccicheck\n set +x\n \n fail=\n-for cocci_patch in contrib/coccinelle/*.patch\n+for cocci_patch in tools/coccinelle/*.patch\n do\n \tif test -s \"$cocci_patch\"\n \tthen\ndiff --git a/contrib/meson.build b/contrib/meson.build\nindex a88c5dfe09..569c23ee76 100644\n--- a/contrib/meson.build\n+++ b/contrib/meson.build\n@@ -2,5 +2,4 @@ foreach feature : get_option('contrib')\n   subdir(feature)\n endforeach\n \n-subdir('coccinelle')\n subdir('credential')\ndiff --git a/contrib/coccinelle/.gitignore b/tools/coccinelle/.gitignore\nsimilarity index 100%\nrename from contrib/coccinelle/.gitignore\nrename to tools/coccinelle/.gitignore\ndiff --git a/contrib/coccinelle/README b/tools/coccinelle/README\nsimilarity index 98%\nrename from contrib/coccinelle/README\nrename to tools/coccinelle/README\nindex 055ad0e06a..fd0a543cc2 100644\n--- a/contrib/coccinelle/README\n+++ b/tools/coccinelle/README\n@@ -38,7 +38,7 @@ that might be useful to developers.\n    So to aid these large scale refactorings, semantic patches can be used.\n    However we do not want to store them in the same place as the checks for\n    bad patterns, as then automated builds would fail.\n-   That is why semantic patches 'contrib/coccinelle/*.pending.cocci'\n+   That is why semantic patches 'tools/coccinelle/*.pending.cocci'\n    are ignored for checks, and can be applied using 'make coccicheck-pending'.\n \n    This allows to expose plans of pending large scale refactorings without\ndiff --git a/contrib/coccinelle/array.cocci b/tools/coccinelle/array.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/array.cocci\nrename to tools/coccinelle/array.cocci\ndiff --git a/contrib/coccinelle/commit.cocci b/tools/coccinelle/commit.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/commit.cocci\nrename to tools/coccinelle/commit.cocci\ndiff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/tools/coccinelle/config_fn_ctx.pending.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/config_fn_ctx.pending.cocci\nrename to tools/coccinelle/config_fn_ctx.pending.cocci\ndiff --git a/contrib/coccinelle/equals-null.cocci b/tools/coccinelle/equals-null.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/equals-null.cocci\nrename to tools/coccinelle/equals-null.cocci\ndiff --git a/contrib/coccinelle/flex_alloc.cocci b/tools/coccinelle/flex_alloc.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/flex_alloc.cocci\nrename to tools/coccinelle/flex_alloc.cocci\ndiff --git a/contrib/coccinelle/free.cocci b/tools/coccinelle/free.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/free.cocci\nrename to tools/coccinelle/free.cocci\ndiff --git a/contrib/coccinelle/git_config_number.cocci b/tools/coccinelle/git_config_number.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/git_config_number.cocci\nrename to tools/coccinelle/git_config_number.cocci\ndiff --git a/contrib/coccinelle/hashmap.cocci b/tools/coccinelle/hashmap.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/hashmap.cocci\nrename to tools/coccinelle/hashmap.cocci\ndiff --git a/contrib/coccinelle/index-compatibility.cocci b/tools/coccinelle/index-compatibility.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/index-compatibility.cocci\nrename to tools/coccinelle/index-compatibility.cocci\ndiff --git a/contrib/coccinelle/meson.build b/tools/coccinelle/meson.build\nsimilarity index 100%\nrename from contrib/coccinelle/meson.build\nrename to tools/coccinelle/meson.build\ndiff --git a/contrib/coccinelle/object_id.cocci b/tools/coccinelle/object_id.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/object_id.cocci\nrename to tools/coccinelle/object_id.cocci\ndiff --git a/contrib/coccinelle/preincr.cocci b/tools/coccinelle/preincr.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/preincr.cocci\nrename to tools/coccinelle/preincr.cocci\ndiff --git a/contrib/coccinelle/qsort.cocci b/tools/coccinelle/qsort.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/qsort.cocci\nrename to tools/coccinelle/qsort.cocci\ndiff --git a/contrib/coccinelle/refs.cocci b/tools/coccinelle/refs.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/refs.cocci\nrename to tools/coccinelle/refs.cocci\ndiff --git a/contrib/coccinelle/spatchcache b/tools/coccinelle/spatchcache\nsimilarity index 97%\nrename from contrib/coccinelle/spatchcache\nrename to tools/coccinelle/spatchcache\nindex 29e9352d8a..efbcbc3827 100755\n--- a/contrib/coccinelle/spatchcache\n+++ b/tools/coccinelle/spatchcache\n@@ -30,7 +30,7 @@\n #\t   out of control.\n #\n # This along with the general incremental \"make\" support for\n-# \"contrib/coccinelle\" makes it viable to (re-)run coccicheck\n+# \"tools/coccinelle\" makes it viable to (re-)run coccicheck\n # e.g. when merging integration branches.\n #\n # Note that the \"--very-quiet\" flag is currently critical. The cache\n@@ -42,7 +42,7 @@\n # to change, so just supply \"--very-quiet\" for now.\n #\n # To use this, simply set SPATCH to\n-# contrib/coccinelle/spatchcache. Then optionally set:\n+# tools/coccinelle/spatchcache. Then optionally set:\n #\n #\t[spatchCache]\n #\t\t# Optional: path to a custom spatch\n@@ -65,7 +65,7 @@\n #\n #\tredis-cli FLUSHALL\n #\t<make && make coccicheck, as above>\n-#\tgrep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/contrib/coccinelle | sort | uniq -c\n+#\tgrep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/tools/coccinelle | sort | uniq -c\n #\t    600 CANTCACHE\n #\t   7365 MISS\n #\t   7365 SET\ndiff --git a/contrib/coccinelle/strbuf.cocci b/tools/coccinelle/strbuf.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/strbuf.cocci\nrename to tools/coccinelle/strbuf.cocci\ndiff --git a/contrib/coccinelle/swap.cocci b/tools/coccinelle/swap.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/swap.cocci\nrename to tools/coccinelle/swap.cocci\ndiff --git a/contrib/coccinelle/tests/free.c b/tools/coccinelle/tests/free.c\nsimilarity index 100%\nrename from contrib/coccinelle/tests/free.c\nrename to tools/coccinelle/tests/free.c\ndiff --git a/contrib/coccinelle/tests/free.res b/tools/coccinelle/tests/free.res\nsimilarity index 100%\nrename from contrib/coccinelle/tests/free.res\nrename to tools/coccinelle/tests/free.res\ndiff --git a/contrib/coccinelle/the_repository.cocci b/tools/coccinelle/the_repository.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/the_repository.cocci\nrename to tools/coccinelle/the_repository.cocci\ndiff --git a/contrib/coccinelle/xcalloc.cocci b/tools/coccinelle/xcalloc.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xcalloc.cocci\nrename to tools/coccinelle/xcalloc.cocci\ndiff --git a/contrib/coccinelle/xopen.cocci b/tools/coccinelle/xopen.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xopen.cocci\nrename to tools/coccinelle/xopen.cocci\ndiff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/tools/coccinelle/xstrdup_or_null.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xstrdup_or_null.cocci\nrename to tools/coccinelle/xstrdup_or_null.cocci\ndiff --git a/contrib/coccinelle/xstrncmpz.cocci b/tools/coccinelle/xstrncmpz.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xstrncmpz.cocci\nrename to tools/coccinelle/xstrncmpz.cocci\ndiff --git a/tools/meson.build b/tools/meson.build\nindex e69de29bb2..f731f74312 100644\n--- a/tools/meson.build\n+++ b/tools/meson.build\n@@ -0,0 +1 @@\n+subdir('coccinelle')\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539085","messageId":"20260316-b4-pks-build-infra-improvements-v2-3-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"[PATCH v2 3/8] contrib: move \"coverage-diff.sh\" script into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:07:58Z","receivedAt":"2026-03-16T10:08:19Z","isPatch":true,"body":"The \"coverage-diff.sh\" script can be used to get information about test\ncoverage fro the Git codebase. It is thus rather specific to our build\nand test infrastructure and part of the developer-facing tooling. The\nfact that this script is part of \"contrib/\" is thus rather misleading\nand a historic wart.\n\nPromote the tool into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n {contrib => tools}/coverage-diff.sh | 0\n 1 file changed, 0 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/coverage-diff.sh b/tools/coverage-diff.sh\nsimilarity index 100%\nrename from contrib/coverage-diff.sh\nrename to tools/coverage-diff.sh\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539086","messageId":"20260316-b4-pks-build-infra-improvements-v2-4-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"[PATCH v2 4/8] contrib: move \"update-unicode.sh\" script into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:07:59Z","receivedAt":"2026-03-16T10:08:21Z","isPatch":true,"body":"The \"update-unicode.sh\" script is used to update the unicode data\ncompiled into Git whenever a new version of the Unicode standard has\nbeen released. As such, it is a natural part of our developer-facing\ntooling, and its presence in \"contrib/\" is misleading.\n\nPromote the script into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n {contrib => tools}/update-unicode/.gitignore        | 0\n {contrib => tools}/update-unicode/README            | 0\n {contrib => tools}/update-unicode/update_unicode.sh | 0\n 3 files changed, 0 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/update-unicode/.gitignore b/tools/update-unicode/.gitignore\nsimilarity index 100%\nrename from contrib/update-unicode/.gitignore\nrename to tools/update-unicode/.gitignore\ndiff --git a/contrib/update-unicode/README b/tools/update-unicode/README\nsimilarity index 100%\nrename from contrib/update-unicode/README\nrename to tools/update-unicode/README\ndiff --git a/contrib/update-unicode/update_unicode.sh b/tools/update-unicode/update_unicode.sh\nsimilarity index 100%\nrename from contrib/update-unicode/update_unicode.sh\nrename to tools/update-unicode/update_unicode.sh\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539087","messageId":"20260316-b4-pks-build-infra-improvements-v2-5-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"[PATCH v2 5/8] builds: move build scripts into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:08:00Z","receivedAt":"2026-03-16T10:08:24Z","isPatch":true,"body":"We have a bunch of scripts used by our different build systems that are\nall located in the top-level directory. Now that we have introduced the\nnew \"tools/\" directory though we have a better home for them.\n\nMove the scripts into the \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile                                           | 34 +++++++++++-----------\n config.mak.dev                                     |  2 +-\n contrib/buildsystems/CMakeLists.txt                | 18 ++++++------\n contrib/subtree/meson.build                        |  2 +-\n meson.build                                        | 14 ++++-----\n check-builtins.sh => tools/check-builtins.sh       |  0\n detect-compiler => tools/detect-compiler           |  0\n generate-cmdlist.sh => tools/generate-cmdlist.sh   |  0\n .../generate-configlist.sh                         |  0\n generate-hooklist.sh => tools/generate-hooklist.sh |  0\n generate-perl.sh => tools/generate-perl.sh         |  0\n generate-python.sh => tools/generate-python.sh     |  0\n generate-script.sh => tools/generate-script.sh     |  0\n 13 files changed, 35 insertions(+), 35 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 8564b1be36..322f5940e3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2689,21 +2689,21 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n-config-list.h: generate-configlist.sh\n+config-list.h: tools/generate-configlist.sh\n \t@mkdir -p .depend\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh . $@ .depend/config-list.h.d\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-configlist.sh . $@ .depend/config-list.h.d\n \n -include .depend/config-list.h.d\n \n-command-list.h: generate-cmdlist.sh command-list.txt\n+command-list.h: tools/generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.adoc)\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh \\\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-cmdlist.sh \\\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\t. $@\n \n-hook-list.h: generate-hooklist.sh Documentation/githooks.adoc\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh . $@\n+hook-list.h: tools/generate-hooklist.sh Documentation/githooks.adoc\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-hooklist.sh . $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):\\\n \t$(localedir_SQ):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n@@ -2716,8 +2716,8 @@ GIT-SCRIPT-DEFINES: FORCE\n \t\techo \"$$FLAGS\" >$@; \\\n             fi\n \n-$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n-\t$(QUIET_GEN)./generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n+$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh tools/generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n+\t$(QUIET_GEN)./tools/generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n \tmv $@+ $@\n \n git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE\n@@ -2757,8 +2757,8 @@ endif\n \n PERL_DEFINES += $(gitexecdir) $(perllibdir) $(localedir)\n \n-$(SCRIPT_PERL_GEN): % : %.perl generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@+\" && \\\n+$(SCRIPT_PERL_GEN): % : %.perl tools/generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@+\" && \\\n \tmv $@+ $@\n \n PERL_DEFINES := $(subst $(space),:,$(PERL_DEFINES))\n@@ -2786,8 +2786,8 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile\n perllibdir:\n \t@echo '$(perllibdir_SQ)'\n \n-git-instaweb: git-instaweb.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n-\t$(QUIET_GEN)./generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n+git-instaweb: git-instaweb.sh tools/generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n+\t$(QUIET_GEN)./tools/generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n \tchmod +x $@+ && \\\n \tmv $@+ $@\n else # NO_PERL\n@@ -2804,9 +2804,9 @@ endif # NO_PERL\n $(SCRIPT_PYTHON_GEN): GIT-BUILD-OPTIONS\n \n ifndef NO_PYTHON\n-$(SCRIPT_PYTHON_GEN): generate-python.sh\n+$(SCRIPT_PYTHON_GEN): tools/generate-python.sh\n $(SCRIPT_PYTHON_GEN): % : %.py\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-python.sh ./GIT-BUILD-OPTIONS \"$<\" \"$@\"\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-python.sh ./GIT-BUILD-OPTIONS \"$<\" \"$@\"\n else # NO_PYTHON\n $(SCRIPT_PYTHON_GEN): % : unimplemented.sh\n \t$(QUIET_GEN) \\\n@@ -3226,9 +3226,9 @@ endif\n NO_PERL_CPAN_FALLBACKS_SQ = $(subst ','\\'',$(NO_PERL_CPAN_FALLBACKS))\n endif\n \n-perl/build/lib/%.pm: perl/%.pm generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES\n+perl/build/lib/%.pm: perl/%.pm tools/generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES\n \t$(call mkdir_p_parent_template)\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@\"\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@\"\n \n perl/build/man/man3/Git.3pm: perl/Git.pm\n \t$(call mkdir_p_parent_template)\n@@ -3936,7 +3936,7 @@ check-docs::\n ### Make sure built-ins do not have dups and listed in git.c\n #\n check-builtins::\n-\t./check-builtins.sh\n+\t./tools/check-builtins.sh\n \n ### Test suite coverage testing\n #\ndiff --git a/config.mak.dev b/config.mak.dev\nindex e86b6e1b34..c8dcf78779 100644\n--- a/config.mak.dev\n+++ b/config.mak.dev\n@@ -1,5 +1,5 @@\n ifndef COMPILER_FEATURES\n-COMPILER_FEATURES := $(shell ./detect-compiler $(CC))\n+COMPILER_FEATURES := $(shell ./tools/detect-compiler $(CC))\n endif\n \n ifeq ($(filter no-error,$(DEVOPTS)),)\ndiff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt\nindex c6cfb874ef..81b4306e72 100644\n--- a/contrib/buildsystems/CMakeLists.txt\n+++ b/contrib/buildsystems/CMakeLists.txt\n@@ -636,7 +636,7 @@ set(EXCLUSION_PROGS_CACHE ${EXCLUSION_PROGS} CACHE STRING \"Programs not built\" F\n if(NOT EXISTS ${CMAKE_BINARY_DIR}/command-list.h OR NOT EXCLUSION_PROGS_CACHE STREQUAL EXCLUSION_PROGS)\n \tlist(REMOVE_ITEM EXCLUSION_PROGS empty)\n \tmessage(\"Generating command-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-cmdlist.sh\"\n+\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-cmdlist.sh\"\n \t\t\t\t${EXCLUSION_PROGS}\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/command-list.h\")\n@@ -644,14 +644,14 @@ endif()\n \n if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)\n \tmessage(\"Generating config-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-configlist.sh\"\n+\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-configlist.sh\"\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/config-list.h\")\n endif()\n \n if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h)\n \tmessage(\"Generating hook-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" ${CMAKE_SOURCE_DIR}/generate-hooklist.sh\n+\texecute_process(COMMAND \"${SH_EXE}\" ${CMAKE_SOURCE_DIR}/tools/generate-hooklist.sh\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/hook-list.h\")\n endif()\n@@ -832,11 +832,11 @@ foreach(script ${git_shell_scripts})\n \tendif()\n \n \tadd_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/${shell_gen_path}\"\n-\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-script.sh\"\n+\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-script.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}.sh\"\n \t\t\t\"${CMAKE_BINARY_DIR}/${shell_gen_path}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n-\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-script.sh\"\n+\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-script.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}.sh\"\n \t\tVERBATIM)\n \tlist(APPEND shell_gen ${CMAKE_BINARY_DIR}/${shell_gen_path})\n@@ -875,13 +875,13 @@ foreach(script ${git_perl_scripts} ${perl_modules})\n \tfile(MAKE_DIRECTORY \"${CMAKE_BINARY_DIR}/${perl_gen_dir}\")\n \n \tadd_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/${perl_gen_path}\"\n-\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-perl.sh\"\n+\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-perl.sh\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-VERSION-FILE\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-PERL-HEADER\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/${perl_gen_path}\"\n-\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-perl.sh\"\n+\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-perl.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-VERSION-FILE\"\n@@ -892,11 +892,11 @@ add_custom_target(perl-gen ALL DEPENDS ${perl_gen})\n \n # Python script\n add_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/git-p4\"\n-\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-python.sh\"\n+\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-python.sh\"\n \t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\"${CMAKE_SOURCE_DIR}/git-p4.py\"\n \t\t\"${CMAKE_BINARY_DIR}/git-p4\"\n-\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-python.sh\"\n+\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-python.sh\"\n \t\t\"${CMAKE_SOURCE_DIR}/git-p4.py\"\n \t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \tVERBATIM)\ndiff --git a/contrib/subtree/meson.build b/contrib/subtree/meson.build\nindex 161435abeb..804c315894 100644\n--- a/contrib/subtree/meson.build\n+++ b/contrib/subtree/meson.build\n@@ -3,7 +3,7 @@ git_subtree = custom_target(\n   output: 'git-subtree',\n   command: [\n     shell,\n-    meson.project_source_root() / 'generate-script.sh',\n+    meson.project_source_root() / 'tools/generate-script.sh',\n     '@INPUT@',\n     '@OUTPUT@',\n     meson.project_build_root() / 'GIT-BUILD-OPTIONS',\ndiff --git a/meson.build b/meson.build\nindex 1d66b5181e..604fe89d2d 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -554,7 +554,7 @@ libgit_sources = [\n libgit_sources += custom_target(\n   input: 'command-list.txt',\n   output: 'command-list.h',\n-  command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],\n+  command: [shell, meson.current_source_dir() + '/tools/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],\n   env: script_environment,\n )\n \n@@ -723,10 +723,10 @@ endif\n builtin_sources += custom_target(\n   output: 'config-list.h',\n   depfile: 'config-list.h.d',\n-  depend_files: [ 'generate-configlist.sh' ],\n+  depend_files: [ 'tools/generate-configlist.sh' ],\n   command: [\n     shell,\n-    meson.current_source_dir() / 'generate-configlist.sh',\n+    meson.current_source_dir() / 'tools/generate-configlist.sh',\n     meson.current_source_dir(),\n     '@OUTPUT@',\n     '@DEPFILE@',\n@@ -739,7 +739,7 @@ builtin_sources += custom_target(\n   output: 'hook-list.h',\n   command: [\n     shell,\n-    meson.current_source_dir() + '/generate-hooklist.sh',\n+    meson.current_source_dir() + '/tools/generate-hooklist.sh',\n     meson.current_source_dir(),\n     '@OUTPUT@',\n   ],\n@@ -1959,7 +1959,7 @@ foreach script : scripts_sh\n     output: fs.stem(script),\n     command: [\n       shell,\n-      meson.project_source_root() / 'generate-script.sh',\n+      meson.project_source_root() / 'tools/generate-script.sh',\n       '@INPUT@',\n       '@OUTPUT@',\n       meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n@@ -2008,7 +2008,7 @@ if perl_features_enabled\n \n   generate_perl_command = [\n     shell,\n-    meson.project_source_root() / 'generate-perl.sh',\n+    meson.project_source_root() / 'tools/generate-perl.sh',\n     meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n     git_version_file.full_path(),\n     perl_header,\n@@ -2057,7 +2057,7 @@ if target_python.found()\n       output: fs.stem(script),\n       command: [\n         shell,\n-        meson.project_source_root() / 'generate-python.sh',\n+        meson.project_source_root() / 'tools/generate-python.sh',\n         meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n         '@INPUT@',\n         '@OUTPUT@',\ndiff --git a/check-builtins.sh b/tools/check-builtins.sh\nsimilarity index 100%\nrename from check-builtins.sh\nrename to tools/check-builtins.sh\ndiff --git a/detect-compiler b/tools/detect-compiler\nsimilarity index 100%\nrename from detect-compiler\nrename to tools/detect-compiler\ndiff --git a/generate-cmdlist.sh b/tools/generate-cmdlist.sh\nsimilarity index 100%\nrename from generate-cmdlist.sh\nrename to tools/generate-cmdlist.sh\ndiff --git a/generate-configlist.sh b/tools/generate-configlist.sh\nsimilarity index 100%\nrename from generate-configlist.sh\nrename to tools/generate-configlist.sh\ndiff --git a/generate-hooklist.sh b/tools/generate-hooklist.sh\nsimilarity index 100%\nrename from generate-hooklist.sh\nrename to tools/generate-hooklist.sh\ndiff --git a/generate-perl.sh b/tools/generate-perl.sh\nsimilarity index 100%\nrename from generate-perl.sh\nrename to tools/generate-perl.sh\ndiff --git a/generate-python.sh b/tools/generate-python.sh\nsimilarity index 100%\nrename from generate-python.sh\nrename to tools/generate-python.sh\ndiff --git a/generate-script.sh b/tools/generate-script.sh\nsimilarity index 100%\nrename from generate-script.sh\nrename to tools/generate-script.sh\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539088","messageId":"20260316-b4-pks-build-infra-improvements-v2-6-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"[PATCH v2 6/8] git-compat-util.h: move warning infra to prepare for PCHs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:08:01Z","receivedAt":"2026-03-16T10:08:26Z","isPatch":true,"body":"The \"git-compat-util.h\" header is supposed to be the first header\nincluded by every code compilation unit. As such, a subsequent commit\nwill start to precompile this header to speed up compilation of Git.\n\nThis will cause an issue though with the way that we have set up the\n\"-Wsign-compare\" warnings. It is expected that any compilation unit that\nfails with that compiler warning sets `DISABLE_SIGN_COMPARE_WARNINGS`\nbefore including \"git-compat-util.h\". If so, we'll disable the warning\nright away via a compiler pragma.\n\nBut with precompiled headers we do not know ahead of time whether the\ncode unit wants to disable those warnings, and thus we'll have to\nprecompile the header without defining `DISABLE_SIGN_COMPARE_WARNINGS`.\nBut as the pragma statement is wrapped by our include guards, the second\ninclude of that file will not have the desired effect of disabling the\nwarnings anymore.\n\nWe could fix this issue by declaring a new macro that compilation units\nare expected to invoke after having included the file. In retrospect,\nthat would have been the better way to handle this as it allows for\nmore flexibility: we could for example toggle the warning for specific\ncode blocks, only. But changing this now would require a bunch of\nchanges, and the churn feels excessive for what we gain.\n\nInstead, prepare for the precompiled headers by moving the code outside\nof the include guards.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n git-compat-util.h | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex bebcf9f698..4b4ea2498f 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -34,10 +34,6 @@ struct strbuf;\n #  define DISABLE_WARNING(warning)\n #endif\n \n-#ifdef DISABLE_SIGN_COMPARE_WARNINGS\n-DISABLE_WARNING(-Wsign-compare)\n-#endif\n-\n #undef FLEX_ARRAY\n #define FLEX_ARRAY /* empty - weather balloon to require C99 FAM */\n \n@@ -1099,3 +1095,7 @@ extern int not_supposed_to_survive;\n #endif /* CHECK_ASSERTION_SIDE_EFFECTS */\n \n #endif\n+\n+#ifdef DISABLE_SIGN_COMPARE_WARNINGS\n+DISABLE_WARNING(-Wsign-compare)\n+#endif\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539089","messageId":"20260316-b4-pks-build-infra-improvements-v2-7-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"[PATCH v2 7/8] meson: compile compatibility sources separately","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:08:02Z","receivedAt":"2026-03-16T10:08:28Z","isPatch":true,"body":"In the next commit we're about to introduce a precompiled header for\n\"git-compat-util.h\". The consequence of this change is that we'll\nimplicitly include that header for every compilation unit that uses the\nprecompiled headers.\n\nThis is okay for our \"normal\" library sources and our builtins. But some\nof our compatibility sources do not include the header on purpose, and\ndoing so would cause compileir errors.\n\nPrepare for this change by splitting out compatibility sources into\ntheir static library. Like this we can selectively enable precompiled\nheaders for the library sources.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 79 +++++++++++++++++++++++++++++++++++--------------------------\n 1 file changed, 45 insertions(+), 34 deletions(-)\n\ndiff --git a/meson.build b/meson.build\nindex 604fe89d2d..cd00be1c23 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -271,6 +271,13 @@ version_gen_environment.set('GIT_VERSION', get_option('version'))\n \n compiler = meson.get_compiler('c')\n \n+compat_sources = [\n+  'compat/nonblock.c',\n+  'compat/obstack.c',\n+  'compat/open.c',\n+  'compat/terminal.c',\n+]\n+\n libgit_sources = [\n   'abspath.c',\n   'add-interactive.c',\n@@ -304,10 +311,6 @@ libgit_sources = [\n   'commit.c',\n   'common-exit.c',\n   'common-init.c',\n-  'compat/nonblock.c',\n-  'compat/obstack.c',\n-  'compat/open.c',\n-  'compat/terminal.c',\n   'compiler-tricks/not-constant.c',\n   'config.c',\n   'connect.c',\n@@ -1163,7 +1166,7 @@ endif\n \n if not has_poll_h and not has_sys_poll_h\n   libgit_c_args += '-DNO_POLL'\n-  libgit_sources += 'compat/poll/poll.c'\n+  compat_sources += 'compat/poll/poll.c'\n   libgit_include_directories += 'compat/poll'\n endif\n \n@@ -1179,7 +1182,7 @@ endif\n # implementation to threat things like drive prefixes specially.\n if host_machine.system() == 'windows' or not compiler.has_header('libgen.h')\n   libgit_c_args += '-DNO_LIBGEN_H'\n-  libgit_sources += 'compat/basename.c'\n+  compat_sources += 'compat/basename.c'\n endif\n \n if compiler.has_header('paths.h')\n@@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'\n   foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']\n     if not compiler.has_function(symbol, dependencies: networking_dependencies)\n       libgit_c_args += '-DNO_' + symbol.to_upper()\n-      libgit_sources += 'compat/' + symbol + '.c'\n+      compat_sources += 'compat/' + symbol + '.c'\n     endif\n   endforeach\n endif\n@@ -1251,18 +1254,18 @@ else\n endif\n \n if host_machine.system() == 'darwin'\n-  libgit_sources += 'compat/precompose_utf8.c'\n+  compat_sources += 'compat/precompose_utf8.c'\n   libgit_c_args += '-DPRECOMPOSE_UNICODE'\n   libgit_c_args += '-DPROTECT_HFS_DEFAULT'\n endif\n \n # Configure general compatibility wrappers.\n if host_machine.system() == 'cygwin'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/win32/path-utils.c',\n   ]\n elif host_machine.system() == 'windows'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/winansi.c',\n     'compat/win32/dirent.c',\n     'compat/win32/flush.c',\n@@ -1289,20 +1292,20 @@ elif host_machine.system() == 'windows'\n   libgit_include_directories += 'compat/win32'\n   if compiler.get_id() == 'msvc'\n     libgit_include_directories += 'compat/vcbuild/include'\n-    libgit_sources += 'compat/msvc.c'\n+    compat_sources += 'compat/msvc.c'\n   else\n-    libgit_sources += 'compat/mingw.c'\n+    compat_sources += 'compat/mingw.c'\n   endif\n endif\n \n if host_machine.system() == 'linux'\n-  libgit_sources += 'compat/linux/procinfo.c'\n+  compat_sources += 'compat/linux/procinfo.c'\n elif host_machine.system() == 'windows'\n-  libgit_sources += 'compat/win32/trace2_win32_process_info.c'\n+  compat_sources += 'compat/win32/trace2_win32_process_info.c'\n elif host_machine.system() == 'darwin'\n-  libgit_sources += 'compat/darwin/procinfo.c'\n+  compat_sources += 'compat/darwin/procinfo.c'\n else\n-  libgit_sources += 'compat/stub/procinfo.c'\n+  compat_sources += 'compat/stub/procinfo.c'\n endif\n \n if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'\n@@ -1315,13 +1318,13 @@ endif\n \n # Configure the simple-ipc subsystem required fro the fsmonitor.\n if host_machine.system() == 'windows'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/simple-ipc/ipc-shared.c',\n     'compat/simple-ipc/ipc-win32.c',\n   ]\n   libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'\n else\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/simple-ipc/ipc-shared.c',\n     'compat/simple-ipc/ipc-unix-socket.c',\n   ]\n@@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''\n   libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND'\n   libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'\n \n-  libgit_sources += [\n+  compat_sources += [\n     'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',\n     'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',\n     'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',\n@@ -1355,7 +1358,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').allo\n \n   if compiler.get_define('REG_ENHANCED', prefix: '#include <regex.h>') != ''\n     libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'\n-    libgit_sources += 'compat/regcomp_enhanced.c'\n+    compat_sources += 'compat/regcomp_enhanced.c'\n   endif\n elif not get_option('regex').enabled()\n   libgit_c_args += [\n@@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()\n     '-DNO_MBSUPPORT',\n   ]\n   build_options_config.set('NO_REGEX', '1')\n-  libgit_sources += 'compat/regex/regex.c'\n+  compat_sources += 'compat/regex/regex.c'\n   libgit_include_directories += 'compat/regex'\n else\n     error('Native regex support requested but not found')\n@@ -1428,7 +1431,7 @@ else\n \n   if get_option('b_sanitize').contains('address')\n     libgit_c_args += '-DNO_MMAP'\n-    libgit_sources += 'compat/mmap.c'\n+    compat_sources += 'compat/mmap.c'\n   else\n     checkfuncs += { 'mmap': ['mmap.c'] }\n   endif\n@@ -1438,7 +1441,7 @@ foreach func, impls : checkfuncs\n   if not compiler.has_function(func)\n     libgit_c_args += '-DNO_' + func.to_upper()\n     foreach impl : impls\n-      libgit_sources += 'compat/' + impl\n+      compat_sources += 'compat/' + impl\n     endforeach\n   endif\n endforeach\n@@ -1449,13 +1452,13 @@ endif\n \n if not compiler.has_function('strdup')\n   libgit_c_args += '-DOVERRIDE_STRDUP'\n-  libgit_sources += 'compat/strdup.c'\n+  compat_sources += 'compat/strdup.c'\n endif\n \n if not compiler.has_function('qsort')\n   libgit_c_args += '-DINTERNAL_QSORT'\n endif\n-libgit_sources += 'compat/qsort_s.c'\n+compat_sources += 'compat/qsort_s.c'\n \n if compiler.has_function('getdelim')\n   libgit_c_args += '-DHAVE_GETDELIM'\n@@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and compiler.run('''\n   }\n ''', name: 'fread reads directories').returncode() == 0\n   libgit_c_args += '-DFREAD_READS_DIRECTORIES'\n-  libgit_sources += 'compat/fopen.c'\n+  compat_sources += 'compat/fopen.c'\n endif\n \n if not meson.is_cross_build() and fs.exists('/dev/tty')\n@@ -1745,14 +1748,22 @@ else\n endif\n \n libgit = declare_dependency(\n-  link_with: static_library('git',\n-    sources: libgit_sources,\n-    c_args: libgit_c_args + [\n-      '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n-    ],\n-    dependencies: libgit_dependencies,\n-    include_directories: libgit_include_directories,\n-  ),\n+  link_with: [\n+    static_library('compat',\n+      sources: compat_sources,\n+      c_args: libgit_c_args,\n+      dependencies: libgit_dependencies,\n+      include_directories: libgit_include_directories,\n+    ),\n+    static_library('git',\n+      sources: libgit_sources,\n+      c_args: libgit_c_args + [\n+        '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n+      ],\n+      dependencies: libgit_dependencies,\n+      include_directories: libgit_include_directories,\n+    ),\n+  ],\n   compile_args: libgit_c_args,\n   dependencies: libgit_dependencies,\n   include_directories: libgit_include_directories,\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539090","messageId":"20260316-b4-pks-build-infra-improvements-v2-8-4b2c2c0c0425@pks.im","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"[PATCH v2 8/8] meson: precompile \"git-compat-util.h\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-16T10:08:03Z","receivedAt":"2026-03-16T10:08:31Z","isPatch":true,"body":"Every compilation unit in Git is expected to include \"git-compat-util.h\"\nfirst, either directly or indirectly via \"builtin.h\". This header papers\nover differences between platforms so that we can expect the typical\nPOSIX functions to exist. Furthermore, it provides functionality that we\nend up using everywhere.\n\nThis header is thus quite heavy as a consequence. Preprocessing it as a\nstandalone unit via `clang -E git-compat-util.h` yields over 23,000\nlines of code overall. Naturally, it takes quite some time to compile\nall of this.\n\nLuckily, this is exactly the kind of use case that precompiled headers\naim to solve: instead of recompiling it every single time, we compile it\nonce and then link the result into the executable. If include guards are\nset up properly it means that the file won't need to be reprocessed.\n\nSet up such a precompiled header for \"git-compat-util.h\" and wire it up\nvia Meson. This causes Meson to implicitly include the precompiled\nheader in all compilation units. With GCC and Clang for example this is\ndone via the \"-include\" statement [1].\n\nThis leads to a significant speedup when performing full builds:\n\n  Benchmark 1: ninja (rev = HEAD~)\n  Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n  Range (min … max):   14.195 s … 14.633 s    10 runs\n\n  Benchmark 2: ninja (rev = HEAD)\n    Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n    Range (min … max):   10.030 s … 10.433 s    10 runs\n\n  Summary\n    ninja (rev = HEAD) ran\n      1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n\n[1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build         | 2 ++\n tools/precompiled.h | 1 +\n 2 files changed, 3 insertions(+)\n\ndiff --git a/meson.build b/meson.build\nindex cd00be1c23..2002f4795e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1760,6 +1760,7 @@ libgit = declare_dependency(\n       c_args: libgit_c_args + [\n         '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n       ],\n+      c_pch: 'tools/precompiled.h',\n       dependencies: libgit_dependencies,\n       include_directories: libgit_include_directories,\n     ),\n@@ -1820,6 +1821,7 @@ test_dependencies = [ ]\n \n git_builtin = executable('git',\n   sources: builtin_sources + 'git.c',\n+  c_pch: 'tools/precompiled.h',\n   dependencies: [libgit_commonmain],\n   install: true,\n   install_dir: git_exec_path,\ndiff --git a/tools/precompiled.h b/tools/precompiled.h\nnew file mode 100644\nindex 0000000000..b2bec0d2b4\n--- /dev/null\n+++ b/tools/precompiled.h\n@@ -0,0 +1 @@\n+#include \"git-compat-util.h\"\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539093","messageId":"204db12f-daef-47c7-ab71-efd8c20ab10f@gmail.com","threadId":"65200","inReplyTo":"abe6pVAzMEY60rJ8@pks.im","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-03-16T10:52:45Z","receivedAt":"2026-03-16T10:52:48Z","isPatch":true,"body":"On 16/03/2026 08:09, Patrick Steinhardt wrote:\n> On Fri, Mar 13, 2026 at 10:33:20AM +0000, Phillip Wood wrote:\n>>\n>> It does mean we're using different includes when compiling with pre-compiled\n>> headers compared to compiling without them though which means contributors\n>> using per-compiled headers could accidentally depend on functions that are\n>> not included when compiling without them. Wasn't the idea behind\n>> \"compat/posix.h\" to avoid including \"git-compat-util.h\" in the reftable\n>> code? The commit message for 75a044f748f (git-compat-util.h: split out\n>> POSIX-emulating bits, 2025-02-18) says\n>>\n>>      This intermixing is a bit of a problem for the reftable library as\n>>      we don't want to recreate the POSIX-like interface there. But\n>>      neither do we want to pull in the Git-specific functionality, as it\n>>      is otherwise quite easy to start depending on the Git codebase\n>>      again.\n>>\n>> We could precompile \"compat/posix.h\" for the code that does not want\n>> \"git-compat-util.h\"\n> \n> In theory, yes. But in practice we'd notice this quite fast via other CI\n> jobs, and it feels a bit ugly to split out so many different libraries.\n> So I'd propose to keep this as-is for now, but iterate in case we notice\n> that it _does_ become a problem.\n\nFair enough, getting feedback via the CI when it could be given locally \nby the compiler isn't great but we don't expect this to be a common problem.\n\nThanks\n\nPhillip\n\n\n> Does that work for you?\n> \n> Thanks!\n> \n> Patrick\n> \n\n"},{"id":"539094","messageId":"7ff11efb-a44c-4c78-b8b2-d38f8a6beb9f@gmail.com","threadId":"65200","inReplyTo":"20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im","subject":"Re: [PATCH v2 0/8] Some build system improvements","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-03-16T10:54:37Z","receivedAt":"2026-03-16T10:54:42Z","isPatch":true,"body":"On 16/03/2026 10:07, Patrick Steinhardt wrote:\n> \n> Changes in v2:\n>    - Turn array of precompiled headers into a simple string.\n>    - Point out in the commit message that the precompiled header is\n>      included implicitly.\n>    - Link to v1: https://lore.kernel.org/r/20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im\n\nThanks for expanding the commit message in patch 8, the range-diff looks \ngood.\n\nPhillip\n\n> Thanks!\n> \n> Patrick\n> \n> [1]: https://lore.kernel.org/git/20250506-pks-contrib-spring-cleanup-v1-0-e6d5ddd79a72@pks.im/\n> \n> ---\n> Patrick Steinhardt (8):\n>        Introduce new \"tools/\" directory\n>        contrib: move \"coccinelle/\" directory into \"tools/\"\n>        contrib: move \"coverage-diff.sh\" script into \"tools/\"\n>        contrib: move \"update-unicode.sh\" script into \"tools/\"\n>        builds: move build scripts into \"tools/\"\n>        git-compat-util.h: move warning infra to prepare for PCHs\n>        meson: compile compatibility sources separately\n>        meson: precompile \"git-compat-util.h\"\n> \n>   Makefile                                           | 76 ++++++++---------\n>   ci/run-static-analysis.sh                          |  2 +-\n>   config.mak.dev                                     |  2 +-\n>   contrib/buildsystems/CMakeLists.txt                | 18 ++--\n>   contrib/meson.build                                |  1 -\n>   contrib/subtree/meson.build                        |  2 +-\n>   git-compat-util.h                                  |  8 +-\n>   meson.build                                        | 96 +++++++++++++---------\n>   tools/README.md                                    |  7 ++\n>   check-builtins.sh => tools/check-builtins.sh       |  0\n>   {contrib => tools}/coccinelle/.gitignore           |  0\n>   {contrib => tools}/coccinelle/README               |  2 +-\n>   {contrib => tools}/coccinelle/array.cocci          |  0\n>   {contrib => tools}/coccinelle/commit.cocci         |  0\n>   .../coccinelle/config_fn_ctx.pending.cocci         |  0\n>   {contrib => tools}/coccinelle/equals-null.cocci    |  0\n>   {contrib => tools}/coccinelle/flex_alloc.cocci     |  0\n>   {contrib => tools}/coccinelle/free.cocci           |  0\n>   .../coccinelle/git_config_number.cocci             |  0\n>   {contrib => tools}/coccinelle/hashmap.cocci        |  0\n>   .../coccinelle/index-compatibility.cocci           |  0\n>   {contrib => tools}/coccinelle/meson.build          |  0\n>   {contrib => tools}/coccinelle/object_id.cocci      |  0\n>   {contrib => tools}/coccinelle/preincr.cocci        |  0\n>   {contrib => tools}/coccinelle/qsort.cocci          |  0\n>   {contrib => tools}/coccinelle/refs.cocci           |  0\n>   {contrib => tools}/coccinelle/spatchcache          |  6 +-\n>   {contrib => tools}/coccinelle/strbuf.cocci         |  0\n>   {contrib => tools}/coccinelle/swap.cocci           |  0\n>   {contrib => tools}/coccinelle/tests/free.c         |  0\n>   {contrib => tools}/coccinelle/tests/free.res       |  0\n>   {contrib => tools}/coccinelle/the_repository.cocci |  0\n>   {contrib => tools}/coccinelle/xcalloc.cocci        |  0\n>   {contrib => tools}/coccinelle/xopen.cocci          |  0\n>   .../coccinelle/xstrdup_or_null.cocci               |  0\n>   {contrib => tools}/coccinelle/xstrncmpz.cocci      |  0\n>   {contrib => tools}/coverage-diff.sh                |  0\n>   detect-compiler => tools/detect-compiler           |  0\n>   generate-cmdlist.sh => tools/generate-cmdlist.sh   |  0\n>   .../generate-configlist.sh                         |  0\n>   generate-hooklist.sh => tools/generate-hooklist.sh |  0\n>   generate-perl.sh => tools/generate-perl.sh         |  0\n>   generate-python.sh => tools/generate-python.sh     |  0\n>   generate-script.sh => tools/generate-script.sh     |  0\n>   tools/meson.build                                  |  1 +\n>   tools/precompiled.h                                |  1 +\n>   {contrib => tools}/update-unicode/.gitignore       |  0\n>   {contrib => tools}/update-unicode/README           |  0\n>   .../update-unicode/update_unicode.sh               |  0\n>   49 files changed, 123 insertions(+), 99 deletions(-)\n> \n> Range-diff versus v1:\n> \n> 1:  224e28be31 = 1:  9d09d2c39a Introduce new \"tools/\" directory\n> 2:  b217df51e5 = 2:  1b96bfe0f4 contrib: move \"coccinelle/\" directory into \"tools/\"\n> 3:  e371b6c221 = 3:  ed6e90bd36 contrib: move \"coverage-diff.sh\" script into \"tools/\"\n> 4:  3efeda9fa0 = 4:  48d8275ed1 contrib: move \"update-unicode.sh\" script into \"tools/\"\n> 5:  ee074c1396 = 5:  daafeb3462 builds: move build scripts into \"tools/\"\n> 6:  d30d4a3119 = 6:  947fc0f7b4 git-compat-util.h: move warning infra to prepare for PCHs\n> 7:  ca118197a9 = 7:  6a2fb99aae meson: compile compatibility sources separately\n> 8:  a865a8650b ! 8:  857b478896 meson: precompile \"git-compat-util.h\"\n>      @@ Commit message\n>           set up properly it means that the file won't need to be reprocessed.\n>       \n>           Set up such a precompiled header for \"git-compat-util.h\" and wire it up\n>      -    via Meson. This leads to a significant speedup when performing full\n>      -    builds:\n>      +    via Meson. This causes Meson to implicitly include the precompiled\n>      +    header in all compilation units. With GCC and Clang for example this is\n>      +    done via the \"-include\" statement [1].\n>      +\n>      +    This leads to a significant speedup when performing full builds:\n>       \n>             Benchmark 1: ninja (rev = HEAD~)\n>             Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n>      @@ Commit message\n>               ninja (rev = HEAD) ran\n>                 1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n>       \n>      +    [1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n>      +\n>           Signed-off-by: Patrick Steinhardt <ps@pks.im>\n>       \n>        ## meson.build ##\n>      @@ meson.build: libgit = declare_dependency(\n>              c_args: libgit_c_args + [\n>                '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n>              ],\n>      -+      c_pch: [ 'tools/precompiled.h' ],\n>      ++      c_pch: 'tools/precompiled.h',\n>              dependencies: libgit_dependencies,\n>              include_directories: libgit_include_directories,\n>            ),\n>      @@ meson.build: test_dependencies = [ ]\n>        \n>        git_builtin = executable('git',\n>          sources: builtin_sources + 'git.c',\n>      -+  c_pch: [ 'tools/precompiled.h' ],\n>      ++  c_pch: 'tools/precompiled.h',\n>          dependencies: [libgit_commonmain],\n>          install: true,\n>          install_dir: git_exec_path,\n> \n> ---\n> base-commit: af2c8a61818d773325ef2324dd135786a03ebca0\n> change-id: 20260304-b4-pks-build-infra-improvements-cc4012c5364e\n> \n> \n\n"},{"id":"539228","messageId":"6b8e418a-cac4-40d0-8f1e-762b15911227@app.fastmail.com","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-7-ec75d0710d6a@pks.im","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-03-17T15:38:31Z","receivedAt":"2026-03-17T15:38:53Z","isPatch":true,"body":"On Tue, Mar 10, 2026, at 18:52, Patrick Steinhardt wrote:\n> In the next commit we're about to introduce a precompiled header for\n> \"git-compat-util.h\". The consequence of this change is that we'll\n> implicitly include that header for every compilation unit that uses the\n> precompiled headers.\n>\n> This is okay for our \"normal\" library sources and our builtins. But some\n> of our compatibility sources do not include the header on purpose, and\n> doing so would cause compileir errors.\n\ns/compileir/compiler/ (or /compilation)\n\n>\n> Prepare for this change by splitting out compatibility sources into\n> their static library. Like this we can selectively enable precompiled\n\ns/Like this/Like this,/ ?\n\n> headers for the library sources.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n>[snip]\n"},{"id":"539341","messageId":"abuKb8OmcgDY1vMy@pks.im","threadId":"65200","inReplyTo":"6b8e418a-cac4-40d0-8f1e-762b15911227@app.fastmail.com","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:32:31Z","receivedAt":"2026-03-19T05:32:44Z","isPatch":true,"body":"On Tue, Mar 17, 2026 at 04:38:31PM +0100, Kristoffer Haugsbakk wrote:\n> On Tue, Mar 10, 2026, at 18:52, Patrick Steinhardt wrote:\n> > In the next commit we're about to introduce a precompiled header for\n> > \"git-compat-util.h\". The consequence of this change is that we'll\n> > implicitly include that header for every compilation unit that uses the\n> > precompiled headers.\n> >\n> > This is okay for our \"normal\" library sources and our builtins. But some\n> > of our compatibility sources do not include the header on purpose, and\n> > doing so would cause compileir errors.\n> \n> s/compileir/compiler/ (or /compilation)\n> \n> >\n> > Prepare for this change by splitting out compatibility sources into\n> > their static library. Like this we can selectively enable precompiled\n> \n> s/Like this/Like this,/ ?\n\nYup, both of these make sense. Thanks!\n\nPatric\n"},{"id":"539342","messageId":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im","subject":"[PATCH v3 0/8] Some build system improvements","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:19Z","receivedAt":"2026-03-19T05:33:28Z","isPatch":true,"body":"Hi,\n\nthis patch series contains a small set of build system improvements:\n\n  - The first couple patches introduce a new \"tools/\" directory that\n    contains items related to our build infrastructure and to our\n    developer tooling. This finally follows up on my promise to do this\n    back when I did the spring clean of \"contrib/\". [1]\n\n  - The last couple patches introduce precompiled headers into Meson for\n    a nice compilation speedup of ~30%. It's \n\nThe two topics are not really related with one another other than being\nrelated to build systems. I decided to throw them in the same patch\nseries though so that I can introduce \"precompiled.h\" in \"tools/\".\n\nChanges in v3:\n  - Improve commit message.\n  - Link to v2: https://lore.kernel.org/r/20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im\n\nChanges in v2:\n  - Turn array of precompiled headers into a simple string.\n  - Point out in the commit message that the precompiled header is\n    included implicitly.\n  - Link to v1: https://lore.kernel.org/r/20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im\n\nThanks!\n\nPatrick\n\n[1]: https://lore.kernel.org/git/20250506-pks-contrib-spring-cleanup-v1-0-e6d5ddd79a72@pks.im/\n\n---\nPatrick Steinhardt (8):\n      Introduce new \"tools/\" directory\n      contrib: move \"coccinelle/\" directory into \"tools/\"\n      contrib: move \"coverage-diff.sh\" script into \"tools/\"\n      contrib: move \"update-unicode.sh\" script into \"tools/\"\n      builds: move build scripts into \"tools/\"\n      git-compat-util.h: move warning infra to prepare for PCHs\n      meson: compile compatibility sources separately\n      meson: precompile \"git-compat-util.h\"\n\n Makefile                                           | 76 ++++++++---------\n ci/run-static-analysis.sh                          |  2 +-\n config.mak.dev                                     |  2 +-\n contrib/buildsystems/CMakeLists.txt                | 18 ++--\n contrib/meson.build                                |  1 -\n contrib/subtree/meson.build                        |  2 +-\n git-compat-util.h                                  |  8 +-\n meson.build                                        | 96 +++++++++++++---------\n tools/README.md                                    |  7 ++\n check-builtins.sh => tools/check-builtins.sh       |  0\n {contrib => tools}/coccinelle/.gitignore           |  0\n {contrib => tools}/coccinelle/README               |  2 +-\n {contrib => tools}/coccinelle/array.cocci          |  0\n {contrib => tools}/coccinelle/commit.cocci         |  0\n .../coccinelle/config_fn_ctx.pending.cocci         |  0\n {contrib => tools}/coccinelle/equals-null.cocci    |  0\n {contrib => tools}/coccinelle/flex_alloc.cocci     |  0\n {contrib => tools}/coccinelle/free.cocci           |  0\n .../coccinelle/git_config_number.cocci             |  0\n {contrib => tools}/coccinelle/hashmap.cocci        |  0\n .../coccinelle/index-compatibility.cocci           |  0\n {contrib => tools}/coccinelle/meson.build          |  0\n {contrib => tools}/coccinelle/object_id.cocci      |  0\n {contrib => tools}/coccinelle/preincr.cocci        |  0\n {contrib => tools}/coccinelle/qsort.cocci          |  0\n {contrib => tools}/coccinelle/refs.cocci           |  0\n {contrib => tools}/coccinelle/spatchcache          |  6 +-\n {contrib => tools}/coccinelle/strbuf.cocci         |  0\n {contrib => tools}/coccinelle/swap.cocci           |  0\n {contrib => tools}/coccinelle/tests/free.c         |  0\n {contrib => tools}/coccinelle/tests/free.res       |  0\n {contrib => tools}/coccinelle/the_repository.cocci |  0\n {contrib => tools}/coccinelle/xcalloc.cocci        |  0\n {contrib => tools}/coccinelle/xopen.cocci          |  0\n .../coccinelle/xstrdup_or_null.cocci               |  0\n {contrib => tools}/coccinelle/xstrncmpz.cocci      |  0\n {contrib => tools}/coverage-diff.sh                |  0\n detect-compiler => tools/detect-compiler           |  0\n generate-cmdlist.sh => tools/generate-cmdlist.sh   |  0\n .../generate-configlist.sh                         |  0\n generate-hooklist.sh => tools/generate-hooklist.sh |  0\n generate-perl.sh => tools/generate-perl.sh         |  0\n generate-python.sh => tools/generate-python.sh     |  0\n generate-script.sh => tools/generate-script.sh     |  0\n tools/meson.build                                  |  1 +\n tools/precompiled.h                                |  1 +\n {contrib => tools}/update-unicode/.gitignore       |  0\n {contrib => tools}/update-unicode/README           |  0\n .../update-unicode/update_unicode.sh               |  0\n 49 files changed, 123 insertions(+), 99 deletions(-)\n\nRange-diff versus v2:\n\n1:  051b66376f = 1:  bc18fe2f2d Introduce new \"tools/\" directory\n2:  275a96c805 = 2:  393b42f433 contrib: move \"coccinelle/\" directory into \"tools/\"\n3:  afc5a1f8b9 = 3:  00284934e9 contrib: move \"coverage-diff.sh\" script into \"tools/\"\n4:  909d996f56 = 4:  9dceec07dd contrib: move \"update-unicode.sh\" script into \"tools/\"\n5:  6396ae723e = 5:  af0ce83627 builds: move build scripts into \"tools/\"\n6:  16b0e9f4fb = 6:  8cb7ea8245 git-compat-util.h: move warning infra to prepare for PCHs\n7:  b4cd150fdf ! 7:  495335a97a meson: compile compatibility sources separately\n    @@ Commit message\n     \n         This is okay for our \"normal\" library sources and our builtins. But some\n         of our compatibility sources do not include the header on purpose, and\n    -    doing so would cause compileir errors.\n    +    doing so would cause compilation errors.\n     \n         Prepare for this change by splitting out compatibility sources into\n    -    their static library. Like this we can selectively enable precompiled\n    +    their static library. Like this, we can selectively enable precompiled\n         headers for the library sources.\n     \n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n8:  5899e0318b = 8:  6923592b62 meson: precompile \"git-compat-util.h\"\n\n---\nbase-commit: af2c8a61818d773325ef2324dd135786a03ebca0\nchange-id: 20260304-b4-pks-build-infra-improvements-cc4012c5364e\n\n"},{"id":"539343","messageId":"20260319-b4-pks-build-infra-improvements-v3-1-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","subject":"[PATCH v3 1/8] Introduce new \"tools/\" directory","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:20Z","receivedAt":"2026-03-19T05:33:29Z","isPatch":true,"body":"According to its readme, the \"contrib/\" directory's main intent is to\ncollect stuff that is not an official part of Git, either because it is\ntoo specialized or because it is still considered experimental. The\nreality tells a bit of a different story though: while it _does_ contain\nsuch things, it also contains other things:\n\n  - Our credential helpers, which are being distributed by many\n    packagers nowadays and which can be considered \"stable\".\n\n  - A bunch of tooling that relates to our build and test\n    infrastructure.\n\nEspecially the second category is somewhat of a sore spot. You really\nwouldn't expect build-related tooling to be considered an optional part\nof Git. Quite the opposite.\n\nCreate a new top-level \"tools/\" directory to fix this discrepancy. This\ndirectory will contain all kind of tools that are related to our build\ninfrastructure and that Git developers are likely to use day to day.\n\nFor now, this directory doesn't contain anything yet except for a\nreadme and a Meson skeleton. This will change in subsequent commits.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile          | 2 ++\n meson.build       | 1 +\n tools/README.md   | 7 +++++++\n tools/meson.build | 0\n 4 files changed, 10 insertions(+)\n\ndiff --git a/Makefile b/Makefile\nindex f3264d0a37..c7cedbcd7c 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1066,11 +1066,13 @@ SOURCES_CMD = ( \\\n \t\t'*.sh' \\\n \t\t':!*[tp][0-9][0-9][0-9][0-9]*' \\\n \t\t':!contrib' \\\n+\t\t':!tools' \\\n \t\t2>/dev/null || \\\n \t$(FIND) . \\\n \t\t\\( -name .git -type d -prune \\) \\\n \t\t-o \\( -name '[tp][0-9][0-9][0-9][0-9]*' -prune \\) \\\n \t\t-o \\( -name contrib -type d -prune \\) \\\n+\t\t-o \\( -name tools -type d -prune \\) \\\n \t\t-o \\( -name build -type d -prune \\) \\\n \t\t-o \\( -name .build -type d -prune \\) \\\n \t\t-o \\( -name 'trash*' -type d -prune \\) \\\ndiff --git a/meson.build b/meson.build\nindex 4b536e0124..1d66b5181e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -2149,6 +2149,7 @@ else\n endif\n \n subdir('contrib')\n+subdir('tools')\n \n # Note that the target is intentionally configured after including the\n # 'contrib' directory, as some tool there also have their own manpages.\ndiff --git a/tools/README.md b/tools/README.md\nnew file mode 100644\nindex 0000000000..d732997136\n--- /dev/null\n+++ b/tools/README.md\n@@ -0,0 +1,7 @@\n+Developer Tooling\n+-----------------\n+\n+This directory is expected to contain all sorts of tooling that\n+relates to our build infrastructure. This includes scripts and\n+inputs required by our build systems, but also scripts that\n+developers are expected to run manually.\ndiff --git a/tools/meson.build b/tools/meson.build\nnew file mode 100644\nindex 0000000000..e69de29bb2\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539344","messageId":"20260319-b4-pks-build-infra-improvements-v3-2-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","subject":"[PATCH v3 2/8] contrib: move \"coccinelle/\" directory into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:21Z","receivedAt":"2026-03-19T05:33:32Z","isPatch":true,"body":"The Coccinelle tool is an ingrained part of our build infrastructure. It\nis executed by our CI to detect antipatterns and is used to detect\nmisuses of certain interfaces. It's presence in \"contrib/\" is thus\nrather misleading.\n\nPromote the configuration into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile                                           | 40 +++++++++++-----------\n ci/run-static-analysis.sh                          |  2 +-\n contrib/meson.build                                |  1 -\n {contrib => tools}/coccinelle/.gitignore           |  0\n {contrib => tools}/coccinelle/README               |  2 +-\n {contrib => tools}/coccinelle/array.cocci          |  0\n {contrib => tools}/coccinelle/commit.cocci         |  0\n .../coccinelle/config_fn_ctx.pending.cocci         |  0\n {contrib => tools}/coccinelle/equals-null.cocci    |  0\n {contrib => tools}/coccinelle/flex_alloc.cocci     |  0\n {contrib => tools}/coccinelle/free.cocci           |  0\n .../coccinelle/git_config_number.cocci             |  0\n {contrib => tools}/coccinelle/hashmap.cocci        |  0\n .../coccinelle/index-compatibility.cocci           |  0\n {contrib => tools}/coccinelle/meson.build          |  0\n {contrib => tools}/coccinelle/object_id.cocci      |  0\n {contrib => tools}/coccinelle/preincr.cocci        |  0\n {contrib => tools}/coccinelle/qsort.cocci          |  0\n {contrib => tools}/coccinelle/refs.cocci           |  0\n {contrib => tools}/coccinelle/spatchcache          |  6 ++--\n {contrib => tools}/coccinelle/strbuf.cocci         |  0\n {contrib => tools}/coccinelle/swap.cocci           |  0\n {contrib => tools}/coccinelle/tests/free.c         |  0\n {contrib => tools}/coccinelle/tests/free.res       |  0\n {contrib => tools}/coccinelle/the_repository.cocci |  0\n {contrib => tools}/coccinelle/xcalloc.cocci        |  0\n {contrib => tools}/coccinelle/xopen.cocci          |  0\n .../coccinelle/xstrdup_or_null.cocci               |  0\n {contrib => tools}/coccinelle/xstrncmpz.cocci      |  0\n tools/meson.build                                  |  1 +\n 30 files changed, 26 insertions(+), 26 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex c7cedbcd7c..8564b1be36 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1005,8 +1005,8 @@ SPATCH_TEST_FLAGS =\n # COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.\n SPATCH_USE_O_DEPENDENCIES = YesPlease\n \n-# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci\n-# files into a single contrib/cocci/ALL.cocci before running\n+# Set SPATCH_CONCAT_COCCI to concatenate the tools/coccinelle/*.cocci\n+# files into a single tools/coccinelle/ALL.cocci before running\n # \"coccicheck\".\n #\n # Pros:\n@@ -1025,7 +1025,7 @@ SPATCH_USE_O_DEPENDENCIES = YesPlease\n #   generate a specific patch, e.g. this will always use strbuf.cocci,\n #   not ALL.cocci:\n #\n-#\tmake contrib/coccinelle/strbuf.cocci.patch\n+#\tmake tools/coccinelle/strbuf.cocci.patch\n SPATCH_CONCAT_COCCI = YesPlease\n \n # Rebuild 'coccicheck' if $(SPATCH), its flags etc. change\n@@ -3457,15 +3457,15 @@ check:\n \t\texit 1; \\\n \tfi\n \n-COCCI_GEN_ALL = .build/contrib/coccinelle/ALL.cocci\n-COCCI_GLOB = $(wildcard contrib/coccinelle/*.cocci)\n+COCCI_GEN_ALL = .build/tools/coccinelle/ALL.cocci\n+COCCI_GLOB = $(wildcard tools/coccinelle/*.cocci)\n COCCI_RULES_TRACKED = $(COCCI_GLOB:%=.build/%)\n COCCI_RULES_TRACKED_NO_PENDING = $(filter-out %.pending.cocci,$(COCCI_RULES_TRACKED))\n COCCI_RULES =\n COCCI_RULES += $(COCCI_GEN_ALL)\n COCCI_RULES += $(COCCI_RULES_TRACKED)\n COCCI_NAMES =\n-COCCI_NAMES += $(COCCI_RULES:.build/contrib/coccinelle/%.cocci=%)\n+COCCI_NAMES += $(COCCI_RULES:.build/tools/coccinelle/%.cocci=%)\n \n COCCICHECK_PENDING = $(filter %.pending.cocci,$(COCCI_RULES))\n COCCICHECK = $(filter-out $(COCCICHECK_PENDING),$(COCCI_RULES))\n@@ -3480,20 +3480,20 @@ COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)\n # on $(MAKECMDGOALS) that match these $(COCCI_RULES)\n COCCI_RULES_GLOB =\n COCCI_RULES_GLOB += cocci%\n-COCCI_RULES_GLOB += .build/contrib/coccinelle/%\n+COCCI_RULES_GLOB += .build/tools/coccinelle/%\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES)\n COCCI_RULES_GLOB += $(COCCICHEC_PATCHES_PENDING)\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_INTREE)\n COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_PENDING_INTREE)\n COCCI_GOALS = $(filter $(COCCI_RULES_GLOB),$(MAKECMDGOALS))\n \n-COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)\n+COCCI_TEST_RES = $(wildcard tools/coccinelle/tests/*.res)\n \n $(COCCI_RULES_TRACKED): .build/% : %\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_CP)cp $< $@\n \n-.build/contrib/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)\n+.build/tools/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_GEN) >$@\n \n@@ -3507,12 +3507,12 @@ endif\n define cocci-rule\n \n ## Rule for .build/$(1).patch/$(2); Params:\n-# $(1) = e.g. \".build/contrib/coccinelle/free.cocci\"\n+# $(1) = e.g. \".build/tools/coccinelle/free.cocci\"\n # $(2) = e.g. \"grep.c\"\n # $(3) = e.g. \"grep.o\"\n-COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch\n+COCCI_$(1:.build/tools/coccinelle/%.cocci=%) += $(1).d/$(2).patch\n $(1).d/$(2).patch: GIT-SPATCH-DEFINES\n-$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)\n+$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/tools/coccinelle/FOUND_H_SOURCES)\n $(1).d/$(2).patch: $(1)\n $(1).d/$(2).patch: $(1).d/%.patch : %\n \t$$(call mkdir_p_parent_template)\n@@ -3538,13 +3538,13 @@ endif\n \n define spatch-rule\n \n-.build/contrib/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))\n+.build/tools/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))\n \t$$(QUIET_SPATCH_CAT)cat $$^ >$$@ && \\\n \tif test -s $$@; \\\n \tthen \\\n \t\techo '    ' SPATCH result: $$@; \\\n \tfi\n-contrib/coccinelle/$(1).cocci.patch: .build/contrib/coccinelle/$(1).cocci.patch\n+tools/coccinelle/$(1).cocci.patch: .build/tools/coccinelle/$(1).cocci.patch\n \t$$(QUIET_CP)cp $$< $$@\n \n endef\n@@ -3558,9 +3558,9 @@ $(COCCI_TEST_RES_GEN): GIT-SPATCH-DEFINES\n $(COCCI_TEST_RES_GEN): .build/%.res : %.c\n $(COCCI_TEST_RES_GEN): .build/%.res : %.res\n ifdef SPATCH_CONCAT_COCCI\n-$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : $(COCCI_GEN_ALL)\n+$(COCCI_TEST_RES_GEN): .build/tools/coccinelle/tests/%.res : $(COCCI_GEN_ALL)\n else\n-$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci\n+$(COCCI_TEST_RES_GEN): .build/tools/coccinelle/tests/%.res : tools/coccinelle/%.cocci\n endif\n \t$(call mkdir_p_parent_template)\n \t$(QUIET_SPATCH_TEST)$(SPATCH) $(SPATCH_TEST_FLAGS) \\\n@@ -3576,14 +3576,14 @@ coccicheck-test: $(COCCI_TEST_RES_GEN)\n coccicheck: coccicheck-test\n \n ifdef SPATCH_CONCAT_COCCI\n-COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = contrib/coccinelle/ALL.cocci.patch\n+COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = tools/coccinelle/ALL.cocci.patch\n else\n COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = $(COCCICHECK_PATCHES_INTREE)\n endif\n coccicheck: $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES)\n \t! grep ^ $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES) /dev/null\n \n-# See contrib/coccinelle/README\n+# See tools/coccinelle/README\n coccicheck-pending: coccicheck-test\n coccicheck-pending: $(COCCICHECK_PATCHES_PENDING_INTREE)\n \n@@ -3857,8 +3857,8 @@ profile-clean:\n \n cocciclean:\n \t$(RM) GIT-SPATCH-DEFINES\n-\t$(RM) -r .build/contrib/coccinelle\n-\t$(RM) contrib/coccinelle/*.cocci.patch\n+\t$(RM) -r .build/tools/coccinelle\n+\t$(RM) tools/coccinelle/*.cocci.patch\n \n clean: profile-clean coverage-clean cocciclean\n \t$(RM) -r .build $(UNIT_TEST_BIN)\ndiff --git a/ci/run-static-analysis.sh b/ci/run-static-analysis.sh\nindex 9e9c72681d..ba67e80b4d 100755\n--- a/ci/run-static-analysis.sh\n+++ b/ci/run-static-analysis.sh\n@@ -10,7 +10,7 @@ make coccicheck\n set +x\n \n fail=\n-for cocci_patch in contrib/coccinelle/*.patch\n+for cocci_patch in tools/coccinelle/*.patch\n do\n \tif test -s \"$cocci_patch\"\n \tthen\ndiff --git a/contrib/meson.build b/contrib/meson.build\nindex a88c5dfe09..569c23ee76 100644\n--- a/contrib/meson.build\n+++ b/contrib/meson.build\n@@ -2,5 +2,4 @@ foreach feature : get_option('contrib')\n   subdir(feature)\n endforeach\n \n-subdir('coccinelle')\n subdir('credential')\ndiff --git a/contrib/coccinelle/.gitignore b/tools/coccinelle/.gitignore\nsimilarity index 100%\nrename from contrib/coccinelle/.gitignore\nrename to tools/coccinelle/.gitignore\ndiff --git a/contrib/coccinelle/README b/tools/coccinelle/README\nsimilarity index 98%\nrename from contrib/coccinelle/README\nrename to tools/coccinelle/README\nindex 055ad0e06a..fd0a543cc2 100644\n--- a/contrib/coccinelle/README\n+++ b/tools/coccinelle/README\n@@ -38,7 +38,7 @@ that might be useful to developers.\n    So to aid these large scale refactorings, semantic patches can be used.\n    However we do not want to store them in the same place as the checks for\n    bad patterns, as then automated builds would fail.\n-   That is why semantic patches 'contrib/coccinelle/*.pending.cocci'\n+   That is why semantic patches 'tools/coccinelle/*.pending.cocci'\n    are ignored for checks, and can be applied using 'make coccicheck-pending'.\n \n    This allows to expose plans of pending large scale refactorings without\ndiff --git a/contrib/coccinelle/array.cocci b/tools/coccinelle/array.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/array.cocci\nrename to tools/coccinelle/array.cocci\ndiff --git a/contrib/coccinelle/commit.cocci b/tools/coccinelle/commit.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/commit.cocci\nrename to tools/coccinelle/commit.cocci\ndiff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/tools/coccinelle/config_fn_ctx.pending.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/config_fn_ctx.pending.cocci\nrename to tools/coccinelle/config_fn_ctx.pending.cocci\ndiff --git a/contrib/coccinelle/equals-null.cocci b/tools/coccinelle/equals-null.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/equals-null.cocci\nrename to tools/coccinelle/equals-null.cocci\ndiff --git a/contrib/coccinelle/flex_alloc.cocci b/tools/coccinelle/flex_alloc.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/flex_alloc.cocci\nrename to tools/coccinelle/flex_alloc.cocci\ndiff --git a/contrib/coccinelle/free.cocci b/tools/coccinelle/free.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/free.cocci\nrename to tools/coccinelle/free.cocci\ndiff --git a/contrib/coccinelle/git_config_number.cocci b/tools/coccinelle/git_config_number.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/git_config_number.cocci\nrename to tools/coccinelle/git_config_number.cocci\ndiff --git a/contrib/coccinelle/hashmap.cocci b/tools/coccinelle/hashmap.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/hashmap.cocci\nrename to tools/coccinelle/hashmap.cocci\ndiff --git a/contrib/coccinelle/index-compatibility.cocci b/tools/coccinelle/index-compatibility.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/index-compatibility.cocci\nrename to tools/coccinelle/index-compatibility.cocci\ndiff --git a/contrib/coccinelle/meson.build b/tools/coccinelle/meson.build\nsimilarity index 100%\nrename from contrib/coccinelle/meson.build\nrename to tools/coccinelle/meson.build\ndiff --git a/contrib/coccinelle/object_id.cocci b/tools/coccinelle/object_id.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/object_id.cocci\nrename to tools/coccinelle/object_id.cocci\ndiff --git a/contrib/coccinelle/preincr.cocci b/tools/coccinelle/preincr.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/preincr.cocci\nrename to tools/coccinelle/preincr.cocci\ndiff --git a/contrib/coccinelle/qsort.cocci b/tools/coccinelle/qsort.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/qsort.cocci\nrename to tools/coccinelle/qsort.cocci\ndiff --git a/contrib/coccinelle/refs.cocci b/tools/coccinelle/refs.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/refs.cocci\nrename to tools/coccinelle/refs.cocci\ndiff --git a/contrib/coccinelle/spatchcache b/tools/coccinelle/spatchcache\nsimilarity index 97%\nrename from contrib/coccinelle/spatchcache\nrename to tools/coccinelle/spatchcache\nindex 29e9352d8a..efbcbc3827 100755\n--- a/contrib/coccinelle/spatchcache\n+++ b/tools/coccinelle/spatchcache\n@@ -30,7 +30,7 @@\n #\t   out of control.\n #\n # This along with the general incremental \"make\" support for\n-# \"contrib/coccinelle\" makes it viable to (re-)run coccicheck\n+# \"tools/coccinelle\" makes it viable to (re-)run coccicheck\n # e.g. when merging integration branches.\n #\n # Note that the \"--very-quiet\" flag is currently critical. The cache\n@@ -42,7 +42,7 @@\n # to change, so just supply \"--very-quiet\" for now.\n #\n # To use this, simply set SPATCH to\n-# contrib/coccinelle/spatchcache. Then optionally set:\n+# tools/coccinelle/spatchcache. Then optionally set:\n #\n #\t[spatchCache]\n #\t\t# Optional: path to a custom spatch\n@@ -65,7 +65,7 @@\n #\n #\tredis-cli FLUSHALL\n #\t<make && make coccicheck, as above>\n-#\tgrep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/contrib/coccinelle | sort | uniq -c\n+#\tgrep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/tools/coccinelle | sort | uniq -c\n #\t    600 CANTCACHE\n #\t   7365 MISS\n #\t   7365 SET\ndiff --git a/contrib/coccinelle/strbuf.cocci b/tools/coccinelle/strbuf.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/strbuf.cocci\nrename to tools/coccinelle/strbuf.cocci\ndiff --git a/contrib/coccinelle/swap.cocci b/tools/coccinelle/swap.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/swap.cocci\nrename to tools/coccinelle/swap.cocci\ndiff --git a/contrib/coccinelle/tests/free.c b/tools/coccinelle/tests/free.c\nsimilarity index 100%\nrename from contrib/coccinelle/tests/free.c\nrename to tools/coccinelle/tests/free.c\ndiff --git a/contrib/coccinelle/tests/free.res b/tools/coccinelle/tests/free.res\nsimilarity index 100%\nrename from contrib/coccinelle/tests/free.res\nrename to tools/coccinelle/tests/free.res\ndiff --git a/contrib/coccinelle/the_repository.cocci b/tools/coccinelle/the_repository.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/the_repository.cocci\nrename to tools/coccinelle/the_repository.cocci\ndiff --git a/contrib/coccinelle/xcalloc.cocci b/tools/coccinelle/xcalloc.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xcalloc.cocci\nrename to tools/coccinelle/xcalloc.cocci\ndiff --git a/contrib/coccinelle/xopen.cocci b/tools/coccinelle/xopen.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xopen.cocci\nrename to tools/coccinelle/xopen.cocci\ndiff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/tools/coccinelle/xstrdup_or_null.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xstrdup_or_null.cocci\nrename to tools/coccinelle/xstrdup_or_null.cocci\ndiff --git a/contrib/coccinelle/xstrncmpz.cocci b/tools/coccinelle/xstrncmpz.cocci\nsimilarity index 100%\nrename from contrib/coccinelle/xstrncmpz.cocci\nrename to tools/coccinelle/xstrncmpz.cocci\ndiff --git a/tools/meson.build b/tools/meson.build\nindex e69de29bb2..f731f74312 100644\n--- a/tools/meson.build\n+++ b/tools/meson.build\n@@ -0,0 +1 @@\n+subdir('coccinelle')\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539345","messageId":"20260319-b4-pks-build-infra-improvements-v3-3-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","subject":"[PATCH v3 3/8] contrib: move \"coverage-diff.sh\" script into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:22Z","receivedAt":"2026-03-19T05:33:35Z","isPatch":true,"body":"The \"coverage-diff.sh\" script can be used to get information about test\ncoverage fro the Git codebase. It is thus rather specific to our build\nand test infrastructure and part of the developer-facing tooling. The\nfact that this script is part of \"contrib/\" is thus rather misleading\nand a historic wart.\n\nPromote the tool into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n {contrib => tools}/coverage-diff.sh | 0\n 1 file changed, 0 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/coverage-diff.sh b/tools/coverage-diff.sh\nsimilarity index 100%\nrename from contrib/coverage-diff.sh\nrename to tools/coverage-diff.sh\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539346","messageId":"20260319-b4-pks-build-infra-improvements-v3-4-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","subject":"[PATCH v3 4/8] contrib: move \"update-unicode.sh\" script into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:23Z","receivedAt":"2026-03-19T05:33:37Z","isPatch":true,"body":"The \"update-unicode.sh\" script is used to update the unicode data\ncompiled into Git whenever a new version of the Unicode standard has\nbeen released. As such, it is a natural part of our developer-facing\ntooling, and its presence in \"contrib/\" is misleading.\n\nPromote the script into the new \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n {contrib => tools}/update-unicode/.gitignore        | 0\n {contrib => tools}/update-unicode/README            | 0\n {contrib => tools}/update-unicode/update_unicode.sh | 0\n 3 files changed, 0 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/update-unicode/.gitignore b/tools/update-unicode/.gitignore\nsimilarity index 100%\nrename from contrib/update-unicode/.gitignore\nrename to tools/update-unicode/.gitignore\ndiff --git a/contrib/update-unicode/README b/tools/update-unicode/README\nsimilarity index 100%\nrename from contrib/update-unicode/README\nrename to tools/update-unicode/README\ndiff --git a/contrib/update-unicode/update_unicode.sh b/tools/update-unicode/update_unicode.sh\nsimilarity index 100%\nrename from contrib/update-unicode/update_unicode.sh\nrename to tools/update-unicode/update_unicode.sh\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539347","messageId":"20260319-b4-pks-build-infra-improvements-v3-5-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","subject":"[PATCH v3 5/8] builds: move build scripts into \"tools/\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:24Z","receivedAt":"2026-03-19T05:33:40Z","isPatch":true,"body":"We have a bunch of scripts used by our different build systems that are\nall located in the top-level directory. Now that we have introduced the\nnew \"tools/\" directory though we have a better home for them.\n\nMove the scripts into the \"tools/\" directory.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Makefile                                           | 34 +++++++++++-----------\n config.mak.dev                                     |  2 +-\n contrib/buildsystems/CMakeLists.txt                | 18 ++++++------\n contrib/subtree/meson.build                        |  2 +-\n meson.build                                        | 14 ++++-----\n check-builtins.sh => tools/check-builtins.sh       |  0\n detect-compiler => tools/detect-compiler           |  0\n generate-cmdlist.sh => tools/generate-cmdlist.sh   |  0\n .../generate-configlist.sh                         |  0\n generate-hooklist.sh => tools/generate-hooklist.sh |  0\n generate-perl.sh => tools/generate-perl.sh         |  0\n generate-python.sh => tools/generate-python.sh     |  0\n generate-script.sh => tools/generate-script.sh     |  0\n 13 files changed, 35 insertions(+), 35 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 8564b1be36..322f5940e3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2689,21 +2689,21 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n-config-list.h: generate-configlist.sh\n+config-list.h: tools/generate-configlist.sh\n \t@mkdir -p .depend\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh . $@ .depend/config-list.h.d\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-configlist.sh . $@ .depend/config-list.h.d\n \n -include .depend/config-list.h.d\n \n-command-list.h: generate-cmdlist.sh command-list.txt\n+command-list.h: tools/generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.adoc)\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh \\\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-cmdlist.sh \\\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\t. $@\n \n-hook-list.h: generate-hooklist.sh Documentation/githooks.adoc\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh . $@\n+hook-list.h: tools/generate-hooklist.sh Documentation/githooks.adoc\n+\t$(QUIET_GEN)$(SHELL_PATH) ./tools/generate-hooklist.sh . $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):\\\n \t$(localedir_SQ):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n@@ -2716,8 +2716,8 @@ GIT-SCRIPT-DEFINES: FORCE\n \t\techo \"$$FLAGS\" >$@; \\\n             fi\n \n-$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n-\t$(QUIET_GEN)./generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n+$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh tools/generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n+\t$(QUIET_GEN)./tools/generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n \tmv $@+ $@\n \n git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE\n@@ -2757,8 +2757,8 @@ endif\n \n PERL_DEFINES += $(gitexecdir) $(perllibdir) $(localedir)\n \n-$(SCRIPT_PERL_GEN): % : %.perl generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@+\" && \\\n+$(SCRIPT_PERL_GEN): % : %.perl tools/generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@+\" && \\\n \tmv $@+ $@\n \n PERL_DEFINES := $(subst $(space),:,$(PERL_DEFINES))\n@@ -2786,8 +2786,8 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile\n perllibdir:\n \t@echo '$(perllibdir_SQ)'\n \n-git-instaweb: git-instaweb.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n-\t$(QUIET_GEN)./generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n+git-instaweb: git-instaweb.sh tools/generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES\n+\t$(QUIET_GEN)./tools/generate-script.sh \"$<\" \"$@+\" ./GIT-BUILD-OPTIONS && \\\n \tchmod +x $@+ && \\\n \tmv $@+ $@\n else # NO_PERL\n@@ -2804,9 +2804,9 @@ endif # NO_PERL\n $(SCRIPT_PYTHON_GEN): GIT-BUILD-OPTIONS\n \n ifndef NO_PYTHON\n-$(SCRIPT_PYTHON_GEN): generate-python.sh\n+$(SCRIPT_PYTHON_GEN): tools/generate-python.sh\n $(SCRIPT_PYTHON_GEN): % : %.py\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-python.sh ./GIT-BUILD-OPTIONS \"$<\" \"$@\"\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-python.sh ./GIT-BUILD-OPTIONS \"$<\" \"$@\"\n else # NO_PYTHON\n $(SCRIPT_PYTHON_GEN): % : unimplemented.sh\n \t$(QUIET_GEN) \\\n@@ -3226,9 +3226,9 @@ endif\n NO_PERL_CPAN_FALLBACKS_SQ = $(subst ','\\'',$(NO_PERL_CPAN_FALLBACKS))\n endif\n \n-perl/build/lib/%.pm: perl/%.pm generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES\n+perl/build/lib/%.pm: perl/%.pm tools/generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES\n \t$(call mkdir_p_parent_template)\n-\t$(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@\"\n+\t$(QUIET_GEN)$(SHELL_PATH) tools/generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER \"$<\" \"$@\"\n \n perl/build/man/man3/Git.3pm: perl/Git.pm\n \t$(call mkdir_p_parent_template)\n@@ -3936,7 +3936,7 @@ check-docs::\n ### Make sure built-ins do not have dups and listed in git.c\n #\n check-builtins::\n-\t./check-builtins.sh\n+\t./tools/check-builtins.sh\n \n ### Test suite coverage testing\n #\ndiff --git a/config.mak.dev b/config.mak.dev\nindex e86b6e1b34..c8dcf78779 100644\n--- a/config.mak.dev\n+++ b/config.mak.dev\n@@ -1,5 +1,5 @@\n ifndef COMPILER_FEATURES\n-COMPILER_FEATURES := $(shell ./detect-compiler $(CC))\n+COMPILER_FEATURES := $(shell ./tools/detect-compiler $(CC))\n endif\n \n ifeq ($(filter no-error,$(DEVOPTS)),)\ndiff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt\nindex c6cfb874ef..81b4306e72 100644\n--- a/contrib/buildsystems/CMakeLists.txt\n+++ b/contrib/buildsystems/CMakeLists.txt\n@@ -636,7 +636,7 @@ set(EXCLUSION_PROGS_CACHE ${EXCLUSION_PROGS} CACHE STRING \"Programs not built\" F\n if(NOT EXISTS ${CMAKE_BINARY_DIR}/command-list.h OR NOT EXCLUSION_PROGS_CACHE STREQUAL EXCLUSION_PROGS)\n \tlist(REMOVE_ITEM EXCLUSION_PROGS empty)\n \tmessage(\"Generating command-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-cmdlist.sh\"\n+\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-cmdlist.sh\"\n \t\t\t\t${EXCLUSION_PROGS}\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/command-list.h\")\n@@ -644,14 +644,14 @@ endif()\n \n if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)\n \tmessage(\"Generating config-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-configlist.sh\"\n+\texecute_process(COMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-configlist.sh\"\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/config-list.h\")\n endif()\n \n if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h)\n \tmessage(\"Generating hook-list.h\")\n-\texecute_process(COMMAND \"${SH_EXE}\" ${CMAKE_SOURCE_DIR}/generate-hooklist.sh\n+\texecute_process(COMMAND \"${SH_EXE}\" ${CMAKE_SOURCE_DIR}/tools/generate-hooklist.sh\n \t\t\t\t\"${CMAKE_SOURCE_DIR}\"\n \t\t\t\t\"${CMAKE_BINARY_DIR}/hook-list.h\")\n endif()\n@@ -832,11 +832,11 @@ foreach(script ${git_shell_scripts})\n \tendif()\n \n \tadd_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/${shell_gen_path}\"\n-\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-script.sh\"\n+\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-script.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}.sh\"\n \t\t\t\"${CMAKE_BINARY_DIR}/${shell_gen_path}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n-\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-script.sh\"\n+\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-script.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}.sh\"\n \t\tVERBATIM)\n \tlist(APPEND shell_gen ${CMAKE_BINARY_DIR}/${shell_gen_path})\n@@ -875,13 +875,13 @@ foreach(script ${git_perl_scripts} ${perl_modules})\n \tfile(MAKE_DIRECTORY \"${CMAKE_BINARY_DIR}/${perl_gen_dir}\")\n \n \tadd_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/${perl_gen_path}\"\n-\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-perl.sh\"\n+\t\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-perl.sh\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-VERSION-FILE\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-PERL-HEADER\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/${perl_gen_path}\"\n-\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-perl.sh\"\n+\t\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-perl.sh\"\n \t\t\t\"${CMAKE_SOURCE_DIR}/${script}\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\t\"${CMAKE_BINARY_DIR}/GIT-VERSION-FILE\"\n@@ -892,11 +892,11 @@ add_custom_target(perl-gen ALL DEPENDS ${perl_gen})\n \n # Python script\n add_custom_command(OUTPUT \"${CMAKE_BINARY_DIR}/git-p4\"\n-\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/generate-python.sh\"\n+\tCOMMAND \"${SH_EXE}\" \"${CMAKE_SOURCE_DIR}/tools/generate-python.sh\"\n \t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \t\t\"${CMAKE_SOURCE_DIR}/git-p4.py\"\n \t\t\"${CMAKE_BINARY_DIR}/git-p4\"\n-\tDEPENDS \"${CMAKE_SOURCE_DIR}/generate-python.sh\"\n+\tDEPENDS \"${CMAKE_SOURCE_DIR}/tools/generate-python.sh\"\n \t\t\"${CMAKE_SOURCE_DIR}/git-p4.py\"\n \t\t\"${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS\"\n \tVERBATIM)\ndiff --git a/contrib/subtree/meson.build b/contrib/subtree/meson.build\nindex 161435abeb..804c315894 100644\n--- a/contrib/subtree/meson.build\n+++ b/contrib/subtree/meson.build\n@@ -3,7 +3,7 @@ git_subtree = custom_target(\n   output: 'git-subtree',\n   command: [\n     shell,\n-    meson.project_source_root() / 'generate-script.sh',\n+    meson.project_source_root() / 'tools/generate-script.sh',\n     '@INPUT@',\n     '@OUTPUT@',\n     meson.project_build_root() / 'GIT-BUILD-OPTIONS',\ndiff --git a/meson.build b/meson.build\nindex 1d66b5181e..604fe89d2d 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -554,7 +554,7 @@ libgit_sources = [\n libgit_sources += custom_target(\n   input: 'command-list.txt',\n   output: 'command-list.h',\n-  command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],\n+  command: [shell, meson.current_source_dir() + '/tools/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],\n   env: script_environment,\n )\n \n@@ -723,10 +723,10 @@ endif\n builtin_sources += custom_target(\n   output: 'config-list.h',\n   depfile: 'config-list.h.d',\n-  depend_files: [ 'generate-configlist.sh' ],\n+  depend_files: [ 'tools/generate-configlist.sh' ],\n   command: [\n     shell,\n-    meson.current_source_dir() / 'generate-configlist.sh',\n+    meson.current_source_dir() / 'tools/generate-configlist.sh',\n     meson.current_source_dir(),\n     '@OUTPUT@',\n     '@DEPFILE@',\n@@ -739,7 +739,7 @@ builtin_sources += custom_target(\n   output: 'hook-list.h',\n   command: [\n     shell,\n-    meson.current_source_dir() + '/generate-hooklist.sh',\n+    meson.current_source_dir() + '/tools/generate-hooklist.sh',\n     meson.current_source_dir(),\n     '@OUTPUT@',\n   ],\n@@ -1959,7 +1959,7 @@ foreach script : scripts_sh\n     output: fs.stem(script),\n     command: [\n       shell,\n-      meson.project_source_root() / 'generate-script.sh',\n+      meson.project_source_root() / 'tools/generate-script.sh',\n       '@INPUT@',\n       '@OUTPUT@',\n       meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n@@ -2008,7 +2008,7 @@ if perl_features_enabled\n \n   generate_perl_command = [\n     shell,\n-    meson.project_source_root() / 'generate-perl.sh',\n+    meson.project_source_root() / 'tools/generate-perl.sh',\n     meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n     git_version_file.full_path(),\n     perl_header,\n@@ -2057,7 +2057,7 @@ if target_python.found()\n       output: fs.stem(script),\n       command: [\n         shell,\n-        meson.project_source_root() / 'generate-python.sh',\n+        meson.project_source_root() / 'tools/generate-python.sh',\n         meson.project_build_root() / 'GIT-BUILD-OPTIONS',\n         '@INPUT@',\n         '@OUTPUT@',\ndiff --git a/check-builtins.sh b/tools/check-builtins.sh\nsimilarity index 100%\nrename from check-builtins.sh\nrename to tools/check-builtins.sh\ndiff --git a/detect-compiler b/tools/detect-compiler\nsimilarity index 100%\nrename from detect-compiler\nrename to tools/detect-compiler\ndiff --git a/generate-cmdlist.sh b/tools/generate-cmdlist.sh\nsimilarity index 100%\nrename from generate-cmdlist.sh\nrename to tools/generate-cmdlist.sh\ndiff --git a/generate-configlist.sh b/tools/generate-configlist.sh\nsimilarity index 100%\nrename from generate-configlist.sh\nrename to tools/generate-configlist.sh\ndiff --git a/generate-hooklist.sh b/tools/generate-hooklist.sh\nsimilarity index 100%\nrename from generate-hooklist.sh\nrename to tools/generate-hooklist.sh\ndiff --git a/generate-perl.sh b/tools/generate-perl.sh\nsimilarity index 100%\nrename from generate-perl.sh\nrename to tools/generate-perl.sh\ndiff --git a/generate-python.sh b/tools/generate-python.sh\nsimilarity index 100%\nrename from generate-python.sh\nrename to tools/generate-python.sh\ndiff --git a/generate-script.sh b/tools/generate-script.sh\nsimilarity index 100%\nrename from generate-script.sh\nrename to tools/generate-script.sh\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539348","messageId":"20260319-b4-pks-build-infra-improvements-v3-6-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","subject":"[PATCH v3 6/8] git-compat-util.h: move warning infra to prepare for PCHs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:25Z","receivedAt":"2026-03-19T05:33:42Z","isPatch":true,"body":"The \"git-compat-util.h\" header is supposed to be the first header\nincluded by every code compilation unit. As such, a subsequent commit\nwill start to precompile this header to speed up compilation of Git.\n\nThis will cause an issue though with the way that we have set up the\n\"-Wsign-compare\" warnings. It is expected that any compilation unit that\nfails with that compiler warning sets `DISABLE_SIGN_COMPARE_WARNINGS`\nbefore including \"git-compat-util.h\". If so, we'll disable the warning\nright away via a compiler pragma.\n\nBut with precompiled headers we do not know ahead of time whether the\ncode unit wants to disable those warnings, and thus we'll have to\nprecompile the header without defining `DISABLE_SIGN_COMPARE_WARNINGS`.\nBut as the pragma statement is wrapped by our include guards, the second\ninclude of that file will not have the desired effect of disabling the\nwarnings anymore.\n\nWe could fix this issue by declaring a new macro that compilation units\nare expected to invoke after having included the file. In retrospect,\nthat would have been the better way to handle this as it allows for\nmore flexibility: we could for example toggle the warning for specific\ncode blocks, only. But changing this now would require a bunch of\nchanges, and the churn feels excessive for what we gain.\n\nInstead, prepare for the precompiled headers by moving the code outside\nof the include guards.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n git-compat-util.h | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex bebcf9f698..4b4ea2498f 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -34,10 +34,6 @@ struct strbuf;\n #  define DISABLE_WARNING(warning)\n #endif\n \n-#ifdef DISABLE_SIGN_COMPARE_WARNINGS\n-DISABLE_WARNING(-Wsign-compare)\n-#endif\n-\n #undef FLEX_ARRAY\n #define FLEX_ARRAY /* empty - weather balloon to require C99 FAM */\n \n@@ -1099,3 +1095,7 @@ extern int not_supposed_to_survive;\n #endif /* CHECK_ASSERTION_SIDE_EFFECTS */\n \n #endif\n+\n+#ifdef DISABLE_SIGN_COMPARE_WARNINGS\n+DISABLE_WARNING(-Wsign-compare)\n+#endif\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539349","messageId":"20260319-b4-pks-build-infra-improvements-v3-7-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","subject":"[PATCH v3 7/8] meson: compile compatibility sources separately","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:26Z","receivedAt":"2026-03-19T05:33:45Z","isPatch":true,"body":"In the next commit we're about to introduce a precompiled header for\n\"git-compat-util.h\". The consequence of this change is that we'll\nimplicitly include that header for every compilation unit that uses the\nprecompiled headers.\n\nThis is okay for our \"normal\" library sources and our builtins. But some\nof our compatibility sources do not include the header on purpose, and\ndoing so would cause compilation errors.\n\nPrepare for this change by splitting out compatibility sources into\ntheir static library. Like this, we can selectively enable precompiled\nheaders for the library sources.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 79 +++++++++++++++++++++++++++++++++++--------------------------\n 1 file changed, 45 insertions(+), 34 deletions(-)\n\ndiff --git a/meson.build b/meson.build\nindex 604fe89d2d..cd00be1c23 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -271,6 +271,13 @@ version_gen_environment.set('GIT_VERSION', get_option('version'))\n \n compiler = meson.get_compiler('c')\n \n+compat_sources = [\n+  'compat/nonblock.c',\n+  'compat/obstack.c',\n+  'compat/open.c',\n+  'compat/terminal.c',\n+]\n+\n libgit_sources = [\n   'abspath.c',\n   'add-interactive.c',\n@@ -304,10 +311,6 @@ libgit_sources = [\n   'commit.c',\n   'common-exit.c',\n   'common-init.c',\n-  'compat/nonblock.c',\n-  'compat/obstack.c',\n-  'compat/open.c',\n-  'compat/terminal.c',\n   'compiler-tricks/not-constant.c',\n   'config.c',\n   'connect.c',\n@@ -1163,7 +1166,7 @@ endif\n \n if not has_poll_h and not has_sys_poll_h\n   libgit_c_args += '-DNO_POLL'\n-  libgit_sources += 'compat/poll/poll.c'\n+  compat_sources += 'compat/poll/poll.c'\n   libgit_include_directories += 'compat/poll'\n endif\n \n@@ -1179,7 +1182,7 @@ endif\n # implementation to threat things like drive prefixes specially.\n if host_machine.system() == 'windows' or not compiler.has_header('libgen.h')\n   libgit_c_args += '-DNO_LIBGEN_H'\n-  libgit_sources += 'compat/basename.c'\n+  compat_sources += 'compat/basename.c'\n endif\n \n if compiler.has_header('paths.h')\n@@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'\n   foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']\n     if not compiler.has_function(symbol, dependencies: networking_dependencies)\n       libgit_c_args += '-DNO_' + symbol.to_upper()\n-      libgit_sources += 'compat/' + symbol + '.c'\n+      compat_sources += 'compat/' + symbol + '.c'\n     endif\n   endforeach\n endif\n@@ -1251,18 +1254,18 @@ else\n endif\n \n if host_machine.system() == 'darwin'\n-  libgit_sources += 'compat/precompose_utf8.c'\n+  compat_sources += 'compat/precompose_utf8.c'\n   libgit_c_args += '-DPRECOMPOSE_UNICODE'\n   libgit_c_args += '-DPROTECT_HFS_DEFAULT'\n endif\n \n # Configure general compatibility wrappers.\n if host_machine.system() == 'cygwin'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/win32/path-utils.c',\n   ]\n elif host_machine.system() == 'windows'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/winansi.c',\n     'compat/win32/dirent.c',\n     'compat/win32/flush.c',\n@@ -1289,20 +1292,20 @@ elif host_machine.system() == 'windows'\n   libgit_include_directories += 'compat/win32'\n   if compiler.get_id() == 'msvc'\n     libgit_include_directories += 'compat/vcbuild/include'\n-    libgit_sources += 'compat/msvc.c'\n+    compat_sources += 'compat/msvc.c'\n   else\n-    libgit_sources += 'compat/mingw.c'\n+    compat_sources += 'compat/mingw.c'\n   endif\n endif\n \n if host_machine.system() == 'linux'\n-  libgit_sources += 'compat/linux/procinfo.c'\n+  compat_sources += 'compat/linux/procinfo.c'\n elif host_machine.system() == 'windows'\n-  libgit_sources += 'compat/win32/trace2_win32_process_info.c'\n+  compat_sources += 'compat/win32/trace2_win32_process_info.c'\n elif host_machine.system() == 'darwin'\n-  libgit_sources += 'compat/darwin/procinfo.c'\n+  compat_sources += 'compat/darwin/procinfo.c'\n else\n-  libgit_sources += 'compat/stub/procinfo.c'\n+  compat_sources += 'compat/stub/procinfo.c'\n endif\n \n if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'\n@@ -1315,13 +1318,13 @@ endif\n \n # Configure the simple-ipc subsystem required fro the fsmonitor.\n if host_machine.system() == 'windows'\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/simple-ipc/ipc-shared.c',\n     'compat/simple-ipc/ipc-win32.c',\n   ]\n   libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'\n else\n-  libgit_sources += [\n+  compat_sources += [\n     'compat/simple-ipc/ipc-shared.c',\n     'compat/simple-ipc/ipc-unix-socket.c',\n   ]\n@@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''\n   libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND'\n   libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'\n \n-  libgit_sources += [\n+  compat_sources += [\n     'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',\n     'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',\n     'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',\n@@ -1355,7 +1358,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').allo\n \n   if compiler.get_define('REG_ENHANCED', prefix: '#include <regex.h>') != ''\n     libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'\n-    libgit_sources += 'compat/regcomp_enhanced.c'\n+    compat_sources += 'compat/regcomp_enhanced.c'\n   endif\n elif not get_option('regex').enabled()\n   libgit_c_args += [\n@@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()\n     '-DNO_MBSUPPORT',\n   ]\n   build_options_config.set('NO_REGEX', '1')\n-  libgit_sources += 'compat/regex/regex.c'\n+  compat_sources += 'compat/regex/regex.c'\n   libgit_include_directories += 'compat/regex'\n else\n     error('Native regex support requested but not found')\n@@ -1428,7 +1431,7 @@ else\n \n   if get_option('b_sanitize').contains('address')\n     libgit_c_args += '-DNO_MMAP'\n-    libgit_sources += 'compat/mmap.c'\n+    compat_sources += 'compat/mmap.c'\n   else\n     checkfuncs += { 'mmap': ['mmap.c'] }\n   endif\n@@ -1438,7 +1441,7 @@ foreach func, impls : checkfuncs\n   if not compiler.has_function(func)\n     libgit_c_args += '-DNO_' + func.to_upper()\n     foreach impl : impls\n-      libgit_sources += 'compat/' + impl\n+      compat_sources += 'compat/' + impl\n     endforeach\n   endif\n endforeach\n@@ -1449,13 +1452,13 @@ endif\n \n if not compiler.has_function('strdup')\n   libgit_c_args += '-DOVERRIDE_STRDUP'\n-  libgit_sources += 'compat/strdup.c'\n+  compat_sources += 'compat/strdup.c'\n endif\n \n if not compiler.has_function('qsort')\n   libgit_c_args += '-DINTERNAL_QSORT'\n endif\n-libgit_sources += 'compat/qsort_s.c'\n+compat_sources += 'compat/qsort_s.c'\n \n if compiler.has_function('getdelim')\n   libgit_c_args += '-DHAVE_GETDELIM'\n@@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and compiler.run('''\n   }\n ''', name: 'fread reads directories').returncode() == 0\n   libgit_c_args += '-DFREAD_READS_DIRECTORIES'\n-  libgit_sources += 'compat/fopen.c'\n+  compat_sources += 'compat/fopen.c'\n endif\n \n if not meson.is_cross_build() and fs.exists('/dev/tty')\n@@ -1745,14 +1748,22 @@ else\n endif\n \n libgit = declare_dependency(\n-  link_with: static_library('git',\n-    sources: libgit_sources,\n-    c_args: libgit_c_args + [\n-      '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n-    ],\n-    dependencies: libgit_dependencies,\n-    include_directories: libgit_include_directories,\n-  ),\n+  link_with: [\n+    static_library('compat',\n+      sources: compat_sources,\n+      c_args: libgit_c_args,\n+      dependencies: libgit_dependencies,\n+      include_directories: libgit_include_directories,\n+    ),\n+    static_library('git',\n+      sources: libgit_sources,\n+      c_args: libgit_c_args + [\n+        '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n+      ],\n+      dependencies: libgit_dependencies,\n+      include_directories: libgit_include_directories,\n+    ),\n+  ],\n   compile_args: libgit_c_args,\n   dependencies: libgit_dependencies,\n   include_directories: libgit_include_directories,\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539350","messageId":"20260319-b4-pks-build-infra-improvements-v3-8-82f5fb3edc3f@pks.im","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-0-82f5fb3edc3f@pks.im","subject":"[PATCH v3 8/8] meson: precompile \"git-compat-util.h\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-19T05:33:27Z","receivedAt":"2026-03-19T05:33:47Z","isPatch":true,"body":"Every compilation unit in Git is expected to include \"git-compat-util.h\"\nfirst, either directly or indirectly via \"builtin.h\". This header papers\nover differences between platforms so that we can expect the typical\nPOSIX functions to exist. Furthermore, it provides functionality that we\nend up using everywhere.\n\nThis header is thus quite heavy as a consequence. Preprocessing it as a\nstandalone unit via `clang -E git-compat-util.h` yields over 23,000\nlines of code overall. Naturally, it takes quite some time to compile\nall of this.\n\nLuckily, this is exactly the kind of use case that precompiled headers\naim to solve: instead of recompiling it every single time, we compile it\nonce and then link the result into the executable. If include guards are\nset up properly it means that the file won't need to be reprocessed.\n\nSet up such a precompiled header for \"git-compat-util.h\" and wire it up\nvia Meson. This causes Meson to implicitly include the precompiled\nheader in all compilation units. With GCC and Clang for example this is\ndone via the \"-include\" statement [1].\n\nThis leads to a significant speedup when performing full builds:\n\n  Benchmark 1: ninja (rev = HEAD~)\n  Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n  Range (min … max):   14.195 s … 14.633 s    10 runs\n\n  Benchmark 2: ninja (rev = HEAD)\n    Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n    Range (min … max):   10.030 s … 10.433 s    10 runs\n\n  Summary\n    ninja (rev = HEAD) ran\n      1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n\n[1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build         | 2 ++\n tools/precompiled.h | 1 +\n 2 files changed, 3 insertions(+)\n\ndiff --git a/meson.build b/meson.build\nindex cd00be1c23..2002f4795e 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1760,6 +1760,7 @@ libgit = declare_dependency(\n       c_args: libgit_c_args + [\n         '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n       ],\n+      c_pch: 'tools/precompiled.h',\n       dependencies: libgit_dependencies,\n       include_directories: libgit_include_directories,\n     ),\n@@ -1820,6 +1821,7 @@ test_dependencies = [ ]\n \n git_builtin = executable('git',\n   sources: builtin_sources + 'git.c',\n+  c_pch: 'tools/precompiled.h',\n   dependencies: [libgit_commonmain],\n   install: true,\n   install_dir: git_exec_path,\ndiff --git a/tools/precompiled.h b/tools/precompiled.h\nnew file mode 100644\nindex 0000000000..b2bec0d2b4\n--- /dev/null\n+++ b/tools/precompiled.h\n@@ -0,0 +1 @@\n+#include \"git-compat-util.h\"\n\n-- \n2.53.0.959.g497ff81fa9.dirty\n\n"},{"id":"539540","messageId":"87341u3dee.fsf@iotcl.com","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-3-82f5fb3edc3f@pks.im","subject":"Re: [PATCH v3 3/8] contrib: move \"coverage-diff.sh\" script into \"tools/\"","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2026-03-20T12:15:37Z","receivedAt":"2026-03-20T12:15:44Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The \"coverage-diff.sh\" script can be used to get information about test\n> coverage fro the Git codebase. It is thus rather specific to our build\n\nTiniest nit s/fro/for\n\n> and test infrastructure and part of the developer-facing tooling. The\n> fact that this script is part of \"contrib/\" is thus rather misleading\n> and a historic wart.\n>\n> Promote the tool into the new \"tools/\" directory.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  {contrib => tools}/coverage-diff.sh | 0\n>  1 file changed, 0 insertions(+), 0 deletions(-)\n>\n> diff --git a/contrib/coverage-diff.sh b/tools/coverage-diff.sh\n> similarity index 100%\n> rename from contrib/coverage-diff.sh\n> rename to tools/coverage-diff.sh\n>\n> -- \n> 2.53.0.959.g497ff81fa9.dirty\n>\n>\n\n-- \nCheers,\nToon\n"},{"id":"539541","messageId":"87y0jm1xxx.fsf@iotcl.com","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-6-82f5fb3edc3f@pks.im","subject":"Re: [PATCH v3 6/8] git-compat-util.h: move warning infra to prepare for PCHs","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2026-03-20T12:34:50Z","receivedAt":"2026-03-20T12:34:57Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The \"git-compat-util.h\" header is supposed to be the first header\n> included by every code compilation unit. As such, a subsequent commit\n> will start to precompile this header to speed up compilation of Git.\n>\n> This will cause an issue though with the way that we have set up the\n> \"-Wsign-compare\" warnings. It is expected that any compilation unit that\n> fails with that compiler warning sets `DISABLE_SIGN_COMPARE_WARNINGS`\n> before including \"git-compat-util.h\". If so, we'll disable the warning\n> right away via a compiler pragma.\n>\n> But with precompiled headers we do not know ahead of time whether the\n> code unit wants to disable those warnings, and thus we'll have to\n> precompile the header without defining `DISABLE_SIGN_COMPARE_WARNINGS`.\n> But as the pragma statement is wrapped by our include guards, the second\n> include of that file will not have the desired effect of disabling the\n> warnings anymore.\n>\n> We could fix this issue by declaring a new macro that compilation units\n> are expected to invoke after having included the file. In retrospect,\n> that would have been the better way to handle this as it allows for\n> more flexibility: we could for example toggle the warning for specific\n> code blocks, only. But changing this now would require a bunch of\n> changes, and the churn feels excessive for what we gain.\n>\n> Instead, prepare for the precompiled headers by moving the code outside\n> of the include guards.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  git-compat-util.h | 8 ++++----\n>  1 file changed, 4 insertions(+), 4 deletions(-)\n>\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index bebcf9f698..4b4ea2498f 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -34,10 +34,6 @@ struct strbuf;\n>  #  define DISABLE_WARNING(warning)\n>  #endif\n>  \n> -#ifdef DISABLE_SIGN_COMPARE_WARNINGS\n> -DISABLE_WARNING(-Wsign-compare)\n> -#endif\n> -\n>  #undef FLEX_ARRAY\n>  #define FLEX_ARRAY /* empty - weather balloon to require C99 FAM */\n>  \n> @@ -1099,3 +1095,7 @@ extern int not_supposed_to_survive;\n>  #endif /* CHECK_ASSERTION_SIDE_EFFECTS */\n>  \n>  #endif\n> +\n> +#ifdef DISABLE_SIGN_COMPARE_WARNINGS\n> +DISABLE_WARNING(-Wsign-compare)\n> +#endif\n\nOkay, so with all patches applied, when a .c file is compiled,\ntools/precompiled.h is included as the first one. That one includes\ngit-compat-util.h and processes everything inside the include guards.\nThen it starts processing the contents of that files and that file might\n#define DISABLE_SIGN_COMPARE_WARNINGS. Usually git-compat-util.h is then\nincluded again, but thanks to the include guards, most of it is ignored,\nexcept for this last bit.\n\nOkay, makes sense.\n\n-- \nCheers,\nToon\n"},{"id":"539542","messageId":"87v7eq1xu6.fsf@iotcl.com","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-8-82f5fb3edc3f@pks.im","subject":"Re: [PATCH v3 8/8] meson: precompile \"git-compat-util.h\"","fromName":"Toon Claes","fromEmail":"toon@iotcl.com","sentAt":"2026-03-20T12:37:05Z","receivedAt":"2026-03-20T12:37:13Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Every compilation unit in Git is expected to include \"git-compat-util.h\"\n> first, either directly or indirectly via \"builtin.h\". This header papers\n> over differences between platforms so that we can expect the typical\n> POSIX functions to exist. Furthermore, it provides functionality that we\n> end up using everywhere.\n>\n> This header is thus quite heavy as a consequence. Preprocessing it as a\n> standalone unit via `clang -E git-compat-util.h` yields over 23,000\n> lines of code overall. Naturally, it takes quite some time to compile\n> all of this.\n>\n> Luckily, this is exactly the kind of use case that precompiled headers\n> aim to solve: instead of recompiling it every single time, we compile it\n> once and then link the result into the executable. If include guards are\n> set up properly it means that the file won't need to be reprocessed.\n>\n> Set up such a precompiled header for \"git-compat-util.h\" and wire it up\n> via Meson. This causes Meson to implicitly include the precompiled\n> header in all compilation units. With GCC and Clang for example this is\n> done via the \"-include\" statement [1].\n>\n> This leads to a significant speedup when performing full builds:\n>\n>   Benchmark 1: ninja (rev = HEAD~)\n>   Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n>   Range (min … max):   14.195 s … 14.633 s    10 runs\n>\n>   Benchmark 2: ninja (rev = HEAD)\n>     Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n>     Range (min … max):   10.030 s … 10.433 s    10 runs\n>\n>   Summary\n>     ninja (rev = HEAD) ran\n>       1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n>\n\nQuite cool! The only nit I would have about this, this optimization is\nnot applied to building with Makefiles. While that isn't an issue, I\nwouldn't have hurt if it was mentioned in the commit message.\n\nAnyway, overall I got nothing that's holding back this series from\nmerging. Looks good!\n\n-- \nCheers,\nToon\n"},{"id":"541376","messageId":"adkUms2ee8aKIdAB@szeder.dev","threadId":"65200","inReplyTo":"abJbhQwc-X0T6S_B@pks.im","subject":"Re: [PATCH 7/8] meson: compile compatibility sources separately","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2026-04-10T15:17:46Z","receivedAt":"2026-04-10T15:17:49Z","isPatch":true,"body":"On Thu, Mar 12, 2026 at 07:21:57AM +0100, Patrick Steinhardt wrote:\n> On Thu, Mar 12, 2026 at 12:27:49AM +0100, SZEDER Gábor wrote:\n> > On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:\n> > > On 11/03/2026 14:32, Phillip Wood wrote:\n> > > > On 10/03/2026 17:52, Patrick Steinhardt wrote:\n> > > > > In the next commit we're about to introduce a precompiled header for\n> > > > > \"git-compat-util.h\". The consequence of this change is that we'll\n> > > > > implicitly include that header for every compilation unit that uses the\n> > > > > precompiled headers.\n> > > > \n> > > > Is that a meson thing? I know it defines precompiled headers on a per-\n> > > > target basis but does it somehow force each source file to include the\n> > > > precompiled header? Looking at the gcc documentation it seems like the\n> > > > precompiled header is only included where the original header is\n> > > > included.\n> > > \n> > > Answering my own question the precompiled header is included via \"-include\"\n> > > on the commandline. This is necessary in the general case because a\n> > > precompiled header cannot be used once the first C token is seen.\n> > > \n> > > As an aside in git we could probably get away without using \"-include\"\n> > > because if we include \"git-compat-util.h\" it is always the first thing we\n> > > do, or we inculde another file like \"builtin.h\" which immediately includes\n> > > \"git-compat-util.h\" and so it is included before the first C token is seen.\n> > \n> > I couldn't find this in the GCC docs, but Make's documentation states\n> > that \"you cannot include a precompiled header from inside another\n> > header.\" [1]\n> \n> I think you must have confused something, because the link _does_ point\n> to GCC's documentation, which does contain the quote.\n\nIndeed.  I wanted to say that I couldn't find this in the GCC *man\npage*...  And then mixed up which documentation site I was looking at,\nas they very much look alike.\n\n> But yes, overall there can only be one precompiled header, and it cannot\n> be used after the first token indeed. The use of \"-include\" is also\n> explicitly noted for \"projects not designed with precompiled headers in\n> mind\", which fits Git. After all, we still have the ability to compile\n> without precompiled headers, and I don't expect that to go away.\n> \n> Patrick\n> \n> > [1] Second bullet point at:\n> >     https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n"},{"id":"541377","messageId":"adkZGavssyxWj27a@szeder.dev","threadId":"65200","inReplyTo":"20260319-b4-pks-build-infra-improvements-v3-8-82f5fb3edc3f@pks.im","subject":"Re: [PATCH v3 8/8] meson: precompile \"git-compat-util.h\"","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2026-04-10T15:36:57Z","receivedAt":"2026-04-10T15:37:00Z","isPatch":true,"body":"On Thu, Mar 19, 2026 at 06:33:27AM +0100, Patrick Steinhardt wrote:\n> Every compilation unit in Git is expected to include \"git-compat-util.h\"\n> first, either directly or indirectly via \"builtin.h\". This header papers\n> over differences between platforms so that we can expect the typical\n> POSIX functions to exist. Furthermore, it provides functionality that we\n> end up using everywhere.\n> \n> This header is thus quite heavy as a consequence. Preprocessing it as a\n> standalone unit via `clang -E git-compat-util.h` yields over 23,000\n> lines of code overall. Naturally, it takes quite some time to compile\n> all of this.\n> \n> Luckily, this is exactly the kind of use case that precompiled headers\n> aim to solve: instead of recompiling it every single time, we compile it\n> once and then link the result into the executable. If include guards are\n> set up properly it means that the file won't need to be reprocessed.\n> \n> Set up such a precompiled header for \"git-compat-util.h\" and wire it up\n> via Meson. This causes Meson to implicitly include the precompiled\n> header in all compilation units. With GCC and Clang for example this is\n> done via the \"-include\" statement [1].\n> \n> This leads to a significant speedup when performing full builds:\n> \n>   Benchmark 1: ninja (rev = HEAD~)\n>   Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n>   Range (min … max):   14.195 s … 14.633 s    10 runs\n> \n>   Benchmark 2: ninja (rev = HEAD)\n>     Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n>     Range (min … max):   10.030 s … 10.433 s    10 runs\n> \n>   Summary\n>     ninja (rev = HEAD) ran\n>       1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n> \n> [1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n> \n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  meson.build         | 2 ++\n>  tools/precompiled.h | 1 +\n>  2 files changed, 3 insertions(+)\n> \n> diff --git a/meson.build b/meson.build\n> index cd00be1c23..2002f4795e 100644\n> --- a/meson.build\n> +++ b/meson.build\n> @@ -1760,6 +1760,7 @@ libgit = declare_dependency(\n>        c_args: libgit_c_args + [\n>          '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n>        ],\n> +      c_pch: 'tools/precompiled.h',\n>        dependencies: libgit_dependencies,\n>        include_directories: libgit_include_directories,\n>      ),\n\nWell, I don't do meson, but...\n\nIf I understand this right, this section here compiles all the source\nfiles listed in \"libgit_sources\" using our new precompiled header.\nBut \"libgit_sources\" contains all source files under \"reftable/\",\nwhich, with the sole exception of \"reftable/system.c\", don't include\n\"git-compat-util.h\".\n\nNow, building the reftable sources with \"git-compat-util.h\" included\nthrough the precompiled header apparently didn't cause any compilation\nerrors...\nBut I think that's just accidental, and if a source file doesn't\ninclude \"git-compat-util.h\", then it shouldn't be compiled with the\nprecompiled header.\n\n\n> @@ -1820,6 +1821,7 @@ test_dependencies = [ ]\n>  \n>  git_builtin = executable('git',\n>    sources: builtin_sources + 'git.c',\n> +  c_pch: 'tools/precompiled.h',\n>    dependencies: [libgit_commonmain],\n>    install: true,\n>    install_dir: git_exec_path,\n> diff --git a/tools/precompiled.h b/tools/precompiled.h\n> new file mode 100644\n> index 0000000000..b2bec0d2b4\n> --- /dev/null\n> +++ b/tools/precompiled.h\n> @@ -0,0 +1 @@\n> +#include \"git-compat-util.h\"\n> \n> -- \n> 2.53.0.959.g497ff81fa9.dirty\n> \n"},{"id":"541382","messageId":"0b67d2fb-3041-4fed-9002-44b7b2e7ecd3@gmail.com","threadId":"65200","inReplyTo":"adkZGavssyxWj27a@szeder.dev","subject":"Re: [PATCH v3 8/8] meson: precompile \"git-compat-util.h\"","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-04-10T15:46:43Z","receivedAt":"2026-04-10T15:46:46Z","isPatch":true,"body":"\n\nOn 10/04/2026 16:36, SZEDER Gábor wrote:\n> On Thu, Mar 19, 2026 at 06:33:27AM +0100, Patrick Steinhardt wrote:\n>> Every compilation unit in Git is expected to include \"git-compat-util.h\"\n>> first, either directly or indirectly via \"builtin.h\". This header papers\n>> over differences between platforms so that we can expect the typical\n>> POSIX functions to exist. Furthermore, it provides functionality that we\n>> end up using everywhere.\n>>\n>> This header is thus quite heavy as a consequence. Preprocessing it as a\n>> standalone unit via `clang -E git-compat-util.h` yields over 23,000\n>> lines of code overall. Naturally, it takes quite some time to compile\n>> all of this.\n>>\n>> Luckily, this is exactly the kind of use case that precompiled headers\n>> aim to solve: instead of recompiling it every single time, we compile it\n>> once and then link the result into the executable. If include guards are\n>> set up properly it means that the file won't need to be reprocessed.\n>>\n>> Set up such a precompiled header for \"git-compat-util.h\" and wire it up\n>> via Meson. This causes Meson to implicitly include the precompiled\n>> header in all compilation units. With GCC and Clang for example this is\n>> done via the \"-include\" statement [1].\n>>\n>> This leads to a significant speedup when performing full builds:\n>>\n>>    Benchmark 1: ninja (rev = HEAD~)\n>>    Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n>>    Range (min … max):   14.195 s … 14.633 s    10 runs\n>>\n>>    Benchmark 2: ninja (rev = HEAD)\n>>      Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n>>      Range (min … max):   10.030 s … 10.433 s    10 runs\n>>\n>>    Summary\n>>      ninja (rev = HEAD) ran\n>>        1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n>>\n>> [1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n>>\n>> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n>> ---\n>>   meson.build         | 2 ++\n>>   tools/precompiled.h | 1 +\n>>   2 files changed, 3 insertions(+)\n>>\n>> diff --git a/meson.build b/meson.build\n>> index cd00be1c23..2002f4795e 100644\n>> --- a/meson.build\n>> +++ b/meson.build\n>> @@ -1760,6 +1760,7 @@ libgit = declare_dependency(\n>>         c_args: libgit_c_args + [\n>>           '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n>>         ],\n>> +      c_pch: 'tools/precompiled.h',\n>>         dependencies: libgit_dependencies,\n>>         include_directories: libgit_include_directories,\n>>       ),\n> \n> Well, I don't do meson, but...\n> \n> If I understand this right, this section here compiles all the source\n> files listed in \"libgit_sources\" using our new precompiled header.\n> But \"libgit_sources\" contains all source files under \"reftable/\",\n> which, with the sole exception of \"reftable/system.c\", don't include\n> \"git-compat-util.h\".\n> \n> Now, building the reftable sources with \"git-compat-util.h\" included\n> through the precompiled header apparently didn't cause any compilation\n> errors...\n> But I think that's just accidental, and if a source file doesn't\n> include \"git-compat-util.h\", then it shouldn't be compiled with the\n> precompiled header.\n\nFWIW I agree it would be better to keep the same includes when building \nwith precompiled headers. There is some discussion about this starting \nat \nhttps://lore.kernel.org/git/2fe87868-dff5-4b3a-95e3-d4b6376b59ed@gmail.com/\n\nThanks\n\nPhillip\n\n> \n>> @@ -1820,6 +1821,7 @@ test_dependencies = [ ]\n>>   \n>>   git_builtin = executable('git',\n>>     sources: builtin_sources + 'git.c',\n>> +  c_pch: 'tools/precompiled.h',\n>>     dependencies: [libgit_commonmain],\n>>     install: true,\n>>     install_dir: git_exec_path,\n>> diff --git a/tools/precompiled.h b/tools/precompiled.h\n>> new file mode 100644\n>> index 0000000000..b2bec0d2b4\n>> --- /dev/null\n>> +++ b/tools/precompiled.h\n>> @@ -0,0 +1 @@\n>> +#include \"git-compat-util.h\"\n>>\n>> -- \n>> 2.53.0.959.g497ff81fa9.dirty\n>>\n\n"},{"id":"541385","messageId":"adkfy4OgGKlJnd5c@szeder.dev","threadId":"65200","inReplyTo":"0b67d2fb-3041-4fed-9002-44b7b2e7ecd3@gmail.com","subject":"Re: [PATCH v3 8/8] meson: precompile \"git-compat-util.h\"","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2026-04-10T16:05:31Z","receivedAt":"2026-04-10T16:05:34Z","isPatch":true,"body":"On Fri, Apr 10, 2026 at 04:46:43PM +0100, Phillip Wood wrote:\n> \n> \n> On 10/04/2026 16:36, SZEDER Gábor wrote:\n> > On Thu, Mar 19, 2026 at 06:33:27AM +0100, Patrick Steinhardt wrote:\n> > > Every compilation unit in Git is expected to include \"git-compat-util.h\"\n> > > first, either directly or indirectly via \"builtin.h\". This header papers\n> > > over differences between platforms so that we can expect the typical\n> > > POSIX functions to exist. Furthermore, it provides functionality that we\n> > > end up using everywhere.\n> > > \n> > > This header is thus quite heavy as a consequence. Preprocessing it as a\n> > > standalone unit via `clang -E git-compat-util.h` yields over 23,000\n> > > lines of code overall. Naturally, it takes quite some time to compile\n> > > all of this.\n> > > \n> > > Luckily, this is exactly the kind of use case that precompiled headers\n> > > aim to solve: instead of recompiling it every single time, we compile it\n> > > once and then link the result into the executable. If include guards are\n> > > set up properly it means that the file won't need to be reprocessed.\n> > > \n> > > Set up such a precompiled header for \"git-compat-util.h\" and wire it up\n> > > via Meson. This causes Meson to implicitly include the precompiled\n> > > header in all compilation units. With GCC and Clang for example this is\n> > > done via the \"-include\" statement [1].\n> > > \n> > > This leads to a significant speedup when performing full builds:\n> > > \n> > >    Benchmark 1: ninja (rev = HEAD~)\n> > >    Time (mean ± σ):     14.467 s ±  0.126 s    [User: 248.133 s, System: 31.298 s]\n> > >    Range (min … max):   14.195 s … 14.633 s    10 runs\n> > > \n> > >    Benchmark 2: ninja (rev = HEAD)\n> > >      Time (mean ± σ):     10.307 s ±  0.111 s    [User: 173.290 s, System: 23.998 s]\n> > >      Range (min … max):   10.030 s … 10.433 s    10 runs\n> > > \n> > >    Summary\n> > >      ninja (rev = HEAD) ran\n> > >        1.40 ± 0.02 times faster than ninja (rev = HEAD~)\n> > > \n> > > [1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html\n> > > \n> > > Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> > > ---\n> > >   meson.build         | 2 ++\n> > >   tools/precompiled.h | 1 +\n> > >   2 files changed, 3 insertions(+)\n> > > \n> > > diff --git a/meson.build b/meson.build\n> > > index cd00be1c23..2002f4795e 100644\n> > > --- a/meson.build\n> > > +++ b/meson.build\n> > > @@ -1760,6 +1760,7 @@ libgit = declare_dependency(\n> > >         c_args: libgit_c_args + [\n> > >           '-DGIT_VERSION_H=\"' + version_def_h.full_path() + '\"',\n> > >         ],\n> > > +      c_pch: 'tools/precompiled.h',\n> > >         dependencies: libgit_dependencies,\n> > >         include_directories: libgit_include_directories,\n> > >       ),\n> > \n> > Well, I don't do meson, but...\n> > \n> > If I understand this right, this section here compiles all the source\n> > files listed in \"libgit_sources\" using our new precompiled header.\n> > But \"libgit_sources\" contains all source files under \"reftable/\",\n> > which, with the sole exception of \"reftable/system.c\", don't include\n> > \"git-compat-util.h\".\n> > \n> > Now, building the reftable sources with \"git-compat-util.h\" included\n> > through the precompiled header apparently didn't cause any compilation\n> > errors...\n> > But I think that's just accidental, and if a source file doesn't\n> > include \"git-compat-util.h\", then it shouldn't be compiled with the\n> > precompiled header.\n> \n> FWIW I agree it would be better to keep the same includes when building with\n> precompiled headers. There is some discussion about this starting at\n> https://lore.kernel.org/git/2fe87868-dff5-4b3a-95e3-d4b6376b59ed@gmail.com/\n\nI'm not sure that \"oh look, it didn't break, so it must be good\" is\nthe right approach...\n\nAnd why was this not mentioned in the commit message?!  Sigh...\n\n\n"}]}