You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

324 lines
9.3 KiB

# Copyright (C) 2011-2020 Daniel Scharrer
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the author(s) be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
get_filename_component(VERSION_SCRIPT_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
set(VERSION_STRING_SCRIPT "${VERSION_SCRIPT_DIR}/VersionScript.cmake")
# Create a rule to generate a version string at compile time.
#
# An optional fifth argument can be used to add additional cmake defines.
#
# SRC is processed using the configure_file() cmake command
# at build to produce DST with the following variable available:
#
# VERSION_SOURCES:
# List of (${var} ${file}) pairs.
#
# for each variable ${var}
# - ${var}: The contents of the associated file
# - ${var}_COUNT: Number of lines in the associated file
# - For each line ${i}:
# - ${var}_${i}: The ${i}-th line of the associated file
# - ${var}_${i}_PREFIX: The first component in the line
# - ${var}_${i}_LINE: Everything except the first component of the line
# - ${var}_${i}_NAME: Everything except the last component of the line
# - ${var}_${i}_STRING: The last component (excluding optional suffix) of the line
# - ${var}_${i}_SUFFIX: Suffix (separated by " + ") of the line
# - ${var}_${i}_MAJOR: First version component in ${var}_${i}_STRING
# - ${var}_${i}_MINOR: Second version component in ${var}_${i}_STRING
# - ${var}_${i}_PATCH: Third version component in ${var}_${i}_STRING
# - ${var}_${i}_BUILD: Fourth version component in ${var}_${i}_STRING
# - ${var}_${i}_NUMBER: Reassembled verion components
# - ${var}_${i}_PRERELEASE: If the version indicates a prerelease build
# - ${var}_${i}_PRIVATE: If the version indicates a private build
# - ${var}_HEAD: The first paragraph of the associated file
# - ${var}_TAIL: The remaining paragraphs of the associated file
#
# - GIT_COMMIT: The current git commit. (not defined if there is no GIT_DIR directory)
# - GIT_COMMIT_PREFIX_${i}: The first ${i} characters of GIT_COMMIT (i=0..39)
# For the exact syntax of SRC see the documentation of the configure_file() cmake command.
# The version file is regenerated whenever VERSION_FILE or the current commit changes.
function(version_file SRC DST VERSION_SOURCES GIT_DIR)
set(MODE_VARIABLE 0)
set(MODE_FILE 1)
set(mode ${MODE_VARIABLE})
set(args)
set(dependencies "${VERSION_STRING_SCRIPT}")
foreach(arg IN LISTS VERSION_SOURCES)
if(mode EQUAL MODE_VARIABLE)
set(mode ${MODE_FILE})
else()
get_filename_component(arg "${arg}" ABSOLUTE)
list(APPEND dependencies ${arg})
set(mode ${MODE_VARIABLE})
endif()
list(APPEND args ${arg})
endforeach()
get_filename_component(abs_src "${SRC}" ABSOLUTE)
get_filename_component(abs_dst "${DST}" ABSOLUTE)
get_filename_component(abs_git_dir "${GIT_DIR}" ABSOLUTE)
set(defines)
if(ARGC GREATER 4)
set(defines ${ARGV4})
endif()
if(EXISTS "${abs_git_dir}")
find_program(GIT_COMMAND git)
if(GIT_COMMAND)
list(APPEND dependencies "${GIT_COMMAND}")
endif()
if(EXISTS "${abs_git_dir}/HEAD")
list(APPEND dependencies "${abs_git_dir}/HEAD")
endif()
if(EXISTS "${abs_git_dir}/packed-refs")
list(APPEND dependencies "${abs_git_dir}/packed-refs")
endif()
if(EXISTS "${abs_git_dir}/logs/HEAD")
list(APPEND dependencies "${abs_git_dir}/logs/HEAD")
endif()
else()
set(abs_git_dir "")
endif()
add_custom_command(
OUTPUT
"${abs_dst}"
COMMAND
${CMAKE_COMMAND}
"-DINPUT=${abs_src}"
"-DOUTPUT=${abs_dst}"
"-DVERSION_SOURCES=${args}"
"-DGIT_DIR=${abs_git_dir}"
"-DGIT_COMMAND=${GIT_COMMAND}"
${defines}
-P "${VERSION_STRING_SCRIPT}"
COMMAND
${CMAKE_COMMAND} -E touch "${abs_dst}"
MAIN_DEPENDENCY
"${abs_src}"
DEPENDS
${dependencies}
COMMENT ""
VERBATIM
)
endfunction()
macro(_version_escape var string)
set(${var} "${string}")
endmacro()
macro(_define_version_var_nostrip suffix contents)
_version_escape(${var}_${suffix} "${${contents}}")
list(APPEND variables ${var}_${suffix})
endmacro()
macro(_define_version_var suffix contents)
string(STRIP "${${contents}}" tmp)
_define_version_var_nostrip(${suffix} tmp)
endmacro()
macro(_define_version_line_var_nostrip suffix contents)
_define_version_var_nostrip(${i}_${suffix} ${contents})
if(line_name)
set(${line_name}_${suffix} "${${var}_${i}_${suffix}}")
list(APPEND variables ${line_name}_${suffix})
endif()
endmacro()
macro(_define_version_line_var suffix contents)
string(STRIP "${${contents}}" tmp)
_define_version_line_var_nostrip(${suffix} tmp)
endmacro()
function(parse_version_file names file)
list(GET names 0 var)
list(LENGTH names names_count)
set(variables)
file(READ "${file}" contents)
string(STRIP "${contents}" contents)
string(REGEX REPLACE "\r\n" "\n" contents "${contents}")
string(REGEX REPLACE "\r" "\n" contents "${contents}")
_version_escape(${var} "${contents}")
list(APPEND variables ${var})
# Split the version file into lines.
string(REGEX MATCHALL "[^\r\n]+" lines "${contents}")
set(i 0)
foreach(line IN LISTS lines)
if(i LESS names_count)
list(GET names ${i} line_name)
else()
set(line_name)
endif()
_define_version_var(${i} line)
if(line MATCHES "^([^ ]*) (.*)$")
set(prefix "${CMAKE_MATCH_1}")
set(notprefix "${CMAKE_MATCH_2}")
_define_version_line_var(PREFIX prefix)
_define_version_line_var(LINE notprefix)
else()
_define_version_line_var(PREFIX line)
endif()
if(line MATCHES "^(.*[^+] )?([^ ]+)( \\+ [^ ]+)?$")
set(name "${CMAKE_MATCH_1}")
set(string "${CMAKE_MATCH_2}")
set(suffix "${CMAKE_MATCH_3}")
_define_version_line_var(NAME name)
_define_version_line_var(STRING string)
_define_version_line_var_nostrip(SUFFIX suffix)
if(i GREATER 0 AND line_name)
set(${line_name} "${${var}_${i}_STRING}")
list(APPEND variables ${line_name})
endif()
if(string MATCHES "^([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(\\.([0-9]+))?)?)?(.*)?$")
set(major "${CMAKE_MATCH_1}")
set(minor "${CMAKE_MATCH_3}")
set(patch "${CMAKE_MATCH_5}")
set(build "${CMAKE_MATCH_7}")
set(release "${CMAKE_MATCH_8}")
set(error 0)
set(newpatch)
set(newbuild)
set(prerelease 0)
set(private 0)
if(release MATCHES "^\\-dev\\-([2-9][0-9][0-9][0-9]+)\\-([0-9][0-9])\\-([0-9][0-9])$")
set(prerelease 1)
set(newpatch "${CMAKE_MATCH_1}")
set(newbuild "${CMAKE_MATCH_2}${CMAKE_MATCH_3}")
elseif(release MATCHES "^\\-rc([0-9]+)$")
set(prerelease 1)
set(newpatch "9999")
set(newbuild "${CMAKE_MATCH_1}")
elseif(release MATCHES "^\\-r([0-9]+)$")
if(build STREQUAL "")
set(build "${CMAKE_MATCH_1}")
else()
set(error 1)
endif()
elseif(release OR suffix)
set(prerelease 1)
set(private 1)
set(newpatch 9999)
set(newbuild 9999)
endif()
foreach(component IN ITEMS major minor patch build newpatch newbuild)
string(REGEX REPLACE "^0+" "" ${component} "${${component}}")
if(NOT ${component})
set(${component} 0)
endif()
endforeach()
if(newpatch)
set(prerelease 1)
if(build)
set(error 1)
else()
if(patch)
if(newpatch EQUAL 9999)
math(EXPR patch "${patch} - 1")
if(newbuild EQUAL 9999)
set(build 9999)
else()
math(EXPR build "${newbuild} + 1000")
endif()
else()
set(error 1)
endif()
else()
if(minor)
math(EXPR minor "${minor} - 1")
else()
if(major)
math(EXPR major "${major} - 1")
else()
set(error 1)
endif()
set(minor 9999)
endif()
set(patch "${newpatch}")
set(build "${newbuild}")
endif()
endif()
endif()
set(number "${major}")
if(minor OR patch OR build)
set(number "${number}.${minor}")
if(patch OR build)
set(number "${number}.${patch}")
if(build)
set(number "${number}.${build}")
endif()
endif()
endif()
_define_version_line_var(MAJOR major)
_define_version_line_var(MINOR minor)
_define_version_line_var(PATCH patch)
_define_version_line_var(BUILD build)
_define_version_line_var(PRERELEASE prerelease)
_define_version_line_var(PRIVATE private)
_define_version_line_var(NUMBER number)
_define_version_line_var(ERROR error)
endif()
endif()
math(EXPR i "${i} + 1")
endforeach()
set(${var}_COUNT ${i} PARENT_SCOPE)
string(REGEX REPLACE "\n\n.*$" "" head "${contents}")
_define_version_var(HEAD head)
string(REGEX MATCH "\n\n.*" tail "${contents}")
_define_version_var(TAIL tail)
foreach(var IN LISTS variables)
set(${var} "${${var}}" PARENT_SCOPE)
endforeach()
endfunction()