diff mbox series

[RFC,v6,08/19] Makefile: refactor GIT-VERSION-GEN to be reusable

Message ID 20241112-pks-meson-v6-8-648b30996827@pks.im (mailing list archive)
State New
Headers show
Series Modernize the build system | expand

Commit Message

Patrick Steinhardt Nov. 12, 2024, 5:02 p.m. UTC
Our "GIT-VERSION-GEN" script always writes the "GIT-VERSION-FILE" into
the current directory, where the expectation is that it should exist in
the source directory. But other build systems that support out-of-tree
builds may not want to do that to keep the source directory pristine,
even though CMake currently doesn't care.

Refactor the script such that it doesn't write output to a file anymore
but so that it instead writes the version to stdout. This makes it
easier to compute the same version as our Makefile would without having
to write the "GIT-VERSION-FILE".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 GIT-VERSION-GEN                     | 12 +-----------
 Makefile                            |  3 ++-
 contrib/buildsystems/CMakeLists.txt | 12 ++++--------
 3 files changed, 7 insertions(+), 20 deletions(-)

Comments

Phillip Wood Nov. 13, 2024, 4:30 p.m. UTC | #1
Hi Patrick

On 12/11/2024 17:02, Patrick Steinhardt wrote:
> Our "GIT-VERSION-GEN" script always writes the "GIT-VERSION-FILE" into
> the current directory, where the expectation is that it should exist in
> the source directory. But other build systems that support out-of-tree
> builds may not want to do that to keep the source directory pristine,
> even though CMake currently doesn't care.
> 
> Refactor the script such that it doesn't write output to a file anymore
> but so that it instead writes the version to stdout. This makes it
> easier to compute the same version as our Makefile would without having
> to write the "GIT-VERSION-FILE".

This patch moves the logic that only updates GIT-VERSION-FILE if the
version has changed from the script into the Makefile. As we really want
the CMake and meson builds to set the string at build time which
probably means extending GIT-VERSION-GEN to write a header file that
defines GIT_VERSION etc. I'm not sure this is a good direction. In the
long run I think we'd be better off with something like the patch below.

Best Wishes

Phillip

---- >8 ----
From: Phillip Wood <phillip.wood@dunelm.org.uk>
Subject: [PATCH] WIP CMake: update GIT_VERSION at runtime

The CMake build defines GIT_VERSION when it is configured and does not
update it when HEAD changes. Fix this by modifying GIT-VERSION-GEN so
that in addition to creating GIT_VERSION-FILE, it creates a header file
containing the version strings that is included in version.c.

TODO:
   - update CMakeLists.txt to set the version information for git.res
     at build time.
   - Check for changes to GIT_USER_AGENT when the version has not
     changed.
   - Maybe remove GIT-VERISON-FILE infavor of parsing version-def.h so
     that there is a single source of truth for the version.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
---
  GIT-VERSION-GEN                     | 17 +++++++++++++----
  Makefile                            | 15 +++++++--------
  contrib/buildsystems/CMakeLists.txt | 26 +++++++++++++++++++-------
  version.c                           |  1 +
  4 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 78e8631f677..25c033fa892 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,6 +1,7 @@
  #!/bin/sh
  
-GVF=GIT-VERSION-FILE
+GVF="$1"
+VERSION_HEADER="$2"
  DEF_VER=v2.47.GIT
  
  LF='
@@ -30,11 +31,19 @@ VN=$(expr "$VN" : v*'\(.*\)')
  
  if test -r $GVF
  then
-	VC=$(sed -e 's/^GIT_VERSION = //' <$GVF)
+	VC=$(sed -e 's/^GIT_VERSION = //' "$GVF")
  else
  	VC=unset
  fi
