Skip to content

Commit

Permalink
Update cmake version script and export with cmake config
Browse files Browse the repository at this point in the history
  • Loading branch information
sethrj committed Aug 2, 2023
1 parent e534a44 commit 9a0c8b1
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 92 deletions.
279 changes: 187 additions & 92 deletions cmake/CgvFindVersion.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
#
# https://github.com/sethrj/cmake-git-version
#
# Copyright 2021 UT-Battelle, LLC and Seth R Johnson
# Copyright 2021-2023 UT-Battelle, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#[=======================================================================[.rst:

CgvFindVersion
Expand All @@ -31,13 +31,15 @@ CgvFindVersion
``<projname>``
Name of the project.

This command sets the following variables in the parent package::
This command sets the numeric (usable in CMake version comparisons) and
extended (useful for exact versioning) version variables in the parent
package::

${projname}_VERSION
${projname}_VERSION_STRING

It takes the project name and version file path as optional arguments to
support using it before the CMake ``project`` command.
It takes the project name as an optional argument so that it may be used
*before* calling the CMake ``project`` command.

The project version string uses an approximation to SemVer strings, appearing
as v0.1.2 if the version is actually a tagged release, or v0.1.3+abcdef if
Expand All @@ -47,10 +49,13 @@ CgvFindVersion
it's impossible to determine the version from the tag, so a warning will be
issued and the version will be set to 0.0.0.

The exact regex used to match the version tag is::
The default regex used to match the numeric version and full version string
from the git tag is::

v([0-9.]+)(-dev[0-9.]+)?

but you can override the regex by setting the ``CGV_TAG_REGEX`` variable
before calling ``cgv_find_version``.

