From 3c81a15f29721cb8bde90132d5d151c10d5daec5 Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Fri, 19 Dec 2025 14:45:40 -0800 Subject: [PATCH 1/2] Add cpp_library_set_version for git-based versioning Introduces the cpp_library_set_version() function to set project version variables from git tags after project() is called, enabling git-based versioning for custom setups. Updates documentation with usage instructions and refactors cpp_library_setup() to use the new function for version management. --- README.md | 50 ++++++++++++++++++++++++++ cmake/cpp-library-install.cmake | 2 +- cpp-library.cmake | 63 ++++++++++++++++++++++----------- 3 files changed, 94 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 62bca07..ae36498 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,56 @@ Your documentation will be automatically built and deployed to `https://your-org ## API Reference +### `cpp_library_set_version` + +```cmake +cpp_library_set_version() +``` + +Updates the project version from git tags after `project()` has been called. This is useful for projects that need custom setup and can't use `cpp_library_setup()` but still want automatic git-based versioning. + +**Usage:** + +```cmake +project(my-library) # No VERSION specified +cpp_library_set_version() +# Now PROJECT_VERSION, PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, +# and PROJECT_VERSION_PATCH are set from git tags +``` + +The function: +- Queries git tags using `git describe --tags --abbrev=0` +- Strips the 'v' prefix if present (e.g., `v1.2.3` → `1.2.3`) +- Respects `CPP_LIBRARY_VERSION` cache variable if set (for package managers) +- Falls back to `0.0.0` if no tag found +- Updates all `PROJECT_VERSION*` variables in parent scope + +**When to use:** +- You have a custom library setup that doesn't use `cpp_library_setup()` +- You want to remove hardcoded versions from your `project()` declaration +- You're migrating to cpp-library incrementally + +**Example for stlab/libraries:** + +```cmake +cmake_minimum_required(VERSION 3.24) +include(cmake/CPM.cmake) + +CPMAddPackage("gh:stlab/cpp-library@5.1.1") +include(${cpp-library_SOURCE_DIR}/cpp-library.cmake) + +cpp_library_enable_dependency_tracking() + +project(stlab LANGUAGES CXX) # No hardcoded version + +# Set version from git tags +cpp_library_set_version() + +# Custom library setup continues... +add_library(stlab) +# ... rest of CMakeLists.txt +``` + ### `cpp_library_setup` ```cmake diff --git a/cmake/cpp-library-install.cmake b/cmake/cpp-library-install.cmake index e624c88..dd78ad5 100644 --- a/cmake/cpp-library-install.cmake +++ b/cmake/cpp-library-install.cmake @@ -482,7 +482,7 @@ function(_cpp_library_setup_install) CALL _cpp_library_setup_install_validation) # Register config generation second so it runs first (LIFO) and sets properties - cmake_language(DEFER DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + cmake_language(DEFER DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} CALL _cpp_library_deferred_generate_config) endfunction() diff --git a/cpp-library.cmake b/cpp-library.cmake index 70c7822..20e4263 100644 --- a/cpp-library.cmake +++ b/cpp-library.cmake @@ -8,6 +8,42 @@ # Determine the directory where this file is located get_filename_component(CPP_LIBRARY_ROOT "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) +# Public function to update project version from git tags after project() has been called. +# This is useful for projects that need custom setup and can't use cpp_library_setup() +# but still want automatic git-based versioning. +# +# Usage: +# project(my-library) # No VERSION specified +# cpp_library_set_version() +# # Now PROJECT_VERSION and related variables are set from git tags +# +# The function respects CPP_LIBRARY_VERSION if set (e.g., by package managers), +# otherwise queries git tags, stripping the 'v' prefix if present. +function(cpp_library_set_version) + # Get version from git tags (respects CPP_LIBRARY_VERSION override) + _cpp_library_get_git_version(GIT_VERSION) + + # Parse version components + string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" VERSION_MATCH "${GIT_VERSION}") + if(VERSION_MATCH) + set(VERSION_MAJOR ${CMAKE_MATCH_1}) + set(VERSION_MINOR ${CMAKE_MATCH_2}) + set(VERSION_PATCH ${CMAKE_MATCH_3}) + else() + set(VERSION_MAJOR 0) + set(VERSION_MINOR 0) + set(VERSION_PATCH 0) + endif() + + # Update project version in parent scope + set(PROJECT_VERSION ${GIT_VERSION} PARENT_SCOPE) + set(PROJECT_VERSION_MAJOR ${VERSION_MAJOR} PARENT_SCOPE) + set(PROJECT_VERSION_MINOR ${VERSION_MINOR} PARENT_SCOPE) + set(PROJECT_VERSION_PATCH ${VERSION_PATCH} PARENT_SCOPE) + + message(STATUS "cpp-library: Set project version to ${GIT_VERSION} from git tags") +endfunction() + # Enable dependency tracking for accurate find_dependency() generation # This function should be called BEFORE project() to install the dependency provider. # Requires CMake 3.24+. @@ -197,27 +233,14 @@ function(cpp_library_setup) set(ARG_REQUIRES_CPP_VERSION 17) endif() - # Get version from git tags - _cpp_library_get_git_version(GIT_VERSION) - set(ARG_VERSION "${GIT_VERSION}") - - # Parse version components - string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" VERSION_MATCH "${ARG_VERSION}") - if(VERSION_MATCH) - set(ARG_VERSION_MAJOR ${CMAKE_MATCH_1}) - set(ARG_VERSION_MINOR ${CMAKE_MATCH_2}) - set(ARG_VERSION_PATCH ${CMAKE_MATCH_3}) - else() - set(ARG_VERSION_MAJOR 0) - set(ARG_VERSION_MINOR 0) - set(ARG_VERSION_PATCH 0) - endif() + # Get version from git tags and update project version variables + cpp_library_set_version() - # Update project version - set(PROJECT_VERSION ${ARG_VERSION} PARENT_SCOPE) - set(PROJECT_VERSION_MAJOR ${ARG_VERSION_MAJOR} PARENT_SCOPE) - set(PROJECT_VERSION_MINOR ${ARG_VERSION_MINOR} PARENT_SCOPE) - set(PROJECT_VERSION_PATCH ${ARG_VERSION_PATCH} PARENT_SCOPE) + # Retrieve the version that was just set + set(ARG_VERSION "${PROJECT_VERSION}") + set(ARG_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) + set(ARG_VERSION_MINOR ${PROJECT_VERSION_MINOR}) + set(ARG_VERSION_PATCH ${PROJECT_VERSION_PATCH}) # Generate full paths for HEADERS and SOURCES based on conventions set(GENERATED_HEADERS "") From 49cd94fccd9436be1a56814fbd932ef4287094b1 Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Fri, 19 Dec 2025 14:54:33 -0800 Subject: [PATCH 2/2] Propagate project version variables to parent scope Adds backward compatibility by setting PROJECT_VERSION and its components (MAJOR, MINOR, PATCH) in the parent scope within cpp_library_setup. --- cpp-library.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cpp-library.cmake b/cpp-library.cmake index 20e4263..77ae632 100644 --- a/cpp-library.cmake +++ b/cpp-library.cmake @@ -242,6 +242,12 @@ function(cpp_library_setup) set(ARG_VERSION_MINOR ${PROJECT_VERSION_MINOR}) set(ARG_VERSION_PATCH ${PROJECT_VERSION_PATCH}) + # Propagate project version to caller's scope (backward compatibility) + set(PROJECT_VERSION ${ARG_VERSION} PARENT_SCOPE) + set(PROJECT_VERSION_MAJOR ${ARG_VERSION_MAJOR} PARENT_SCOPE) + set(PROJECT_VERSION_MINOR ${ARG_VERSION_MINOR} PARENT_SCOPE) + set(PROJECT_VERSION_PATCH ${ARG_VERSION_PATCH} PARENT_SCOPE) + # Generate full paths for HEADERS and SOURCES based on conventions set(GENERATED_HEADERS "") foreach(header IN LISTS ARG_HEADERS)