diff options
Diffstat (limited to 'cmake')
-rw-r--r-- | cmake/GitRelease.cmake | 1009 | ||||
-rw-r--r-- | cmake/boost-checks.cmake | 87 | ||||
-rw-r--r-- | cmake/regex-checks.cmake | 61 |
3 files changed, 1157 insertions, 0 deletions
diff --git a/cmake/GitRelease.cmake b/cmake/GitRelease.cmake new file mode 100644 index 00000000..577660b5 --- /dev/null +++ b/cmake/GitRelease.cmake @@ -0,0 +1,1009 @@ +# Copyright © 2009-2013 Roger Leigh <rleigh@debian.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# <http://www.gnu.org/licenses/>. +# +##################################################################### + +# Versioning, releasing and distribution management with git and cmake +# ==================================================================== +# +# This facility is a cmake reimplementation of an earlier +# autoconf/automake version from +# http://anonscm.debian.org/gitweb/?p=buildd-tools/schroot.git;a=blob;f=scripts/git-dist.mk;hb=refs/heads/schroot-1.6 +# but is further generalised and is rather more configurable, and +# integrates quite seamlessly with cmake. +# +# Most projects currently handle versioning by hardcoding the version +# number in the source repository in some form, for example in the +# cmake scripts, or in the sources or some other file. This script +# handles release versioning using the metadata in git tags, and for +# distributed release archives, it embeds a generated file so that git +# isn't required to retrieve the release metadata. +# +# This script also handles release and distribution of a project +# entirely within git, which is described in more detail below. +# +# A number of variables customise the behaviour of the script for a +# particular project; set them before including this file. While the +# defaults will work for most projects, it will typically require +# adapting to the existing conventions used by a particular project. +# +# The intended use of this facility is to replace a manual step in the +# release process with an automated one, such that releasing may be +# done entirely automatically, and the version numbering may be +# controlled at a higher level, for example via a continuous +# integration system such as Jenkins, or by a release manager, etc. +# The versioning is handled external to the source tree, but is done +# entirely within the git repository. +# +# Terms +# ----- +# +# Release +# Tagging the working git branch with a "release tag". This tag is +# signed by default, and the naming scheme allows identification of +# the current or previous release when running cmake. +# +# Distribution +# Creation of a distributable form of the tagged release. This +# involves committing of the tagged release source tree to a +# "distribution branch" and creation of a "distribution tag". This +# tag is signed by default. The distributed source tree is the +# release source tree with the addition of release metadata +# including the version number, and may also include other generated +# data, e.g. documentation. This tagged distribution may be +# subsequently exported as a tarfile or zipfile with "git archive", +# or used directly from git by downstream consumers. +# +# +# Version metadata +# ---------------- +# +# Set GIT_VERSION_FILE, which is the location of a cmake script +# relative to PROJECT_SOURCE_DIR. The default is "version.cmake". +# For backward compatibility with the preexisting autoconf/automake +# implementation, GIT_VERSION_FILE_COMPAT may also be set, defaulting +# to "VERSION"; this also needs GIT_VERSION_FILE_USE_COMPAT setting to +# ON (default is OFF). +# +# When developing from git, no version file will be used; version +# information will be obtained directly from git. When using a +# distributed release, version information will be obtained from the +# version file. +# +# +# Release configuration +# --------------------- +# +# This script will not allow tagging of a release if the working git +# branch contains uncommitted changes. This is in order to prevent +# creation of broken releases—the working tree may appear to build +# and work correctly, but the uncommitted changes won't be tagged. +# Additionally, it will not allow tagging of a release if untracked +# files are present in the tree (for the same reasons--the untracked +# files may require adding and committing). Set +# GIT_RELEASE_CHECK_UNTRACKED to OFF to allow releasing if untracked +# files are present. +# +# Releasing isn't enabled by default in order to prevent unintentional +# or accidental modification of the git repository. That is to say, +# making a release must be explicitly requested as a safety check; set +# GIT_RELEASE_ENABLE to ON in order to make a release. +# +# Release tagging is customised using the following options: +# +# GIT_RELEASE_TAG_OPTIONS +# A list of options to pass to "git tag"; defaults to "-s" to sign +# the tag. +# +# GIT_RELEASE_TAG_NAME +# The name of the release tag. Defaults to +# "release/${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION}", but may be +# changed to just "v${GIT_RELEASE_VERSION}" or any name desired. +# The only restriction is that it must contain the release version +# somewhere in the string, and must be a valid git tag name. +# +# GIT_RELEASE_TAG_MATCH +# A pattern to patch all release versions when using "git describe +# --match". Defaults to "release/${CMAKE_PROJECT_NAME}-*", +# i.e. containing the constant part of GIT_RELEASE_TAG_NAME without +# the version number. Must be changed appropriately if +# GIT_RELEASE_TAG_NAME is customised. +# +# GIT_RELEASE_TAG_REGEX +# A regular expression to match the release version in the tag name. +# The release version number must be the first match ("\1"). +# Defaults to "^release/${CMAKE_PROJECT_NAME}-([0-9].*)\$". Must be +# changed appropriately if GIT_RELEASE_TAG_NAME is customised. +# +# GIT_RELEASE_TAG_MESSAGE +# The release tag message. Any text is permitted here, though it is +# advisable (but not required) to include GIT_RELEASE_VERSION as +# part of the message. +# +# +# Releasing +# --------- +# +# Run "cmake" as normal, but add the options: +# +# -DGIT_RELEASE_ENABLE=ON -DGIT_RELEASE_VERSION=${new_version} +# +# This will provide a new "git-release" target. If using make, run: +# +# make git-release +# +# If tag signing is enabled, you'll be prompted for your key +# passphrase. +# +# Run "git log --decorate" or "git describe" and you'll see the +# release tag. This tag marks the current commit as the release of +# version ${new_version}. +# +# +# Distribution configuration +# -------------------------- +# +# Making a distribution of a release requires releasing first (as +# documented above) +# +# Distributing isn't enabled by default in order to prevent +# unintentional or accidental modification of the git repository. +# That is to say, making a distribution must be explicitly requested +# as a safety check; set GIT_DIST_ENABLE to ON in order to make a +# distribution. +# +# Distribution tagging is customised using the following options: +# +# GIT_DIST_TAG_OPTIONS +# A list of options to pass to "git tag"; defaults to "-s" to sign +# the tag. +# +# GIT_DIST_TAG_NAME +# The name of the distribution tag. Defaults to +# "distribution/${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION}", but +# may be changed to just "v${GIT_RELEASE_VERSION}" or any name +# desired. The only restriction is that it must contain the +# distribution version somewhere in the string, and must be a valid +# git tag name. +# +# GIT_DIST_TAG_MESSAGE +# The distribution tag message. Any text is permitted here, though +# it is advisable (but not required) to include GIT_DIST_VERSION as +# part of the message. +# +# Distribution committing and branching is customised using the +# following options: +# +# GIT_DIST_BRANCH +# The name of the branch to commit onto. The branch will be created +# if it does not already exist. The default is +# "distribution/${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION_MAJOR}.${GIT_RELEASE_VERSION_MINOR}" +# which is to say that it includes the major and minor version +# numbers, so that you get a new distribution branch each time the +# major or minor number is changed, with the patch release versions +# being committed in sequence on each branch. This enables +# downstream tracking of a given release series, and maintenance of +# multiple release series in parallel. It is advised to customise +# this to meet the project's versioning and release strategy such +# that major stable release series are kept on different branches. +# +# GIT_DIST_COMMIT_MESSAGE +# The distribution commit message. Any text is permitted here, +# though it is advisable (but not required) to include +# GIT_DIST_VERSION as part of the message. +# +# GIT_DIST_NAME +# Naming scheme for the release. This is the name of the release +# directory, and will be used to prefix the path for release +# archives. Defaults to +# "${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION}". +# +# GIT_DIST_TMPDIR +# Temporary directory used for staging the release distribution tree +# prior to committing into git. Defaults to +# "${PROJECT_BINARY_DIR}/GitRelease" but may be +# adjusted if this clashes with existing usage of this path. +# +# GIT_DIST_ROOT +# Root of the staged release distribution. Defaults to +# "${GIT_DIST_TMPDIR}/${GIT_DIST_NAME}". +# +# +# +# Distributing +# ------------ +# +# Run "cmake" as normal, but add the option: +# +# -DGIT_DIST_ENABLE=ON +# +# This will provide a new "git-dist" target. If using make, run: +# +# make git-dist +# +# If tag signing is enabled, you'll be prompted for your key +# passphrase. +# +# Look at the distribution branch with "git log --decorate --graph" or +# "gitk". You'll see that the distribution has the tagged release as +# its parent and (if present) the prior distribution. That is to say, +# the relationships between the releases and distributions are +# explicitly defined. While this might not be of immediately obvious +# benefit, it means that downstream consumers can make changes and +# push them back to you; merging the changes back upstream is much +# easier since the origin of the changes is fully described by the +# dependency graph. + +cmake_policy(SET CMP0007 NEW) + +# Settings file used to pass configuration settings +set(GIT_RELEASE_SETTINGS "${CMAKE_BINARY_DIR}/GitRelease.cmake") + +# When running in script mode, read the saved settings first +if (CMAKE_SCRIPT_MODE_FILE) + include("${GIT_RELEASE_SETTINGS}") +endif (CMAKE_SCRIPT_MODE_FILE) + +if (NOT CMAKE_SCRIPT_MODE_FILE) +# Version file settings +set(GIT_VERSION_FILE "GitVersion.cmake" + CACHE FILEPATH "Relative path to cmake version file in distributed source tree") +set(GIT_VERSION_FILE_COMPAT "VERSION" + CACHE FILEPATH "Relative path to compatibility version file in distributed source tree") +set(GIT_VERSION_FILE_USE_COMPAT OFF + CACHE BOOL "Create compatibility version file in distributed source tree") +mark_as_advanced(FORCE GIT_VERSION_FILE GIT_VERSION_FILE_COMPAT GIT_VERSION_FILE_USE_COMPAT) + +# Release sanity checking +set(GIT_RELEASE_CHECK_UNCOMMITTED ON + CACHE BOOL "Check for uncommitted files in working tree") +set(GIT_RELEASE_CHECK_UNTRACKED ON + CACHE BOOL "Check for untracked files in working tree") +set(GIT_RELEASE_ENABLE OFF + CACHE BOOL "Enable to permit git-release; not enabled by default for safety") +mark_as_advanced(FORCE GIT_RELEASE_CHECK_UNCOMMITTED GIT_RELEASE_CHECK_UNTRACKED GIT_RELEASE_ENABLE) + +# Release matching +set(GIT_RELEASE_TAG_MATCH "release/${CMAKE_PROJECT_NAME}-*" + CACHE STRING "Pattern match for all release tags for use with \"git describe --match\"") +set(GIT_RELEASE_TAG_REGEX "^release/${CMAKE_PROJECT_NAME}-([0-9].*)\$" +CACHE STRING "Regular expression to extract the version number from the tag name") +mark_as_advanced(FORCE GIT_RELEASE_TAG_MATCH GIT_RELEASE_TAG_REGEX) + +# Distribution sanity checking +set(GIT_DIST_ENABLE OFF + CACHE BOOL "Enable to permit git-dist; not enabled by default for safety") +mark_as_advanced(FORCE GIT_DIST_ENABLE) +endif (NOT CMAKE_SCRIPT_MODE_FILE) + +# Split a version number into separate components +# version the version number to split +# major variable name to store the major version in +# minor variable name to store the minor version in +# patch variable name to store the patch version in +# extra variable name to store a version suffix in +function(git_release_version_split version major minor patch extra) + string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" version_valid ${version}) + if(version_valid) + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" "\\1;\\2;\\3;\\4" VERSION_MATCHES ${version}) + list(GET VERSION_MATCHES 0 version_major) + set(${major} ${version_major} PARENT_SCOPE) + list(GET VERSION_MATCHES 1 version_minor) + set(${minor} ${version_minor} PARENT_SCOPE) + list(GET VERSION_MATCHES 2 version_patch) + set(${patch} ${version_patch} PARENT_SCOPE) + list(GET VERSION_MATCHES 3 version_extra) + set(${extra} ${version_extra} PARENT_SCOPE) + else(version_valid) + message(AUTHOR_WARNING "Bad version ${version}; falling back to 0 (have you made an initial release?)") + set(${major} "0" PARENT_SCOPE) + set(${minor} "" PARENT_SCOPE) + set(${patch} "" PARENT_SCOPE) + set(${extra} "" PARENT_SCOPE) + endif(version_valid) +endfunction(git_release_version_split) + +function(git_release_version_from_file_compat git_version_file) + if(NOT EXISTS ${git_version_file}) + message(FATAL_ERROR "git version file ${git_version_file} does not exist") + endif(NOT EXISTS ${git_version_file}) + FILE(READ "${git_version_file}" VERSION_CONTENT) + STRING(REGEX REPLACE ";" "\\\\;" VERSION_CONTENT "${VERSION_CONTENT}") + STRING(REGEX REPLACE "\n" ";" VERSION_CONTENT "${VERSION_CONTENT}") + + foreach(line ${VERSION_CONTENT}) + string(REGEX MATCH "^([A-Z][a-zA-Z-]*): (.*)" line_valid ${line}) + if(line_valid) + string(REGEX REPLACE "^([A-Z][a-zA-Z-]*): (.*)" "\\1;\\2" line_matches ${line}) + list(GET line_matches 0 key) + list(GET line_matches 1 value) + + if (${key} STREQUAL "Package") + if (NOT ${CMAKE_PROJECT_NAME} STREQUAL ${value}) + message(FATAL_ERROR "Project name ${CMAKE_PROJECT_NAME} does not match name in ${git_version_file} (${value})") + endif (NOT ${CMAKE_PROJECT_NAME} STREQUAL ${value}) + set(GIT_RELEASE_PACKAGE ${value} PARENT_SCOPE) + endif(${key} STREQUAL "Package") + if (${key} STREQUAL "Version") + set(GIT_RELEASE_VERSION ${value} PARENT_SCOPE) + endif(${key} STREQUAL "Version") + if (${key} STREQUAL "Release-Date") + set(GIT_RELEASE_DATE ${value} PARENT_SCOPE) + endif(${key} STREQUAL "Release-Date") + if (${key} STREQUAL "Release-Date-Unix") + set(GIT_RELEASE_DATE_UNIX ${value} PARENT_SCOPE) + endif(${key} STREQUAL "Release-Date-Unix") + if (${key} STREQUAL "Released-By") + set(GIT_RELEASE_BY ${value} PARENT_SCOPE) + endif(${key} STREQUAL "Released-By") + if (${key} STREQUAL "Git-Tag") + set(GIT_RELEASE_TAG ${value} PARENT_SCOPE) + endif(${key} STREQUAL "Git-Tag") + endif(line_valid) + endforeach(line) +endfunction(git_release_version_from_file_compat) + +function(git_release_version_from_file git_version_file) + include("${git_version_file}") + + set(GIT_RELEASE_PACKAGE ${GIT_RELEASE_PACKAGE} PARENT_SCOPE) + set(GIT_RELEASE_VERSION ${GIT_RELEASE_VERSION} PARENT_SCOPE) + set(GIT_RELEASE_DATE ${GIT_RELEASE_DATE} PARENT_SCOPE) + set(GIT_RELEASE_DATE_UNIX ${GIT_RELEASE_DATE_UNIX} PARENT_SCOPE) + set(GIT_RELEASE_BY ${GIT_RELEASE_BY} PARENT_SCOPE) + set(GIT_RELEASE_TAG ${GIT_RELEASE_TAG} PARENT_SCOPE) +endfunction(git_release_version_from_file) + +function(git_release_version_from_git_tag git_tag tag_exists) + execute_process(COMMAND git show ${git_tag} + OUTPUT_VARIABLE tag_content RESULT_VARIABLE show_fail ERROR_QUIET + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if (tag_exists AND show_fail) + message(FATAL_ERROR "Could not obtain release tag ${git_tag} from git") + endif (tag_exists AND show_fail) + STRING(REGEX REPLACE ";" "\\\\;" tag_content "${tag_content}") + STRING(REGEX REPLACE "\n" ";" tag_content "${tag_content}") + + foreach(line ${tag_content}) + string(REGEX MATCH "^Tagger: (.*)" tagger_valid ${line}) + if (tagger_valid) + string(REGEX REPLACE "^Tagger: (.*)" "\\1" tagger ${line}) + endif (tagger_valid) + endforeach(line) + + # If tagger is undefined, set to "Unreleased". + if(NOT tagger) + set(tagger "Unreleased") + endif(NOT tagger) + set(GIT_RELEASE_BY ${tagger} PARENT_SCOPE) + + set(GIT_RELEASE_TAG ${git_tag} PARENT_SCOPE) + execute_process(COMMAND git rev-parse "${git_tag}^{}" + OUTPUT_VARIABLE commit RESULT_VARIABLE revparse_fail ERROR_QUIET + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if (revparse_fail) + message(FATAL_ERROR "Could not obtain release commit information from git") + endif (revparse_fail) + string(REPLACE "\n" "" commit "${commit}") + execute_process(COMMAND git log -1 "${commit}" --pretty=%ai + OUTPUT_VARIABLE commit_date RESULT_VARIABLE revparse_fail ERROR_QUIET + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if (revparse_fail) + message(FATAL_ERROR "Could not obtain release commit date from git") + endif (revparse_fail) + string(REPLACE "\n" "" commit_date "${commit_date}") + execute_process(COMMAND git log -1 "${commit}" --pretty=%at + OUTPUT_VARIABLE commit_date_unix RESULT_VARIABLE revparse_fail ERROR_QUIET + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if (revparse_fail) + message(FATAL_ERROR "Could not obtain release commit timestamp from git") + endif (revparse_fail) + string(REPLACE "\n" "" commit_date_unix "${commit_date_unix}") + + set(GIT_RELEASE_DATE ${commit_date} PARENT_SCOPE) + set(GIT_RELEASE_DATE_UNIX ${commit_date_unix} PARENT_SCOPE) + set(GIT_RELEASE_PACKAGE ${CMAKE_PROJECT_NAME} PARENT_SCOPE) + + string(REGEX REPLACE "${GIT_RELEASE_TAG_REGEX}" "\\1" git_release_version ${git_tag}) + set(GIT_RELEASE_VERSION ${git_release_version} PARENT_SCOPE) +endfunction(git_release_version_from_git_tag) + +function(git_release_version_from_git tag_match) + set(tag_exists TRUE) + + execute_process(COMMAND git describe --match "${tag_match}" --exact-match + OUTPUT_VARIABLE git_tag RESULT_VARIABLE git_fail ERROR_QUIET + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + string(REPLACE "\n" "" git_tag "${git_tag}") + if(git_fail) + set(tag_exists FALSE) + # This commit is not a tagged release; + execute_process(COMMAND git describe --match "${tag_match}" + OUTPUT_VARIABLE git_tag RESULT_VARIABLE git_fail2 ERROR_QUIET + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + string(REPLACE "\n" "" git_tag "${git_tag}") + if(git_fail2) + message(FATAL_ERROR "Could not obtain release information from git") + endif(git_fail2) + endif(git_fail) + + git_release_version_from_git_tag(${git_tag} ${tag_exists}) + + set(GIT_RELEASE_PACKAGE ${GIT_RELEASE_PACKAGE} PARENT_SCOPE) + set(GIT_RELEASE_VERSION ${GIT_RELEASE_VERSION} PARENT_SCOPE) + set(GIT_RELEASE_DATE ${GIT_RELEASE_DATE} PARENT_SCOPE) + set(GIT_RELEASE_DATE_UNIX ${GIT_RELEASE_DATE_UNIX} PARENT_SCOPE) + set(GIT_RELEASE_BY ${GIT_RELEASE_BY} PARENT_SCOPE) + set(GIT_RELEASE_TAG ${GIT_RELEASE_TAG} PARENT_SCOPE) +endfunction(git_release_version_from_git) + +function(git_release_version_to_file_compat git_version_file) + set(keys + "Package: ${CMAKE_PROJECT_NAME}" + "Version: ${GIT_RELEASE_VERSION}") + if (GIT_RELEASE_DATE) + set(keys ${keys} "Release-Date: ${GIT_RELEASE_DATE}") + endif (GIT_RELEASE_DATE) + if (GIT_RELEASE_DATE_UNIX) + set(keys ${keys} "Release-Date-Unix: ${GIT_RELEASE_DATE_UNIX}") + endif (GIT_RELEASE_DATE_UNIX) + if (GIT_RELEASE_BY) + set(keys ${keys} "Released-By: ${GIT_RELEASE_BY}") + endif (GIT_RELEASE_BY) + if (GIT_RELEASE_TAG) + set(keys ${keys} "Git-Tag: ${GIT_RELEASE_TAG}") + endif (GIT_RELEASE_TAG) + STRING(REGEX REPLACE ";" "\\n" keys "${keys}") + + get_filename_component(dirname ${git_version_file} PATH) + file(MAKE_DIRECTORY "${dirname}") + file(WRITE "${git_version_file}" "${keys}\n") +endfunction(git_release_version_to_file_compat) + +function(git_release_version_to_file git_version_file) + set(lines + "set(GIT_RELEASE_PACKAGE \"${CMAKE_PROJECT_NAME}\")") + set(lines ${lines} + "set(GIT_RELEASE_VERSION \"${GIT_RELEASE_VERSION}\")") + if (GIT_RELEASE_DATE) + set(lines ${lines} + "set(GIT_RELEASE_DATE \"${GIT_RELEASE_DATE}\")") + endif (GIT_RELEASE_DATE) + if (GIT_RELEASE_DATE_UNIX) + set(lines ${lines} + "set(GIT_RELEASE_DATE_UNIX \"${GIT_RELEASE_DATE_UNIX}\")") + endif (GIT_RELEASE_DATE_UNIX) + if (GIT_RELEASE_BY) + set(lines ${lines} + "set(GIT_RELEASE_BY \"${GIT_RELEASE_BY}\")") + endif (GIT_RELEASE_BY) + if (GIT_RELEASE_TAG) + set(lines ${lines} + "set(GIT_RELEASE_TAG \"${GIT_RELEASE_TAG}\")") + endif (GIT_RELEASE_TAG) + STRING(REGEX REPLACE ";" "\\n" lines "${lines}") + + get_filename_component(dirname ${git_version_file} PATH) + file(MAKE_DIRECTORY "${dirname}") + file(WRITE "${git_version_file}" "${lines}\n") +endfunction(git_release_version_to_file) + +function(git_release_version tag_match) + if(GIT_RELEASE_ENABLE OR GIT_DIST_ENABLE) + if (NOT GIT_RELEASE_VERSION) + message(FATAL_ERROR "GIT_RELEASE_VERSION not set; required if GIT_RELEASE_ENABLE or GIT_DIST_ENABLE is enabled") + endif (NOT GIT_RELEASE_VERSION) + else(GIT_RELEASE_ENABLE OR GIT_DIST_ENABLE) + if(EXISTS "${PROJECT_SOURCE_DIR}/${GIT_VERSION_FILE}") + message(STATUS "Reading release metadata from ${GIT_VERSION_FILE}") + git_release_version_from_file("${PROJECT_SOURCE_DIR}/${GIT_VERSION_FILE}") + else(EXISTS "${PROJECT_SOURCE_DIR}/${GIT_VERSION_FILE}") + if(GIT_VERSION_FILE_USE_COMPAT AND EXISTS "${PROJECT_SOURCE_DIR}/${GIT_VERSION_FILE_COMPAT}") + message(STATUS "Reading release metadata from ${GIT_VERSION_FILE_COMPAT}") + git_release_version_from_file_compat("${PROJECT_SOURCE_DIR}/${GIT_VERSION_FILE_COMPAT}") + else(GIT_VERSION_FILE_USE_COMPAT AND EXISTS "${PROJECT_SOURCE_DIR}/${GIT_VERSION_FILE_COMPAT}") + message(STATUS "Reading release metadata from git") + git_release_version_from_git("${tag_match}") + endif(GIT_VERSION_FILE_USE_COMPAT AND EXISTS "${PROJECT_SOURCE_DIR}/${GIT_VERSION_FILE_COMPAT}") + endif(EXISTS "${PROJECT_SOURCE_DIR}/${GIT_VERSION_FILE}") + endif(GIT_RELEASE_ENABLE OR GIT_DIST_ENABLE) + + git_release_version_split(${GIT_RELEASE_VERSION} major minor patch extra) + + if(NOT GIT_RELEASE_DATE) + set(GIT_RELEASE_DATE "unreleased") + endif(NOT GIT_RELEASE_DATE) + if(NOT GIT_RELEASE_DATE_UNIX) + set(GIT_RELEASE_DATE_UNIX 0) + endif(NOT GIT_RELEASE_DATE_UNIX) + + set(GIT_RELEASE_PACKAGE ${GIT_RELEASE_PACKAGE} PARENT_SCOPE) + set(GIT_RELEASE_VERSION ${GIT_RELEASE_VERSION} PARENT_SCOPE) + set(GIT_RELEASE_VERSION_MAJOR ${major} PARENT_SCOPE) + set(GIT_RELEASE_VERSION_MINOR ${minor} PARENT_SCOPE) + set(GIT_RELEASE_VERSION_PATCH ${patch} PARENT_SCOPE) + set(GIT_RELEASE_VERSION_EXTRA ${extra} PARENT_SCOPE) + set(GIT_RELEASE_DATE ${GIT_RELEASE_DATE} PARENT_SCOPE) + set(GIT_RELEASE_DATE_UNIX ${GIT_RELEASE_DATE_UNIX} PARENT_SCOPE) + set(GIT_RELEASE_BY ${GIT_RELEASE_BY} PARENT_SCOPE) + set(GIT_RELEASE_TAG ${GIT_RELEASE_TAG} PARENT_SCOPE) +endfunction(git_release_version) + +if (NOT CMAKE_SCRIPT_MODE_FILE) +# Get initial version information + git_release_version("${GIT_RELEASE_TAG_MATCH}") + +set(GIT_RELEASE_VERSION "${GIT_RELEASE_VERSION}" + CACHE STRING "Release version number") +mark_as_advanced(FORCE GIT_RELEASE_VERSION) + +# Release tagging +set(GIT_RELEASE_TAG_OPTIONS "-s" + CACHE STRING "GPG release tagging options; signing enabled by default") +set(GIT_RELEASE_TAG_NAME "release/${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION}" + CACHE STRING "Naming scheme for release tags; must include version number") +set(GIT_RELEASE_TAG_MESSAGE "Release of ${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION}" + CACHE STRING "Message for release tags") +mark_as_advanced(FORCE GIT_RELEASE_TAG_OPTIONS GIT_RELEASE_TAG_NAME GIT_RELEASE_TAG_MESSAGE) + +# Distribution tagging +set(GIT_DIST_TAG_OPTIONS "-s" + CACHE STRING "GPG distribution tagging options; signing enabled by default") +set(GIT_DIST_TAG_NAME distribution/${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION} + CACHE STRING "Naming scheme for distribution tags; must include version number") +set(GIT_DIST_TAG_MESSAGE "Distribution of ${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION}" + CACHE STRING "Message for distribution tags") +mark_as_advanced(FORCE GIT_DIST_TAG_OPTIONS GIT_DIST_TAG_NAME GIT_DIST_TAG_MESSAGE) + +# Distribution branch commit +set(GIT_DIST_BRANCH distribution/${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION_MAJOR}.${GIT_RELEASE_VERSION_MINOR} + CACHE STRING "Branch to place distributed release on") +# Message for distribution commit +set(GIT_DIST_COMMIT_MESSAGE "Distribution of ${CMAKE_PROJECT_NAME} version ${GIT_RELEASE_VERSION}" + CACHE STRING "Message for distribution commit") +# Release directory to distribute +set(GIT_DIST_NAME ${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION} + CACHE STRING "Name of the release distribution; must include version number") +set(GIT_DIST_TMPDIR ${PROJECT_BINARY_DIR}/GitRelease + CACHE STRING "Temporary staging directory for release") +set(GIT_DIST_ROOT ${GIT_DIST_TMPDIR}/${GIT_DIST_NAME} + CACHE STRING "Release directory to distribute; must include version number") +mark_as_advanced(FORCE GIT_DIST_BRANCH GIT_DIST_COMMIT_MESSAGE GIT_DIST_NAME GIT_DIST_TMPDIR GIT_DIST_ROOT) +endif (NOT CMAKE_SCRIPT_MODE_FILE) + + +function(git_check_repo) + if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git) + message(FATAL_ERROR "Source directory ${PROJECT_SOURCE_DIR} is not a git repository") + endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git) +endfunction(git_check_repo) + +# Check that the working tree and index are clean prior to making any +# changes. If dirty, then the changes may be unreproducible and not +# match what was expected. For example, the distributed files may not +# match those actually committed or may not even be under version +# control. +# +# Project customisation: +# Checking of untracked files may be disabled by setting +# GIT_RELEASE_CHECK_UNTRACKED to OFF. +function(git_check_clean) + git_check_repo() + + execute_process(COMMAND git diff-index --quiet HEAD + RESULT_VARIABLE diff_index_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if(diff_index_status GREATER 1) + message(FATAL_ERROR "Error checking git index git diff-index: error status ${diff_index_status}") + endif(diff_index_status GREATER 1) + if(diff_index_status EQUAL 1) + if (GIT_RELEASE_CHECK_UNCOMMITTED) + message(FATAL_ERROR "Uncommitted changes in source directory") + else (GIT_RELEASE_CHECK_UNCOMMITTED) + message(WARNING "Uncommitted changes in source directory") + endif (GIT_RELEASE_CHECK_UNCOMMITTED) + endif(diff_index_status EQUAL 1) + + if(diff_index_status EQUAL 0 OR diff_index_status EQUAL 1) + execute_process(COMMAND git ls-files --others --exclude-standard --error-unmatch . + OUTPUT_FILE /dev/null + ERROR_FILE /dev/null + RESULT_VARIABLE ls_files_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + # Exit status 1 is OK. + if(ls_files_status GREATER 1) + message(FATAL_ERROR "Error checking working directory with git ls-files: error status ${ls_files_status}") + endif(ls_files_status GREATER 1) + if(ls_files_status EQUAL 0) + if (GIT_RELEASE_CHECK_UNTRACKED) + message(FATAL_ERROR "Untracked files present in working directory") + else (GIT_RELEASE_CHECK_UNTRACKED) + message(WARNING "Untracked files present in working directory") + endif (GIT_RELEASE_CHECK_UNTRACKED) + endif(ls_files_status EQUAL 0) + endif(diff_index_status EQUAL 0 OR diff_index_status EQUAL 1) +endfunction(git_check_clean) + +# Make a release. +# +# The current working tree is tagged as a new release. If the release +# tag already exists then the operation will do nothing if the tag +# matches the current working tree, or else it will abort with an +# error. If the repository has been accidentally tagged previously, +# then remove the tag with "git tag -d TAG" before releasing. +# +# NOTE: Set GIT_RELEASE_ENABLE=true when running make. This is a +# safety check to avoid accidental damage to the git repository. +# +# NOTE: Running release-git independently of dist-git is NOT +# RECOMMENDED. The distdir rule can update files in the working tree +# (for example, gettext translations in po/), so running "make +# distdir" prior to tagging the release will ensure the tagged release +# will not differ from the distributed release. +# +# Project customisation: +# The tag will be signed by default; set GIT_RELEASE_TAG_OPTIONS to +# alter. The tag will be named using GIT_RELEASE_TAG_NAME with the +# GIT_RELEASE_TAG_MESSAGE specifying an appropriate message for the +# tag. +function(git_release fail_if_tag_exists) + # Check if release tag exists + execute_process(COMMAND git show-ref --tags -q ${GIT_RELEASE_TAG_NAME} + RESULT_VARIABLE show_ref_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if (show_ref_status EQUAL 0) + # Release tag already exists + if(fail_if_tag_exists) + message(FATAL_ERROR "git release tag ${GIT_RELEASE_TAG_NAME} already exists; not releasing") + else(fail_if_tag_exists) + message(STATUS "git release tag ${GIT_RELEASE_TAG_NAME} found") + endif(fail_if_tag_exists) + else(show_ref_status EQUAL 0) + # Release tag does not exist + if (NOT GIT_RELEASE_ENABLE) + message(FATAL_ERROR "GIT_RELEASE_ENABLE not set; not releasing") + endif (NOT GIT_RELEASE_ENABLE) + + # Check repository is clean to tag + git_check_clean() + + # Create release tag + message("Releasing ${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION}") + message("Creating git release tag ${GIT_RELEASE_TAG_NAME}") + execute_process(COMMAND git tag -m "${GIT_RELEASE_TAG_MESSAGE}" + ${GIT_RELEASE_TAG_OPTIONS} "${GIT_RELEASE_TAG_NAME}" + HEAD + RESULT_VARIABLE tag_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if(tag_status GREATER 0) + message(FATAL_ERROR "Failed to create release tag ${GIT_RELEASE_TAG_NAME}: error status ${tag_status}") + endif(tag_status GREATER 0) + + message(STATUS "${CMAKE_PROJECT_NAME} ${GIT_RELEASE_VERSION} release tagged as ${GIT_RELEASE_TAG_NAME}") + endif (show_ref_status EQUAL 0) + +endfunction(git_release) + +# Make a distribution of a release. +# +# A distribution is created and committed onto the specified branch. +# The commit is then tagged. The distribution commit will have the +# release commit and the previous distribution (if any) as its +# parents. Thus distribution releases appear to git as merges (with +# the exception of the initial release). +# +# NOTE: Set GIT_DIST_ENABLE=true when running make, plus +# GIT_RELEASE_ENABLE=true if the working tree has not already been +# tagged with a release tag. This is a safety check to avoid +# accidental damage to the git repository. +# +# Project customisation: +# GIT_DIST_COMMIT_MESSAGE specifies the commit message for the commit, +# and GIT_DIST_BRANCH specifies the branch to add the commit to. +# The tag will be signed by default; set GIT_DIST_TAG_OPTIONS to +# alter. The tag will be named using GIT_DIST_TAG_NAME with the +# GIT_DIST_TAG_MESSAGE specifying an appropriate message for the +# tag. +function(git_rev_parse ref var) + execute_process(COMMAND git rev-parse ${ref} + OUTPUT_VARIABLE rev_parse_output + RESULT_VARIABLE rev_parse_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if(rev_parse_status GREATER 0) + message(FATAL_ERROR "git rev-parse failed to parse ref ${ref}") + endif(rev_parse_status GREATER 0) + string(REPLACE "\n" "" rev_parse_output "${rev_parse_output}") + set(${var} ${rev_parse_output} PARENT_SCOPE) +endfunction(git_rev_parse) + +function(git_archive_tree) + # TODO: Add full export. + file(REMOVE_RECURSE "${GIT_DIST_TMPDIR}") + file(MAKE_DIRECTORY "${GIT_DIST_TMPDIR}") + execute_process(COMMAND git archive --prefix "${GIT_DIST_NAME}/" + -o "${GIT_DIST_TMPDIR}/tmp.tar" "${GIT_RELEASE_TAG_NAME}" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + execute_process(COMMAND tar -xf tmp.tar + WORKING_DIRECTORY "${GIT_DIST_TMPDIR}") + file(REMOVE "${GIT_DIST_TMPDIR}/tmp.tar") +endfunction(git_archive_tree) + +function(git_dist) + git_release(OFF) + + git_rev_parse("${GIT_RELEASE_TAG_NAME}^{}" release_commit) + git_rev_parse(HEAD head_commit) + + if(NOT ${release_commit} STREQUAL ${head_commit}) + message(FATAL_ERROR "Working directory is not at release tag ${GIT_RELEASE_TAG_NAME}^{} (commit ${release_commit}); not distributing") + endif(NOT ${release_commit} STREQUAL ${head_commit}) + + git_check_clean() + + git_archive_tree() + + git_release_version_from_git_tag("${GIT_RELEASE_TAG_NAME}" TRUE) + + git_release_version_to_file("${GIT_DIST_ROOT}/${GIT_VERSION_FILE}") + if(GIT_VERSION_FILE_USE_COMPAT) + git_release_version_to_file_compat("${GIT_DIST_ROOT}/${GIT_VERSION_FILE_COMPAT}") + endif(GIT_VERSION_FILE_USE_COMPAT) + + git_dist_generic() +endfunction(git_dist) + +# Make a distribution of an arbitrary release. +# +# The same as git_dist, but this allows addition of any distribution +# rather than just the release in the current working tree. This rule +# is intended for allowing retrospective addition of a project's +# entire release history (driven by a shell script), for example. +# See below for an example of how to do this. +# +# GIT_DIST_ROOT must be set to specify the release to distribute and +# GIT_RELEASE_VERSION must match the release version. GIT_DIST_BRANCH may also +# require setting if not using the default. GIT_RELEASE_TAG_NAME must +# be set to the tag name of the existing release. +function(git_dist_generic) + git_check_repo() + + execute_process(COMMAND git show-ref --tags -q ${GIT_DIST_TAG_NAME} + RESULT_VARIABLE show_ref_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if (show_ref_status EQUAL 0) + message(FATAL_ERROR "git dist tag ${GIT_DIST_TAG_NAME} already exists; not distributing") + endif (show_ref_status EQUAL 0) + + if (NOT GIT_DIST_ENABLE) + message(FATAL_ERROR "GIT_DIST_ENABLE not set; not distributing") + endif (NOT GIT_DIST_ENABLE) + + message("Distributing ${CMAKE_PROJECT_NAME}-${GIT_RELEASE_VERSION} on git branch ${GIT_DIST_BRANCH}") + set(dist_index "${GIT_DIST_TMPDIR}/index") + if(EXISTS ${dist_index}) + file(REMOVE ${dist_index}) + endif(EXISTS ${dist_index}) + + set(ENV{GIT_INDEX_FILE} ${dist_index}) + set(ENV{GIT_WORK_TREE} ${GIT_DIST_ROOT}) + execute_process(COMMAND git add -A + RESULT_VARIABLE git_add_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + unset(ENV{GIT_WORK_TREE}) + if(git_add_status GREATER 0) + message(FATAL_ERROR "Failed to add archive tree to git index") + endif(git_add_status GREATER 0) + + execute_process(COMMAND git write-tree + OUTPUT_VARIABLE tree + RESULT_VARIABLE git_write_tree_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + string(REPLACE "\n" "" tree "${tree}") + if(git_tree_write_status GREATER 0) + message(FATAL_ERROR "Failed to write git index to tree") + endif(git_tree_write_status GREATER 0) + + unset(ENV{GIT_INDEX_FILE}) + + file(REMOVE ${dist_index}) + + string(LENGTH ${tree} tree_length) + if (tree_length EQUAL 0) + message(FATAL_ERROR "Failed to get tree hash") + endif (tree_length EQUAL 0) + + git_rev_parse("${GIT_RELEASE_TAG_NAME}^{}" release_commit) + + set(commit_options -p ${release_commit}) + + execute_process(COMMAND git show-ref --heads -s refs/heads/${GIT_DIST_BRANCH} + OUTPUT_VARIABLE dist_parent + RESULT_VARIABLE show_ref_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + string(REPLACE "\n" "" dist_parent "${dist_parent}") + if (show_ref_status GREATER 0) + set(newroot "(root-commit) ") + else (show_ref_status GREATER 0) + set(commit_opts ${commit_opts} -p ${dist_parent}) + endif (show_ref_status GREATER 0) + + file(WRITE "${GIT_DIST_TMPDIR}/commit-message" "${GIT_DIST_COMMIT_MESSAGE}") + execute_process(COMMAND git commit-tree -F "${GIT_DIST_TMPDIR}/commit-message" "${tree}" ${commit_options} + OUTPUT_VARIABLE commit + RESULT_VARIABLE commit_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + file(REMOVE "${GIT_DIST_TMPDIR}/commit-message") + string(REPLACE "\n" "" commit "${commit}") + if (commit_status GREATER 0) + message(FATAL_ERROR "Failed to commit tree") + endif (commit_status GREATER 0) + + string(LENGTH ${commit} commit_length) + if(${commit_length} EQUAL 0) + message(FATAL_ERROR "Failed to get commit hash") + endif(${commit_length} EQUAL 0) + + execute_process(COMMAND git update-ref "refs/heads/${GIT_DIST_BRANCH}" ${commit} ${dist_parent} + RESULT_VARIABLE update_ref_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if (update_ref_status GREATER 0) + message(FATAL_ERROR "Failed to update reference for commit") + endif (update_ref_status GREATER 0) + + message("[${GIT_DIST_BRANCH} ${newroot}${commit}] ${GIT_DIST_COMMIT_MESSAGE}") + + message("Creating git distribution tag ${GIT_DIST_TAG_NAME}") + execute_process(COMMAND git tag -m "${GIT_DIST_TAG_MESSAGE}" ${GIT_DIST_TAG_OPTIONS} "${GIT_DIST_TAG_NAME}" ${commit} + RESULT_VARIABLE tag_status + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + if(tag_status GREATER 0) + message(FATAL_ERROR "Failed to create distribution tag ${GIT_DIST_TAG_NAME}: error status ${tag_status}") + endif(tag_status GREATER 0) + + message(STATUS "${CMAKE_PROJECT_NAME} ${GIT_RELEASE_VERSION} distribution tagged as ${GIT_DIST_TAG_NAME}") +endfunction(git_dist_generic) + +# Add targets if not in script mode +if (NOT CMAKE_SCRIPT_MODE_FILE) + + set(script_options + -D CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME} + -D PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -D PROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}) + + if (GIT_RELEASE_ENABLE OR GIT_DIST_ENABLE) + # Preserve current configuration in a form which may be sourced by + # a standalone script file. + file(WRITE "${GIT_RELEASE_SETTINGS}" +"set(GIT_VERSION_FILE \"${GIT_VERSION_FILE}\") +set(GIT_VERSION_FILE_COMPAT \"${GIT_VERSION_FILE_COMPAT}\") +set(GIT_VERSION_FILE_USE_COMPAT \"${GIT_VERSION_FILE_USE_COMPAT}\") +set(GIT_RELEASE_VERSION \"${GIT_RELEASE_VERSION}\") +set(GIT_RELEASE_CHECK_UNCOMMITTED ${GIT_RELEASE_CHECK_UNCOMMITTED}) +set(GIT_RELEASE_CHECK_UNTRACKED ${GIT_RELEASE_CHECK_UNTRACKED}) +set(GIT_RELEASE_ENABLE ${GIT_RELEASE_ENABLE}) +set(GIT_RELEASE_TAG_OPTIONS \"${GIT_RELEASE_TAG_OPTIONS}\") +set(GIT_RELEASE_TAG_NAME \"${GIT_RELEASE_TAG_NAME}\") +set(GIT_RELEASE_TAG_MATCH \"${GIT_RELEASE_TAG_MATCH}\") +set(GIT_RELEASE_TAG_REGEX \"${GIT_RELEASE_TAG_REGEX}\") +set(GIT_RELEASE_TAG_MESSAGE \"${GIT_RELEASE_TAG_MESSAGE}\") +set(GIT_DIST_ENABLE ${GIT_DIST_ENABLE}) +set(GIT_DIST_TAG_OPTIONS \"${GIT_DIST_TAG_OPTIONS}\") +set(GIT_DIST_TAG_NAME \"${GIT_DIST_TAG_NAME}\") +set(GIT_DIST_TAG_MESSAGE \"${GIT_DIST_TAG_MESSAGE}\") +set(GIT_DIST_BRANCH \"${GIT_DIST_BRANCH}\") +set(GIT_DIST_COMMIT_MESSAGE \"${GIT_DIST_COMMIT_MESSAGE}\") +set(GIT_DIST_NAME \"${GIT_DIST_NAME}\") +set(GIT_DIST_TMPDIR \"${GIT_DIST_TMPDIR}\") +set(GIT_DIST_ROOT \"${GIT_DIST_ROOT}\") +") + + # The following targets re-execute this script file with the above + # configuration. + + add_custom_target(git-check-repo + COMMAND ${CMAKE_COMMAND} ${script_options} + -D git_release_command=git-check-repo + -P ${CMAKE_CURRENT_LIST_FILE}) + endif (GIT_RELEASE_ENABLE OR GIT_DIST_ENABLE) + + if (GIT_RELEASE_ENABLE) + add_custom_target(git-check-clean + COMMAND ${CMAKE_COMMAND} ${script_options} + -D PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -D git_release_command=git-check-clean + -P ${CMAKE_CURRENT_LIST_FILE}) + + add_custom_target(git-release + COMMAND ${CMAKE_COMMAND} ${script_options} + -D PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -D git_release_command=git-release + -P ${CMAKE_CURRENT_LIST_FILE}) + endif (GIT_RELEASE_ENABLE) + + if (GIT_DIST_ENABLE) + add_custom_target(git-dist + COMMAND ${CMAKE_COMMAND} ${script_options} + -D PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -D git_release_command=git-dist + -P ${CMAKE_CURRENT_LIST_FILE}) + endif (GIT_DIST_ENABLE) +endif (NOT CMAKE_SCRIPT_MODE_FILE) + +# In script mode, run specified command +if (CMAKE_SCRIPT_MODE_FILE) + if(git_release_command) + if(git_release_command STREQUAL git-check-repo) + git_check_repo() + endif(git_release_command STREQUAL git-check-repo) + + if(git_release_command STREQUAL git-check-clean) + git_check_clean() + endif(git_release_command STREQUAL git-check-clean) + + if(git_release_command STREQUAL git-release) + git_release(ON) + endif(git_release_command STREQUAL git-release) + + if(git_release_command STREQUAL git-dist) + git_dist() + endif(git_release_command STREQUAL git-dist) + endif(git_release_command) +endif (CMAKE_SCRIPT_MODE_FILE) + +# Example: How to retrospectively insert the complete distribution +# history for a project. Note: GIT_RELEASE_TAG_NAME must match the +# pattern used to tag all previous releases since this requires tags +# for all releases. +# +# #!/bin/sh +# +# set -e +# +# # Clean up any existing distribution branches and tags which could +# # interfere with addition of a complete clean distribution history. +# git tag -l | grep distribution | while read tag; do +# git tag -d $tag +# done; +# git branch -l | grep distribution | while read branch; do +# git branch -D $branch +# done; +# +# # Read an ordered list of versions from release-versions and get +# # distribution for each version from the given path and distribute +# # in git +# while read version; do +# make git_dist_generic GIT_DIST_ROOT="/path/to/unpacked/releases/$package-$version" GIT_RELEASE_VERSION="$version" GIT_DIST_ENABLE=true +# done < release-versions + +# Example: How to check that the added distributions are correctly +# representing the content of the old distributed releases following +# import as in the above example. +# +# #!/bin/sh +# +# set -e +# +# # For each version in the list of releases, check out and unpack +# # that version, and then compare it with the original. +# while read version; do +# git checkout distribution/package-$version +# rm -rf /tmp/package-$version +# mkdir /tmp/package-$version +# git archive HEAD | tar -x -C /tmp/$package-$version +# diff -urN /tmp/$package-$version "/path/to/unpacked/releases/$package-$version" | lsdiff +# rm -rf /tmp/package-$version +# done < release-versions diff --git a/cmake/boost-checks.cmake b/cmake/boost-checks.cmake new file mode 100644 index 00000000..ccb33e23 --- /dev/null +++ b/cmake/boost-checks.cmake @@ -0,0 +1,87 @@ +include(CheckIncludeFileCXX) +include(CheckCXXSourceCompiles) + +check_include_file_cxx (boost/format.hpp HAVE_BOOST_FORMAT_HPP) +# boost/iostreams/device/file_descriptor.hpp +check_include_file_cxx (boost/iostreams/device/file_descriptor.hpp HAVE_BOOST_IOSTREAMS_DEVICE_FILE_DESCRIPTOR_HPP) +# boost/program_options.hpp +check_include_file_cxx (boost/program_options.hpp HAVE_BOOST_PROGRAM_OPTIONS_HPP) +# boost/type_traits.hpp +check_include_file_cxx (boost/type_traits.hpp HAVE_BOOST_TYPE_TRAITS_HPP) + +# Boost library checks could be dropped? +# boost::program_options::variables_map in -lboost_program_options +# + BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD (drop?) +SET(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES}) +SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE}) + +check_cxx_source_compiles( +"#include <boost/program_options.hpp> + +int main() { + boost::program_options::variables_map dummy(); +}" +BOOST_PROGRAM_OPTIONS_LINK) +# boost::program_options::validation_error in -lboost_program_options +# + BOOST_PROGRAM_OPTIONS_VALIDATION_ERROR_OLD (drop?) + +check_cxx_source_compiles( +"#include <boost/program_options.hpp> + +int main() { + boost::program_options::validation_error + err(boost::program_options::validation_error::invalid_option, \"error\"); +}" +BOOST_PROGRAM_OPTIONS_DESCRIPTION_CURRENT_LINK) + +SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_SAVE}) + +set(BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD 0) +if (BOOST_PROGRAM_OPTIONS AND NOT BOOST_PROGRAM_OPTIONS_DESCRIPTION_CURRENT) + set(BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD 1) +endif(BOOST_PROGRAM_OPTIONS AND NOT BOOST_PROGRAM_OPTIONS_DESCRIPTION_CURRENT) + +SET(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES}) +SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${Boost_IOSTREAMS_LIBRARY_RELEASE}) +# <regex> tests; boost/regex.hpp fallback ==> HAVE_REGEX +# boost::iostreams in -lboost_iostreams +check_cxx_source_compiles( +"#include <boost/iostreams/device/file_descriptor.hpp> +#include <boost/iostreams/stream.hpp> + +int main() { + boost::iostreams::stream<boost::iostreams::file_descriptor> fdstream; +}" +BOOST_IOSTREAMS_LINK) +# boost::iostreams::file_descriptor_source in -lboost_iostreams +# + BOOST_IOSTREAMS_CLOSE_HANDLE_OLD + +check_cxx_source_compiles( +"#include <boost/iostreams/device/file_descriptor.hpp> +#include <boost/iostreams/stream.hpp> +#include <unistd.h> + +int main() { +boost::iostreams::file_descriptor_sink dummy(STDOUT_FILENO, boost::iostreams::close_handle); +}" +BOOST_IOSTREAMS_CLOSE_HANDLE_CURRENT_LINK) + +SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_SAVE}) + +set(BOOST_IOSTREAMS_CLOSE_HANDLE_OLD 0) +if (BOOST_IOSTREAMS AND NOT BOOST_IOSTREAMS_CLOSE_HANDLE_CURRENT) + set(BOOST_IOSTREAMS_CLOSE_HANDLE_OLD 1) +endif(BOOST_IOSTREAMS AND NOT BOOST_IOSTREAMS_CLOSE_HANDLE_CURRENT) + + +SET(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES}) +SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${Boost_FILESYSTEM_LIBRARY_RELEASE} ${Boost_SYSTEM_LIBRARY_RELEASE}) +# boost::filesystem in -lboost_filesystem +check_cxx_source_compiles( +"#include <boost/filesystem.hpp> + +int main() { + boost::filesystem::is_directory(\"/\"); +}" +BOOST_FILESYSTEM_LINK) +SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_SAVE}) diff --git a/cmake/regex-checks.cmake b/cmake/regex-checks.cmake new file mode 100644 index 00000000..366240b4 --- /dev/null +++ b/cmake/regex-checks.cmake @@ -0,0 +1,61 @@ +include(CheckCXXSourceRuns) +#regex +check_cxx_source_runs( +"#include <regex> + +int main() { + std::regex foo(\"^foo[bar]\$\"); + std::regex bar(\"^foo[bar]\$\", std::regex::extended); + std::regex check(\"^[^:/,.][^:/,]*\$\", std::regex::extended); +}" +STD_REGEX) + +# regex broken +check_cxx_source_runs( +"#include <regex> + +int main() { + std::regex foo(\"^foo[bar]\$\"); + std::regex bar(\"^foo[bar]\$\", std::regex::extended); +}" +STD_REGEX_BROKEN) + +# tr1 regex +check_cxx_source_runs( +"#include <tr1/regex> + +int main() { + std::tr1::regex foo(\"^foo[bar]\$\"); + std::tr1::regex bar(\"^foo[bar]\$\", std::tr1::regex::extended); + std::tr1::regex check(\"^[^:/,.][^:/,]*\$\", std::tr1::regex::extended); +}" +TR1_REGEX) + +# tr1 regex broken +check_cxx_source_runs( +"#include <tr1/regex> + +int main() { + std::tr1::regex foo(\"^foo[bar]\$\"); + std::tr1::regex bar(\"^foo[bar]\$\", std::tr1::regex::extended); +}" +TR1_REGEX_BROKEN) + +# boost regex +SET(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES}) +SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${Boost_REGEX_LIBRARY_RELEASE}) +check_cxx_source_runs( +"#include <boost/regex.hpp> + +int main() { + boost::regex(\"^foo[bar]\$\"); + boost::regex bar(\"^foo[bar]\$\", boost::regex::extended); +}" +BOOST_REGEX) +SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_SAVE}) + +if(NOT STD_REGEX OR NOT STD_REGEX_BROKEN) + if(NOT TR1_REGEX OR NOT TR1_REGEX_BROKEN) + set(REGEX_LIBRARY ${Boost_REGEX_LIBRARY_RELEASE}) + endif(NOT TR1_REGEX OR NOT TR1_REGEX_BROKEN) +endif(NOT STD_REGEX OR NOT STD_REGEX_BROKEN) |