Adding Git Version Information to Your App
Erbsland Core provides a small CMake helper that generates a source file containing version information from your Git repository.
This allows an application to report its own version without introducing generated include directories, generated public headers, or additional build-time dependencies throughout the code base.
The helper is intentionally designed for quiet and efficient builds.
It tracks the current Git HEAD, the active branch reference, a submodule or worktree .git file, and
packed-refs.
It does not track the repository’s dirty state and does not recursively scan all references.
This keeps dependency tracking predictable while still updating the generated version whenever the effective repository
version changes.
If Git is unavailable, the source tree does not contain a .git entry, or the version information cannot be parsed,
all generated values fall back to 0.0.0.0.
Subclass Pattern
This pattern is useful when your application already derives from
Application to provide custom
initialization, command-line handling, or other startup logic.
Add two static accessors to your application class:
#pragma once
#include <erbsland/Application.hpp>
#include <erbsland/String.hpp>
#include <erbsland/Version.hpp>
class MyApplication final : public el::Application {
public:
using el::Application::Application;
[[nodiscard]] static auto appVersion() noexcept -> el::Version;
[[nodiscard]] static auto appVersionText() noexcept -> el::String;
void initialize() override;
};
Implement initialize() as usual and use the generated version information to populate the application metadata.
#include "MyApplication.hpp"
void MyApplication::initialize() {
using namespace el::text::literals;
el::Application::initialize();
info().setApplicationName("MyApp"_el);
info().setApplicationVersion(appVersion());
}
Next, create MyApplication_version.in.cpp next to your application sources.
This file acts as a template.
During configuration, CMake generates the final source file in the build directory and automatically adds it to the
target.
#include "MyApplication.hpp"
using namespace el::text::literals;
auto MyApplication::appVersion() noexcept -> el::Version {
return el::Version{
@ERBSLAND_GIT_VERSION_MAJOR@U,
@ERBSLAND_GIT_VERSION_MINOR@U,
@ERBSLAND_GIT_VERSION_REVISION@U,
@ERBSLAND_GIT_VERSION_BUILD@U,
};
}
auto MyApplication::appVersionText() noexcept -> el::String {
return "@ERBSLAND_GIT_VERSION_TEXT@"_el;
}
Finally, register the template with the target that contains MyApplication.
add_executable(my-app
src/main.cpp
src/Application.hpp
src/Application.cpp
# ... more sources ...
)
erbsland_core_add_git_version(
TARGET my-app
PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/../"
TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/src/MyApplication_version.in.cpp"
)
Direct Application Pattern
This pattern is useful when main() creates
Application directly and
assigns the main function with
Application::setMainFn().
Create a small AppVersion.hpp header that declares free functions for accessing the generated version information.
#pragma once
#include <erbsland/String.hpp>
#include <erbsland/Version.hpp>
[[nodiscard]] auto appVersion() noexcept -> el::Version;
[[nodiscard]] auto appVersionText() noexcept -> el::String;
Create the matching AppVersion.in.cpp template:
#include "AppVersion.hpp"
auto appVersion() noexcept -> el::Version {
return el::Version{
@ERBSLAND_GIT_VERSION_MAJOR@U,
@ERBSLAND_GIT_VERSION_MINOR@U,
@ERBSLAND_GIT_VERSION_REVISION@U,
@ERBSLAND_GIT_VERSION_BUILD@U,
};
}
auto appVersionText() noexcept -> el::String {
using namespace el::text::literals;
return "@ERBSLAND_GIT_VERSION_TEXT@"_el;
}
After creating the application object, use these functions to populate the application metadata.
#include "AppVersion.hpp"
#include <erbsland/Application.hpp>
auto main(int argc, char *argv[]) -> int {
using namespace el::text::literals;
el::Application app{argc, argv};
app.info().setApplicationName("MyApp"_el);
app.info().setApplicationVersion(appVersion());
app.setMainFn([]() -> el::ExitCode {
// do something
return el::ExitCode::success();
});
return app.run();
}
Register the template with the target:
add_executable(my-app)
erbsland_core_add_git_version(
TARGET my-app
PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/../"
TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/src/AppVersion.in.cpp"
)
CMake Setup
When Erbsland Core is added as a subdirectory, the helper becomes available immediately after the add_subdirectory()
call.
add_subdirectory(erbsland)
add_library(my-lib STATIC)
erbsland_core_add_git_version(
TARGET my-lib
PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/../"
TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/src/version.in.cpp"
)
Installed packages provide the same helper through find_package(erbsland-core).
By default, the generated source file is written below:
${CMAKE_CURRENT_BINARY_DIR}/<target>-git-version/
Specify OUTPUT only when a target requires a specific filename or location for the generated file.
erbsland_core_add_git_version(
TARGET my-lib
PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/../"
TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/src/version.in.cpp"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/MyLibVersion.cpp"
VARIABLE_PREFIX MY_LIB_VERSION
)
With this custom prefix, placeholders such as @MY_LIB_VERSION_MAJOR@ and @MY_LIB_VERSION_TEXT@ become available
in the template.