From: Patrick Steinhardt <hidden> Date: 2026-03-10 17:52:57
According to its readme, the "contrib/" directory's main intent is to
collect stuff that is not an official part of Git, either because it is
too specialized or because it is still considered experimental. The
reality tells a bit of a different story though: while it _does_ contain
such things, it also contains other things:
- Our credential helpers, which are being distributed by many
packagers nowadays and which can be considered "stable".
- A bunch of tooling that relates to our build and test
infrastructure.
Especially the second category is somewhat of a sore spot. You really
wouldn't expect build-related tooling to be considered an optional part
of Git. Quite the opposite.
Create a new top-level "tools/" directory to fix this discrepancy. This
directory will contain all kind of tools that are related to our build
infrastructure and that Git developers are likely to use day to day.
For now, this directory doesn't contain anything yet except for a
readme and a Meson skeleton. This will change in subsequent commits.
Signed-off-by: Patrick Steinhardt <redacted>
---
Makefile | 2 ++
meson.build | 1 +
tools/README.md | 7 +++++++
tools/meson.build | 0
4 files changed, 10 insertions(+)
@@ -2149,6 +2149,7 @@ elseendifsubdir('contrib')+subdir('tools')# Note that the target is intentionally configured after including the# 'contrib' directory, as some tool there also have their own manpages.
@@ -0,0 +1,7 @@+Developer Tooling+-----------------++This directory is expected to contain all sorts of tooling that+relates to our build infrastructure. This includes scripts and+inputs required by our build systems, but also scripts that+developers are expected to run manually.
@@ -1005,8 +1005,8 @@ SPATCH_TEST_FLAGS =# COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.SPATCH_USE_O_DEPENDENCIES=YesPlease-# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci-# files into a single contrib/cocci/ALL.cocci before running+# Set SPATCH_CONCAT_COCCI to concatenate the tools/coccinelle/*.cocci+# files into a single tools/coccinelle/ALL.cocci before running# "coccicheck".## Pros:
@@ -1025,7 +1025,7 @@ SPATCH_USE_O_DEPENDENCIES = YesPlease# generate a specific patch, e.g. this will always use strbuf.cocci,# not ALL.cocci:#-# make contrib/coccinelle/strbuf.cocci.patch+# make tools/coccinelle/strbuf.cocci.patchSPATCH_CONCAT_COCCI=YesPlease# Rebuild 'coccicheck' if $(SPATCH), its flags etc. change
@@ -3480,20 +3480,20 @@ COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)# on $(MAKECMDGOALS) that match these $(COCCI_RULES)COCCI_RULES_GLOB=COCCI_RULES_GLOB+=cocci%-COCCI_RULES_GLOB+=.build/contrib/coccinelle/%+COCCI_RULES_GLOB+=.build/tools/coccinelle/%COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES)COCCI_RULES_GLOB+=$(COCCICHEC_PATCHES_PENDING)COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES_INTREE)COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES_PENDING_INTREE)COCCI_GOALS=$(filter$(COCCI_RULES_GLOB),$(MAKECMDGOALS))-COCCI_TEST_RES=$(wildcardcontrib/coccinelle/tests/*.res)+COCCI_TEST_RES=$(wildcardtools/coccinelle/tests/*.res)$(COCCI_RULES_TRACKED):.build/% : %$(callmkdir_p_parent_template)$(QUIET_CP)cp$<$@-.build/contrib/coccinelle/FOUND_H_SOURCES:$(FOUND_H_SOURCES)+.build/tools/coccinelle/FOUND_H_SOURCES:$(FOUND_H_SOURCES)$(callmkdir_p_parent_template)$(QUIET_GEN)>$@
@@ -3507,12 +3507,12 @@ endifdefine cocci-rule## Rule for .build/$(1).patch/$(2); Params:-# $(1) = e.g. ".build/contrib/coccinelle/free.cocci"+# $(1) = e.g. ".build/tools/coccinelle/free.cocci"# $(2) = e.g. "grep.c"# $(3) = e.g. "grep.o"-COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch+COCCI_$(1:.build/tools/coccinelle/%.cocci=%) += $(1).d/$(2).patch$(1).d/$(2).patch:GIT-SPATCH-DEFINES-$(1).d/$(2).patch:$(if$(and$(SPATCH_USE_O_DEPENDENCIES),$(wildcard$(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)+$(1).d/$(2).patch:$(if$(and$(SPATCH_USE_O_DEPENDENCIES),$(wildcard$(3))),$(3),.build/tools/coccinelle/FOUND_H_SOURCES)$(1).d/$(2).patch:$(1)$(1).d/$(2).patch:$(1).d/%.patch : %$$(callmkdir_p_parent_template)
@@ -3538,13 +3538,13 @@ endifdefine spatch-rule-.build/contrib/coccinelle/$(1).cocci.patch:$$(COCCI_$(1))+.build/tools/coccinelle/$(1).cocci.patch:$$(COCCI_$(1))$$(QUIET_SPATCH_CAT)cat$$^>$$@&&\ if test -s $$@; \then\echo' 'SPATCHresult:$$@;\fi-contrib/coccinelle/$(1).cocci.patch:.build/contrib/coccinelle/$(1).cocci.patch+tools/coccinelle/$(1).cocci.patch:.build/tools/coccinelle/$(1).cocci.patch$$(QUIET_CP)cp$$<$$@endef
diff --git a/contrib/coccinelle/.gitignore b/tools/coccinelle/.gitignoresimilarity index 100%rename from contrib/coccinelle/.gitignorerename to tools/coccinelle/.gitignorediff --git a/contrib/coccinelle/README b/tools/coccinelle/READMEsimilarity index 98%rename from contrib/coccinelle/READMErename to tools/coccinelle/READMEindex 055ad0e06a..fd0a543cc2 100644--- a/contrib/coccinelle/README+++ b/tools/coccinelle/README
@@ -38,7 +38,7 @@ that might be useful to developers. So to aid these large scale refactorings, semantic patches can be used. However we do not want to store them in the same place as the checks for bad patterns, as then automated builds would fail.- That is why semantic patches 'contrib/coccinelle/*.pending.cocci'+ That is why semantic patches 'tools/coccinelle/*.pending.cocci' are ignored for checks, and can be applied using 'make coccicheck-pending'. This allows to expose plans of pending large scale refactorings without
diff --git a/contrib/coccinelle/array.cocci b/tools/coccinelle/array.coccisimilarity index 100%rename from contrib/coccinelle/array.coccirename to tools/coccinelle/array.coccidiff --git a/contrib/coccinelle/commit.cocci b/tools/coccinelle/commit.coccisimilarity index 100%rename from contrib/coccinelle/commit.coccirename to tools/coccinelle/commit.coccidiff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/tools/coccinelle/config_fn_ctx.pending.coccisimilarity index 100%rename from contrib/coccinelle/config_fn_ctx.pending.coccirename to tools/coccinelle/config_fn_ctx.pending.coccidiff --git a/contrib/coccinelle/equals-null.cocci b/tools/coccinelle/equals-null.coccisimilarity index 100%rename from contrib/coccinelle/equals-null.coccirename to tools/coccinelle/equals-null.coccidiff --git a/contrib/coccinelle/flex_alloc.cocci b/tools/coccinelle/flex_alloc.coccisimilarity index 100%rename from contrib/coccinelle/flex_alloc.coccirename to tools/coccinelle/flex_alloc.coccidiff --git a/contrib/coccinelle/free.cocci b/tools/coccinelle/free.coccisimilarity index 100%rename from contrib/coccinelle/free.coccirename to tools/coccinelle/free.coccidiff --git a/contrib/coccinelle/git_config_number.cocci b/tools/coccinelle/git_config_number.coccisimilarity index 100%rename from contrib/coccinelle/git_config_number.coccirename to tools/coccinelle/git_config_number.coccidiff --git a/contrib/coccinelle/hashmap.cocci b/tools/coccinelle/hashmap.coccisimilarity index 100%rename from contrib/coccinelle/hashmap.coccirename to tools/coccinelle/hashmap.coccidiff --git a/contrib/coccinelle/index-compatibility.cocci b/tools/coccinelle/index-compatibility.coccisimilarity index 100%rename from contrib/coccinelle/index-compatibility.coccirename to tools/coccinelle/index-compatibility.coccidiff --git a/contrib/coccinelle/meson.build b/tools/coccinelle/meson.buildsimilarity index 100%rename from contrib/coccinelle/meson.buildrename to tools/coccinelle/meson.builddiff --git a/contrib/coccinelle/object_id.cocci b/tools/coccinelle/object_id.coccisimilarity index 100%rename from contrib/coccinelle/object_id.coccirename to tools/coccinelle/object_id.coccidiff --git a/contrib/coccinelle/preincr.cocci b/tools/coccinelle/preincr.coccisimilarity index 100%rename from contrib/coccinelle/preincr.coccirename to tools/coccinelle/preincr.coccidiff --git a/contrib/coccinelle/qsort.cocci b/tools/coccinelle/qsort.coccisimilarity index 100%rename from contrib/coccinelle/qsort.coccirename to tools/coccinelle/qsort.coccidiff --git a/contrib/coccinelle/refs.cocci b/tools/coccinelle/refs.coccisimilarity index 100%rename from contrib/coccinelle/refs.coccirename to tools/coccinelle/refs.coccidiff --git a/contrib/coccinelle/spatchcache b/tools/coccinelle/spatchcachesimilarity index 97%rename from contrib/coccinelle/spatchcacherename to tools/coccinelle/spatchcacheindex 29e9352d8a..efbcbc3827 100755--- a/contrib/coccinelle/spatchcache+++ b/tools/coccinelle/spatchcache
@@ -30,7 +30,7 @@ # out of control. # # This along with the general incremental "make" support for-# "contrib/coccinelle" makes it viable to (re-)run coccicheck+# "tools/coccinelle" makes it viable to (re-)run coccicheck # e.g. when merging integration branches. # # Note that the "--very-quiet" flag is currently critical. The cache
@@ -42,7 +42,7 @@ # to change, so just supply "--very-quiet" for now. # # To use this, simply set SPATCH to-# contrib/coccinelle/spatchcache. Then optionally set:+# tools/coccinelle/spatchcache. Then optionally set: # # [spatchCache] # # Optional: path to a custom spatch
@@ -65,7 +65,7 @@ # # redis-cli FLUSHALL # <make && make coccicheck, as above>-# grep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/contrib/coccinelle | sort | uniq -c+# grep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/tools/coccinelle | sort | uniq -c # 600 CANTCACHE # 7365 MISS # 7365 SET
diff --git a/contrib/coccinelle/strbuf.cocci b/tools/coccinelle/strbuf.coccisimilarity index 100%rename from contrib/coccinelle/strbuf.coccirename to tools/coccinelle/strbuf.coccidiff --git a/contrib/coccinelle/swap.cocci b/tools/coccinelle/swap.coccisimilarity index 100%rename from contrib/coccinelle/swap.coccirename to tools/coccinelle/swap.coccidiff --git a/contrib/coccinelle/tests/free.c b/tools/coccinelle/tests/free.csimilarity index 100%rename from contrib/coccinelle/tests/free.crename to tools/coccinelle/tests/free.cdiff --git a/contrib/coccinelle/tests/free.res b/tools/coccinelle/tests/free.ressimilarity index 100%rename from contrib/coccinelle/tests/free.resrename to tools/coccinelle/tests/free.resdiff --git a/contrib/coccinelle/the_repository.cocci b/tools/coccinelle/the_repository.coccisimilarity index 100%rename from contrib/coccinelle/the_repository.coccirename to tools/coccinelle/the_repository.coccidiff --git a/contrib/coccinelle/xcalloc.cocci b/tools/coccinelle/xcalloc.coccisimilarity index 100%rename from contrib/coccinelle/xcalloc.coccirename to tools/coccinelle/xcalloc.coccidiff --git a/contrib/coccinelle/xopen.cocci b/tools/coccinelle/xopen.coccisimilarity index 100%rename from contrib/coccinelle/xopen.coccirename to tools/coccinelle/xopen.coccidiff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/tools/coccinelle/xstrdup_or_null.coccisimilarity index 100%rename from contrib/coccinelle/xstrdup_or_null.coccirename to tools/coccinelle/xstrdup_or_null.coccidiff --git a/contrib/coccinelle/xstrncmpz.cocci b/tools/coccinelle/xstrncmpz.coccisimilarity index 100%rename from contrib/coccinelle/xstrncmpz.coccirename to tools/coccinelle/xstrncmpz.coccidiff --git a/tools/meson.build b/tools/meson.buildindex e69de29bb2..f731f74312 100644--- a/tools/meson.build+++ b/tools/meson.build
From: Patrick Steinhardt <hidden> Date: 2026-03-10 17:53:02
The "coverage-diff.sh" script can be used to get information about test
coverage fro the Git codebase. It is thus rather specific to our build
and test infrastructure and part of the developer-facing tooling. The
fact that this script is part of "contrib/" is thus rather misleading
and a historic wart.
Promote the tool into the new "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
{contrib => tools}/coverage-diff.sh | 0
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/contrib/coverage-diff.sh b/tools/coverage-diff.shsimilarity index 100%rename from contrib/coverage-diff.shrename to tools/coverage-diff.sh
--
2.53.0.880.g73c4285caa.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-10 17:53:04
The "update-unicode.sh" script is used to update the unicode data
compiled into Git whenever a new version of the Unicode standard has
been released. As such, it is a natural part of our developer-facing
tooling, and its presence in "contrib/" is misleading.
Promote the script into the new "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
{contrib => tools}/update-unicode/.gitignore | 0
{contrib => tools}/update-unicode/README | 0
{contrib => tools}/update-unicode/update_unicode.sh | 0
3 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/contrib/update-unicode/.gitignore b/tools/update-unicode/.gitignoresimilarity index 100%rename from contrib/update-unicode/.gitignorerename to tools/update-unicode/.gitignorediff --git a/contrib/update-unicode/README b/tools/update-unicode/READMEsimilarity index 100%rename from contrib/update-unicode/READMErename to tools/update-unicode/READMEdiff --git a/contrib/update-unicode/update_unicode.sh b/tools/update-unicode/update_unicode.shsimilarity index 100%rename from contrib/update-unicode/update_unicode.shrename to tools/update-unicode/update_unicode.sh
--
2.53.0.880.g73c4285caa.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-10 17:53:07
We have a bunch of scripts used by our different build systems that are
all located in the top-level directory. Now that we have introduced the
new "tools/" directory though we have a better home for them.
Move the scripts into the "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
Makefile | 34 +++++++++++-----------
config.mak.dev | 2 +-
contrib/buildsystems/CMakeLists.txt | 18 ++++++------
contrib/subtree/meson.build | 2 +-
meson.build | 14 ++++-----
check-builtins.sh => tools/check-builtins.sh | 0
detect-compiler => tools/detect-compiler | 0
generate-cmdlist.sh => tools/generate-cmdlist.sh | 0
.../generate-configlist.sh | 0
generate-hooklist.sh => tools/generate-hooklist.sh | 0
generate-perl.sh => tools/generate-perl.sh | 0
generate-python.sh => tools/generate-python.sh | 0
generate-script.sh => tools/generate-script.sh | 0
13 files changed, 35 insertions(+), 35 deletions(-)
@@ -3936,7 +3936,7 @@ check-docs::### Make sure built-ins do not have dups and listed in git.c#check-builtins::-./check-builtins.sh+./tools/check-builtins.sh### Test suite coverage testing#
@@ -2008,7 +2008,7 @@ if perl_features_enabledgenerate_perl_command=[shell,-meson.project_source_root()/'generate-perl.sh',+meson.project_source_root()/'tools/generate-perl.sh',meson.project_build_root()/'GIT-BUILD-OPTIONS',git_version_file.full_path(),perl_header,
@@ -2057,7 +2057,7 @@ if target_python.found()output:fs.stem(script),command:[shell,-meson.project_source_root()/'generate-python.sh',+meson.project_source_root()/'tools/generate-python.sh',meson.project_build_root()/'GIT-BUILD-OPTIONS','@INPUT@','@OUTPUT@',
diff --git a/check-builtins.sh b/tools/check-builtins.shsimilarity index 100%rename from check-builtins.shrename to tools/check-builtins.shdiff --git a/detect-compiler b/tools/detect-compilersimilarity index 100%rename from detect-compilerrename to tools/detect-compilerdiff --git a/generate-cmdlist.sh b/tools/generate-cmdlist.shsimilarity index 100%rename from generate-cmdlist.shrename to tools/generate-cmdlist.shdiff --git a/generate-configlist.sh b/tools/generate-configlist.shsimilarity index 100%rename from generate-configlist.shrename to tools/generate-configlist.shdiff --git a/generate-hooklist.sh b/tools/generate-hooklist.shsimilarity index 100%rename from generate-hooklist.shrename to tools/generate-hooklist.shdiff --git a/generate-perl.sh b/tools/generate-perl.shsimilarity index 100%rename from generate-perl.shrename to tools/generate-perl.shdiff --git a/generate-python.sh b/tools/generate-python.shsimilarity index 100%rename from generate-python.shrename to tools/generate-python.shdiff --git a/generate-script.sh b/tools/generate-script.shsimilarity index 100%rename from generate-script.shrename to tools/generate-script.sh
--
2.53.0.880.g73c4285caa.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-10 17:53:09
The "git-compat-util.h" header is supposed to be the first header
included by every code compilation unit. As such, a subsequent commit
will start to precompile this header to speed up compilation of Git.
This will cause an issue though with the way that we have set up the
"-Wsign-compare" warnings. It is expected that any compilation unit that
fails with that compiler warning sets `DISABLE_SIGN_COMPARE_WARNINGS`
before including "git-compat-util.h". If so, we'll disable the warning
right away via a compiler pragma.
But with precompiled headers we do not know ahead of time whether the
code unit wants to disable those warnings, and thus we'll have to
precompile the header without defining `DISABLE_SIGN_COMPARE_WARNINGS`.
But as the pragma statement is wrapped by our include guards, the second
include of that file will not have the desired effect of disabling the
warnings anymore.
We could fix this issue by declaring a new macro that compilation units
are expected to invoke after having included the file. In retrospect,
that would have been the better way to handle this as it allows for
more flexibility: we could for example toggle the warning for specific
code blocks, only. But changing this now would require a bunch of
changes, and the churn feels excessive for what we gain.
Instead, prepare for the precompiled headers by moving the code outside
of the include guards.
Signed-off-by: Patrick Steinhardt <redacted>
---
git-compat-util.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2026-03-10 17:53:11
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
This is okay for our "normal" library sources and our builtins. But some
of our compatibility sources do not include the header on purpose, and
doing so would cause compileir errors.
Prepare for this change by splitting out compatibility sources into
their static library. Like this we can selectively enable precompiled
headers for the library sources.
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 79 +++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 45 insertions(+), 34 deletions(-)
@@ -1179,7 +1182,7 @@ endif# implementation to threat things like drive prefixes specially.ifhost_machine.system()=='windows'ornotcompiler.has_header('libgen.h')libgit_c_args+='-DNO_LIBGEN_H'-libgit_sources+='compat/basename.c'+compat_sources+='compat/basename.c'endififcompiler.has_header('paths.h')
@@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'foreachsymbol:['inet_ntop','inet_pton','hstrerror']ifnotcompiler.has_function(symbol,dependencies:networking_dependencies)libgit_c_args+='-DNO_'+symbol.to_upper()-libgit_sources+='compat/'+symbol+'.c'+compat_sources+='compat/'+symbol+'.c'endifendforeachendif
@@ -1251,18 +1254,18 @@ elseendififhost_machine.system()=='darwin'-libgit_sources+='compat/precompose_utf8.c'+compat_sources+='compat/precompose_utf8.c'libgit_c_args+='-DPRECOMPOSE_UNICODE'libgit_c_args+='-DPROTECT_HFS_DEFAULT'endif# Configure general compatibility wrappers.ifhost_machine.system()=='cygwin'-libgit_sources+=[+compat_sources+=['compat/win32/path-utils.c',]elifhost_machine.system()=='windows'-libgit_sources+=[+compat_sources+=['compat/winansi.c','compat/win32/dirent.c','compat/win32/flush.c',
@@ -1315,13 +1318,13 @@ endif# Configure the simple-ipc subsystem required fro the fsmonitor.ifhost_machine.system()=='windows'-libgit_sources+=[+compat_sources+=['compat/simple-ipc/ipc-shared.c','compat/simple-ipc/ipc-win32.c',]libgit_c_args+='-DSUPPORTS_SIMPLE_IPC'else-libgit_sources+=[+compat_sources+=['compat/simple-ipc/ipc-shared.c','compat/simple-ipc/ipc-unix-socket.c',]
@@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''libgit_c_args+='-DHAVE_FSMONITOR_DAEMON_BACKEND'libgit_c_args+='-DHAVE_FSMONITOR_OS_SETTINGS'-libgit_sources+=[+compat_sources+=['compat/fsmonitor/fsm-health-'+fsmonitor_backend+'.c','compat/fsmonitor/fsm-ipc-'+fsmonitor_backend+'.c','compat/fsmonitor/fsm-listen-'+fsmonitor_backend+'.c',
@@ -1355,7 +1358,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').alloifcompiler.get_define('REG_ENHANCED',prefix:'#include <regex.h>')!=''libgit_c_args+='-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'-libgit_sources+='compat/regcomp_enhanced.c'+compat_sources+='compat/regcomp_enhanced.c'endifelifnotget_option('regex').enabled()libgit_c_args+=[
@@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()'-DNO_MBSUPPORT',]build_options_config.set('NO_REGEX','1')-libgit_sources+='compat/regex/regex.c'+compat_sources+='compat/regex/regex.c'libgit_include_directories+='compat/regex'elseerror('Native regex support requested but not found')
@@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and compiler.run('''}''', name: 'freadreadsdirectories').returncode()==0libgit_c_args+='-DFREAD_READS_DIRECTORIES'-libgit_sources+='compat/fopen.c'+compat_sources+='compat/fopen.c'endififnotmeson.is_cross_build()andfs.exists('/dev/tty')
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
Is that a meson thing? I know it defines precompiled headers on a
per-target basis but does it somehow force each source file to include
the precompiled header? Looking at the gcc documentation it seems like
the precompiled header is only included where the original header is
included. Splitting out the sources that do not depend on
"git-compat-util.h" does mean we get some additional parallelism while
we're precompiling the header which is probably a good thing.
Thanks
Phillip
quoted hunk
This is okay for our "normal" library sources and our builtins. But some
of our compatibility sources do not include the header on purpose, and
doing so would cause compileir errors.
Prepare for this change by splitting out compatibility sources into
their static library. Like this we can selectively enable precompiled
headers for the library sources.
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 79 +++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 45 insertions(+), 34 deletions(-)
@@ -1179,7 +1182,7 @@ endif# implementation to threat things like drive prefixes specially.ifhost_machine.system()=='windows'ornotcompiler.has_header('libgen.h')libgit_c_args+='-DNO_LIBGEN_H'-libgit_sources+='compat/basename.c'+compat_sources+='compat/basename.c'endififcompiler.has_header('paths.h')
@@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'foreachsymbol:['inet_ntop','inet_pton','hstrerror']ifnotcompiler.has_function(symbol,dependencies:networking_dependencies)libgit_c_args+='-DNO_'+symbol.to_upper()-libgit_sources+='compat/'+symbol+'.c'+compat_sources+='compat/'+symbol+'.c'endifendforeachendif
@@ -1251,18 +1254,18 @@ elseendififhost_machine.system()=='darwin'-libgit_sources+='compat/precompose_utf8.c'+compat_sources+='compat/precompose_utf8.c'libgit_c_args+='-DPRECOMPOSE_UNICODE'libgit_c_args+='-DPROTECT_HFS_DEFAULT'endif# Configure general compatibility wrappers.ifhost_machine.system()=='cygwin'-libgit_sources+=[+compat_sources+=['compat/win32/path-utils.c',]elifhost_machine.system()=='windows'-libgit_sources+=[+compat_sources+=['compat/winansi.c','compat/win32/dirent.c','compat/win32/flush.c',
@@ -1315,13 +1318,13 @@ endif# Configure the simple-ipc subsystem required fro the fsmonitor.ifhost_machine.system()=='windows'-libgit_sources+=[+compat_sources+=['compat/simple-ipc/ipc-shared.c','compat/simple-ipc/ipc-win32.c',]libgit_c_args+='-DSUPPORTS_SIMPLE_IPC'else-libgit_sources+=[+compat_sources+=['compat/simple-ipc/ipc-shared.c','compat/simple-ipc/ipc-unix-socket.c',]
@@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''libgit_c_args+='-DHAVE_FSMONITOR_DAEMON_BACKEND'libgit_c_args+='-DHAVE_FSMONITOR_OS_SETTINGS'-libgit_sources+=[+compat_sources+=['compat/fsmonitor/fsm-health-'+fsmonitor_backend+'.c','compat/fsmonitor/fsm-ipc-'+fsmonitor_backend+'.c','compat/fsmonitor/fsm-listen-'+fsmonitor_backend+'.c',
@@ -1355,7 +1358,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').alloifcompiler.get_define('REG_ENHANCED',prefix:'#include <regex.h>')!=''libgit_c_args+='-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'-libgit_sources+='compat/regcomp_enhanced.c'+compat_sources+='compat/regcomp_enhanced.c'endifelifnotget_option('regex').enabled()libgit_c_args+=[
@@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()'-DNO_MBSUPPORT',]build_options_config.set('NO_REGEX','1')-libgit_sources+='compat/regex/regex.c'+compat_sources+='compat/regex/regex.c'libgit_include_directories+='compat/regex'elseerror('Native regex support requested but not found')
@@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and compiler.run('''}''', name: 'freadreadsdirectories').returncode()==0libgit_c_args+='-DFREAD_READS_DIRECTORIES'-libgit_sources+='compat/fopen.c'+compat_sources+='compat/fopen.c'endififnotmeson.is_cross_build()andfs.exists('/dev/tty')
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
Is that a meson thing? I know it defines precompiled headers on a per-
target basis but does it somehow force each source file to include the
precompiled header? Looking at the gcc documentation it seems like the
precompiled header is only included where the original header is
included.
Answering my own question the precompiled header is included via
"-include" on the commandline. This is necessary in the general case
because a precompiled header cannot be used once the first C token is seen.
As an aside in git we could probably get away without using "-include"
because if we include "git-compat-util.h" it is always the first thing
we do, or we inculde another file like "builtin.h" which immediately
includes "git-compat-util.h" and so it is included before the first C
token is seen. However meson cannot rely on that.
I notice the reftable sources don't seem to include "git-compat-util.h",
do they need special handling here as well?
Thanks
Phillip
Splitting out the sources that do not depend on "git-compat-
util.h" does mean we get some additional parallelism while we're
precompiling the header which is probably a good thing.
Thanks
Phillip
quoted
This is okay for our "normal" library sources and our builtins. But some
of our compatibility sources do not include the header on purpose, and
doing so would cause compileir errors.
Prepare for this change by splitting out compatibility sources into
their static library. Like this we can selectively enable precompiled
headers for the library sources.
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 79 ++++++++++++++++++++++++++++++++++
+--------------------------
1 file changed, 45 insertions(+), 34 deletions(-)
if not has_poll_h and not has_sys_poll_h
libgit_c_args += '-DNO_POLL'
- libgit_sources += 'compat/poll/poll.c'
+ compat_sources += 'compat/poll/poll.c'
libgit_include_directories += 'compat/poll'
endif
@@ -1179,7 +1182,7 @@ endif
# implementation to threat things like drive prefixes specially.
if host_machine.system() == 'windows' or not
compiler.has_header('libgen.h')
libgit_c_args += '-DNO_LIBGEN_H'
- libgit_sources += 'compat/basename.c'
+ compat_sources += 'compat/basename.c'
endif
if compiler.has_header('paths.h')
@@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'
foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']
if not compiler.has_function(symbol, dependencies:
networking_dependencies)
libgit_c_args += '-DNO_' + symbol.to_upper()
- libgit_sources += 'compat/' + symbol + '.c'
+ compat_sources += 'compat/' + symbol + '.c'
endif
endforeach
endif
From: SZEDER Gábor <hidden> Date: 2026-03-11 23:28:02
On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:
On 11/03/2026 14:32, Phillip Wood wrote:
quoted
On 10/03/2026 17:52, Patrick Steinhardt wrote:
quoted
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
Is that a meson thing? I know it defines precompiled headers on a per-
target basis but does it somehow force each source file to include the
precompiled header? Looking at the gcc documentation it seems like the
precompiled header is only included where the original header is
included.
Answering my own question the precompiled header is included via "-include"
on the commandline. This is necessary in the general case because a
precompiled header cannot be used once the first C token is seen.
As an aside in git we could probably get away without using "-include"
because if we include "git-compat-util.h" it is always the first thing we
do, or we inculde another file like "builtin.h" which immediately includes
"git-compat-util.h" and so it is included before the first C token is seen.
I couldn't find this in the GCC docs, but Make's documentation states
that "you cannot include a precompiled header from inside another
header." [1]
The strace of compiling a 'builtin/*.c' source file seems to confirm
it, the compiler (gcc-12) does look for 'builtin.h.gch', but doesn't
look for 'git-compat-util.h.gch':
592662 newfstatat(AT_FDCWD, "builtin/builtin.h.gch", 0x7fff2066e610, 0) = -1 ENOENT (No such file or directory)
592662 openat(AT_FDCWD, "builtin/builtin.h", O_RDONLY|O_NOCTTY) = -1 ENOENT (No such file or directory)
592662 newfstatat(AT_FDCWD, "./builtin.h.gch", 0x7fff2066e610, 0) = -1 ENOENT (No such file or directory)
592662 openat(AT_FDCWD, "./builtin.h", O_RDONLY|O_NOCTTY) = 4
592662 newfstatat(4, "", {st_mode=S_IFREG|0664, st_size=17968, ...}, AT_EMPTY_PATH) = 0
592662 read(4, "#ifndef BUILTIN_H\n#define BUILTI"..., 17968) = 17968
592662 close(4) = 0
592662 openat(AT_FDCWD, "./git-compat-util.h", O_RDONLY|O_NOCTTY) = 4
[1] Second bullet point at:
https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
From: Patrick Steinhardt <hidden> Date: 2026-03-12 06:22:02
On Thu, Mar 12, 2026 at 12:27:49AM +0100, SZEDER Gábor wrote:
On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:
quoted
On 11/03/2026 14:32, Phillip Wood wrote:
quoted
On 10/03/2026 17:52, Patrick Steinhardt wrote:
quoted
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
Is that a meson thing? I know it defines precompiled headers on a per-
target basis but does it somehow force each source file to include the
precompiled header? Looking at the gcc documentation it seems like the
precompiled header is only included where the original header is
included.
Answering my own question the precompiled header is included via "-include"
on the commandline. This is necessary in the general case because a
precompiled header cannot be used once the first C token is seen.
As an aside in git we could probably get away without using "-include"
because if we include "git-compat-util.h" it is always the first thing we
do, or we inculde another file like "builtin.h" which immediately includes
"git-compat-util.h" and so it is included before the first C token is seen.
I couldn't find this in the GCC docs, but Make's documentation states
that "you cannot include a precompiled header from inside another
header." [1]
I think you must have confused something, because the link _does_ point
to GCC's documentation, which does contain the quote.
But yes, overall there can only be one precompiled header, and it cannot
be used after the first token indeed. The use of "-include" is also
explicitly noted for "projects not designed with precompiled headers in
mind", which fits Git. After all, we still have the ability to compile
without precompiled headers, and I don't expect that to go away.
Patrick
On Thu, Mar 12, 2026 at 12:27:49AM +0100, SZEDER Gábor wrote:
quoted
On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:
quoted
On 11/03/2026 14:32, Phillip Wood wrote:
quoted
On 10/03/2026 17:52, Patrick Steinhardt wrote:
quoted
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
Is that a meson thing? I know it defines precompiled headers on a per-
target basis but does it somehow force each source file to include the
precompiled header? Looking at the gcc documentation it seems like the
precompiled header is only included where the original header is
included.
Answering my own question the precompiled header is included via "-include"
on the commandline. This is necessary in the general case because a
precompiled header cannot be used once the first C token is seen.
As an aside in git we could probably get away without using "-include"
because if we include "git-compat-util.h" it is always the first thing we
do, or we inculde another file like "builtin.h" which immediately includes
"git-compat-util.h" and so it is included before the first C token is seen.
I couldn't find this in the GCC docs, but Make's documentation states
that "you cannot include a precompiled header from inside another
header." [1]
I think you must have confused something, because the link _does_ point
to GCC's documentation, which does contain the quote.
But yes, overall there can only be one precompiled header, and it cannot
be used after the first token indeed. The use of "-include" is also
explicitly noted for "projects not designed with precompiled headers in
mind", which fits Git. After all, we still have the ability to compile
without precompiled headers, and I don't expect that to go away.
Thanks to you both for the explanation. Should we explain this in the
commit message?
Thanks
Phillip
From: Patrick Steinhardt <hidden> Date: 2026-03-16 08:09:20
On Fri, Mar 13, 2026 at 10:33:36AM +0000, Phillip Wood wrote:
On 12/03/2026 06:21, Patrick Steinhardt wrote:
quoted
On Thu, Mar 12, 2026 at 12:27:49AM +0100, SZEDER Gábor wrote:
quoted
On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:
quoted
On 11/03/2026 14:32, Phillip Wood wrote:
quoted
On 10/03/2026 17:52, Patrick Steinhardt wrote:
quoted
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
Is that a meson thing? I know it defines precompiled headers on a per-
target basis but does it somehow force each source file to include the
precompiled header? Looking at the gcc documentation it seems like the
precompiled header is only included where the original header is
included.
Answering my own question the precompiled header is included via "-include"
on the commandline. This is necessary in the general case because a
precompiled header cannot be used once the first C token is seen.
As an aside in git we could probably get away without using "-include"
because if we include "git-compat-util.h" it is always the first thing we
do, or we inculde another file like "builtin.h" which immediately includes
"git-compat-util.h" and so it is included before the first C token is seen.
I couldn't find this in the GCC docs, but Make's documentation states
that "you cannot include a precompiled header from inside another
header." [1]
I think you must have confused something, because the link _does_ point
to GCC's documentation, which does contain the quote.
But yes, overall there can only be one precompiled header, and it cannot
be used after the first token indeed. The use of "-include" is also
explicitly noted for "projects not designed with precompiled headers in
mind", which fits Git. After all, we still have the ability to compile
without precompiled headers, and I don't expect that to go away.
Thanks to you both for the explanation. Should we explain this in the commit
message?
Yeah, let's add a note for how this works internally. Let's also
highlight that we typically only have a single precompiled header by not
passing the headers as an array.
Patrick
From: SZEDER Gábor <hidden> Date: 2026-04-10 15:17:49
On Thu, Mar 12, 2026 at 07:21:57AM +0100, Patrick Steinhardt wrote:
On Thu, Mar 12, 2026 at 12:27:49AM +0100, SZEDER Gábor wrote:
quoted
On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:
quoted
On 11/03/2026 14:32, Phillip Wood wrote:
quoted
On 10/03/2026 17:52, Patrick Steinhardt wrote:
quoted
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
Is that a meson thing? I know it defines precompiled headers on a per-
target basis but does it somehow force each source file to include the
precompiled header? Looking at the gcc documentation it seems like the
precompiled header is only included where the original header is
included.
Answering my own question the precompiled header is included via "-include"
on the commandline. This is necessary in the general case because a
precompiled header cannot be used once the first C token is seen.
As an aside in git we could probably get away without using "-include"
because if we include "git-compat-util.h" it is always the first thing we
do, or we inculde another file like "builtin.h" which immediately includes
"git-compat-util.h" and so it is included before the first C token is seen.
I couldn't find this in the GCC docs, but Make's documentation states
that "you cannot include a precompiled header from inside another
header." [1]
I think you must have confused something, because the link _does_ point
to GCC's documentation, which does contain the quote.
Indeed. I wanted to say that I couldn't find this in the GCC *man
page*... And then mixed up which documentation site I was looking at,
as they very much look alike.
But yes, overall there can only be one precompiled header, and it cannot
be used after the first token indeed. The use of "-include" is also
explicitly noted for "projects not designed with precompiled headers in
mind", which fits Git. After all, we still have the ability to compile
without precompiled headers, and I don't expect that to go away.
Patrick
From: Patrick Steinhardt <hidden> Date: 2026-03-12 06:22:07
On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:
On 11/03/2026 14:32, Phillip Wood wrote:
quoted
On 10/03/2026 17:52, Patrick Steinhardt wrote:
quoted
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
Is that a meson thing? I know it defines precompiled headers on a per-
target basis but does it somehow force each source file to include the
precompiled header? Looking at the gcc documentation it seems like the
precompiled header is only included where the original header is
included.
Answering my own question the precompiled header is included via "-include"
on the commandline. This is necessary in the general case because a
precompiled header cannot be used once the first C token is seen.
As an aside in git we could probably get away without using "-include"
because if we include "git-compat-util.h" it is always the first thing we
do, or we inculde another file like "builtin.h" which immediately includes
"git-compat-util.h" and so it is included before the first C token is seen.
However meson cannot rely on that.
I notice the reftable sources don't seem to include "git-compat-util.h", do
they need special handling here as well?
I don't see a strong reason to do so. The reason why we need to be
careful with "compat/" is that we redefine a bunch of standard symbols
there, and that requires us to play a couple of tricks with preprocessor
macros (see e.g. "compat/fopen.c").
We don't do anything like that in the reftable library, and we already
include "compat/posix.h". So in practice, it shouldn't have much of a
consueqence if we start to include "git-compat-util.h" implicitly over
there.
But if it ever does we can treat it the same as the compat library.
Patrick
On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:
quoted
I notice the reftable sources don't seem to include "git-compat-util.h", do
they need special handling here as well?
I don't see a strong reason to do so. The reason why we need to be
careful with "compat/" is that we redefine a bunch of standard symbols
there, and that requires us to play a couple of tricks with preprocessor
macros (see e.g. "compat/fopen.c").
We don't do anything like that in the reftable library, and we already
include "compat/posix.h". So in practice, it shouldn't have much of a
consueqence if we start to include "git-compat-util.h" implicitly over
there.
It does mean we're using different includes when compiling with
pre-compiled headers compared to compiling without them though which
means contributors using per-compiled headers could accidentally depend
on functions that are not included when compiling without them. Wasn't
the idea behind "compat/posix.h" to avoid including "git-compat-util.h"
in the reftable code? The commit message for 75a044f748f
(git-compat-util.h: split out POSIX-emulating bits, 2025-02-18) says
This intermixing is a bit of a problem for the reftable library as
we don't want to recreate the POSIX-like interface there. But
neither do we want to pull in the Git-specific functionality, as it
is otherwise quite easy to start depending on the Git codebase
again.
We could precompile "compat/posix.h" for the code that does not want
"git-compat-util.h"
Thanks
Phillip
But if it ever does we can treat it the same as the compat library.
Patrick
From: Patrick Steinhardt <hidden> Date: 2026-03-16 08:09:14
On Fri, Mar 13, 2026 at 10:33:20AM +0000, Phillip Wood wrote:
On 12/03/2026 06:22, Patrick Steinhardt wrote:
quoted
On Wed, Mar 11, 2026 at 02:56:24PM +0000, Phillip Wood wrote:
quoted
I notice the reftable sources don't seem to include "git-compat-util.h", do
they need special handling here as well?
I don't see a strong reason to do so. The reason why we need to be
careful with "compat/" is that we redefine a bunch of standard symbols
there, and that requires us to play a couple of tricks with preprocessor
macros (see e.g. "compat/fopen.c").
We don't do anything like that in the reftable library, and we already
include "compat/posix.h". So in practice, it shouldn't have much of a
consueqence if we start to include "git-compat-util.h" implicitly over
there.
It does mean we're using different includes when compiling with pre-compiled
headers compared to compiling without them though which means contributors
using per-compiled headers could accidentally depend on functions that are
not included when compiling without them. Wasn't the idea behind
"compat/posix.h" to avoid including "git-compat-util.h" in the reftable
code? The commit message for 75a044f748f (git-compat-util.h: split out
POSIX-emulating bits, 2025-02-18) says
This intermixing is a bit of a problem for the reftable library as
we don't want to recreate the POSIX-like interface there. But
neither do we want to pull in the Git-specific functionality, as it
is otherwise quite easy to start depending on the Git codebase
again.
We could precompile "compat/posix.h" for the code that does not want
"git-compat-util.h"
In theory, yes. But in practice we'd notice this quite fast via other CI
jobs, and it feels a bit ugly to split out so many different libraries.
So I'd propose to keep this as-is for now, but iterate in case we notice
that it _does_ become a problem.
Does that work for you?
Thanks!
Patrick
On Fri, Mar 13, 2026 at 10:33:20AM +0000, Phillip Wood wrote:
quoted
It does mean we're using different includes when compiling with pre-compiled
headers compared to compiling without them though which means contributors
using per-compiled headers could accidentally depend on functions that are
not included when compiling without them. Wasn't the idea behind
"compat/posix.h" to avoid including "git-compat-util.h" in the reftable
code? The commit message for 75a044f748f (git-compat-util.h: split out
POSIX-emulating bits, 2025-02-18) says
This intermixing is a bit of a problem for the reftable library as
we don't want to recreate the POSIX-like interface there. But
neither do we want to pull in the Git-specific functionality, as it
is otherwise quite easy to start depending on the Git codebase
again.
We could precompile "compat/posix.h" for the code that does not want
"git-compat-util.h"
In theory, yes. But in practice we'd notice this quite fast via other CI
jobs, and it feels a bit ugly to split out so many different libraries.
So I'd propose to keep this as-is for now, but iterate in case we notice
that it _does_ become a problem.
Fair enough, getting feedback via the CI when it could be given locally
by the compiler isn't great but we don't expect this to be a common problem.
Thanks
Phillip
On Tue, Mar 10, 2026, at 18:52, Patrick Steinhardt wrote:
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
This is okay for our "normal" library sources and our builtins. But some
of our compatibility sources do not include the header on purpose, and
doing so would cause compileir errors.
s/compileir/compiler/ (or /compilation)
Prepare for this change by splitting out compatibility sources into
their static library. Like this we can selectively enable precompiled
s/Like this/Like this,/ ?
headers for the library sources.
Signed-off-by: Patrick Steinhardt <redacted>
[snip]
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:32:44
On Tue, Mar 17, 2026 at 04:38:31PM +0100, Kristoffer Haugsbakk wrote:
On Tue, Mar 10, 2026, at 18:52, Patrick Steinhardt wrote:
quoted
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
This is okay for our "normal" library sources and our builtins. But some
of our compatibility sources do not include the header on purpose, and
doing so would cause compileir errors.
s/compileir/compiler/ (or /compilation)
quoted
Prepare for this change by splitting out compatibility sources into
their static library. Like this we can selectively enable precompiled
From: Patrick Steinhardt <hidden> Date: 2026-03-10 17:53:14
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This leads to a significant speedup when performing full
builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 2 ++
tools/precompiled.h | 1 +
2 files changed, 3 insertions(+)
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This leads to a significant speedup when performing full
builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
This is a nice speedup for a full build. I'm not sure about dumping the
precompiled header in tools/ though, it seems like an odd location for a
header file. It is a requirement of meson that the source for the
precompiled header lives in a separate directory to the rest of the
sources but it might be better to adopt the suggestion in the
documentation of a "pch" (or maybe "precompiled"?) directory rather than
mixing it in with our build scripts.
Thanks
Phillip
From: Patrick Steinhardt <hidden> Date: 2026-03-12 06:21:58
On Wed, Mar 11, 2026 at 02:32:36PM +0000, Phillip Wood wrote:
On 10/03/2026 17:52, Patrick Steinhardt wrote:
quoted
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This leads to a significant speedup when performing full
builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
This is a nice speedup for a full build. I'm not sure about dumping the
precompiled header in tools/ though, it seems like an odd location for a
header file. It is a requirement of meson that the source for the
precompiled header lives in a separate directory to the rest of the sources
but it might be better to adopt the suggestion in the documentation of a
"pch" (or maybe "precompiled"?) directory rather than mixing it in with our
build scripts.
Yeah, it's a bit on the odd side. The reason I decided on "tools/"
though is that it now contains our build infra and developer tooling, so
it's an okayish fit. And I didn't feel like creating a directory for a
single file, only.
Patrick
From: Patrick Steinhardt <hidden> Date: 2026-03-16 10:08:13
Hi,
this patch series contains a small set of build system improvements:
- The first couple patches introduce a new "tools/" directory that
contains items related to our build infrastructure and to our
developer tooling. This finally follows up on my promise to do this
back when I did the spring clean of "contrib/". [1]
- The last couple patches introduce precompiled headers into Meson for
a nice compilation speedup of ~30%. It's
The two topics are not really related with one another other than being
related to build systems. I decided to throw them in the same patch
series though so that I can introduce "precompiled.h" in "tools/".
Changes in v2:
- Turn array of precompiled headers into a simple string.
- Point out in the commit message that the precompiled header is
included implicitly.
- Link to v1: https://lore.kernel.org/r/20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im
Thanks!
Patrick
[1]: https://lore.kernel.org/git/20250506-pks-contrib-spring-cleanup-v1-0-e6d5ddd79a72@pks.im/
---
Patrick Steinhardt (8):
Introduce new "tools/" directory
contrib: move "coccinelle/" directory into "tools/"
contrib: move "coverage-diff.sh" script into "tools/"
contrib: move "update-unicode.sh" script into "tools/"
builds: move build scripts into "tools/"
git-compat-util.h: move warning infra to prepare for PCHs
meson: compile compatibility sources separately
meson: precompile "git-compat-util.h"
Makefile | 76 ++++++++---------
ci/run-static-analysis.sh | 2 +-
config.mak.dev | 2 +-
contrib/buildsystems/CMakeLists.txt | 18 ++--
contrib/meson.build | 1 -
contrib/subtree/meson.build | 2 +-
git-compat-util.h | 8 +-
meson.build | 96 +++++++++++++---------
tools/README.md | 7 ++
check-builtins.sh => tools/check-builtins.sh | 0
{contrib => tools}/coccinelle/.gitignore | 0
{contrib => tools}/coccinelle/README | 2 +-
{contrib => tools}/coccinelle/array.cocci | 0
{contrib => tools}/coccinelle/commit.cocci | 0
.../coccinelle/config_fn_ctx.pending.cocci | 0
{contrib => tools}/coccinelle/equals-null.cocci | 0
{contrib => tools}/coccinelle/flex_alloc.cocci | 0
{contrib => tools}/coccinelle/free.cocci | 0
.../coccinelle/git_config_number.cocci | 0
{contrib => tools}/coccinelle/hashmap.cocci | 0
.../coccinelle/index-compatibility.cocci | 0
{contrib => tools}/coccinelle/meson.build | 0
{contrib => tools}/coccinelle/object_id.cocci | 0
{contrib => tools}/coccinelle/preincr.cocci | 0
{contrib => tools}/coccinelle/qsort.cocci | 0
{contrib => tools}/coccinelle/refs.cocci | 0
{contrib => tools}/coccinelle/spatchcache | 6 +-
{contrib => tools}/coccinelle/strbuf.cocci | 0
{contrib => tools}/coccinelle/swap.cocci | 0
{contrib => tools}/coccinelle/tests/free.c | 0
{contrib => tools}/coccinelle/tests/free.res | 0
{contrib => tools}/coccinelle/the_repository.cocci | 0
{contrib => tools}/coccinelle/xcalloc.cocci | 0
{contrib => tools}/coccinelle/xopen.cocci | 0
.../coccinelle/xstrdup_or_null.cocci | 0
{contrib => tools}/coccinelle/xstrncmpz.cocci | 0
{contrib => tools}/coverage-diff.sh | 0
detect-compiler => tools/detect-compiler | 0
generate-cmdlist.sh => tools/generate-cmdlist.sh | 0
.../generate-configlist.sh | 0
generate-hooklist.sh => tools/generate-hooklist.sh | 0
generate-perl.sh => tools/generate-perl.sh | 0
generate-python.sh => tools/generate-python.sh | 0
generate-script.sh => tools/generate-script.sh | 0
tools/meson.build | 1 +
tools/precompiled.h | 1 +
{contrib => tools}/update-unicode/.gitignore | 0
{contrib => tools}/update-unicode/README | 0
.../update-unicode/update_unicode.sh | 0
49 files changed, 123 insertions(+), 99 deletions(-)
Range-diff versus v1:
1: 224e28be31 = 1: 9d09d2c39a Introduce new "tools/" directory
2: b217df51e5 = 2: 1b96bfe0f4 contrib: move "coccinelle/" directory into "tools/"
3: e371b6c221 = 3: ed6e90bd36 contrib: move "coverage-diff.sh" script into "tools/"
4: 3efeda9fa0 = 4: 48d8275ed1 contrib: move "update-unicode.sh" script into "tools/"
5: ee074c1396 = 5: daafeb3462 builds: move build scripts into "tools/"
6: d30d4a3119 = 6: 947fc0f7b4 git-compat-util.h: move warning infra to prepare for PCHs
7: ca118197a9 = 7: 6a2fb99aae meson: compile compatibility sources separately
8: a865a8650b ! 8: 857b478896 meson: precompile "git-compat-util.h"
@@ Commit message
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
- via Meson. This leads to a significant speedup when performing full
- builds:
+ via Meson. This causes Meson to implicitly include the precompiled
+ header in all compilation units. With GCC and Clang for example this is
+ done via the "-include" statement [1].
+
+ This leads to a significant speedup when performing full builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
@@ Commit message
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
+ [1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
+
Signed-off-by: Patrick Steinhardt [off-list ref]
## meson.build ##
@@ meson.build: libgit = declare_dependency(
c_args: libgit_c_args + [
'-DGIT_VERSION_H="' + version_def_h.full_path() + '"',
],
-+ c_pch: [ 'tools/precompiled.h' ],
++ c_pch: 'tools/precompiled.h',
dependencies: libgit_dependencies,
include_directories: libgit_include_directories,
),
@@ meson.build: test_dependencies = [ ]
git_builtin = executable('git',
sources: builtin_sources + 'git.c',
-+ c_pch: [ 'tools/precompiled.h' ],
++ c_pch: 'tools/precompiled.h',
dependencies: [libgit_commonmain],
install: true,
install_dir: git_exec_path,
---
base-commit: af2c8a61818d773325ef2324dd135786a03ebca0
change-id: 20260304-b4-pks-build-infra-improvements-cc4012c5364e
From: Patrick Steinhardt <hidden> Date: 2026-03-16 10:08:14
According to its readme, the "contrib/" directory's main intent is to
collect stuff that is not an official part of Git, either because it is
too specialized or because it is still considered experimental. The
reality tells a bit of a different story though: while it _does_ contain
such things, it also contains other things:
- Our credential helpers, which are being distributed by many
packagers nowadays and which can be considered "stable".
- A bunch of tooling that relates to our build and test
infrastructure.
Especially the second category is somewhat of a sore spot. You really
wouldn't expect build-related tooling to be considered an optional part
of Git. Quite the opposite.
Create a new top-level "tools/" directory to fix this discrepancy. This
directory will contain all kind of tools that are related to our build
infrastructure and that Git developers are likely to use day to day.
For now, this directory doesn't contain anything yet except for a
readme and a Meson skeleton. This will change in subsequent commits.
Signed-off-by: Patrick Steinhardt <redacted>
---
Makefile | 2 ++
meson.build | 1 +
tools/README.md | 7 +++++++
tools/meson.build | 0
4 files changed, 10 insertions(+)
@@ -2149,6 +2149,7 @@ elseendifsubdir('contrib')+subdir('tools')# Note that the target is intentionally configured after including the# 'contrib' directory, as some tool there also have their own manpages.
@@ -0,0 +1,7 @@+Developer Tooling+-----------------++This directory is expected to contain all sorts of tooling that+relates to our build infrastructure. This includes scripts and+inputs required by our build systems, but also scripts that+developers are expected to run manually.
@@ -1005,8 +1005,8 @@ SPATCH_TEST_FLAGS =# COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.SPATCH_USE_O_DEPENDENCIES=YesPlease-# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci-# files into a single contrib/cocci/ALL.cocci before running+# Set SPATCH_CONCAT_COCCI to concatenate the tools/coccinelle/*.cocci+# files into a single tools/coccinelle/ALL.cocci before running# "coccicheck".## Pros:
@@ -1025,7 +1025,7 @@ SPATCH_USE_O_DEPENDENCIES = YesPlease# generate a specific patch, e.g. this will always use strbuf.cocci,# not ALL.cocci:#-# make contrib/coccinelle/strbuf.cocci.patch+# make tools/coccinelle/strbuf.cocci.patchSPATCH_CONCAT_COCCI=YesPlease# Rebuild 'coccicheck' if $(SPATCH), its flags etc. change
@@ -3480,20 +3480,20 @@ COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)# on $(MAKECMDGOALS) that match these $(COCCI_RULES)COCCI_RULES_GLOB=COCCI_RULES_GLOB+=cocci%-COCCI_RULES_GLOB+=.build/contrib/coccinelle/%+COCCI_RULES_GLOB+=.build/tools/coccinelle/%COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES)COCCI_RULES_GLOB+=$(COCCICHEC_PATCHES_PENDING)COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES_INTREE)COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES_PENDING_INTREE)COCCI_GOALS=$(filter$(COCCI_RULES_GLOB),$(MAKECMDGOALS))-COCCI_TEST_RES=$(wildcardcontrib/coccinelle/tests/*.res)+COCCI_TEST_RES=$(wildcardtools/coccinelle/tests/*.res)$(COCCI_RULES_TRACKED):.build/% : %$(callmkdir_p_parent_template)$(QUIET_CP)cp$<$@-.build/contrib/coccinelle/FOUND_H_SOURCES:$(FOUND_H_SOURCES)+.build/tools/coccinelle/FOUND_H_SOURCES:$(FOUND_H_SOURCES)$(callmkdir_p_parent_template)$(QUIET_GEN)>$@
@@ -3507,12 +3507,12 @@ endifdefine cocci-rule## Rule for .build/$(1).patch/$(2); Params:-# $(1) = e.g. ".build/contrib/coccinelle/free.cocci"+# $(1) = e.g. ".build/tools/coccinelle/free.cocci"# $(2) = e.g. "grep.c"# $(3) = e.g. "grep.o"-COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch+COCCI_$(1:.build/tools/coccinelle/%.cocci=%) += $(1).d/$(2).patch$(1).d/$(2).patch:GIT-SPATCH-DEFINES-$(1).d/$(2).patch:$(if$(and$(SPATCH_USE_O_DEPENDENCIES),$(wildcard$(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)+$(1).d/$(2).patch:$(if$(and$(SPATCH_USE_O_DEPENDENCIES),$(wildcard$(3))),$(3),.build/tools/coccinelle/FOUND_H_SOURCES)$(1).d/$(2).patch:$(1)$(1).d/$(2).patch:$(1).d/%.patch : %$$(callmkdir_p_parent_template)
@@ -3538,13 +3538,13 @@ endifdefine spatch-rule-.build/contrib/coccinelle/$(1).cocci.patch:$$(COCCI_$(1))+.build/tools/coccinelle/$(1).cocci.patch:$$(COCCI_$(1))$$(QUIET_SPATCH_CAT)cat$$^>$$@&&\ if test -s $$@; \then\echo' 'SPATCHresult:$$@;\fi-contrib/coccinelle/$(1).cocci.patch:.build/contrib/coccinelle/$(1).cocci.patch+tools/coccinelle/$(1).cocci.patch:.build/tools/coccinelle/$(1).cocci.patch$$(QUIET_CP)cp$$<$$@endef
diff --git a/contrib/coccinelle/.gitignore b/tools/coccinelle/.gitignoresimilarity index 100%rename from contrib/coccinelle/.gitignorerename to tools/coccinelle/.gitignorediff --git a/contrib/coccinelle/README b/tools/coccinelle/READMEsimilarity index 98%rename from contrib/coccinelle/READMErename to tools/coccinelle/READMEindex 055ad0e06a..fd0a543cc2 100644--- a/contrib/coccinelle/README+++ b/tools/coccinelle/README
@@ -38,7 +38,7 @@ that might be useful to developers. So to aid these large scale refactorings, semantic patches can be used. However we do not want to store them in the same place as the checks for bad patterns, as then automated builds would fail.- That is why semantic patches 'contrib/coccinelle/*.pending.cocci'+ That is why semantic patches 'tools/coccinelle/*.pending.cocci' are ignored for checks, and can be applied using 'make coccicheck-pending'. This allows to expose plans of pending large scale refactorings without
diff --git a/contrib/coccinelle/array.cocci b/tools/coccinelle/array.coccisimilarity index 100%rename from contrib/coccinelle/array.coccirename to tools/coccinelle/array.coccidiff --git a/contrib/coccinelle/commit.cocci b/tools/coccinelle/commit.coccisimilarity index 100%rename from contrib/coccinelle/commit.coccirename to tools/coccinelle/commit.coccidiff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/tools/coccinelle/config_fn_ctx.pending.coccisimilarity index 100%rename from contrib/coccinelle/config_fn_ctx.pending.coccirename to tools/coccinelle/config_fn_ctx.pending.coccidiff --git a/contrib/coccinelle/equals-null.cocci b/tools/coccinelle/equals-null.coccisimilarity index 100%rename from contrib/coccinelle/equals-null.coccirename to tools/coccinelle/equals-null.coccidiff --git a/contrib/coccinelle/flex_alloc.cocci b/tools/coccinelle/flex_alloc.coccisimilarity index 100%rename from contrib/coccinelle/flex_alloc.coccirename to tools/coccinelle/flex_alloc.coccidiff --git a/contrib/coccinelle/free.cocci b/tools/coccinelle/free.coccisimilarity index 100%rename from contrib/coccinelle/free.coccirename to tools/coccinelle/free.coccidiff --git a/contrib/coccinelle/git_config_number.cocci b/tools/coccinelle/git_config_number.coccisimilarity index 100%rename from contrib/coccinelle/git_config_number.coccirename to tools/coccinelle/git_config_number.coccidiff --git a/contrib/coccinelle/hashmap.cocci b/tools/coccinelle/hashmap.coccisimilarity index 100%rename from contrib/coccinelle/hashmap.coccirename to tools/coccinelle/hashmap.coccidiff --git a/contrib/coccinelle/index-compatibility.cocci b/tools/coccinelle/index-compatibility.coccisimilarity index 100%rename from contrib/coccinelle/index-compatibility.coccirename to tools/coccinelle/index-compatibility.coccidiff --git a/contrib/coccinelle/meson.build b/tools/coccinelle/meson.buildsimilarity index 100%rename from contrib/coccinelle/meson.buildrename to tools/coccinelle/meson.builddiff --git a/contrib/coccinelle/object_id.cocci b/tools/coccinelle/object_id.coccisimilarity index 100%rename from contrib/coccinelle/object_id.coccirename to tools/coccinelle/object_id.coccidiff --git a/contrib/coccinelle/preincr.cocci b/tools/coccinelle/preincr.coccisimilarity index 100%rename from contrib/coccinelle/preincr.coccirename to tools/coccinelle/preincr.coccidiff --git a/contrib/coccinelle/qsort.cocci b/tools/coccinelle/qsort.coccisimilarity index 100%rename from contrib/coccinelle/qsort.coccirename to tools/coccinelle/qsort.coccidiff --git a/contrib/coccinelle/refs.cocci b/tools/coccinelle/refs.coccisimilarity index 100%rename from contrib/coccinelle/refs.coccirename to tools/coccinelle/refs.coccidiff --git a/contrib/coccinelle/spatchcache b/tools/coccinelle/spatchcachesimilarity index 97%rename from contrib/coccinelle/spatchcacherename to tools/coccinelle/spatchcacheindex 29e9352d8a..efbcbc3827 100755--- a/contrib/coccinelle/spatchcache+++ b/tools/coccinelle/spatchcache
@@ -30,7 +30,7 @@ # out of control. # # This along with the general incremental "make" support for-# "contrib/coccinelle" makes it viable to (re-)run coccicheck+# "tools/coccinelle" makes it viable to (re-)run coccicheck # e.g. when merging integration branches. # # Note that the "--very-quiet" flag is currently critical. The cache
@@ -42,7 +42,7 @@ # to change, so just supply "--very-quiet" for now. # # To use this, simply set SPATCH to-# contrib/coccinelle/spatchcache. Then optionally set:+# tools/coccinelle/spatchcache. Then optionally set: # # [spatchCache] # # Optional: path to a custom spatch
@@ -65,7 +65,7 @@ # # redis-cli FLUSHALL # <make && make coccicheck, as above>-# grep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/contrib/coccinelle | sort | uniq -c+# grep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/tools/coccinelle | sort | uniq -c # 600 CANTCACHE # 7365 MISS # 7365 SET
diff --git a/contrib/coccinelle/strbuf.cocci b/tools/coccinelle/strbuf.coccisimilarity index 100%rename from contrib/coccinelle/strbuf.coccirename to tools/coccinelle/strbuf.coccidiff --git a/contrib/coccinelle/swap.cocci b/tools/coccinelle/swap.coccisimilarity index 100%rename from contrib/coccinelle/swap.coccirename to tools/coccinelle/swap.coccidiff --git a/contrib/coccinelle/tests/free.c b/tools/coccinelle/tests/free.csimilarity index 100%rename from contrib/coccinelle/tests/free.crename to tools/coccinelle/tests/free.cdiff --git a/contrib/coccinelle/tests/free.res b/tools/coccinelle/tests/free.ressimilarity index 100%rename from contrib/coccinelle/tests/free.resrename to tools/coccinelle/tests/free.resdiff --git a/contrib/coccinelle/the_repository.cocci b/tools/coccinelle/the_repository.coccisimilarity index 100%rename from contrib/coccinelle/the_repository.coccirename to tools/coccinelle/the_repository.coccidiff --git a/contrib/coccinelle/xcalloc.cocci b/tools/coccinelle/xcalloc.coccisimilarity index 100%rename from contrib/coccinelle/xcalloc.coccirename to tools/coccinelle/xcalloc.coccidiff --git a/contrib/coccinelle/xopen.cocci b/tools/coccinelle/xopen.coccisimilarity index 100%rename from contrib/coccinelle/xopen.coccirename to tools/coccinelle/xopen.coccidiff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/tools/coccinelle/xstrdup_or_null.coccisimilarity index 100%rename from contrib/coccinelle/xstrdup_or_null.coccirename to tools/coccinelle/xstrdup_or_null.coccidiff --git a/contrib/coccinelle/xstrncmpz.cocci b/tools/coccinelle/xstrncmpz.coccisimilarity index 100%rename from contrib/coccinelle/xstrncmpz.coccirename to tools/coccinelle/xstrncmpz.coccidiff --git a/tools/meson.build b/tools/meson.buildindex e69de29bb2..f731f74312 100644--- a/tools/meson.build+++ b/tools/meson.build
From: Patrick Steinhardt <hidden> Date: 2026-03-16 10:08:19
The "coverage-diff.sh" script can be used to get information about test
coverage fro the Git codebase. It is thus rather specific to our build
and test infrastructure and part of the developer-facing tooling. The
fact that this script is part of "contrib/" is thus rather misleading
and a historic wart.
Promote the tool into the new "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
{contrib => tools}/coverage-diff.sh | 0
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/contrib/coverage-diff.sh b/tools/coverage-diff.shsimilarity index 100%rename from contrib/coverage-diff.shrename to tools/coverage-diff.sh
--
2.53.0.959.g497ff81fa9.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-16 10:08:21
The "update-unicode.sh" script is used to update the unicode data
compiled into Git whenever a new version of the Unicode standard has
been released. As such, it is a natural part of our developer-facing
tooling, and its presence in "contrib/" is misleading.
Promote the script into the new "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
{contrib => tools}/update-unicode/.gitignore | 0
{contrib => tools}/update-unicode/README | 0
{contrib => tools}/update-unicode/update_unicode.sh | 0
3 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/contrib/update-unicode/.gitignore b/tools/update-unicode/.gitignoresimilarity index 100%rename from contrib/update-unicode/.gitignorerename to tools/update-unicode/.gitignorediff --git a/contrib/update-unicode/README b/tools/update-unicode/READMEsimilarity index 100%rename from contrib/update-unicode/READMErename to tools/update-unicode/READMEdiff --git a/contrib/update-unicode/update_unicode.sh b/tools/update-unicode/update_unicode.shsimilarity index 100%rename from contrib/update-unicode/update_unicode.shrename to tools/update-unicode/update_unicode.sh
--
2.53.0.959.g497ff81fa9.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-16 10:08:24
We have a bunch of scripts used by our different build systems that are
all located in the top-level directory. Now that we have introduced the
new "tools/" directory though we have a better home for them.
Move the scripts into the "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
Makefile | 34 +++++++++++-----------
config.mak.dev | 2 +-
contrib/buildsystems/CMakeLists.txt | 18 ++++++------
contrib/subtree/meson.build | 2 +-
meson.build | 14 ++++-----
check-builtins.sh => tools/check-builtins.sh | 0
detect-compiler => tools/detect-compiler | 0
generate-cmdlist.sh => tools/generate-cmdlist.sh | 0
.../generate-configlist.sh | 0
generate-hooklist.sh => tools/generate-hooklist.sh | 0
generate-perl.sh => tools/generate-perl.sh | 0
generate-python.sh => tools/generate-python.sh | 0
generate-script.sh => tools/generate-script.sh | 0
13 files changed, 35 insertions(+), 35 deletions(-)
@@ -3936,7 +3936,7 @@ check-docs::### Make sure built-ins do not have dups and listed in git.c#check-builtins::-./check-builtins.sh+./tools/check-builtins.sh### Test suite coverage testing#
@@ -2008,7 +2008,7 @@ if perl_features_enabledgenerate_perl_command=[shell,-meson.project_source_root()/'generate-perl.sh',+meson.project_source_root()/'tools/generate-perl.sh',meson.project_build_root()/'GIT-BUILD-OPTIONS',git_version_file.full_path(),perl_header,
@@ -2057,7 +2057,7 @@ if target_python.found()output:fs.stem(script),command:[shell,-meson.project_source_root()/'generate-python.sh',+meson.project_source_root()/'tools/generate-python.sh',meson.project_build_root()/'GIT-BUILD-OPTIONS','@INPUT@','@OUTPUT@',
diff --git a/check-builtins.sh b/tools/check-builtins.shsimilarity index 100%rename from check-builtins.shrename to tools/check-builtins.shdiff --git a/detect-compiler b/tools/detect-compilersimilarity index 100%rename from detect-compilerrename to tools/detect-compilerdiff --git a/generate-cmdlist.sh b/tools/generate-cmdlist.shsimilarity index 100%rename from generate-cmdlist.shrename to tools/generate-cmdlist.shdiff --git a/generate-configlist.sh b/tools/generate-configlist.shsimilarity index 100%rename from generate-configlist.shrename to tools/generate-configlist.shdiff --git a/generate-hooklist.sh b/tools/generate-hooklist.shsimilarity index 100%rename from generate-hooklist.shrename to tools/generate-hooklist.shdiff --git a/generate-perl.sh b/tools/generate-perl.shsimilarity index 100%rename from generate-perl.shrename to tools/generate-perl.shdiff --git a/generate-python.sh b/tools/generate-python.shsimilarity index 100%rename from generate-python.shrename to tools/generate-python.shdiff --git a/generate-script.sh b/tools/generate-script.shsimilarity index 100%rename from generate-script.shrename to tools/generate-script.sh
--
2.53.0.959.g497ff81fa9.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-16 10:08:26
The "git-compat-util.h" header is supposed to be the first header
included by every code compilation unit. As such, a subsequent commit
will start to precompile this header to speed up compilation of Git.
This will cause an issue though with the way that we have set up the
"-Wsign-compare" warnings. It is expected that any compilation unit that
fails with that compiler warning sets `DISABLE_SIGN_COMPARE_WARNINGS`
before including "git-compat-util.h". If so, we'll disable the warning
right away via a compiler pragma.
But with precompiled headers we do not know ahead of time whether the
code unit wants to disable those warnings, and thus we'll have to
precompile the header without defining `DISABLE_SIGN_COMPARE_WARNINGS`.
But as the pragma statement is wrapped by our include guards, the second
include of that file will not have the desired effect of disabling the
warnings anymore.
We could fix this issue by declaring a new macro that compilation units
are expected to invoke after having included the file. In retrospect,
that would have been the better way to handle this as it allows for
more flexibility: we could for example toggle the warning for specific
code blocks, only. But changing this now would require a bunch of
changes, and the churn feels excessive for what we gain.
Instead, prepare for the precompiled headers by moving the code outside
of the include guards.
Signed-off-by: Patrick Steinhardt <redacted>
---
git-compat-util.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2026-03-16 10:08:28
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
This is okay for our "normal" library sources and our builtins. But some
of our compatibility sources do not include the header on purpose, and
doing so would cause compileir errors.
Prepare for this change by splitting out compatibility sources into
their static library. Like this we can selectively enable precompiled
headers for the library sources.
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 79 +++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 45 insertions(+), 34 deletions(-)
@@ -1179,7 +1182,7 @@ endif# implementation to threat things like drive prefixes specially.ifhost_machine.system()=='windows'ornotcompiler.has_header('libgen.h')libgit_c_args+='-DNO_LIBGEN_H'-libgit_sources+='compat/basename.c'+compat_sources+='compat/basename.c'endififcompiler.has_header('paths.h')
@@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'foreachsymbol:['inet_ntop','inet_pton','hstrerror']ifnotcompiler.has_function(symbol,dependencies:networking_dependencies)libgit_c_args+='-DNO_'+symbol.to_upper()-libgit_sources+='compat/'+symbol+'.c'+compat_sources+='compat/'+symbol+'.c'endifendforeachendif
@@ -1251,18 +1254,18 @@ elseendififhost_machine.system()=='darwin'-libgit_sources+='compat/precompose_utf8.c'+compat_sources+='compat/precompose_utf8.c'libgit_c_args+='-DPRECOMPOSE_UNICODE'libgit_c_args+='-DPROTECT_HFS_DEFAULT'endif# Configure general compatibility wrappers.ifhost_machine.system()=='cygwin'-libgit_sources+=[+compat_sources+=['compat/win32/path-utils.c',]elifhost_machine.system()=='windows'-libgit_sources+=[+compat_sources+=['compat/winansi.c','compat/win32/dirent.c','compat/win32/flush.c',
@@ -1315,13 +1318,13 @@ endif# Configure the simple-ipc subsystem required fro the fsmonitor.ifhost_machine.system()=='windows'-libgit_sources+=[+compat_sources+=['compat/simple-ipc/ipc-shared.c','compat/simple-ipc/ipc-win32.c',]libgit_c_args+='-DSUPPORTS_SIMPLE_IPC'else-libgit_sources+=[+compat_sources+=['compat/simple-ipc/ipc-shared.c','compat/simple-ipc/ipc-unix-socket.c',]
@@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''libgit_c_args+='-DHAVE_FSMONITOR_DAEMON_BACKEND'libgit_c_args+='-DHAVE_FSMONITOR_OS_SETTINGS'-libgit_sources+=[+compat_sources+=['compat/fsmonitor/fsm-health-'+fsmonitor_backend+'.c','compat/fsmonitor/fsm-ipc-'+fsmonitor_backend+'.c','compat/fsmonitor/fsm-listen-'+fsmonitor_backend+'.c',
@@ -1355,7 +1358,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').alloifcompiler.get_define('REG_ENHANCED',prefix:'#include <regex.h>')!=''libgit_c_args+='-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'-libgit_sources+='compat/regcomp_enhanced.c'+compat_sources+='compat/regcomp_enhanced.c'endifelifnotget_option('regex').enabled()libgit_c_args+=[
@@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()'-DNO_MBSUPPORT',]build_options_config.set('NO_REGEX','1')-libgit_sources+='compat/regex/regex.c'+compat_sources+='compat/regex/regex.c'libgit_include_directories+='compat/regex'elseerror('Native regex support requested but not found')
@@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and compiler.run('''}''', name: 'freadreadsdirectories').returncode()==0libgit_c_args+='-DFREAD_READS_DIRECTORIES'-libgit_sources+='compat/fopen.c'+compat_sources+='compat/fopen.c'endififnotmeson.is_cross_build()andfs.exists('/dev/tty')
From: Patrick Steinhardt <hidden> Date: 2026-03-16 10:08:31
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This causes Meson to implicitly include the precompiled
header in all compilation units. With GCC and Clang for example this is
done via the "-include" statement [1].
This leads to a significant speedup when performing full builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
[1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 2 ++
tools/precompiled.h | 1 +
2 files changed, 3 insertions(+)
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:33:28
Hi,
this patch series contains a small set of build system improvements:
- The first couple patches introduce a new "tools/" directory that
contains items related to our build infrastructure and to our
developer tooling. This finally follows up on my promise to do this
back when I did the spring clean of "contrib/". [1]
- The last couple patches introduce precompiled headers into Meson for
a nice compilation speedup of ~30%. It's
The two topics are not really related with one another other than being
related to build systems. I decided to throw them in the same patch
series though so that I can introduce "precompiled.h" in "tools/".
Changes in v3:
- Improve commit message.
- Link to v2: https://lore.kernel.org/r/20260316-b4-pks-build-infra-improvements-v2-0-4b2c2c0c0425@pks.im
Changes in v2:
- Turn array of precompiled headers into a simple string.
- Point out in the commit message that the precompiled header is
included implicitly.
- Link to v1: https://lore.kernel.org/r/20260310-b4-pks-build-infra-improvements-v1-0-ec75d0710d6a@pks.im
Thanks!
Patrick
[1]: https://lore.kernel.org/git/20250506-pks-contrib-spring-cleanup-v1-0-e6d5ddd79a72@pks.im/
---
Patrick Steinhardt (8):
Introduce new "tools/" directory
contrib: move "coccinelle/" directory into "tools/"
contrib: move "coverage-diff.sh" script into "tools/"
contrib: move "update-unicode.sh" script into "tools/"
builds: move build scripts into "tools/"
git-compat-util.h: move warning infra to prepare for PCHs
meson: compile compatibility sources separately
meson: precompile "git-compat-util.h"
Makefile | 76 ++++++++---------
ci/run-static-analysis.sh | 2 +-
config.mak.dev | 2 +-
contrib/buildsystems/CMakeLists.txt | 18 ++--
contrib/meson.build | 1 -
contrib/subtree/meson.build | 2 +-
git-compat-util.h | 8 +-
meson.build | 96 +++++++++++++---------
tools/README.md | 7 ++
check-builtins.sh => tools/check-builtins.sh | 0
{contrib => tools}/coccinelle/.gitignore | 0
{contrib => tools}/coccinelle/README | 2 +-
{contrib => tools}/coccinelle/array.cocci | 0
{contrib => tools}/coccinelle/commit.cocci | 0
.../coccinelle/config_fn_ctx.pending.cocci | 0
{contrib => tools}/coccinelle/equals-null.cocci | 0
{contrib => tools}/coccinelle/flex_alloc.cocci | 0
{contrib => tools}/coccinelle/free.cocci | 0
.../coccinelle/git_config_number.cocci | 0
{contrib => tools}/coccinelle/hashmap.cocci | 0
.../coccinelle/index-compatibility.cocci | 0
{contrib => tools}/coccinelle/meson.build | 0
{contrib => tools}/coccinelle/object_id.cocci | 0
{contrib => tools}/coccinelle/preincr.cocci | 0
{contrib => tools}/coccinelle/qsort.cocci | 0
{contrib => tools}/coccinelle/refs.cocci | 0
{contrib => tools}/coccinelle/spatchcache | 6 +-
{contrib => tools}/coccinelle/strbuf.cocci | 0
{contrib => tools}/coccinelle/swap.cocci | 0
{contrib => tools}/coccinelle/tests/free.c | 0
{contrib => tools}/coccinelle/tests/free.res | 0
{contrib => tools}/coccinelle/the_repository.cocci | 0
{contrib => tools}/coccinelle/xcalloc.cocci | 0
{contrib => tools}/coccinelle/xopen.cocci | 0
.../coccinelle/xstrdup_or_null.cocci | 0
{contrib => tools}/coccinelle/xstrncmpz.cocci | 0
{contrib => tools}/coverage-diff.sh | 0
detect-compiler => tools/detect-compiler | 0
generate-cmdlist.sh => tools/generate-cmdlist.sh | 0
.../generate-configlist.sh | 0
generate-hooklist.sh => tools/generate-hooklist.sh | 0
generate-perl.sh => tools/generate-perl.sh | 0
generate-python.sh => tools/generate-python.sh | 0
generate-script.sh => tools/generate-script.sh | 0
tools/meson.build | 1 +
tools/precompiled.h | 1 +
{contrib => tools}/update-unicode/.gitignore | 0
{contrib => tools}/update-unicode/README | 0
.../update-unicode/update_unicode.sh | 0
49 files changed, 123 insertions(+), 99 deletions(-)
Range-diff versus v2:
1: 051b66376f = 1: bc18fe2f2d Introduce new "tools/" directory
2: 275a96c805 = 2: 393b42f433 contrib: move "coccinelle/" directory into "tools/"
3: afc5a1f8b9 = 3: 00284934e9 contrib: move "coverage-diff.sh" script into "tools/"
4: 909d996f56 = 4: 9dceec07dd contrib: move "update-unicode.sh" script into "tools/"
5: 6396ae723e = 5: af0ce83627 builds: move build scripts into "tools/"
6: 16b0e9f4fb = 6: 8cb7ea8245 git-compat-util.h: move warning infra to prepare for PCHs
7: b4cd150fdf ! 7: 495335a97a meson: compile compatibility sources separately
@@ Commit message
This is okay for our "normal" library sources and our builtins. But some
of our compatibility sources do not include the header on purpose, and
- doing so would cause compileir errors.
+ doing so would cause compilation errors.
Prepare for this change by splitting out compatibility sources into
- their static library. Like this we can selectively enable precompiled
+ their static library. Like this, we can selectively enable precompiled
headers for the library sources.
Signed-off-by: Patrick Steinhardt [off-list ref]
8: 5899e0318b = 8: 6923592b62 meson: precompile "git-compat-util.h"
---
base-commit: af2c8a61818d773325ef2324dd135786a03ebca0
change-id: 20260304-b4-pks-build-infra-improvements-cc4012c5364e
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:33:29
According to its readme, the "contrib/" directory's main intent is to
collect stuff that is not an official part of Git, either because it is
too specialized or because it is still considered experimental. The
reality tells a bit of a different story though: while it _does_ contain
such things, it also contains other things:
- Our credential helpers, which are being distributed by many
packagers nowadays and which can be considered "stable".
- A bunch of tooling that relates to our build and test
infrastructure.
Especially the second category is somewhat of a sore spot. You really
wouldn't expect build-related tooling to be considered an optional part
of Git. Quite the opposite.
Create a new top-level "tools/" directory to fix this discrepancy. This
directory will contain all kind of tools that are related to our build
infrastructure and that Git developers are likely to use day to day.
For now, this directory doesn't contain anything yet except for a
readme and a Meson skeleton. This will change in subsequent commits.
Signed-off-by: Patrick Steinhardt <redacted>
---
Makefile | 2 ++
meson.build | 1 +
tools/README.md | 7 +++++++
tools/meson.build | 0
4 files changed, 10 insertions(+)
@@ -2149,6 +2149,7 @@ elseendifsubdir('contrib')+subdir('tools')# Note that the target is intentionally configured after including the# 'contrib' directory, as some tool there also have their own manpages.
@@ -0,0 +1,7 @@+Developer Tooling+-----------------++This directory is expected to contain all sorts of tooling that+relates to our build infrastructure. This includes scripts and+inputs required by our build systems, but also scripts that+developers are expected to run manually.
@@ -1005,8 +1005,8 @@ SPATCH_TEST_FLAGS =# COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.SPATCH_USE_O_DEPENDENCIES=YesPlease-# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci-# files into a single contrib/cocci/ALL.cocci before running+# Set SPATCH_CONCAT_COCCI to concatenate the tools/coccinelle/*.cocci+# files into a single tools/coccinelle/ALL.cocci before running# "coccicheck".## Pros:
@@ -1025,7 +1025,7 @@ SPATCH_USE_O_DEPENDENCIES = YesPlease# generate a specific patch, e.g. this will always use strbuf.cocci,# not ALL.cocci:#-# make contrib/coccinelle/strbuf.cocci.patch+# make tools/coccinelle/strbuf.cocci.patchSPATCH_CONCAT_COCCI=YesPlease# Rebuild 'coccicheck' if $(SPATCH), its flags etc. change
@@ -3480,20 +3480,20 @@ COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)# on $(MAKECMDGOALS) that match these $(COCCI_RULES)COCCI_RULES_GLOB=COCCI_RULES_GLOB+=cocci%-COCCI_RULES_GLOB+=.build/contrib/coccinelle/%+COCCI_RULES_GLOB+=.build/tools/coccinelle/%COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES)COCCI_RULES_GLOB+=$(COCCICHEC_PATCHES_PENDING)COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES_INTREE)COCCI_RULES_GLOB+=$(COCCICHECK_PATCHES_PENDING_INTREE)COCCI_GOALS=$(filter$(COCCI_RULES_GLOB),$(MAKECMDGOALS))-COCCI_TEST_RES=$(wildcardcontrib/coccinelle/tests/*.res)+COCCI_TEST_RES=$(wildcardtools/coccinelle/tests/*.res)$(COCCI_RULES_TRACKED):.build/% : %$(callmkdir_p_parent_template)$(QUIET_CP)cp$<$@-.build/contrib/coccinelle/FOUND_H_SOURCES:$(FOUND_H_SOURCES)+.build/tools/coccinelle/FOUND_H_SOURCES:$(FOUND_H_SOURCES)$(callmkdir_p_parent_template)$(QUIET_GEN)>$@
@@ -3507,12 +3507,12 @@ endifdefine cocci-rule## Rule for .build/$(1).patch/$(2); Params:-# $(1) = e.g. ".build/contrib/coccinelle/free.cocci"+# $(1) = e.g. ".build/tools/coccinelle/free.cocci"# $(2) = e.g. "grep.c"# $(3) = e.g. "grep.o"-COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch+COCCI_$(1:.build/tools/coccinelle/%.cocci=%) += $(1).d/$(2).patch$(1).d/$(2).patch:GIT-SPATCH-DEFINES-$(1).d/$(2).patch:$(if$(and$(SPATCH_USE_O_DEPENDENCIES),$(wildcard$(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)+$(1).d/$(2).patch:$(if$(and$(SPATCH_USE_O_DEPENDENCIES),$(wildcard$(3))),$(3),.build/tools/coccinelle/FOUND_H_SOURCES)$(1).d/$(2).patch:$(1)$(1).d/$(2).patch:$(1).d/%.patch : %$$(callmkdir_p_parent_template)
@@ -3538,13 +3538,13 @@ endifdefine spatch-rule-.build/contrib/coccinelle/$(1).cocci.patch:$$(COCCI_$(1))+.build/tools/coccinelle/$(1).cocci.patch:$$(COCCI_$(1))$$(QUIET_SPATCH_CAT)cat$$^>$$@&&\ if test -s $$@; \then\echo' 'SPATCHresult:$$@;\fi-contrib/coccinelle/$(1).cocci.patch:.build/contrib/coccinelle/$(1).cocci.patch+tools/coccinelle/$(1).cocci.patch:.build/tools/coccinelle/$(1).cocci.patch$$(QUIET_CP)cp$$<$$@endef
diff --git a/contrib/coccinelle/.gitignore b/tools/coccinelle/.gitignoresimilarity index 100%rename from contrib/coccinelle/.gitignorerename to tools/coccinelle/.gitignorediff --git a/contrib/coccinelle/README b/tools/coccinelle/READMEsimilarity index 98%rename from contrib/coccinelle/READMErename to tools/coccinelle/READMEindex 055ad0e06a..fd0a543cc2 100644--- a/contrib/coccinelle/README+++ b/tools/coccinelle/README
@@ -38,7 +38,7 @@ that might be useful to developers. So to aid these large scale refactorings, semantic patches can be used. However we do not want to store them in the same place as the checks for bad patterns, as then automated builds would fail.- That is why semantic patches 'contrib/coccinelle/*.pending.cocci'+ That is why semantic patches 'tools/coccinelle/*.pending.cocci' are ignored for checks, and can be applied using 'make coccicheck-pending'. This allows to expose plans of pending large scale refactorings without
diff --git a/contrib/coccinelle/array.cocci b/tools/coccinelle/array.coccisimilarity index 100%rename from contrib/coccinelle/array.coccirename to tools/coccinelle/array.coccidiff --git a/contrib/coccinelle/commit.cocci b/tools/coccinelle/commit.coccisimilarity index 100%rename from contrib/coccinelle/commit.coccirename to tools/coccinelle/commit.coccidiff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/tools/coccinelle/config_fn_ctx.pending.coccisimilarity index 100%rename from contrib/coccinelle/config_fn_ctx.pending.coccirename to tools/coccinelle/config_fn_ctx.pending.coccidiff --git a/contrib/coccinelle/equals-null.cocci b/tools/coccinelle/equals-null.coccisimilarity index 100%rename from contrib/coccinelle/equals-null.coccirename to tools/coccinelle/equals-null.coccidiff --git a/contrib/coccinelle/flex_alloc.cocci b/tools/coccinelle/flex_alloc.coccisimilarity index 100%rename from contrib/coccinelle/flex_alloc.coccirename to tools/coccinelle/flex_alloc.coccidiff --git a/contrib/coccinelle/free.cocci b/tools/coccinelle/free.coccisimilarity index 100%rename from contrib/coccinelle/free.coccirename to tools/coccinelle/free.coccidiff --git a/contrib/coccinelle/git_config_number.cocci b/tools/coccinelle/git_config_number.coccisimilarity index 100%rename from contrib/coccinelle/git_config_number.coccirename to tools/coccinelle/git_config_number.coccidiff --git a/contrib/coccinelle/hashmap.cocci b/tools/coccinelle/hashmap.coccisimilarity index 100%rename from contrib/coccinelle/hashmap.coccirename to tools/coccinelle/hashmap.coccidiff --git a/contrib/coccinelle/index-compatibility.cocci b/tools/coccinelle/index-compatibility.coccisimilarity index 100%rename from contrib/coccinelle/index-compatibility.coccirename to tools/coccinelle/index-compatibility.coccidiff --git a/contrib/coccinelle/meson.build b/tools/coccinelle/meson.buildsimilarity index 100%rename from contrib/coccinelle/meson.buildrename to tools/coccinelle/meson.builddiff --git a/contrib/coccinelle/object_id.cocci b/tools/coccinelle/object_id.coccisimilarity index 100%rename from contrib/coccinelle/object_id.coccirename to tools/coccinelle/object_id.coccidiff --git a/contrib/coccinelle/preincr.cocci b/tools/coccinelle/preincr.coccisimilarity index 100%rename from contrib/coccinelle/preincr.coccirename to tools/coccinelle/preincr.coccidiff --git a/contrib/coccinelle/qsort.cocci b/tools/coccinelle/qsort.coccisimilarity index 100%rename from contrib/coccinelle/qsort.coccirename to tools/coccinelle/qsort.coccidiff --git a/contrib/coccinelle/refs.cocci b/tools/coccinelle/refs.coccisimilarity index 100%rename from contrib/coccinelle/refs.coccirename to tools/coccinelle/refs.coccidiff --git a/contrib/coccinelle/spatchcache b/tools/coccinelle/spatchcachesimilarity index 97%rename from contrib/coccinelle/spatchcacherename to tools/coccinelle/spatchcacheindex 29e9352d8a..efbcbc3827 100755--- a/contrib/coccinelle/spatchcache+++ b/tools/coccinelle/spatchcache
@@ -30,7 +30,7 @@ # out of control. # # This along with the general incremental "make" support for-# "contrib/coccinelle" makes it viable to (re-)run coccicheck+# "tools/coccinelle" makes it viable to (re-)run coccicheck # e.g. when merging integration branches. # # Note that the "--very-quiet" flag is currently critical. The cache
@@ -42,7 +42,7 @@ # to change, so just supply "--very-quiet" for now. # # To use this, simply set SPATCH to-# contrib/coccinelle/spatchcache. Then optionally set:+# tools/coccinelle/spatchcache. Then optionally set: # # [spatchCache] # # Optional: path to a custom spatch
@@ -65,7 +65,7 @@ # # redis-cli FLUSHALL # <make && make coccicheck, as above>-# grep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/contrib/coccinelle | sort | uniq -c+# grep -hore HIT -e MISS -e SET -e NOCACHE -e CANTCACHE .build/tools/coccinelle | sort | uniq -c # 600 CANTCACHE # 7365 MISS # 7365 SET
diff --git a/contrib/coccinelle/strbuf.cocci b/tools/coccinelle/strbuf.coccisimilarity index 100%rename from contrib/coccinelle/strbuf.coccirename to tools/coccinelle/strbuf.coccidiff --git a/contrib/coccinelle/swap.cocci b/tools/coccinelle/swap.coccisimilarity index 100%rename from contrib/coccinelle/swap.coccirename to tools/coccinelle/swap.coccidiff --git a/contrib/coccinelle/tests/free.c b/tools/coccinelle/tests/free.csimilarity index 100%rename from contrib/coccinelle/tests/free.crename to tools/coccinelle/tests/free.cdiff --git a/contrib/coccinelle/tests/free.res b/tools/coccinelle/tests/free.ressimilarity index 100%rename from contrib/coccinelle/tests/free.resrename to tools/coccinelle/tests/free.resdiff --git a/contrib/coccinelle/the_repository.cocci b/tools/coccinelle/the_repository.coccisimilarity index 100%rename from contrib/coccinelle/the_repository.coccirename to tools/coccinelle/the_repository.coccidiff --git a/contrib/coccinelle/xcalloc.cocci b/tools/coccinelle/xcalloc.coccisimilarity index 100%rename from contrib/coccinelle/xcalloc.coccirename to tools/coccinelle/xcalloc.coccidiff --git a/contrib/coccinelle/xopen.cocci b/tools/coccinelle/xopen.coccisimilarity index 100%rename from contrib/coccinelle/xopen.coccirename to tools/coccinelle/xopen.coccidiff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/tools/coccinelle/xstrdup_or_null.coccisimilarity index 100%rename from contrib/coccinelle/xstrdup_or_null.coccirename to tools/coccinelle/xstrdup_or_null.coccidiff --git a/contrib/coccinelle/xstrncmpz.cocci b/tools/coccinelle/xstrncmpz.coccisimilarity index 100%rename from contrib/coccinelle/xstrncmpz.coccirename to tools/coccinelle/xstrncmpz.coccidiff --git a/tools/meson.build b/tools/meson.buildindex e69de29bb2..f731f74312 100644--- a/tools/meson.build+++ b/tools/meson.build
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:33:35
The "coverage-diff.sh" script can be used to get information about test
coverage fro the Git codebase. It is thus rather specific to our build
and test infrastructure and part of the developer-facing tooling. The
fact that this script is part of "contrib/" is thus rather misleading
and a historic wart.
Promote the tool into the new "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
{contrib => tools}/coverage-diff.sh | 0
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/contrib/coverage-diff.sh b/tools/coverage-diff.shsimilarity index 100%rename from contrib/coverage-diff.shrename to tools/coverage-diff.sh
--
2.53.0.959.g497ff81fa9.dirty
The "coverage-diff.sh" script can be used to get information about test
coverage fro the Git codebase. It is thus rather specific to our build
Tiniest nit s/fro/for
quoted hunk
and test infrastructure and part of the developer-facing tooling. The
fact that this script is part of "contrib/" is thus rather misleading
and a historic wart.
Promote the tool into the new "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
{contrib => tools}/coverage-diff.sh | 0
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/contrib/coverage-diff.sh b/tools/coverage-diff.shsimilarity index 100%rename from contrib/coverage-diff.shrename to tools/coverage-diff.sh
--
2.53.0.959.g497ff81fa9.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:33:37
The "update-unicode.sh" script is used to update the unicode data
compiled into Git whenever a new version of the Unicode standard has
been released. As such, it is a natural part of our developer-facing
tooling, and its presence in "contrib/" is misleading.
Promote the script into the new "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
{contrib => tools}/update-unicode/.gitignore | 0
{contrib => tools}/update-unicode/README | 0
{contrib => tools}/update-unicode/update_unicode.sh | 0
3 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/contrib/update-unicode/.gitignore b/tools/update-unicode/.gitignoresimilarity index 100%rename from contrib/update-unicode/.gitignorerename to tools/update-unicode/.gitignorediff --git a/contrib/update-unicode/README b/tools/update-unicode/READMEsimilarity index 100%rename from contrib/update-unicode/READMErename to tools/update-unicode/READMEdiff --git a/contrib/update-unicode/update_unicode.sh b/tools/update-unicode/update_unicode.shsimilarity index 100%rename from contrib/update-unicode/update_unicode.shrename to tools/update-unicode/update_unicode.sh
--
2.53.0.959.g497ff81fa9.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:33:40
We have a bunch of scripts used by our different build systems that are
all located in the top-level directory. Now that we have introduced the
new "tools/" directory though we have a better home for them.
Move the scripts into the "tools/" directory.
Signed-off-by: Patrick Steinhardt <redacted>
---
Makefile | 34 +++++++++++-----------
config.mak.dev | 2 +-
contrib/buildsystems/CMakeLists.txt | 18 ++++++------
contrib/subtree/meson.build | 2 +-
meson.build | 14 ++++-----
check-builtins.sh => tools/check-builtins.sh | 0
detect-compiler => tools/detect-compiler | 0
generate-cmdlist.sh => tools/generate-cmdlist.sh | 0
.../generate-configlist.sh | 0
generate-hooklist.sh => tools/generate-hooklist.sh | 0
generate-perl.sh => tools/generate-perl.sh | 0
generate-python.sh => tools/generate-python.sh | 0
generate-script.sh => tools/generate-script.sh | 0
13 files changed, 35 insertions(+), 35 deletions(-)
@@ -3936,7 +3936,7 @@ check-docs::### Make sure built-ins do not have dups and listed in git.c#check-builtins::-./check-builtins.sh+./tools/check-builtins.sh### Test suite coverage testing#
@@ -2008,7 +2008,7 @@ if perl_features_enabledgenerate_perl_command=[shell,-meson.project_source_root()/'generate-perl.sh',+meson.project_source_root()/'tools/generate-perl.sh',meson.project_build_root()/'GIT-BUILD-OPTIONS',git_version_file.full_path(),perl_header,
@@ -2057,7 +2057,7 @@ if target_python.found()output:fs.stem(script),command:[shell,-meson.project_source_root()/'generate-python.sh',+meson.project_source_root()/'tools/generate-python.sh',meson.project_build_root()/'GIT-BUILD-OPTIONS','@INPUT@','@OUTPUT@',
diff --git a/check-builtins.sh b/tools/check-builtins.shsimilarity index 100%rename from check-builtins.shrename to tools/check-builtins.shdiff --git a/detect-compiler b/tools/detect-compilersimilarity index 100%rename from detect-compilerrename to tools/detect-compilerdiff --git a/generate-cmdlist.sh b/tools/generate-cmdlist.shsimilarity index 100%rename from generate-cmdlist.shrename to tools/generate-cmdlist.shdiff --git a/generate-configlist.sh b/tools/generate-configlist.shsimilarity index 100%rename from generate-configlist.shrename to tools/generate-configlist.shdiff --git a/generate-hooklist.sh b/tools/generate-hooklist.shsimilarity index 100%rename from generate-hooklist.shrename to tools/generate-hooklist.shdiff --git a/generate-perl.sh b/tools/generate-perl.shsimilarity index 100%rename from generate-perl.shrename to tools/generate-perl.shdiff --git a/generate-python.sh b/tools/generate-python.shsimilarity index 100%rename from generate-python.shrename to tools/generate-python.shdiff --git a/generate-script.sh b/tools/generate-script.shsimilarity index 100%rename from generate-script.shrename to tools/generate-script.sh
--
2.53.0.959.g497ff81fa9.dirty
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:33:42
The "git-compat-util.h" header is supposed to be the first header
included by every code compilation unit. As such, a subsequent commit
will start to precompile this header to speed up compilation of Git.
This will cause an issue though with the way that we have set up the
"-Wsign-compare" warnings. It is expected that any compilation unit that
fails with that compiler warning sets `DISABLE_SIGN_COMPARE_WARNINGS`
before including "git-compat-util.h". If so, we'll disable the warning
right away via a compiler pragma.
But with precompiled headers we do not know ahead of time whether the
code unit wants to disable those warnings, and thus we'll have to
precompile the header without defining `DISABLE_SIGN_COMPARE_WARNINGS`.
But as the pragma statement is wrapped by our include guards, the second
include of that file will not have the desired effect of disabling the
warnings anymore.
We could fix this issue by declaring a new macro that compilation units
are expected to invoke after having included the file. In retrospect,
that would have been the better way to handle this as it allows for
more flexibility: we could for example toggle the warning for specific
code blocks, only. But changing this now would require a bunch of
changes, and the churn feels excessive for what we gain.
Instead, prepare for the precompiled headers by moving the code outside
of the include guards.
Signed-off-by: Patrick Steinhardt <redacted>
---
git-compat-util.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
The "git-compat-util.h" header is supposed to be the first header
included by every code compilation unit. As such, a subsequent commit
will start to precompile this header to speed up compilation of Git.
This will cause an issue though with the way that we have set up the
"-Wsign-compare" warnings. It is expected that any compilation unit that
fails with that compiler warning sets `DISABLE_SIGN_COMPARE_WARNINGS`
before including "git-compat-util.h". If so, we'll disable the warning
right away via a compiler pragma.
But with precompiled headers we do not know ahead of time whether the
code unit wants to disable those warnings, and thus we'll have to
precompile the header without defining `DISABLE_SIGN_COMPARE_WARNINGS`.
But as the pragma statement is wrapped by our include guards, the second
include of that file will not have the desired effect of disabling the
warnings anymore.
We could fix this issue by declaring a new macro that compilation units
are expected to invoke after having included the file. In retrospect,
that would have been the better way to handle this as it allows for
more flexibility: we could for example toggle the warning for specific
code blocks, only. But changing this now would require a bunch of
changes, and the churn feels excessive for what we gain.
Instead, prepare for the precompiled headers by moving the code outside
of the include guards.
Signed-off-by: Patrick Steinhardt <redacted>
---
git-compat-util.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
Okay, so with all patches applied, when a .c file is compiled,
tools/precompiled.h is included as the first one. That one includes
git-compat-util.h and processes everything inside the include guards.
Then it starts processing the contents of that files and that file might
#define DISABLE_SIGN_COMPARE_WARNINGS. Usually git-compat-util.h is then
included again, but thanks to the include guards, most of it is ignored,
except for this last bit.
Okay, makes sense.
--
Cheers,
Toon
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:33:45
In the next commit we're about to introduce a precompiled header for
"git-compat-util.h". The consequence of this change is that we'll
implicitly include that header for every compilation unit that uses the
precompiled headers.
This is okay for our "normal" library sources and our builtins. But some
of our compatibility sources do not include the header on purpose, and
doing so would cause compilation errors.
Prepare for this change by splitting out compatibility sources into
their static library. Like this, we can selectively enable precompiled
headers for the library sources.
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 79 +++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 45 insertions(+), 34 deletions(-)
@@ -1179,7 +1182,7 @@ endif# implementation to threat things like drive prefixes specially.ifhost_machine.system()=='windows'ornotcompiler.has_header('libgen.h')libgit_c_args+='-DNO_LIBGEN_H'-libgit_sources+='compat/basename.c'+compat_sources+='compat/basename.c'endififcompiler.has_header('paths.h')
@@ -1209,7 +1212,7 @@ if host_machine.system() != 'windows'foreachsymbol:['inet_ntop','inet_pton','hstrerror']ifnotcompiler.has_function(symbol,dependencies:networking_dependencies)libgit_c_args+='-DNO_'+symbol.to_upper()-libgit_sources+='compat/'+symbol+'.c'+compat_sources+='compat/'+symbol+'.c'endifendforeachendif
@@ -1251,18 +1254,18 @@ elseendififhost_machine.system()=='darwin'-libgit_sources+='compat/precompose_utf8.c'+compat_sources+='compat/precompose_utf8.c'libgit_c_args+='-DPRECOMPOSE_UNICODE'libgit_c_args+='-DPROTECT_HFS_DEFAULT'endif# Configure general compatibility wrappers.ifhost_machine.system()=='cygwin'-libgit_sources+=[+compat_sources+=['compat/win32/path-utils.c',]elifhost_machine.system()=='windows'-libgit_sources+=[+compat_sources+=['compat/winansi.c','compat/win32/dirent.c','compat/win32/flush.c',
@@ -1315,13 +1318,13 @@ endif# Configure the simple-ipc subsystem required fro the fsmonitor.ifhost_machine.system()=='windows'-libgit_sources+=[+compat_sources+=['compat/simple-ipc/ipc-shared.c','compat/simple-ipc/ipc-win32.c',]libgit_c_args+='-DSUPPORTS_SIMPLE_IPC'else-libgit_sources+=[+compat_sources+=['compat/simple-ipc/ipc-shared.c','compat/simple-ipc/ipc-unix-socket.c',]
@@ -1339,7 +1342,7 @@ if fsmonitor_backend != ''libgit_c_args+='-DHAVE_FSMONITOR_DAEMON_BACKEND'libgit_c_args+='-DHAVE_FSMONITOR_OS_SETTINGS'-libgit_sources+=[+compat_sources+=['compat/fsmonitor/fsm-health-'+fsmonitor_backend+'.c','compat/fsmonitor/fsm-ipc-'+fsmonitor_backend+'.c','compat/fsmonitor/fsm-listen-'+fsmonitor_backend+'.c',
@@ -1355,7 +1358,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').alloifcompiler.get_define('REG_ENHANCED',prefix:'#include <regex.h>')!=''libgit_c_args+='-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'-libgit_sources+='compat/regcomp_enhanced.c'+compat_sources+='compat/regcomp_enhanced.c'endifelifnotget_option('regex').enabled()libgit_c_args+=[
@@ -1364,7 +1367,7 @@ elif not get_option('regex').enabled()'-DNO_MBSUPPORT',]build_options_config.set('NO_REGEX','1')-libgit_sources+='compat/regex/regex.c'+compat_sources+='compat/regex/regex.c'libgit_include_directories+='compat/regex'elseerror('Native regex support requested but not found')
@@ -1511,7 +1514,7 @@ if meson.can_run_host_binaries() and compiler.run('''}''', name: 'freadreadsdirectories').returncode()==0libgit_c_args+='-DFREAD_READS_DIRECTORIES'-libgit_sources+='compat/fopen.c'+compat_sources+='compat/fopen.c'endififnotmeson.is_cross_build()andfs.exists('/dev/tty')
From: Patrick Steinhardt <hidden> Date: 2026-03-19 05:33:47
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This causes Meson to implicitly include the precompiled
header in all compilation units. With GCC and Clang for example this is
done via the "-include" statement [1].
This leads to a significant speedup when performing full builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
[1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 2 ++
tools/precompiled.h | 1 +
2 files changed, 3 insertions(+)
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This causes Meson to implicitly include the precompiled
header in all compilation units. With GCC and Clang for example this is
done via the "-include" statement [1].
This leads to a significant speedup when performing full builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
Quite cool! The only nit I would have about this, this optimization is
not applied to building with Makefiles. While that isn't an issue, I
wouldn't have hurt if it was mentioned in the commit message.
Anyway, overall I got nothing that's holding back this series from
merging. Looks good!
--
Cheers,
Toon
From: SZEDER Gábor <hidden> Date: 2026-04-10 15:37:00
On Thu, Mar 19, 2026 at 06:33:27AM +0100, Patrick Steinhardt wrote:
quoted hunk
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This causes Meson to implicitly include the precompiled
header in all compilation units. With GCC and Clang for example this is
done via the "-include" statement [1].
This leads to a significant speedup when performing full builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
[1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 2 ++
tools/precompiled.h | 1 +
2 files changed, 3 insertions(+)
Well, I don't do meson, but...
If I understand this right, this section here compiles all the source
files listed in "libgit_sources" using our new precompiled header.
But "libgit_sources" contains all source files under "reftable/",
which, with the sole exception of "reftable/system.c", don't include
"git-compat-util.h".
Now, building the reftable sources with "git-compat-util.h" included
through the precompiled header apparently didn't cause any compilation
errors...
But I think that's just accidental, and if a source file doesn't
include "git-compat-util.h", then it shouldn't be compiled with the
precompiled header.
On Thu, Mar 19, 2026 at 06:33:27AM +0100, Patrick Steinhardt wrote:
quoted
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This causes Meson to implicitly include the precompiled
header in all compilation units. With GCC and Clang for example this is
done via the "-include" statement [1].
This leads to a significant speedup when performing full builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
[1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 2 ++
tools/precompiled.h | 1 +
2 files changed, 3 insertions(+)
Well, I don't do meson, but...
If I understand this right, this section here compiles all the source
files listed in "libgit_sources" using our new precompiled header.
But "libgit_sources" contains all source files under "reftable/",
which, with the sole exception of "reftable/system.c", don't include
"git-compat-util.h".
Now, building the reftable sources with "git-compat-util.h" included
through the precompiled header apparently didn't cause any compilation
errors...
But I think that's just accidental, and if a source file doesn't
include "git-compat-util.h", then it shouldn't be compiled with the
precompiled header.
From: SZEDER Gábor <hidden> Date: 2026-04-10 16:05:34
On Fri, Apr 10, 2026 at 04:46:43PM +0100, Phillip Wood wrote:
On 10/04/2026 16:36, SZEDER Gábor wrote:
quoted
On Thu, Mar 19, 2026 at 06:33:27AM +0100, Patrick Steinhardt wrote:
quoted
Every compilation unit in Git is expected to include "git-compat-util.h"
first, either directly or indirectly via "builtin.h". This header papers
over differences between platforms so that we can expect the typical
POSIX functions to exist. Furthermore, it provides functionality that we
end up using everywhere.
This header is thus quite heavy as a consequence. Preprocessing it as a
standalone unit via `clang -E git-compat-util.h` yields over 23,000
lines of code overall. Naturally, it takes quite some time to compile
all of this.
Luckily, this is exactly the kind of use case that precompiled headers
aim to solve: instead of recompiling it every single time, we compile it
once and then link the result into the executable. If include guards are
set up properly it means that the file won't need to be reprocessed.
Set up such a precompiled header for "git-compat-util.h" and wire it up
via Meson. This causes Meson to implicitly include the precompiled
header in all compilation units. With GCC and Clang for example this is
done via the "-include" statement [1].
This leads to a significant speedup when performing full builds:
Benchmark 1: ninja (rev = HEAD~)
Time (mean ± σ): 14.467 s ± 0.126 s [User: 248.133 s, System: 31.298 s]
Range (min … max): 14.195 s … 14.633 s 10 runs
Benchmark 2: ninja (rev = HEAD)
Time (mean ± σ): 10.307 s ± 0.111 s [User: 173.290 s, System: 23.998 s]
Range (min … max): 10.030 s … 10.433 s 10 runs
Summary
ninja (rev = HEAD) ran
1.40 ± 0.02 times faster than ninja (rev = HEAD~)
[1]: https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
Signed-off-by: Patrick Steinhardt <redacted>
---
meson.build | 2 ++
tools/precompiled.h | 1 +
2 files changed, 3 insertions(+)
Well, I don't do meson, but...
If I understand this right, this section here compiles all the source
files listed in "libgit_sources" using our new precompiled header.
But "libgit_sources" contains all source files under "reftable/",
which, with the sole exception of "reftable/system.c", don't include
"git-compat-util.h".
Now, building the reftable sources with "git-compat-util.h" included
through the precompiled header apparently didn't cause any compilation
errors...
But I think that's just accidental, and if a source file doesn't
include "git-compat-util.h", then it shouldn't be compiled with the
precompiled header.
I'm not sure that "oh look, it didn't break, so it must be good" is
the right approach...
And why was this not mentioned in the commit message?! Sigh...