-test "$VN" = "$VC" || {
+test "$VN" = "$VC" && test -f "$VERSION_HEADER" || {
  	echo >&2 "GIT_VERSION = $VN"
-	echo "GIT_VERSION = $VN" >$GVF
+	echo "GIT_VERSION = $VN" >"$GVF"
+	USER_AGENT="${GIT_USER_AGENT:-git/$VN}"
+	HEAD="$(GIT_CEILING_DIRECTORIES=.. \
+		git rev-parse -q --verify HEAD 2>/dev/null)"
+	cat <<-EOF >"$VERSION_HEADER"
+	#define GIT_VERSION "$VN"
+	#define GIT_BUILT_FROM_COMMIT "$HEAD"
+	#define GIT_USER_AGENT "$USER_AGENT"
+	EOF
  }
diff --git a/Makefile b/Makefile
index 2afad000762..7cd42e2bed7 100644
--- a/Makefile
+++ b/Makefile
@@ -592,7 +592,11 @@ include shared.mak
  #        Disable -pedantic compilation.
  
  GIT-VERSION-FILE: FORCE
-	@$(SHELL_PATH) ./GIT-VERSION-GEN
+	@$(SHELL_PATH) ./GIT-VERSION-GEN GIT-VERSION-FILE version-def.h
+
+version-def.h: GIT-VERSION-FILE
+	@touch $@
+
  -include GIT-VERSION-FILE
  
  # Set our default configuration.
@@ -919,6 +923,7 @@ REFTABLE_LIB = reftable/libreftable.a
  GENERATED_H += command-list.h
  GENERATED_H += config-list.h
  GENERATED_H += hook-list.h
+GENERATED_H += version-def.h
  GENERATED_H += $(UNIT_TEST_DIR)/clar-decls.h
  GENERATED_H += $(UNIT_TEST_DIR)/clar.suite
  
@@ -2505,13 +2510,7 @@ PAGER_ENV_CQ_SQ = $(subst ','\'',$(PAGER_ENV_CQ))
  pager.sp pager.s pager.o: EXTRA_CPPFLAGS = \
  	-DPAGER_ENV='$(PAGER_ENV_CQ_SQ)'
  
-version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT
-version.sp version.s version.o: EXTRA_CPPFLAGS = \
-	'-DGIT_VERSION="$(GIT_VERSION)"' \
-	'-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)' \
-	'-DGIT_BUILT_FROM_COMMIT="$(shell \
-		GIT_CEILING_DIRECTORIES="$(CURDIR)/.." \
-		git rev-parse -q --verify HEAD 2>/dev/null)"'
+version.sp version.s version.o: version-def.h GIT-USER-AGENT
  
  $(BUILT_INS): git$X
  	$(QUIET_BUILT_IN)$(RM) $@ && \
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2e22e87d188..e64045c4dbd 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -86,12 +86,15 @@ endif()
  #Create GIT-VERSION-FILE using GIT-VERSION-GEN
  if(NOT EXISTS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE)
  	message("Generating GIT-VERSION-FILE")
-	execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN
-		WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+	execute_process(COMMAND ${SH_EXE}
+				"${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+				"${CMAKE_BINARY_DIR}/GIT-VERSION-FILE"
+				"${CMAKE_BINARY_DIR}/version-def.h"
+			WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
  endif()
  
  #Parse GIT-VERSION-FILE to get the version
-file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE git_version REGEX "GIT_VERSION = (.*)")
+file(STRINGS "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE" git_version REGEX "^GIT_VERSION = (.*)")
  string(REPLACE "GIT_VERSION = " "" git_version ${git_version})
  string(FIND ${git_version} "GIT" location)
  if(location EQUAL -1)
@@ -101,6 +104,16 @@ else()
  	string(APPEND git_version ".0") #for building from a snapshot
  endif()
  
+add_custom_target(version-def
+	COMMAND ${SH_EXE}
+		./GIT-VERSION-GEN
+		"${CMAKE_BINARY_DIR}/GIT-VERSION-FILE"
+		"${CMAKE_BINARY_DIR}/version-def.h"
+	WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+	BYPRODUCTS "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE"
+		-  "${CMAKE_BINARY_DIR}/version-def.h"
+	VERBATIM)
+
  project(git
  	VERSION ${git_version}
  	LANGUAGES C)
@@ -240,10 +253,7 @@ add_compile_definitions(PAGER_ENV="LESS=FRX LV=-c"
  			GIT_HTML_PATH="share/doc/git-doc"
  			DEFAULT_HELP_FORMAT="html"
  			DEFAULT_GIT_TEMPLATE_DIR="share/git-core/templates"
-			GIT_VERSION="${PROJECT_VERSION}.GIT"
-			GIT_USER_AGENT="git/${PROJECT_VERSION}.GIT"
-			BINDIR="bin"
-			GIT_BUILT_FROM_COMMIT="")
+			BINDIR="bin")
  
  if(WIN32)
  	set(FALLBACK_RUNTIME_PREFIX /mingw64)
