Versioning reference#
Exact resolution rules, version string formats, and variables for LIBRA’s versioning. For the model behind them – why tags, why two versions, and a recommended release workflow – see Versioning.
Tag grammar#
A version tag is an optional v followed by a SemVer core and optional
prerelease:
v?MAJOR.MINOR.PATCH(-PRERELEASE)?
where PRERELEASE starts with an alphanumeric and contains only
alphanumerics, ., _, and -. Build metadata (+...) is not
allowed in tags; LIBRA adds its own for untagged commits.
Tag |
Numeric |
Prerelease |
|---|---|---|
|
|
(empty) |
|
|
|
|
|
|
|
|
|
Note
The CMake resolver accepts tags with or without the leading v,
but clibra version --bump only considers v-prefixed tags. Use the
v prefix everywhere.
Warning
git describe returns the nearest tag of any name. If the
nearest tag to an untagged commit doesn’t match this grammar (e.g.
nightly), resolution fails with an unrecognized git describe format
warning and falls through to 0.0.0, even if an older valid tag exists.
Don’t mix non-version tags into a branch whose version LIBRA resolves.
Version string formats#
The full version (LIBRA_PROJECT_VERSION,
LIBRA_VERSION) is a valid SemVer 2.0 string with no leading
v. On an untagged commit, the distance from the nearest tag and the
abbreviated commit hash are appended as build metadata, +<distance>.g<sha>:
Git state |
Full version |
Numeric version |
|---|---|---|
|
|
|
|
|
|
5 commits past |
|
|
5 commits past |
|
|
Nothing resolvable |
|
|
Per SemVer, build metadata does not affect precedence: 1.5.0+5.g230f029
sorts equal to 1.5.0.
Project version resolution#
libra_extract_version() resolves the calling project’s version
by trying each tier in order and stopping at the first that succeeds. Git is
run in CMAKE_CURRENT_SOURCE_DIR of the caller, and is allowed to find a
repository in any parent directory.
# |
Tier |
Source |
Diagnostics |
|---|---|---|---|
1 |
Exact tag on |
|
|
2 |
Untagged commit |
|
|
3 |
Baked version (LIBRA only) |
|
|
4 |
Nothing available |
|
|
Any git failure (git not installed, not a repository, no tags, shallow clone with no reachable tag) is treated as “unavailable” and falls through to the next tier.
Scope. When called from the top-level CMakeLists.txt, the results are
written as INTERNAL cache variables, which is where clibra version reads
them. When called from a subproject (e.g. a dependency brought in with
add_subdirectory() that also calls it), the results are set as normal
variables in that subproject’s directory scope only, so each project sees its
own version and the cache keeps the top-level project’s.
LIBRA version resolution#
LIBRA_VERSION is resolved by
libra_resolve_self_version(), which include(libra/project)
calls automatically. It never emits warnings.
# |
Tier |
Notes |
|---|---|---|
1 |
Baked version in |
Used if the file exists and contains a real version. An unexpanded
|
2 |
Git in LIBRA’s own directory |
Same exact-tag / describe logic as the project version, but only if
|
3 |
|
What that means for each way of consuming LIBRA:
Consumption mode |
Tier used |
Example |
|---|---|---|
Conan package |
1 (baked) |
|
CPM git fetch, git submodule, development clone |
2 (git) |
|
|
1 if |
|
|
3 |
|
Copy of LIBRA without its own |
3 |
|
Bump rules#
clibra version --bump prints the next development version; it does not
create or push tags. It takes the highest v-prefixed SemVer tag in the
local repository by SemVer precedence – not the nearest reachable one, see
“What version is this?” vs. “What version is next?” – and applies:
Highest tag |
Next version |
Why |
|---|---|---|
|
|
Stable: start a dev stream toward the next patch. |
|
|
Continue the dev stream. |
|
|
|
|
|
|
(no tags) |
|
Bootstrap. |
The result always has strictly higher SemVer precedence than its input. Because
only local tags are considered, run git fetch --tags first (or use
fetch-depth: 0 on shallow CI checkouts); a tag that exists only on the
remote is invisible, and the collision surfaces when git push rejects the
duplicate tag.
To move to a new minor or major version, create the first tag of the new
series by hand (e.g. v1.3.0-dev.1 or v2.0.0); subsequent bumps continue
from it.
API#
- libra_extract_version#
Derive the project version from the current git state and expose it as CMake variables in the calling scope.
This function MUST be called before
project()so thatLIBRA_PROJECT_VERSION_NUMERICis available forproject(VERSION ...). Because it runs beforelibra/messagingis loaded it uses plainmessage()internally rather thanlibra_message().Version is resolved through a four-tier priority chain (exact tag -> untagged commit annotated via
git describe-> bakedself.cmakefallback ->0.0.0). See Git tags as the single source of truth for the authoritative description of each tier and the resulting version strings; this docstring intentionally does not restate it to avoid drift.Git is run in the calling project’s source directory (
CMAKE_CURRENT_SOURCE_DIR), never in LIBRA’s. The bakedself.cmaketier applies only when the calling project is LIBRA; any other project without git gets0.0.0rather than LIBRA’s version.Cache variables set:
Typical usage in a consuming project:
# CMakeLists.txt -- before including libra/project include(libra/version) libra_extract_version() # libra/project then calls: # project(... VERSION ${LIBRA_PROJECT_VERSION_NUMERIC} ...) include(libra/project) message(STATUS "${PROJECT_NAME} ${LIBRA_PROJECT_VERSION}")
CPM dependency consumption:
# GIT_TAG takes the full semver tag (prerelease suffix included). # VERSION takes the numeric component only (CMake deduplication key). CPMAddPackage( NAME mydep GIT_TAG v${LIBRA_PROJECT_VERSION} VERSION ${LIBRA_PROJECT_VERSION_NUMERIC} )
Note
LIBRA_PROJECT_VERSION_NUMERICmaps to CMake’sPROJECT_VERSIONafter theproject()call, which also sets the standardPROJECT_VERSION_MAJOR,PROJECT_VERSION_MINOR, andPROJECT_VERSION_PATCHcomponents.LIBRA_PROJECT_VERSIONandLIBRA_PROJECT_VERSION_PRERELEASEcarry the information that CMake’s own version machinery cannot represent.Note
This variable family is distinct from
LIBRA_VERSION, which is the version of the LIBRA build framework itself.