Simplify your Semantic-Version automation within every developer build using code commits and repository tags.
- Use CMake to build your project.
- Use Git as your code repository.
💡 If you are using a different SCM please raise an issue - Structure your project. See Here.
- Use modern CMake features like targets and properties. See here and here.
- Understand semantic versioning here and here.
- Tag your releases with the version prefixed by a
v.
💎 This is now optional but still preferred -Version.cmakeshould detect if your tag is 'version-like' - Use a 'Prefix' for your project options in CMake options:
💎 Instead ofBUILD_TESTINGuseMYLIBRARY_BUILD_TESTING
All CMake variables use the form VERSION_<field>:
| Variable | Description | Example |
|---|---|---|
VERSION_SET |
TRUE if version fields were populated successfully |
TRUE |
VERSION_MAJOR |
Major semantic-version extracted from repository tag | 0 |
VERSION_MINOR |
Minor semantic-version extracted from repository tag | 1 |
VERSION_PATCH |
Patch semantic-version extracted from repository tag | 2 |
VERSION_COMMIT |
Commit count since last tag | 30 |
VERSION_SHA |
Revision-specific unique SHA hash | 4c757e7 |
VERSION_SEMANTIC |
Full semantic version major.minor.patch.commit |
0.1.2.30 |
VERSION_FULL |
Full git describe output, useful for ABI compatibility | v0.1.2-30-g4c757e7-dirty |
We recommend using CPM.cmake so you stay up to date with the latest fixes and features.
Alternatively, you may directly include Version.cmake in your project but we don't encourage this as you may miss important updates.
After adding CPM.cmake, add the following to your CMakeLists.txt:
CPMAddPackage("gh:BareCpper/[email protected]")You may wish to optionally set the project version on the project(...) call.
If so, we recommend checking VERSION_SET:
if(NOT VERSION_SET)
message(FATAL_ERROR "Version.cmake is required")
endif()
project(MyProject VERSION ${VERSION_SEMANTIC})To use the version information within a CMake build target:
- Add
version::versionto thetarget_link_librariesfor the target library/executable. - Add
Version.hvia the#includedirective. - Use the
VERSION_<field>preprocessor values in your code.
💎 The default template defines C-preprocessor directives. For C++17 and later, see the constexpr template below.
target_link_libraries(MyLibrary
PRIVATE
version::version
)#include "Version.h"All variables are optional — sensible defaults are provided for every one.
Override any of them in your CMakeLists.txt before calling CPMAddPackage / include(Version.cmake):
| Variable | Default | Description |
|---|---|---|
VERSION_OUT_DIR |
CMAKE_BINARY_DIR |
Output directory for the generated header. Override to place the header inside a sub-directory already on the include path (e.g. ${CMAKE_BINARY_DIR}/include/myapp). |
VERSION_SOURCE_DIR |
CMAKE_SOURCE_DIR |
The git repository root to query. Override for sub-module or CPM-fetched versioning. |
VERSION_PREFIX |
"" |
Optional prefix for C preprocessor macros. "MYAPP_" produces MYAPP_VERSION_MAJOR. Useful when multiple libraries use Version.cmake in the same build. |
VERSION_H_FILENAME |
"${VERSION_PREFIX}Version.h" |
Output filename. Set to "version.hpp" to select the C++17 constexpr template instead of the default C-preprocessor template. |
VERSION_NAMESPACE |
"" |
Optional C++ namespace for constexpr constants in Version.hpp.in. Supports nested namespaces (e.g. "myapp::version"). Only used when VERSION_H_FILENAME ends in .hpp. |
Set VERSION_H_FILENAME and VERSION_NAMESPACE to get inline constexpr constants in a named namespace:
💎 This is the recommended approach for C++17 (and later) projects.
set(VERSION_OUT_DIR "${CMAKE_BINARY_DIR}/include/myapp")
set(VERSION_PREFIX "MYAPP_")
set(VERSION_H_FILENAME "version.hpp")
set(VERSION_NAMESPACE "myapp::version")
CPMAddPackage("gh:BareCpper/[email protected]")
target_link_libraries(MyLibrary PUBLIC version::version)Generated include/myapp/version.hpp:
// Generated by Version.cmake -- do not edit.
#pragma once
#include <cstdint>
#include <string_view>
namespace myapp::version {
inline constexpr std::uint32_t version_major = 0;
inline constexpr std::uint32_t version_minor = 1;
inline constexpr std::uint32_t version_patch = 2;
inline constexpr std::uint32_t version_commit = 30;
inline constexpr std::string_view version_sha = "4c757e7";
inline constexpr std::string_view version_string = "0.1.2.30";
inline constexpr std::string_view version_full = "v0.1.2-30-g4c757e7";
} // namespace myapp::version
// Legacy C preprocessor macros (for C ABI and pre-C++20 code)
#define MYAPP_VERSION_MAJOR 0
#define MYAPP_VERSION_STRING "0.1.2.30"
// ...#include "myapp/version.hpp"
// C++ constexpr path
static_assert(myapp::version::version_major >= 0);
// C legacy path (e.g. in a C ABI header)
// MYAPP_VERSION_MAJOR == 0Set VERSION_H_FILENAME to any filename; Version.cmake looks for a matching .in file in the Version.cmake package directory. If no matching .in file is found, the default C-preprocessor template is auto-generated.
To provide your own template, place a <filename>.in file in your project and point VERSION_H_TEMPLATE at it:
set(VERSION_H_TEMPLATE "${CMAKE_SOURCE_DIR}/cmake/MyVersion.h.in")Available substitution variables inside any template:
| Template variable | Value |
|---|---|
@_VERSION_MAJOR@ |
Major component (integer) |
@_VERSION_MINOR@ |
Minor component (integer) |
@_VERSION_PATCH@ |
Patch component (integer) |
@_VERSION_COMMIT@ |
Commit count (integer) |
@_VERSION_SHA@ |
Short SHA string |
@_VERSION_SEMANTIC@ |
Full semantic string |
@_VERSION_FULL@ |
Full git describe string |
@_VERSION_PREFIX@ |
Resolved prefix (with trailing _ if non-empty) |
@_VERSION_NAMESPACE_BEGIN@ |
namespace X { or empty |
@_VERSION_NAMESPACE_END@ |
} // namespace X or empty |
- Small and reusable so can be added to any CMake build.
- No re-configuring of CMake necessary — the build-time step updates version information transparently.
- C and C++ compatible — default template uses C preprocessor; C++17
constexprtemplate available viaVERSION_H_FILENAME. - Namespace scoping —
VERSION_NAMESPACEprevents symbol collisions when multiple libraries use Version.cmake. - Prefix scoping —
VERSION_PREFIXscopes C preprocessor macros.
- Requires git on
PATHat build time. - The generated header is regenerated on every build (tracks
HEADand.git/index) — this is intentional, ensuring version information always reflects the actual commit. - No support for non-git SCMs — raise an issue if you need support for another SCM.