@@ -680,6 +690,8 @@ parse_makefile_for_sources(libgit_SOURCES "LIB_OBJS")
  list(TRANSFORM libgit_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
  list(TRANSFORM compat_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
  add_library(libgit ${libgit_SOURCES} ${compat_SOURCES})
+target_include_directories(libgit PRIVATE "${CMAKE_BINARY_DIR}")
+add_dependencies(libgit version-def)
  
  #libxdiff
  parse_makefile_for_sources(libxdiff_SOURCES "XDIFF_OBJS")
diff --git a/version.c b/version.c
index 41b718c29e1..7adc4d51ff2 100644
--- a/version.c
+++ b/version.c
@@ -1,5 +1,6 @@
  #include "git-compat-util.h"
  #include "version.h"
+#include "version-def.h"
  #include "strbuf.h"
  
  const char git_version_string[] = GIT_VERSION;
Patrick Steinhardt Nov. 14, 2024, 9:10 a.m. UTC | #2
On Wed, Nov 13, 2024 at 04:30:33PM +0000, Phillip Wood wrote:
> Hi Patrick
> 
> On 12/11/2024 17:02, Patrick Steinhardt wrote:
> > Our "GIT-VERSION-GEN" script always writes the "GIT-VERSION-FILE" into
> > the current directory, where the expectation is that it should exist in
> > the source directory. But other build systems that support out-of-tree
> > builds may not want to do that to keep the source directory pristine,
> > even though CMake currently doesn't care.
> > 
> > Refactor the script such that it doesn't write output to a file anymore
> > but so that it instead writes the version to stdout. This makes it
> > easier to compute the same version as our Makefile would without having
> > to write the "GIT-VERSION-FILE".
> 
> This patch moves the logic that only updates GIT-VERSION-FILE if the
> version has changed from the script into the Makefile. As we really want
> the CMake and meson builds to set the string at build time which
> probably means extending GIT-VERSION-GEN to write a header file that
> defines GIT_VERSION etc. I'm not sure this is a good direction. In the
> long run I think we'd be better off with something like the patch below.

Yes, I fully agree that using a version header would make more sense. I
had the intent to do this as a follow-up, but I'll have a look at your
patch and maybe do it now already.

Thanks!

Patrick
diff mbox series

Patch

diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 78e8631f677bbebe8f18d83191f0fd014465563e..671f853512a8cfafe85dc18ec5bf85e52018ca69 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,6 +1,5 @@ 
 #!/bin/sh
 
-GVF=GIT-VERSION-FILE
 DEF_VER=v2.47.GIT
 
 LF='
@@ -28,13 +27,4 @@  fi
 
 VN=$(expr "$VN" : v*'\(.*\)')
 
-if test -r $GVF
-then
-	VC=$(sed -e 's/^GIT_VERSION = //' <$GVF)
-else
-	VC=unset
-fi
-test "$VN" = "$VC" || {
-	echo >&2 "GIT_VERSION = $VN"
-	echo "GIT_VERSION = $VN" >$GVF
-}
+echo "$VN"
diff --git a/Makefile b/Makefile
index 28f5e96c4def70f2eed3675cfad665022ad91704..96b4a860f5d560344b680403574302761184af04 100644
--- a/Makefile
+++ b/Makefile
@@ -592,7 +592,8 @@  include shared.mak
 #        Disable -pedantic compilation.
 
 GIT-VERSION-FILE: FORCE
-	@$(SHELL_PATH) ./GIT-VERSION-GEN
+	@printf "GIT_VERSION = %s\n" $$($(SHELL_PATH) GIT-VERSION-GEN) >$@+
+	@if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else cat $@+ >&2 && mv $@+ $@; fi
 -include GIT-VERSION-FILE
 
 # Set our default configuration.
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index d2ec6cfc78f092f6299a624d5382d71fcb4d0644..689b76578ad1e39b09e0dcd62bfc0508cc081364 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -83,16 +83,12 @@  if(NOT SH_EXE)
 			"On Windows, you can get it as part of 'Git for Windows' install at https://gitforwindows.org/")
 endif()
 
-#Create GIT-VERSION-FILE using GIT-VERSION-GEN
-if(NOT EXISTS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE)
-	message("Generating GIT-VERSION-FILE")
-	execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN
-		WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
-endif()
+execute_process(COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
+	WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+	OUTPUT_VARIABLE git_version
+	OUTPUT_STRIP_TRAILING_WHITESPACE)
 
 #Parse GIT-VERSION-FILE to get the version
-file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE git_version REGEX "GIT_VERSION = (.*)")
-string(REPLACE "GIT_VERSION = " "" git_version ${git_version})
 string(FIND ${git_version} "GIT" location)
 if(location EQUAL -1)
 	string(REGEX MATCH "[0-9]*\\.[0-9]*\\.[0-9]*" git_version ${git_version})