From 51e43eb826f39bd7eeb2950a8187b54b1332afcd Mon Sep 17 00:00:00 2001
From: Sebastian Eibl <sebastian.eibl@mpcdf.mpg.de>
Date: Tue, 26 Jul 2022 12:08:55 +0200
Subject: [PATCH] example 07_git_build added

---
 .gitlab-ci.yml                           |  6 +++++-
 07_git_build/CMakeLists.txt              | 27 ++++++++++++++++++++++++
 07_git_build/README.md                   | 18 ++++++++++++++++
 07_git_build/cmake/update_git_hash.cmake | 18 ++++++++++++++++
 07_git_build/githash.cpp.in              |  3 +++
 07_git_build/githash.hpp                 |  3 +++
 07_git_build/main.cpp                    |  9 ++++++++
 README.md                                |  1 +
 8 files changed, 84 insertions(+), 1 deletion(-)
 create mode 100644 07_git_build/CMakeLists.txt
 create mode 100644 07_git_build/README.md
 create mode 100644 07_git_build/cmake/update_git_hash.cmake
 create mode 100644 07_git_build/githash.cpp.in
 create mode 100644 07_git_build/githash.hpp
 create mode 100644 07_git_build/main.cpp

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8700f59..557914a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -38,4 +38,8 @@ check-recipes:
     - cmake --build 05_build
     - 05_build/version-info
 
-    - cmake -S 06_git_configure -B 06_build
\ No newline at end of file
+    - cmake -S 06_git_configure -B 06_build
+
+    - cmake -S 07_git_build -B 07_build
+    - cmake --build 07_build
+    - 07_build/git-hash
\ No newline at end of file
diff --git a/07_git_build/CMakeLists.txt b/07_git_build/CMakeLists.txt
new file mode 100644
index 0000000..07bfea8
--- /dev/null
+++ b/07_git_build/CMakeLists.txt
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 3.20)
+
+project(07_git_build
+        LANGUAGES CXX)
+
+add_executable(git-hash)
+target_sources(git-hash PRIVATE main.cpp githash.hpp)
+target_sources(git-hash PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/githash.cpp)
+target_include_directories(git-hash PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(GIT_HASH_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/githash.cpp.in)
+set(GIT_HASH_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/githash.cpp)
+add_custom_command(
+        OUTPUT
+        ${GIT_HASH_OUTPUT}
+        ALL
+        COMMAND
+        ${CMAKE_COMMAND} -DINPUT_FILE=${GIT_HASH_INPUT} -DOUTPUT_FILE=${GIT_HASH_OUTPUT} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/update_git_hash.cmake
+)
+add_custom_target(
+        update-git-hash
+        ALL
+        DEPENDS
+        ${GIT_HASH_OUTPUT}
+)
+add_dependencies(git-hash update-git-hash)
+
diff --git a/07_git_build/README.md b/07_git_build/README.md
new file mode 100644
index 0000000..f783472
--- /dev/null
+++ b/07_git_build/README.md
@@ -0,0 +1,18 @@
+# How to get the current git hash at build time?
+
+We will use the ability of CMake to run as an interpreter 
+[interpreter](https://cmake.org/cmake/help/latest/manual/cmake.1.html#run-a-script)
+to retrieve the git hash at runtime.  
+The idea works as follows:
+ * Use [How to get the current git hash at configure time?](06_git_configure) to get the git hash.
+ * Use [How to pass information from CMake to your code?](05_configure_file) to write the hash
+   into a source file.
+ * Move the logic into a separate CMake [file](cmake/update_git_hash.cmake).
+ * Use [add_custom_command](https://cmake.org/cmake/help/latest/command/add_custom_command.html)
+   to invoke the [CMake interpreter](https://cmake.org/cmake/help/latest/manual/cmake.1.html#run-a-script).
+ * Move everything into its own target to allow parallel execution: 
+   [add_custom_target](https://cmake.org/cmake/help/latest/command/add_custom_target.html).
+ * Add a [dependency](https://cmake.org/cmake/help/latest/command/add_dependencies.html)
+   so it gets executed whenever the project is rebuild.
+
+Note, we configure a cpp file here to avoid recompilation of huge portions of the code!
\ No newline at end of file
diff --git a/07_git_build/cmake/update_git_hash.cmake b/07_git_build/cmake/update_git_hash.cmake
new file mode 100644
index 0000000..c764691
--- /dev/null
+++ b/07_git_build/cmake/update_git_hash.cmake
@@ -0,0 +1,18 @@
+set(GIT_HASH "unknown")
+
+find_package(Git QUIET)
+if (GIT_FOUND)
+    execute_process(
+            COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%H
+            OUTPUT_VARIABLE GIT_HASH
+            OUTPUT_STRIP_TRAILING_WHITESPACE
+            ERROR_QUIET
+            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+    )
+endif ()
+
+configure_file(
+        ${INPUT_FILE}
+        ${OUTPUT_FILE}
+        @ONLY
+)
\ No newline at end of file
diff --git a/07_git_build/githash.cpp.in b/07_git_build/githash.cpp.in
new file mode 100644
index 0000000..178f2de
--- /dev/null
+++ b/07_git_build/githash.cpp.in
@@ -0,0 +1,3 @@
+#include "githash.hpp"
+
+char const * GIT_HASH = "@GIT_HASH@";
diff --git a/07_git_build/githash.hpp b/07_git_build/githash.hpp
new file mode 100644
index 0000000..f71c94d
--- /dev/null
+++ b/07_git_build/githash.hpp
@@ -0,0 +1,3 @@
+#pragma once
+
+extern char const * GIT_HASH;
diff --git a/07_git_build/main.cpp b/07_git_build/main.cpp
new file mode 100644
index 0000000..603b43e
--- /dev/null
+++ b/07_git_build/main.cpp
@@ -0,0 +1,9 @@
+#include <iostream>
+
+#include "githash.hpp"
+
+int main()
+{
+    std::cout << "git hash: " << GIT_HASH << std::endl;
+    exit(EXIT_SUCCESS);
+}
diff --git a/README.md b/README.md
index 315c99b..c38c340 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ we run them in our CI.
  * [Local and cache variables?](https://cliutils.gitlab.io/modern-cmake/chapters/basics/variables.html)
  * [How to pass information from CMake to your code?](05_configure_file)
  * [How to get the current git hash at configure time?](06_git_configure)
+ * [How to get the current git hash at build time?](07_git_build)
 
 ## Why CMake?
  * Automatically search for programs, libraries, and header files
-- 
GitLab