1## Utility CMake functions.
2
3# ----------------------------------------------------------------------------
4## Convert boolean value to 0 or 1
5macro (bool_to_int VAR)
6  if (${VAR})
7    set (${VAR} 1)
8  else ()
9    set (${VAR} 0)
10  endif ()
11endmacro ()
12
13# ----------------------------------------------------------------------------
14## Extract version numbers from version string
15function (version_numbers version major minor patch)
16  if (version MATCHES "([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?(rc[1-9][0-9]*|[a-z]+)?")
17    if (CMAKE_MATCH_1)
18      set (_major ${CMAKE_MATCH_1})
19    else ()
20      set (_major 0)
21    endif ()
22    if (CMAKE_MATCH_2)
23      set (_minor ${CMAKE_MATCH_2})
24      string (REGEX REPLACE "^\\." "" _minor "${_minor}")
25    else ()
26      set (_minor 0)
27    endif ()
28    if (CMAKE_MATCH_3)
29      set (_patch ${CMAKE_MATCH_3})
30      string (REGEX REPLACE "^\\." "" _patch "${_patch}")
31    else ()
32      set (_patch 0)
33    endif ()
34  else ()
35    set (_major 0)
36    set (_minor 0)
37    set (_patch 0)
38  endif ()
39  set ("${major}" "${_major}" PARENT_SCOPE)
40  set ("${minor}" "${_minor}" PARENT_SCOPE)
41  set ("${patch}" "${_patch}" PARENT_SCOPE)
42endfunction ()
43
44# ----------------------------------------------------------------------------
45## Determine if cache entry exists
46macro (gflags_is_cached retvar varname)
47  if (DEFINED ${varname})
48    get_property (${retvar} CACHE ${varname} PROPERTY TYPE SET)
49  else ()
50    set (${retvar} FALSE)
51  endif ()
52endmacro ()
53
54# ----------------------------------------------------------------------------
55## Add gflags configuration variable
56#
57# The default value of the (cached) configuration value can be overridden either
58# on the CMake command-line or the super-project by setting the GFLAGS_<varname>
59# variable. When gflags is a subproject of another project (GFLAGS_IS_SUBPROJECT),
60# the variable is not added to the CMake cache. Otherwise it is cached.
61macro (gflags_define type varname docstring default)
62  # note that ARGC must be expanded here, as it is not a "real" variable
63  # (see the CMake documentation for the macro command)
64  if ("${ARGC}" GREATER 5)
65    message (FATAL_ERROR "gflags_variable: Too many macro arguments")
66  endif ()
67  if (NOT DEFINED GFLAGS_${varname})
68    if (GFLAGS_IS_SUBPROJECT AND "${ARGC}" EQUAL 5)
69      set (GFLAGS_${varname} "${ARGV4}")
70    else ()
71      set (GFLAGS_${varname} "${default}")
72    endif ()
73  endif ()
74  if (GFLAGS_IS_SUBPROJECT)
75    if (NOT DEFINED ${varname})
76      set (${varname} "${GFLAGS_${varname}}")
77    endif ()
78  else ()
79    set (${varname} "${GFLAGS_${varname}}" CACHE ${type} "${docstring}")
80  endif ()
81endmacro ()
82
83# ----------------------------------------------------------------------------
84## Set property of cached gflags configuration variable
85macro (gflags_property varname property value)
86  gflags_is_cached (_cached ${varname})
87  if (_cached)
88    # note that property must be expanded here, as it is not a "real" variable
89    # (see the CMake documentation for the macro command)
90    if ("${property}" STREQUAL "ADVANCED")
91      if (${value})
92        mark_as_advanced (FORCE ${varname})
93      else ()
94        mark_as_advanced (CLEAR ${varname})
95      endif ()
96    else ()
97      set_property (CACHE ${varname} PROPERTY "${property}" "${value}")
98    endif ()
99  endif ()
100  unset (_cached)
101endmacro ()
102
103# ----------------------------------------------------------------------------
104## Modify value of gflags configuration variable
105macro (gflags_set varname value)
106  gflags_is_cached (_cached ${varname})
107  if (_cached)
108    set_property (CACHE ${varname} PROPERTY VALUE "${value}")
109  else ()
110    set (${varname} "${value}")
111  endif ()
112  unset (_cached)
113endmacro ()
114
115# ----------------------------------------------------------------------------
116## Configure public header files
117function (configure_headers out)
118  set (tmp)
119  foreach (src IN LISTS ARGN)
120    if (IS_ABSOLUTE "${src}")
121      list (APPEND tmp "${src}")
122    elseif (EXISTS "${PROJECT_SOURCE_DIR}/src/${src}.in")
123      configure_file ("${PROJECT_SOURCE_DIR}/src/${src}.in" "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}" @ONLY)
124      list (APPEND tmp "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}")
125    else ()
126	    configure_file ("${PROJECT_SOURCE_DIR}/src/${src}" "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}" COPYONLY)
127      list (APPEND tmp "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}")
128    endif ()
129  endforeach ()
130  set (${out} "${tmp}" PARENT_SCOPE)
131endfunction ()
132
133# ----------------------------------------------------------------------------
134## Configure source files with .in suffix
135function (configure_sources out)
136  set (tmp)
137  foreach (src IN LISTS ARGN)
138    if (src MATCHES ".h$" AND EXISTS "${PROJECT_SOURCE_DIR}/src/${src}.in")
139      configure_file ("${PROJECT_SOURCE_DIR}/src/${src}.in" "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}" @ONLY)
140      list (APPEND tmp "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}")
141    else ()
142      list (APPEND tmp "${PROJECT_SOURCE_DIR}/src/${src}")
143    endif ()
144  endforeach ()
145  set (${out} "${tmp}" PARENT_SCOPE)
146endfunction ()
147
148# ----------------------------------------------------------------------------
149## Add usage test
150#
151# Using PASS_REGULAR_EXPRESSION and FAIL_REGULAR_EXPRESSION would
152# do as well, but CMake/CTest does not allow us to specify an
153# expected exit status. Moreover, the execute_test.cmake script
154# sets environment variables needed by the --fromenv/--tryfromenv tests.
155macro (add_gflags_test name expected_rc expected_output unexpected_output cmd)
156  set (args "--test_tmpdir=${PROJECT_BINARY_DIR}/Testing/Temporary"
157            "--srcdir=${PROJECT_SOURCE_DIR}/test")
158  add_test (
159    NAME    ${name}
160    COMMAND "${CMAKE_COMMAND}" "-DCOMMAND:STRING=$<TARGET_FILE:${cmd}>;${args};${ARGN}"
161                               "-DEXPECTED_RC:STRING=${expected_rc}"
162                               "-DEXPECTED_OUTPUT:STRING=${expected_output}"
163                               "-DUNEXPECTED_OUTPUT:STRING=${unexpected_output}"
164                               -P "${PROJECT_SOURCE_DIR}/cmake/execute_test.cmake"
165    WORKING_DIRECTORY "${GFLAGS_FLAGFILES_DIR}"
166  )
167endmacro ()
168
169# ------------------------------------------------------------------------------
170## Register installed package with CMake
171#
172# This function adds an entry to the CMake registry for packages with the
173# path of the directory where the package configuration file of the installed
174# package is located in order to help CMake find the package in a custom
175# installation prefix. This differs from CMake's export(PACKAGE) command
176# which registers the build directory instead.
177function (register_gflags_package CONFIG_DIR)
178  if (NOT IS_ABSOLUTE "${CONFIG_DIR}")
179    set (CONFIG_DIR "${CMAKE_INSTALL_PREFIX}/${CONFIG_DIR}")
180  endif ()
181  string (MD5 REGISTRY_ENTRY "${CONFIG_DIR}")
182  if (WIN32)
183    install (CODE
184      "execute_process (
185         COMMAND reg add \"HKCU\\\\Software\\\\Kitware\\\\CMake\\\\Packages\\\\${PACKAGE_NAME}\" /v \"${REGISTRY_ENTRY}\" /d \"${CONFIG_DIR}\" /t REG_SZ /f
186         RESULT_VARIABLE RT
187         ERROR_VARIABLE  ERR
188         OUTPUT_QUIET
189       )
190       if (RT EQUAL 0)
191         message (STATUS \"Register:   Added HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMake\\\\Packages\\\\${PACKAGE_NAME}\\\\${REGISTRY_ENTRY}\")
192       else ()
193         string (STRIP \"\${ERR}\" ERR)
194         message (STATUS \"Register:   Failed to add registry entry: \${ERR}\")
195       endif ()"
196    )
197  elseif (IS_DIRECTORY "$ENV{HOME}")
198    file (WRITE "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-registry-entry" "${CONFIG_DIR}")
199    install (
200      FILES       "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-registry-entry"
201      DESTINATION "$ENV{HOME}/.cmake/packages/${PACKAGE_NAME}"
202      RENAME      "${REGISTRY_ENTRY}"
203    )
204  endif ()
205endfunction ()
206