.. note:: In order for this script to work properly with archived git
repositories (generated with ``git-archive`` or GitHub's release tarball
Expand All @@ -64,108 +69,198 @@ if(CMAKE_SCRIPT_MODE_FILE)
cmake_minimum_required(VERSION 3.8)
endif()

function(cgv_find_version)
set(projname "${ARGV0}")
if(NOT projname)
set(projname "${CMAKE_PROJECT_NAME}")
if(NOT projname)
message(FATAL_ERROR "Project name is not defined")
endif()
#-----------------------------------------------------------------------------#

function(_cgv_store_version string suffix hash)
if(NOT string)
message(WARNING "The version metadata for ${CGV_PROJECT} could not "
"be determined: installed version number may be incorrect")
endif()
set(_CACHED_VERSION "${string}" "${suffix}" "${hash}")
# Note: extra 'unset' is necessary if using CMake presets with
# ${CGV_PROJECT}_GIT_DESCRIBE="", even with INTERNAL/FORCE
unset(${CGV_CACHE_VAR} CACHE)
set(${CGV_CACHE_VAR} "${_CACHED_VERSION}" CACHE INTERNAL
"Version string and hash for ${CGV_PROJECT}")
endfunction()

#-----------------------------------------------------------------------------#

function(_cgv_try_archive_md)
# Get a possible Git version generated using git-archive (see the
# .gitattributes file)
set(_ARCHIVE_DESCR "$Format:%$")
set(_ARCHIVE_TAG "$Format:%D$")
set(_ARCHIVE_HASH "$Format:%h$")
if(_ARCHIVE_HASH MATCHES "Format:%h")
# Not a git archive
return()
endif()

set(_TAG_REGEX "v([0-9.]+)(-dev[0-9.]+)?")
set(_HASH_REGEX "([0-9a-f]+)")

if(_ARCHIVE_HASH MATCHES "%h")
# Not a "git archive": use live git information
set(_CACHE_VAR "${projname}_GIT_DESCRIBE")
set(_CACHED_VERSION "${${_CACHE_VAR}}")
if(NOT _CACHED_VERSION)
# Building from a git checkout rather than a distribution
if(NOT GIT_EXECUTABLE)
find_package(Git QUIET REQUIRED)
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" "describe" "--tags" "--match" "v*"
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
ERROR_VARIABLE _GIT_ERR
OUTPUT_VARIABLE _VERSION_STRING
RESULT_VARIABLE _GIT_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(_GIT_RESULT)
message(AUTHOR_WARNING "No git tags in ${projname} matched 'v*': "
"${_GIT_ERR}")
elseif(NOT _VERSION_STRING)
message(WARNING "Failed to get ${projname} version from git: "
"git describe returned an empty string")
else()
# Process description tag: e.g. v0.4.0-2-gc4af497 or v0.4.0
# or v2.0.0-dev2
string(REGEX MATCH "^${_TAG_REGEX}(-[0-9]+-g${_HASH_REGEX})?" _MATCH
"${_VERSION_STRING}"
)
if(_MATCH)
set(_VERSION_STRING "${CMAKE_MATCH_1}")
set(_VERSION_STRING_SUFFIX "${CMAKE_MATCH_2}")
if(CMAKE_MATCH_3)
# *not* a tagged release
set(_VERSION_HASH "${CMAKE_MATCH_4}")
endif()
endif()
endif()
if(NOT _VERSION_STRING)
execute_process(
COMMAND "${GIT_EXECUTABLE}" "log" "-1" "--format=%h" "HEAD"
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
OUTPUT_VARIABLE _VERSION_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
set(_CACHED_VERSION "${_VERSION_STRING}" "${_VERSION_STRING_SUFFIX}" "${_VERSION_HASH}")
set("${_CACHE_VAR}" "${_CACHED_VERSION}" CACHE INTERNAL
"Version string and hash for ${projname}")
endif()
list(GET _CACHED_VERSION 0 _VERSION_STRING)
list(GET _CACHED_VERSION 1 _VERSION_STRING_SUFFIX)
list(GET _CACHED_VERSION 2 _VERSION_HASH)
string(REGEX MATCH "tag: *${CGV_TAG_REGEX}" _MATCH "${_ARCHIVE_TAG}")
if(_MATCH)
_cgv_store_version("${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}" "")
else()
string(REGEX MATCH "tag: *${_TAG_REGEX}" _MATCH "${_ARCHIVE_TAG}")
message(WARNING "Could not match a version tag for "
"git description '${_ARCHIVE_TAG}': perhaps this archive was not "
"exported from a tagged commit?")
string(REGEX MATCH " *([0-9a-f]+)" _MATCH "${_ARCHIVE_HASH}")
if(_MATCH)
set(_VERSION_STRING "${CMAKE_MATCH_1}")
set(_VERSION_STRING_SUFFIX "${CMAKE_MATCH_2}")
_cgv_store_version("" "" "${CMAKE_MATCH_1}")
endif()
endif()
endfunction()

#-----------------------------------------------------------------------------#

function(_cgv_try_git_describe)
# First time calling "git describe"
if(NOT Git_FOUND)
find_package(Git QUIET)
if(NOT Git_FOUND)
message(WARNING "Could not find Git, needed to find the version tag")
return()
endif()
endif()

# Load git description
execute_process(
COMMAND "${GIT_EXECUTABLE}" "describe" "--tags" "--match" "v*"
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
ERROR_VARIABLE _GIT_ERR
OUTPUT_VARIABLE _VERSION_STRING
RESULT_VARIABLE _GIT_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(_GIT_RESULT)
message(WARNING "No git tags in ${CGV_PROJECT} matched 'v*': "
"${_GIT_ERR}")
return()
elseif(NOT _VERSION_STRING)
message(WARNING "Failed to get ${CGV_PROJECT} version from git: "
"git describe returned an empty string")
return()
endif()

# Process description tag: e.g. v0.4.0-2-gc4af497 or v0.4.0
# or v2.0.0-dev2
set(_DESCR_REGEX "^${CGV_TAG_REGEX}(-([0-9]+)-g([0-9a-f]+))?")
string(REGEX MATCH "${_DESCR_REGEX}" _MATCH "${_VERSION_STRING}")
if(NOT _MATCH)
message(WARNING "Failed to parse description '${_VERSION_STRING}' "
"with regex '${_DESCR_REGEX}'"
)
return()
endif()

if(NOT CMAKE_MATCH_3)
# This is a tagged release!
_cgv_store_version("${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}" "")
else()
if(CMAKE_MATCH_2)
set(_suffix ${CMAKE_MATCH_2}.${CMAKE_MATCH_4})
else()
message(AUTHOR_WARNING "Could not match a version tag for "
"git description '${_ARCHIVE_TAG}': perhaps this archive was not "
"exported from a tagged commit?")
string(REGEX MATCH " *${_HASH_REGEX}" _MATCH "${_ARCHIVE_HASH}")
if(_MATCH)
set(_VERSION_HASH "${CMAKE_MATCH_1}")
set(_suffix -${CMAKE_MATCH_4})
endif()
# Qualify the version number and save the hash
_cgv_store_version(
"${CMAKE_MATCH_1}" # [0-9.]+
"${_suffix}" # (-dev[0-9.]*)? \. ([0-9]+)
"${CMAKE_MATCH_5}" ([0-9a-f]+)
)
endif()
endfunction()

#-----------------------------------------------------------------------------#

function(_cgv_try_git_hash)
if(NOT GIT_EXECUTABLE)
return()
endif()
# Fall back to just getting the hash
execute_process(
COMMAND "${GIT_EXECUTABLE}" "log" "-1" "--format=%h" "HEAD"
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
OUTPUT_VARIABLE _VERSION_HASH
RESULT_VARIABLE _GIT_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(_GIT_RESULT)
message(WARNING "Failed to get current commit hash from git: "
"${_GIT_ERR}")
return()
endif()
_cgv_store_version("" "" "${_VERSION_HASH}")
endfunction()

#-----------------------------------------------------------------------------#

function(cgv_find_version)
# Set CGV_ variables that are used in embedded macros/functions
if(ARGC GREATER 0)
set(CGV_PROJECT "${ARGV0}")
elseif(NOT CGV_PROJECT)
if(NOT CMAKE_PROJECT_NAME)
message(FATAL_ERROR "Project name is not defined")
endif()
set(CGV_PROJECT "${CMAKE_PROJECT_NAME}")
endif()

if(NOT CGV_TAG_REGEX)
set(CGV_TAG_REGEX "v([0-9.]+)(-[a-z]+[0-9.]*)?")
endif()

set(CGV_CACHE_VAR "${CGV_PROJECT}_GIT_DESCRIBE")

# Successively try archive metadata, git description, or just git hash
if(NOT ${CGV_CACHE_VAR})
_cgv_try_archive_md()
if(NOT ${CGV_CACHE_VAR})
_cgv_try_git_describe()
if(NOT ${CGV_CACHE_VAR})
_cgv_try_git_hash()
if(NOT ${CGV_CACHE_VAR})
set(${CGV_CACHE_VAR} "" "-unknown" "")
endif()
endif()
endif()
endif()

# Unpack stored version
set(_CACHED_VERSION "${${CGV_CACHE_VAR}}")
list(GET _CACHED_VERSION 0 _VERSION_STRING)
list(GET _CACHED_VERSION 1 _VERSION_STRING_SUFFIX)
list(GET _CACHED_VERSION 2 _VERSION_HASH)

if(NOT _VERSION_STRING)
set(_VERSION_STRING "0.0.0")
endif()

if(_VERSION_HASH)
set(_FULL_VERSION_STRING "v${_VERSION_STRING}${_VERSION_STRING_SUFFIX}+${_VERSION_HASH}")
set(_FULL_VERSION_STRING "${_VERSION_STRING}${_VERSION_STRING_SUFFIX}+${_VERSION_HASH}")
else()
set(_FULL_VERSION_STRING "v${_VERSION_STRING}${_VERSION_STRING_SUFFIX}")
set(_FULL_VERSION_STRING "${_VERSION_STRING}${_VERSION_STRING_SUFFIX}")
endif()

set(${projname}_VERSION "${_VERSION_STRING}" PARENT_SCOPE)
set(${projname}_VERSION_STRING "${_FULL_VERSION_STRING}" PARENT_SCOPE)
# Set version number and descriptive version in parent scope
set(${CGV_PROJECT}_VERSION "${_VERSION_STRING}" PARENT_SCOPE)
set(${CGV_PROJECT}_VERSION_STRING "${_FULL_VERSION_STRING}" PARENT_SCOPE)
endfunction()

#-----------------------------------------------------------------------------#

if(CMAKE_SCRIPT_MODE_FILE)
cgv_find_version(TEMP)
message("VERSION=\"${TEMP_VERSION}\"")
message("VERSION_STRING=\"${TEMP_VERSION_STRING}\"")
if(DEFINED ONLY)
# Print only the given variable, presumably VERSION or VERSION_STRING
# (will print to stderr)
set(VERSION "${TEMP_VERSION}")
set(VERSION_STRING "${TEMP_VERSION_STRING}")
message("${${ONLY}}")
else()
message("VERSION=\"${TEMP_VERSION}\"")
message("VERSION_STRING=\"${TEMP_VERSION_STRING}\"")
endif()
endif()

# cmake-git-version 1.1.1
2 changes: 2 additions & 0 deletions cmake/FlibcppConfig.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ if(NOT TARGET @FLIBCPP_NAMESPACE@flc)
include("${Flibcpp_CMAKE_DIR}/FlibcppTargets.cmake")
endif()

set(Flibcpp_VERSION_STRING "@Flibcpp_VERSION_STRING@")

set(Flibcpp_LIBRARIES @FLIBCPP_LIBRARIES@)

set(FLIBCPP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
Expand Down

0 comments on commit 9a0c8b1

Please sign in to comment.