From ceb2e1da12768b383c1cb058b75ca106d71dfed9 Mon Sep 17 00:00:00 2001 From: tad1 Date: Mon, 9 Sep 2024 16:27:28 +0200 Subject: [PATCH 01/10] modify for Nabla use --- CMakeLists.txt | 8 +-- git.c.in | 32 ---------- git.h | 154 ---------------------------------------------- git_info.cpp.in | 21 +++++++ git_info.h | 28 +++++++++ git_watcher.cmake | 24 ++++++++ 6 files changed, 75 insertions(+), 192 deletions(-) delete mode 100644 git.c.in delete mode 100644 git.h create mode 100644 git_info.cpp.in create mode 100644 git_info.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a5cd69..d6ab7cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,8 @@ project(cmake_git_version_tracking # Define the two required variables before including # the source code for watching a git repository. -set(PRE_CONFIGURE_FILE "git.c.in") -set(POST_CONFIGURE_FILE "${CMAKE_CURRENT_BINARY_DIR}/git.c") +set(PRE_CONFIGURE_FILE "git_info.cpp.in") +set(POST_CONFIGURE_FILE "${CMAKE_CURRENT_BINARY_DIR}/git_info.cpp") include(git_watcher.cmake) # Create a library out of the compiled post-configure file. @@ -17,7 +17,3 @@ add_library(${PROJECT_NAME} STATIC ${POST_CONFIGURE_FILE}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) add_dependencies(${PROJECT_NAME} check_git) -# The C99 standard is only required because we're using . -# This could be removed if it's a problem for users, but would require the -# cmake configure() commands to translate true/false literals to 1/0. -set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99) diff --git a/git.c.in b/git.c.in deleted file mode 100644 index a26d27c..0000000 --- a/git.c.in +++ /dev/null @@ -1,32 +0,0 @@ -#include "git.h" - -bool git_IsPopulated() { - return @GIT_RETRIEVED_STATE@; -} -bool git_AnyUncommittedChanges() { - return @GIT_IS_DIRTY@; -} -const char* git_AuthorName() { - return "@GIT_AUTHOR_NAME@"; -} -const char* git_AuthorEmail() { - return "@GIT_AUTHOR_EMAIL@"; -} -const char* git_CommitSHA1() { - return "@GIT_HEAD_SHA1@"; -} -const char* git_CommitDate() { - return "@GIT_COMMIT_DATE_ISO8601@"; -} -const char* git_CommitSubject() { - return "@GIT_COMMIT_SUBJECT@"; -} -const char* git_CommitBody() { - return "@GIT_COMMIT_BODY@"; -} -const char* git_Describe() { - return "@GIT_DESCRIBE@"; -} -const char* git_Branch() { - return "@GIT_BRANCH@"; -} diff --git a/git.h b/git.h deleted file mode 100644 index 91ce40b..0000000 --- a/git.h +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once -// git.h -// https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git.h -// -// Released under the MIT License. -// https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE - -#include - -#ifdef __cplusplus -#define GIT_VERSION_TRACKING_EXTERN_C_BEGIN extern "C" { -#define GIT_VERSION_TRACKING_EXTERN_C_END } -#else -#define GIT_VERSION_TRACKING_EXTERN_C_BEGIN -#define GIT_VERSION_TRACKING_EXTERN_C_END -#endif - -// Don't mangle the C function names if included in a CXX file. -GIT_VERSION_TRACKING_EXTERN_C_BEGIN - -/// Is the metadata populated? -// -/// We may not have metadata if there wasn't a .git directory -/// (e.g. downloaded source code without revision history). -bool git_IsPopulated(); - -/// Were there any uncommitted changes that won't be reflected -/// in the CommitID? -bool git_AnyUncommittedChanges(); - -/// The commit author's name. -const char* git_AuthorName(); - -/// The commit author's email. -const char* git_AuthorEmail(); - -/// The commit SHA1. -const char* git_CommitSHA1(); - -/// The ISO8601 commit date. -const char* git_CommitDate(); - -/// The commit subject. -const char* git_CommitSubject(); - -/// The commit body. -const char* git_CommitBody(); - -/// The commit describe. -const char* git_Describe(); - -/// The symbolic reference tied to HEAD. -const char* git_Branch(); - -GIT_VERSION_TRACKING_EXTERN_C_END -#undef GIT_VERSION_TRACKING_EXTERN_C_BEGIN -#undef GIT_VERSION_TRACKING_EXTERN_C_END - -#ifdef __cplusplus - -/// This is a utility extension for C++ projects. -/// It provides a "git" namespace that wraps the -/// C methods in more(?) ergonomic types. -/// -/// This is header-only in an effort to keep the -/// underlying static library C99 compliant. - - -// We really want to use std::string_view if it appears -// that the compiler will support it. If that fails, -// revert back to std::string. -#define GIT_VERSION_TRACKING_CPP_17_STANDARD 201703L -#if __cplusplus >= GIT_VERSION_TRACKING_CPP_17_STANDARD -#define GIT_VERSION_USE_STRING_VIEW 1 -#else -#define GIT_VERSION_USE_STRING_VIEW 0 -#endif - - -#if GIT_VERSION_USE_STRING_VIEW -#include -#include -#else -#include -#endif - -namespace git { - -#if GIT_VERSION_USE_STRING_VIEW -using StringOrView = std::string_view; -#else -typedef std::string StringOrView; -#endif - -namespace internal { - -/// Short-hand method for initializing a std::string or std::string_view given a C-style const char*. -inline const StringOrView InitString(const char* from_c_interface) { - #if GIT_VERSION_USE_STRING_VIEW - return StringOrView { from_c_interface, std::strlen(from_c_interface) }; - #else - return std::string(from_c_interface); - #endif -} - -} // namespace internal - -inline bool IsPopulated() { - return git_IsPopulated(); -} -inline bool AnyUncommittedChanges() { - return git_AnyUncommittedChanges(); -} -inline const StringOrView& AuthorName() { - static const StringOrView kValue = internal::InitString(git_AuthorName()); - return kValue; -} -inline const StringOrView AuthorEmail() { - static const StringOrView kValue = internal::InitString(git_AuthorEmail()); - return kValue; -} -inline const StringOrView CommitSHA1() { - static const StringOrView kValue = internal::InitString(git_CommitSHA1()); - return kValue; -} -inline const StringOrView CommitDate() { - static const StringOrView kValue = internal::InitString(git_CommitDate()); - return kValue; -} -inline const StringOrView CommitSubject() { - static const StringOrView kValue = internal::InitString(git_CommitSubject()); - return kValue; -} -inline const StringOrView CommitBody() { - static const StringOrView kValue = internal::InitString(git_CommitBody()); - return kValue; -} -inline const StringOrView Describe() { - static const StringOrView kValue = internal::InitString(git_Describe()); - return kValue; -} -inline const StringOrView Branch() { - static const StringOrView kValue = internal::InitString(git_Branch()); - return kValue; -} - -} // namespace git - - -// Cleanup our defines to avoid polluting. -#undef GIT_VERSION_USE_STRING_VIEW -#undef GIT_VERSION_TRACKING_CPP_17_STANDARD - -#endif // __cplusplus diff --git a/git_info.cpp.in b/git_info.cpp.in new file mode 100644 index 0000000..ce6623c --- /dev/null +++ b/git_info.cpp.in @@ -0,0 +1,21 @@ +#include "git_info.h" + +const GitInfo git_info = { + .isPopulated = @GIT_RETRIEVED_STATE@, + .hasUncommittedChanges = @GIT_IS_DIRTY@, + .commitAuthorName = "@GIT_AUTHOR_NAME@", + .commitAuthorEmail = "@GIT_AUTHOR_EMAIL@", + .commitHash = "@GIT_HEAD_SHA1@", + .commitShortHash = "@GIT_HEAD_SHORT_SHA1@", + .commitDate = "@GIT_COMMIT_DATE_ISO8601@", + .commitSubject = "@GIT_COMMIT_SUBJECT@", + .commitBody = "@GIT_COMMIT_BODY@", + .describe = "@GIT_DESCRIBE@", + .branchName = "@GIT_BRANCH@", + .latestTag = "@GIT_TAG@", + .latestTagName = "@GIT_TAG_NAME@" +}; + +const GitInfo getGitInfo() { + return git_info; +}; diff --git a/git_info.h b/git_info.h new file mode 100644 index 0000000..f7ee2e0 --- /dev/null +++ b/git_info.h @@ -0,0 +1,28 @@ +#pragma once +// based on https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git.h +// > Released under the MIT License. +// > https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE + +#include "BuildConfigOptions.h" + +struct GitInfo { + bool isPopulated; + bool hasUncommittedChanges; + const char* commitAuthorName; + const char* commitAuthorEmail; + const char* commitHash; + const char* commitShortHash; + const char* commitDate; + const char* commitSubject; + const char* commitBody; + const char* describe; + const char* branchName; + const char* latestTag; + const char* latestTagName; +}; + +// internal use +extern const GitInfo git_info; + +// public use +NBL_API2 const GitInfo getGitInfo(); \ No newline at end of file diff --git a/git_watcher.cmake b/git_watcher.cmake index 32313a3..152d59e 100644 --- a/git_watcher.cmake +++ b/git_watcher.cmake @@ -97,6 +97,7 @@ CHECK_REQUIRED_VARIABLE(GIT_EXECUTABLE) set(_state_variable_names GIT_RETRIEVED_STATE GIT_HEAD_SHA1 + GIT_HEAD_SHORT_SHA1 GIT_IS_DIRTY GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL @@ -105,6 +106,8 @@ set(_state_variable_names GIT_COMMIT_BODY GIT_DESCRIBE GIT_BRANCH + GIT_TAG + GIT_TAG_NAME # >>> # 1. Add the name of the additional git variable you're interested in monitoring # to this list. @@ -177,6 +180,11 @@ function(GetGitState _working_dir) set(ENV{GIT_HEAD_SHA1} ${output}) endif() + RunGitCommand(show -s "--format=%h" ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_HEAD_SHORT_SHA1} "${output}") + endif() + RunGitCommand(show -s "--format=%an" ${object}) if(exit_code EQUAL 0) set(ENV{GIT_AUTHOR_NAME} "${output}") @@ -231,6 +239,22 @@ function(GetGitState _working_dir) set(ENV{GIT_DESCRIBE} "${output}") endif() + # Get latest tag + RunGitCommand(describe --tags ${object}) + if(NOT exit_code EQUAL 0) + set(ENV{GIT_TAG} "unknown") + else() + set(ENV{GIT_TAG} "${output}") + endif() + + # Get latest tag name + RunGitCommand(describe --tags --abbrev=0 ${object}) + if(NOT exit_code EQUAL 0) + set(ENV{GIT_TAG_NAME} "unknown") + else() + set(ENV{GIT_TAG_NAME} "${output}") + endif() + # Convert HEAD to a symbolic ref. This can fail, in which case we just # set that variable to HEAD. set(_permit_git_failure ON) From 3950403de5cbbaa7bdc47ba158cc7de0289686ce Mon Sep 17 00:00:00 2001 From: tad1 Date: Mon, 9 Sep 2024 16:48:17 +0200 Subject: [PATCH 02/10] wrap into nbl namespace --- git_info.cpp.in | 12 +++++++----- git_info.h | 41 ++++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/git_info.cpp.in b/git_info.cpp.in index ce6623c..cfed75d 100644 --- a/git_info.cpp.in +++ b/git_info.cpp.in @@ -1,6 +1,7 @@ #include "git_info.h" -const GitInfo git_info = { +namespace nbl{ + const GitInfo git_info = { .isPopulated = @GIT_RETRIEVED_STATE@, .hasUncommittedChanges = @GIT_IS_DIRTY@, .commitAuthorName = "@GIT_AUTHOR_NAME@", @@ -14,8 +15,9 @@ const GitInfo git_info = { .branchName = "@GIT_BRANCH@", .latestTag = "@GIT_TAG@", .latestTagName = "@GIT_TAG_NAME@" -}; + }; -const GitInfo getGitInfo() { - return git_info; -}; + const GitInfo getGitInfo() { + return git_info; + }; +} // namespace nbl \ No newline at end of file diff --git a/git_info.h b/git_info.h index f7ee2e0..d47ae5b 100644 --- a/git_info.h +++ b/git_info.h @@ -5,24 +5,27 @@ #include "BuildConfigOptions.h" -struct GitInfo { - bool isPopulated; - bool hasUncommittedChanges; - const char* commitAuthorName; - const char* commitAuthorEmail; - const char* commitHash; - const char* commitShortHash; - const char* commitDate; - const char* commitSubject; - const char* commitBody; - const char* describe; - const char* branchName; - const char* latestTag; - const char* latestTagName; -}; +namespace nbl { + struct GitInfo { + bool isPopulated; + bool hasUncommittedChanges; + const char* commitAuthorName; + const char* commitAuthorEmail; + const char* commitHash; + const char* commitShortHash; + const char* commitDate; + const char* commitSubject; + const char* commitBody; + const char* describe; + const char* branchName; + const char* latestTag; + const char* latestTagName; + }; -// internal use -extern const GitInfo git_info; -// public use -NBL_API2 const GitInfo getGitInfo(); \ No newline at end of file + // internal use + extern const GitInfo git_info; + + // public use + NBL_API2 const GitInfo getGitInfo(); +} // namespece nbl From 308cc51830ea045f9d688723404b1d37294cd919 Mon Sep 17 00:00:00 2001 From: tad1 Date: Wed, 11 Sep 2024 19:24:52 +0200 Subject: [PATCH 03/10] convert to multi-repo utility library --- CMakeLists.txt | 85 ++++++++++++++++++++++++++++++++-------- git_info.cpp.in | 26 +++--------- git_info.h.in | 39 ++++++++++++++++++ git_watcher.cmake | 24 ++++++------ template_git_info.cpp.in | 20 ++++++++++ 5 files changed, 147 insertions(+), 47 deletions(-) create mode 100644 git_info.h.in create mode 100644 template_git_info.cpp.in diff --git a/CMakeLists.txt b/CMakeLists.txt index d6ab7cd..d65fa5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,72 @@ cmake_minimum_required(VERSION 3.2...3.27) project(cmake_git_version_tracking - LANGUAGES C) - -# Define the two required variables before including -# the source code for watching a git repository. -set(PRE_CONFIGURE_FILE "git_info.cpp.in") -set(POST_CONFIGURE_FILE "${CMAKE_CURRENT_BINARY_DIR}/git_info.cpp") -include(git_watcher.cmake) - -# Create a library out of the compiled post-configure file. -# -# Note that the include is a system include. This was done -# so downstream projects don't suffer from warnings on a -# 3rdparty library. -add_library(${PROJECT_NAME} STATIC ${POST_CONFIGURE_FILE}) -target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -add_dependencies(${PROJECT_NAME} check_git) + LANGUAGES CXX) +set(NBL_GTML_TRACKED_TARGETS CACHE INTERNAL "") +set(NBL_GTML_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE INTERNAL "") +set(NBL_GTML_PROJECT_NAME "${PROJECT_NAME}" CACHE INTERNAL "") + +# useage notes: +# 1. `add_subdirectory` this project +# 2. use function `NBL_ADD_GIT_TRACKING_META_LIBRARY("name" "GIT_PATH")` to track any git_repo +# 3. call `NBL_GENERATE_GIT_TRACKING_META()` to finalize and configure required headers/sources +# 4. link this anywhere you need `target_link_libraries(TARGET PUBLIC cmake_git_version_tracking)` +# 5. #include "git_info.h" in your code +# 6. profit + +function(NBL_ADD_GIT_TRACKING_META_LIBRARY GTML_NAME GIT_WORKING_DIR) + if(NOT GTML_NAME MATCHES "^[a-zA-Z0-9_]+$") + message(SEND_ERROR "Name \"${GTML_NAME}\" contains illegal characters, name needs to match '^[a-zA-Z0-9_]+$' regex") + endif() + if(GTML_NAME IN_LIST NBL_GTML_TRACKED_TARGETS) + message(SEND_ERROR "Name \"${GTML_NAME}\" is already specified") + endif() + + set(SRC_DIR "${CMAKE_CURRENT_FUNCTION_LIST_DIR}") + set(PRE_CONFIGURE_FILENAME "template_git_info.cpp.in") + set(PRE_CONFIGURE_FILE "${SRC_DIR}/${PRE_CONFIGURE_FILENAME}") + + set(GTML_INFO "/* This file is auto-generated by CMake's configure_file function from the template: `${PRE_CONFIGURE_FILENAME}`. * Do not edit this file manually. */") + + set(GTML_TARGET_NAME "${GTML_NAME}_check_git") + set(POST_CONFIGURE_FILE "${NBL_GTML_BINARY_DIR}/${GTML_NAME}_git_info.cpp") + include("${SRC_DIR}/git_watcher.cmake") + + set(NBL_GTML_TRACKED_TARGETS ${NBL_GTML_TRACKED_TARGETS} "${GTML_NAME}" CACHE INTERNAL "") +endfunction(NBL_ADD_GIT_TRACKING_META_LIBRARY) + +# TODO: for QoL auto-generate instead of relying of function call to finalize configuration +# finalize configuration, generates headers +function(NBL_GENERATE_GIT_TRACKING_META) + set(SRC_DIR "${CMAKE_CURRENT_FUNCTION_LIST_DIR}") + + list(SORT NBL_GTML_TRACKED_TARGETS) + + set(GTML_TARGET_NAMES ${NBL_GTML_TRACKED_TARGETS}) + set(GTML_TARGET_SOURCES ${NBL_GTML_TRACKED_TARGETS}) + set(GTML_ENUMS ${NBL_GTML_TRACKED_TARGETS}) + set(GTML_EXTERNS ${NBL_GTML_TRACKED_TARGETS}) + set(GTML_ARRAY ${NBL_GTML_TRACKED_TARGETS}) + list(TRANSFORM GTML_TARGET_NAMES APPEND _check_git) + list(TRANSFORM GTML_TARGET_SOURCES REPLACE "^(.+)$" "${NBL_GTML_BINARY_DIR}/\\1_git_info.cpp") + list(TRANSFORM GTML_ENUMS TOUPPER) + list(TRANSFORM GTML_ENUMS PREPEND EGRM_) + string(REGEX REPLACE ";" ", " GTML_ENUMS "${GTML_ENUMS}") + list(TRANSFORM GTML_EXTERNS REPLACE "^(.+)$" "\nextern const GitInfo \\1_git_info") + list(TRANSFORM GTML_ARRAY REPLACE "^(.+)$" "\\1_git_info") + string(REGEX REPLACE ";" ", " GTML_ARRAY "${GTML_ARRAY}") + + set(HEADER_NAME "git_info.h.in") + set(SOURCE_NAME "git_info.cpp.in") + + set(GTML_INFO "/* This file is auto-generated by CMake's configure_file function from the template: `${HEADER_NAME}`.\n * Do not edit this file manually. */") + configure_file("${SRC_DIR}/${HEADER_NAME}" "${NBL_GTML_BINARY_DIR}/git_info.h" @ONLY) + + set(GTML_INFO "/* This file is auto-generated by CMake's configure_file function from the template: `${SOURCE_NAME}`.\n * Do not edit this file manually. */") + configure_file("${SRC_DIR}/${SOURCE_NAME}" "${NBL_GTML_BINARY_DIR}/git_info.cpp" @ONLY) + + add_library("${NBL_GTML_PROJECT_NAME}" STATIC ${GTML_TARGET_SOURCES} "${NBL_GTML_BINARY_DIR}/git_info.cpp") + target_include_directories("${NBL_GTML_PROJECT_NAME}" SYSTEM PUBLIC "${NBL_GTML_BINARY_DIR}") + add_dependencies("${NBL_GTML_PROJECT_NAME}" ${GTML_TARGET_NAMES}) + +endfunction(NBL_GENERATE_GIT_TRACKING_META) diff --git a/git_info.cpp.in b/git_info.cpp.in index cfed75d..d03b9c6 100644 --- a/git_info.cpp.in +++ b/git_info.cpp.in @@ -1,23 +1,9 @@ -#include "git_info.h" +@GTML_INFO@ -namespace nbl{ - const GitInfo git_info = { - .isPopulated = @GIT_RETRIEVED_STATE@, - .hasUncommittedChanges = @GIT_IS_DIRTY@, - .commitAuthorName = "@GIT_AUTHOR_NAME@", - .commitAuthorEmail = "@GIT_AUTHOR_EMAIL@", - .commitHash = "@GIT_HEAD_SHA1@", - .commitShortHash = "@GIT_HEAD_SHORT_SHA1@", - .commitDate = "@GIT_COMMIT_DATE_ISO8601@", - .commitSubject = "@GIT_COMMIT_SUBJECT@", - .commitBody = "@GIT_COMMIT_BODY@", - .describe = "@GIT_DESCRIBE@", - .branchName = "@GIT_BRANCH@", - .latestTag = "@GIT_TAG@", - .latestTagName = "@GIT_TAG_NAME@" - }; +#include "git_info.h" - const GitInfo getGitInfo() { - return git_info; +namespace nbl::gtml { + const GitInfo gitMeta[EGRM_COUNT] = { + @GTML_ARRAY@ }; -} // namespace nbl \ No newline at end of file +} // namespace nbl::gtml \ No newline at end of file diff --git a/git_info.h.in b/git_info.h.in new file mode 100644 index 0000000..fbbc90f --- /dev/null +++ b/git_info.h.in @@ -0,0 +1,39 @@ +#ifndef __GIT_INFO_H_INCLUDED__ +#define __GIT_INFO_H_INCLUDED__ +@GTML_INFO@ + +// based on https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git.h +// > Released under the MIT License. +// > https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE + +#include + +namespace nbl::gtml { + struct GitInfo { + bool isPopulated; + bool hasUncommittedChanges; + const char* commitAuthorName; + const char* commitAuthorEmail; + const char* commitHash; + const char* commitShortHash; + const char* commitDate; + const char* commitSubject; + const char* commitBody; + const char* describe; + const char* branchName; + const char* latestTag; + const char* latestTagName; + }; + + enum E_GIT_REPO_META : uint8_t + { + @GTML_ENUMS@, + EGRM_COUNT + }; + + extern const GitInfo gitMeta[EGRM_COUNT]; + @GTML_EXTERNS@; + +} // namespece nbl::gtml + +#endif //__GIT_INFO_H_INCLUDED__ \ No newline at end of file diff --git a/git_watcher.cmake b/git_watcher.cmake index 152d59e..3947887 100644 --- a/git_watcher.cmake +++ b/git_watcher.cmake @@ -321,7 +321,7 @@ function(CheckGit _working_dir _state_changed) # Update the state to include the SHA256 for the pre-configure file. # This forces the post-configure file to be regenerated if the # pre-configure file has changed. - file(SHA256 ${PRE_CONFIGURE_FILE} preconfig_hash) + file(SHA256 "${PRE_CONFIGURE_FILE}" preconfig_hash) string(SHA256 state "${preconfig_hash}${state}") # Check if the state has changed compared to the backup on disk. @@ -348,23 +348,25 @@ endfunction() # check the state of git before every build. If the state has # changed, then a file is configured. function(SetupGitMonitoring) - add_custom_target(check_git + add_custom_target("${GTML_TARGET_NAME}" ALL - DEPENDS ${PRE_CONFIGURE_FILE} + DEPENDS "${PRE_CONFIGURE_FILE}" BYPRODUCTS - ${POST_CONFIGURE_FILE} - ${GIT_STATE_FILE} + "${POST_CONFIGURE_FILE}" + "${GIT_STATE_FILE}" COMMENT "Checking the git repository for changes..." COMMAND - ${CMAKE_COMMAND} + "${CMAKE_COMMAND}" -D_BUILD_TIME_CHECK_GIT=TRUE - -DGIT_WORKING_DIR=${GIT_WORKING_DIR} - -DGIT_EXECUTABLE=${GIT_EXECUTABLE} - -DGIT_STATE_FILE=${GIT_STATE_FILE} - -DPRE_CONFIGURE_FILE=${PRE_CONFIGURE_FILE} - -DPOST_CONFIGURE_FILE=${POST_CONFIGURE_FILE} + -DGIT_WORKING_DIR="${GIT_WORKING_DIR}" + -DGIT_EXECUTABLE="${GIT_EXECUTABLE}" + -DGIT_STATE_FILE="${GIT_STATE_FILE}" + -DPRE_CONFIGURE_FILE="${PRE_CONFIGURE_FILE}" + -DPOST_CONFIGURE_FILE="${POST_CONFIGURE_FILE}" -DGIT_FAIL_IF_NONZERO_EXIT=${GIT_FAIL_IF_NONZERO_EXIT} -DGIT_IGNORE_UNTRACKED=${GIT_IGNORE_UNTRACKED} + -DGTML_NAME="${GTML_NAME}" + -DGTML_INFO="${GTML_INFO}" -P "${CMAKE_CURRENT_LIST_FILE}") endfunction() diff --git a/template_git_info.cpp.in b/template_git_info.cpp.in new file mode 100644 index 0000000..3df2887 --- /dev/null +++ b/template_git_info.cpp.in @@ -0,0 +1,20 @@ +@GTML_INFO@ +#include "git_info.h" + +namespace nbl::gtml { + const GitInfo @GTML_NAME@_git_info = { + .isPopulated = @GIT_RETRIEVED_STATE@, + .hasUncommittedChanges = @GIT_IS_DIRTY@, + .commitAuthorName = "@GIT_AUTHOR_NAME@", + .commitAuthorEmail = "@GIT_AUTHOR_EMAIL@", + .commitHash = "@GIT_HEAD_SHA1@", + .commitShortHash = "@GIT_HEAD_SHORT_SHA1@", + .commitDate = "@GIT_COMMIT_DATE_ISO8601@", + .commitSubject = "@GIT_COMMIT_SUBJECT@", + .commitBody = "@GIT_COMMIT_BODY@", + .describe = "@GIT_DESCRIBE@", + .branchName = "@GIT_BRANCH@", + .latestTag = "@GIT_TAG@", + .latestTagName = "@GIT_TAG_NAME@" + }; +} // namespace nbl::gtml \ No newline at end of file From adfb23c16e170f611766ee9ab2b12f7dd4b027fa Mon Sep 17 00:00:00 2001 From: tad1 Date: Wed, 11 Sep 2024 21:59:51 +0200 Subject: [PATCH 04/10] use custom commands instead multiple targets --- CMakeLists.txt | 6 +++++- git_watcher.cmake | 10 ++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d65fa5d..d7dd5c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ project(cmake_git_version_tracking set(NBL_GTML_TRACKED_TARGETS CACHE INTERNAL "") set(NBL_GTML_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE INTERNAL "") set(NBL_GTML_PROJECT_NAME "${PROJECT_NAME}" CACHE INTERNAL "") +set(NBL_GTML_STAMP_FILE "${NBL_GTML_BINARY_DIR}/stamp" CACHE INTERNAL "") # useage notes: # 1. `add_subdirectory` this project @@ -67,6 +68,9 @@ function(NBL_GENERATE_GIT_TRACKING_META) add_library("${NBL_GTML_PROJECT_NAME}" STATIC ${GTML_TARGET_SOURCES} "${NBL_GTML_BINARY_DIR}/git_info.cpp") target_include_directories("${NBL_GTML_PROJECT_NAME}" SYSTEM PUBLIC "${NBL_GTML_BINARY_DIR}") - add_dependencies("${NBL_GTML_PROJECT_NAME}" ${GTML_TARGET_NAMES}) + + # triggers all git check custom commands each build + add_custom_target(gtml_git_check ALL COMMAND "${CMAKE_COMMAND}" -E touch "${NBL_GTML_STAMP_FILE}") + add_dependencies("${NBL_GTML_PROJECT_NAME}" gtml_git_check) endfunction(NBL_GENERATE_GIT_TRACKING_META) diff --git a/git_watcher.cmake b/git_watcher.cmake index 3947887..ff21167 100644 --- a/git_watcher.cmake +++ b/git_watcher.cmake @@ -348,12 +348,10 @@ endfunction() # check the state of git before every build. If the state has # changed, then a file is configured. function(SetupGitMonitoring) - add_custom_target("${GTML_TARGET_NAME}" - ALL - DEPENDS "${PRE_CONFIGURE_FILE}" - BYPRODUCTS - "${POST_CONFIGURE_FILE}" - "${GIT_STATE_FILE}" + add_custom_command( + OUTPUT "${POST_CONFIGURE_FILE}" + DEPENDS "${PRE_CONFIGURE_FILE}" "${NBL_GTML_STAMP_FILE}" + BYPRODUCTS "${GIT_STATE_FILE}" COMMENT "Checking the git repository for changes..." COMMAND "${CMAKE_COMMAND}" From 069ffc1af6e0500af755d67cf2ce288be20b7013 Mon Sep 17 00:00:00 2001 From: tad1 Date: Wed, 11 Sep 2024 22:00:09 +0200 Subject: [PATCH 05/10] rename project --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7dd5c8..96da5ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.2...3.27) -project(cmake_git_version_tracking +# gtml - git tracking meta library +project(gtml LANGUAGES CXX) set(NBL_GTML_TRACKED_TARGETS CACHE INTERNAL "") From 6980df412afc61f4bc6785917e768f6a607584e5 Mon Sep 17 00:00:00 2001 From: tad1 Date: Wed, 11 Sep 2024 22:03:14 +0200 Subject: [PATCH 06/10] fix details --- CMakeLists.txt | 2 +- README.md | 17 ++--------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96da5ca..f9c1592 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(NBL_GTML_STAMP_FILE "${NBL_GTML_BINARY_DIR}/stamp" CACHE INTERNAL "") # 1. `add_subdirectory` this project # 2. use function `NBL_ADD_GIT_TRACKING_META_LIBRARY("name" "GIT_PATH")` to track any git_repo # 3. call `NBL_GENERATE_GIT_TRACKING_META()` to finalize and configure required headers/sources -# 4. link this anywhere you need `target_link_libraries(TARGET PUBLIC cmake_git_version_tracking)` +# 4. link this anywhere you need `target_link_libraries(TARGET PUBLIC gtml)` # 5. #include "git_info.h" in your code # 6. profit diff --git a/README.md b/README.md index 2181aed..c35f7b9 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,8 @@ The core capability is baked into single self-contained - C Compiler (with C99 standard support) - Git -## Quickstart via FetchContent -You can use CMake's `FetchContent` module to build the static library `cmake_git_version_tracking`: -```cmake -include(FetchContent) -FetchContent_Declare(cmake_git_version_tracking - GIT_REPOSITORY https://github.com/andrew-hardin/cmake-git-version-tracking.git - GIT_TAG 904dbda1336ba4b9a1415a68d5f203f576b696bb -) -FetchContent_MakeAvailable(cmake_git_version_tracking) - -target_link_libraries(your_target - cmake_git_version_tracking -) -``` -Then [`#include git.h`](./git.h) and use the provided functions to retrieve git metadata. +## How to use +read note in CMakeLists.txt ## Intended use case You're continuously shipping prebuilt binaries for an From d284b01339c9f732ad8ac2d59fb17732b826af3d Mon Sep 17 00:00:00 2001 From: tad1 Date: Thu, 12 Sep 2024 17:39:52 +0200 Subject: [PATCH 07/10] use single underscore guard --- git_info.h.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git_info.h.in b/git_info.h.in index fbbc90f..36dc6bf 100644 --- a/git_info.h.in +++ b/git_info.h.in @@ -1,5 +1,5 @@ -#ifndef __GIT_INFO_H_INCLUDED__ -#define __GIT_INFO_H_INCLUDED__ +#ifndef _GIT_INFO_H_INCLUDED_ +#define _GIT_INFO_H_INCLUDED_ @GTML_INFO@ // based on https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git.h @@ -36,4 +36,4 @@ namespace nbl::gtml { } // namespece nbl::gtml -#endif //__GIT_INFO_H_INCLUDED__ \ No newline at end of file +#endif //_GIT_INFO_H_INCLUDED_ \ No newline at end of file From 101470518f59da5dacb8b252a30adc31489dce73 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Tue, 15 Oct 2024 00:23:42 +0200 Subject: [PATCH 08/10] remove old unused git_info.h, make tracking cpp sources build with jumbo mode (unity builds), add GIT_EXCLUDE_IS_DIRTY option & leave comments for Tadzio how to improve it even more and decrease iteration build times --- CMakeLists.txt | 1 + git_info.h | 31 ------------------------------- git_info.h.in | 3 ++- git_watcher.cmake | 23 +++++++++++++++++------ 4 files changed, 20 insertions(+), 38 deletions(-) delete mode 100644 git_info.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f9c1592..2d98029 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,7 @@ function(NBL_GENERATE_GIT_TRACKING_META) add_library("${NBL_GTML_PROJECT_NAME}" STATIC ${GTML_TARGET_SOURCES} "${NBL_GTML_BINARY_DIR}/git_info.cpp") target_include_directories("${NBL_GTML_PROJECT_NAME}" SYSTEM PUBLIC "${NBL_GTML_BINARY_DIR}") + set_target_properties("${NBL_GTML_PROJECT_NAME}" PROPERTIES UNITY_BUILD TRUE) # triggers all git check custom commands each build add_custom_target(gtml_git_check ALL COMMAND "${CMAKE_COMMAND}" -E touch "${NBL_GTML_STAMP_FILE}") diff --git a/git_info.h b/git_info.h deleted file mode 100644 index d47ae5b..0000000 --- a/git_info.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -// based on https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git.h -// > Released under the MIT License. -// > https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE - -#include "BuildConfigOptions.h" - -namespace nbl { - struct GitInfo { - bool isPopulated; - bool hasUncommittedChanges; - const char* commitAuthorName; - const char* commitAuthorEmail; - const char* commitHash; - const char* commitShortHash; - const char* commitDate; - const char* commitSubject; - const char* commitBody; - const char* describe; - const char* branchName; - const char* latestTag; - const char* latestTagName; - }; - - - // internal use - extern const GitInfo git_info; - - // public use - NBL_API2 const GitInfo getGitInfo(); -} // namespece nbl diff --git a/git_info.h.in b/git_info.h.in index 36dc6bf..5440fff 100644 --- a/git_info.h.in +++ b/git_info.h.in @@ -7,11 +7,12 @@ // > https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE #include +#include namespace nbl::gtml { struct GitInfo { bool isPopulated; - bool hasUncommittedChanges; + std::optional hasUncommittedChanges; const char* commitAuthorName; const char* commitAuthorEmail; const char* commitHash; diff --git a/git_watcher.cmake b/git_watcher.cmake index ff21167..4d57c50 100644 --- a/git_watcher.cmake +++ b/git_watcher.cmake @@ -85,6 +85,7 @@ CHECK_OPTIONAL_VARIABLE(GIT_STATE_FILE "${CMAKE_CURRENT_BINARY_DIR}/git-state-ha CHECK_OPTIONAL_VARIABLE(GIT_WORKING_DIR "${CMAKE_SOURCE_DIR}") CHECK_OPTIONAL_VARIABLE_NOPATH(GIT_FAIL_IF_NONZERO_EXIT TRUE) CHECK_OPTIONAL_VARIABLE_NOPATH(GIT_IGNORE_UNTRACKED FALSE) +CHECK_OPTIONAL_VARIABLE_NOPATH(GIT_EXCLUDE_IS_DIRTY FALSE) # Check the optional git variable. # If it's not set, we'll try to find it using the CMake packaging system. @@ -162,18 +163,27 @@ function(GetGitState _working_dir) else() set(untracked_flag "-unormal") endif() - RunGitCommand(status --porcelain ${untracked_flag}) - if(NOT exit_code EQUAL 0) - set(ENV{GIT_IS_DIRTY} "false") + + if(GIT_EXCLUDE_IS_DIRTY) + set(ENV{GIT_IS_DIRTY} "std::nullopt, // ") else() - if(NOT "${output}" STREQUAL "") - set(ENV{GIT_IS_DIRTY} "true") - else() + RunGitCommand(status --porcelain ${untracked_flag}) + if(NOT exit_code EQUAL 0) set(ENV{GIT_IS_DIRTY} "false") + else() + if(NOT "${output}" STREQUAL "") + set(ENV{GIT_IS_DIRTY} "true") + else() + set(ENV{GIT_IS_DIRTY} "false") + endif() endif() endif() # There's a long list of attributes grabbed from git show. + # TODO: Tadzio, execute everything within single execute_command - the reason is all COMMANDS + # within single invocation will be tried concurently and you can gain a lot of perf there + # total 11 separate execute_commands gets executed currently + set(object HEAD) RunGitCommand(show -s "--format=%H" ${object}) if(exit_code EQUAL 0) @@ -363,6 +373,7 @@ function(SetupGitMonitoring) -DPOST_CONFIGURE_FILE="${POST_CONFIGURE_FILE}" -DGIT_FAIL_IF_NONZERO_EXIT=${GIT_FAIL_IF_NONZERO_EXIT} -DGIT_IGNORE_UNTRACKED=${GIT_IGNORE_UNTRACKED} + -DGIT_EXCLUDE_IS_DIRTY=${GIT_EXCLUDE_IS_DIRTY} -DGTML_NAME="${GTML_NAME}" -DGTML_INFO="${GTML_INFO}" -P "${CMAKE_CURRENT_LIST_FILE}") From 65a43dc5f5db0833177b788d21df1e38080371b2 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Fri, 18 Oct 2024 18:17:08 +0200 Subject: [PATCH 09/10] fix byproduct issues for ninja/makefile generators --- CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d98029..fd23f40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ function(NBL_ADD_GIT_TRACKING_META_LIBRARY GTML_NAME GIT_WORKING_DIR) set(GTML_TARGET_NAME "${GTML_NAME}_check_git") set(POST_CONFIGURE_FILE "${NBL_GTML_BINARY_DIR}/${GTML_NAME}_git_info.cpp") + set(GIT_STATE_FILE "${CMAKE_CURRENT_BINARY_DIR}/${GTML_NAME}_git-state-hash") include("${SRC_DIR}/git_watcher.cmake") set(NBL_GTML_TRACKED_TARGETS ${NBL_GTML_TRACKED_TARGETS} "${GTML_NAME}" CACHE INTERNAL "") @@ -72,7 +73,9 @@ function(NBL_GENERATE_GIT_TRACKING_META) set_target_properties("${NBL_GTML_PROJECT_NAME}" PROPERTIES UNITY_BUILD TRUE) # triggers all git check custom commands each build - add_custom_target(gtml_git_check ALL COMMAND "${CMAKE_COMMAND}" -E touch "${NBL_GTML_STAMP_FILE}") - add_dependencies("${NBL_GTML_PROJECT_NAME}" gtml_git_check) + add_custom_target("gtml_git_check" ALL COMMAND "${CMAKE_COMMAND}" -E touch "${NBL_GTML_STAMP_FILE}" + BYPRODUCTS "${NBL_GTML_STAMP_FILE}" + ) + add_dependencies("${NBL_GTML_PROJECT_NAME}" "gtml_git_check") endfunction(NBL_GENERATE_GIT_TRACKING_META) From 6c3ecac5f0297877d1573ef4e3cdb537c5feeb62 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sat, 13 Sep 2025 17:47:01 +0200 Subject: [PATCH 10/10] add template_git_info.json.in and update script to also gen json version --- CMakeLists.txt | 3 +++ git_watcher.cmake | 7 ++++++- template_git_info.json.in | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 template_git_info.json.in diff --git a/CMakeLists.txt b/CMakeLists.txt index fd23f40..1e5703f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,12 +26,15 @@ function(NBL_ADD_GIT_TRACKING_META_LIBRARY GTML_NAME GIT_WORKING_DIR) set(SRC_DIR "${CMAKE_CURRENT_FUNCTION_LIST_DIR}") set(PRE_CONFIGURE_FILENAME "template_git_info.cpp.in") + set(PRE_CONFIGURE_FILENAME_JSON "template_git_info.json.in") set(PRE_CONFIGURE_FILE "${SRC_DIR}/${PRE_CONFIGURE_FILENAME}") + set(PRE_CONFIGURE_FILE_JSON "${SRC_DIR}/${PRE_CONFIGURE_FILENAME_JSON}") set(GTML_INFO "/* This file is auto-generated by CMake's configure_file function from the template: `${PRE_CONFIGURE_FILENAME}`. * Do not edit this file manually. */") set(GTML_TARGET_NAME "${GTML_NAME}_check_git") set(POST_CONFIGURE_FILE "${NBL_GTML_BINARY_DIR}/${GTML_NAME}_git_info.cpp") + set(POST_CONFIGURE_FILE_JSON "${NBL_GTML_BINARY_DIR}/${GTML_NAME}_git_info.json") set(GIT_STATE_FILE "${CMAKE_CURRENT_BINARY_DIR}/${GTML_NAME}_git-state-hash") include("${SRC_DIR}/git_watcher.cmake") diff --git a/git_watcher.cmake b/git_watcher.cmake index 4d57c50..839ee6f 100644 --- a/git_watcher.cmake +++ b/git_watcher.cmake @@ -81,6 +81,8 @@ endmacro() CHECK_REQUIRED_VARIABLE(PRE_CONFIGURE_FILE) CHECK_REQUIRED_VARIABLE(POST_CONFIGURE_FILE) +CHECK_REQUIRED_VARIABLE(PRE_CONFIGURE_FILE_JSON) +CHECK_REQUIRED_VARIABLE(POST_CONFIGURE_FILE_JSON) CHECK_OPTIONAL_VARIABLE(GIT_STATE_FILE "${CMAKE_CURRENT_BINARY_DIR}/git-state-hash") CHECK_OPTIONAL_VARIABLE(GIT_WORKING_DIR "${CMAKE_SOURCE_DIR}") CHECK_OPTIONAL_VARIABLE_NOPATH(GIT_FAIL_IF_NONZERO_EXIT TRUE) @@ -294,6 +296,7 @@ function(GitStateChangedAction) set(${var_name} $ENV{${var_name}}) endforeach() configure_file("${PRE_CONFIGURE_FILE}" "${POST_CONFIGURE_FILE}" @ONLY) + configure_file("${PRE_CONFIGURE_FILE_JSON}" "${POST_CONFIGURE_FILE_JSON}" @ONLY) endfunction() @@ -362,7 +365,7 @@ function(SetupGitMonitoring) OUTPUT "${POST_CONFIGURE_FILE}" DEPENDS "${PRE_CONFIGURE_FILE}" "${NBL_GTML_STAMP_FILE}" BYPRODUCTS "${GIT_STATE_FILE}" - COMMENT "Checking the git repository for changes..." + COMMENT "Checking target \"${GTML_NAME}\"'s git repository for changes..." COMMAND "${CMAKE_COMMAND}" -D_BUILD_TIME_CHECK_GIT=TRUE @@ -371,6 +374,8 @@ function(SetupGitMonitoring) -DGIT_STATE_FILE="${GIT_STATE_FILE}" -DPRE_CONFIGURE_FILE="${PRE_CONFIGURE_FILE}" -DPOST_CONFIGURE_FILE="${POST_CONFIGURE_FILE}" + -DPRE_CONFIGURE_FILE_JSON="${PRE_CONFIGURE_FILE_JSON}" + -DPOST_CONFIGURE_FILE_JSON="${POST_CONFIGURE_FILE_JSON}" -DGIT_FAIL_IF_NONZERO_EXIT=${GIT_FAIL_IF_NONZERO_EXIT} -DGIT_IGNORE_UNTRACKED=${GIT_IGNORE_UNTRACKED} -DGIT_EXCLUDE_IS_DIRTY=${GIT_EXCLUDE_IS_DIRTY} diff --git a/template_git_info.json.in b/template_git_info.json.in new file mode 100644 index 0000000..df84298 --- /dev/null +++ b/template_git_info.json.in @@ -0,0 +1,15 @@ +{ + "isPopulated": @GIT_RETRIEVED_STATE@, + "hasUncommittedChanges": @GIT_IS_DIRTY@, + "commitAuthorName": "@GIT_AUTHOR_NAME@", + "commitAuthorEmail": "@GIT_AUTHOR_EMAIL@", + "commitHash": "@GIT_HEAD_SHA1@", + "commitShortHash": "@GIT_HEAD_SHORT_SHA1@", + "commitDate": "@GIT_COMMIT_DATE_ISO8601@", + "commitSubject": "@GIT_COMMIT_SUBJECT@", + "commitBody": "@GIT_COMMIT_BODY@", + "describe": "@GIT_DESCRIBE@", + "branchName": "@GIT_BRANCH@", + "latestTag": "@GIT_TAG@", + "latestTagName": "@GIT_TAG_NAME@" +} \ No newline at end of file