1# Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2# file Copyright.txt or https://cmake.org/licensing for details. 3 4#[=======================================================================[.rst: 5CMakePackageConfigHelpers 6------------------------- 7 8Helpers functions for creating config files that can be included by other 9projects to find and use a package. 10 11Adds the :command:`configure_package_config_file()` and 12:command:`write_basic_package_version_file()` commands. 13 14Generating a Package Configuration File 15^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 16 17.. command:: configure_package_config_file 18 19 Create a config file for a project:: 20 21 configure_package_config_file(<input> <output> 22 INSTALL_DESTINATION <path> 23 [PATH_VARS <var1> <var2> ... <varN>] 24 [NO_SET_AND_CHECK_MACRO] 25 [NO_CHECK_REQUIRED_COMPONENTS_MACRO] 26 [INSTALL_PREFIX <path>] 27 ) 28 29``configure_package_config_file()`` should be used instead of the plain 30:command:`configure_file()` command when creating the ``<PackageName>Config.cmake`` 31or ``<PackageName>-config.cmake`` file for installing a project or library. 32It helps making the resulting package relocatable by avoiding hardcoded paths 33in the installed ``Config.cmake`` file. 34 35In a ``FooConfig.cmake`` file there may be code like this to make the install 36destinations know to the using project: 37 38.. code-block:: cmake 39 40 set(FOO_INCLUDE_DIR "@CMAKE_INSTALL_FULL_INCLUDEDIR@" ) 41 set(FOO_DATA_DIR "@CMAKE_INSTALL_PREFIX@/@RELATIVE_DATA_INSTALL_DIR@" ) 42 set(FOO_ICONS_DIR "@CMAKE_INSTALL_PREFIX@/share/icons" ) 43 #...logic to determine installedPrefix from the own location... 44 set(FOO_CONFIG_DIR "${installedPrefix}/@CONFIG_INSTALL_DIR@" ) 45 46All 4 options shown above are not sufficient, since the first 3 hardcode the 47absolute directory locations, and the 4th case works only if the logic to 48determine the ``installedPrefix`` is correct, and if ``CONFIG_INSTALL_DIR`` 49contains a relative path, which in general cannot be guaranteed. This has the 50effect that the resulting ``FooConfig.cmake`` file would work poorly under 51Windows and OSX, where users are used to choose the install location of a 52binary package at install time, independent from how 53:variable:`CMAKE_INSTALL_PREFIX` was set at build/cmake time. 54 55Using ``configure_package_config_file`` helps. If used correctly, it makes 56the resulting ``FooConfig.cmake`` file relocatable. Usage: 57 581. write a ``FooConfig.cmake.in`` file as you are used to 592. insert a line containing only the string ``@PACKAGE_INIT@`` 603. instead of ``set(FOO_DIR "@SOME_INSTALL_DIR@")``, use 61 ``set(FOO_DIR "@PACKAGE_SOME_INSTALL_DIR@")`` (this must be after the 62 ``@PACKAGE_INIT@`` line) 634. instead of using the normal :command:`configure_file()`, use 64 ``configure_package_config_file()`` 65 66 67 68The ``<input>`` and ``<output>`` arguments are the input and output file, the 69same way as in :command:`configure_file()`. 70 71The ``<path>`` given to ``INSTALL_DESTINATION`` must be the destination where 72the ``FooConfig.cmake`` file will be installed to. This path can either be 73absolute, or relative to the ``INSTALL_PREFIX`` path. 74 75The variables ``<var1>`` to ``<varN>`` given as ``PATH_VARS`` are the 76variables which contain install destinations. For each of them the macro will 77create a helper variable ``PACKAGE_<var...>``. These helper variables must be 78used in the ``FooConfig.cmake.in`` file for setting the installed location. 79They are calculated by ``configure_package_config_file`` so that they are 80always relative to the installed location of the package. This works both for 81relative and also for absolute locations. For absolute locations it works 82only if the absolute location is a subdirectory of ``INSTALL_PREFIX``. 83 84.. versionadded:: 3.1 85 If the ``INSTALL_PREFIX`` argument is passed, this is used as base path to 86 calculate all the relative paths. The ``<path>`` argument must be an absolute 87 path. If this argument is not passed, the :variable:`CMAKE_INSTALL_PREFIX` 88 variable will be used instead. The default value is good when generating a 89 FooConfig.cmake file to use your package from the install tree. When 90 generating a FooConfig.cmake file to use your package from the build tree this 91 option should be used. 92 93By default ``configure_package_config_file`` also generates two helper macros, 94``set_and_check()`` and ``check_required_components()`` into the 95``FooConfig.cmake`` file. 96 97``set_and_check()`` should be used instead of the normal ``set()`` command for 98setting directories and file locations. Additionally to setting the variable 99it also checks that the referenced file or directory actually exists and fails 100with a ``FATAL_ERROR`` otherwise. This makes sure that the created 101``FooConfig.cmake`` file does not contain wrong references. 102When using the ``NO_SET_AND_CHECK_MACRO``, this macro is not generated 103into the ``FooConfig.cmake`` file. 104 105``check_required_components(<PackageName>)`` should be called at the end of 106the ``FooConfig.cmake`` file. This macro checks whether all requested, 107non-optional components have been found, and if this is not the case, sets 108the ``Foo_FOUND`` variable to ``FALSE``, so that the package is considered to 109be not found. It does that by testing the ``Foo_<Component>_FOUND`` 110variables for all requested required components. This macro should be 111called even if the package doesn't provide any components to make sure 112users are not specifying components erroneously. When using the 113``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` option, this macro is not generated 114into the ``FooConfig.cmake`` file. 115 116For an example see below the documentation for 117:command:`write_basic_package_version_file()`. 118 119Generating a Package Version File 120^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 121 122.. command:: write_basic_package_version_file 123 124 Create a version file for a project:: 125 126 write_basic_package_version_file(<filename> 127 [VERSION <major.minor.patch>] 128 COMPATIBILITY <AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion> 129 [ARCH_INDEPENDENT] ) 130 131 132Writes a file for use as ``<PackageName>ConfigVersion.cmake`` file to 133``<filename>``. See the documentation of :command:`find_package()` for 134details on this. 135 136``<filename>`` is the output filename, it should be in the build tree. 137``<major.minor.patch>`` is the version number of the project to be installed. 138 139If no ``VERSION`` is given, the :variable:`PROJECT_VERSION` variable is used. 140If this hasn't been set, it errors out. 141 142The ``COMPATIBILITY`` mode ``AnyNewerVersion`` means that the installed 143package version will be considered compatible if it is newer or exactly the 144same as the requested version. This mode should be used for packages which 145are fully backward compatible, also across major versions. 146If ``SameMajorVersion`` is used instead, then the behavior differs from 147``AnyNewerVersion`` in that the major version number must be the same as 148requested, e.g. version 2.0 will not be considered compatible if 1.0 is 149requested. This mode should be used for packages which guarantee backward 150compatibility within the same major version. 151If ``SameMinorVersion`` is used, the behavior is the same as 152``SameMajorVersion``, but both major and minor version must be the same as 153requested, e.g version 0.2 will not be compatible if 0.1 is requested. 154If ``ExactVersion`` is used, then the package is only considered compatible if 155the requested version matches exactly its own version number (not considering 156the tweak version). For example, version 1.2.3 of a package is only 157considered compatible to requested version 1.2.3. This mode is for packages 158without compatibility guarantees. 159If your project has more elaborated version matching rules, you will need to 160write your own custom ``ConfigVersion.cmake`` file instead of using this 161macro. 162 163.. versionadded:: 3.11 164 The ``SameMinorVersion`` compatibility mode. 165 166.. versionadded:: 3.14 167 If ``ARCH_INDEPENDENT`` is given, the installed package version will be 168 considered compatible even if it was built for a different architecture than 169 the requested architecture. Otherwise, an architecture check will be performed, 170 and the package will be considered compatible only if the architecture matches 171 exactly. For example, if the package is built for a 32-bit architecture, the 172 package is only considered compatible if it is used on a 32-bit architecture, 173 unless ``ARCH_INDEPENDENT`` is given, in which case the package is considered 174 compatible on any architecture. 175 176.. note:: ``ARCH_INDEPENDENT`` is intended for header-only libraries or similar 177 packages with no binaries. 178 179.. versionadded:: 3.19 180 ``COMPATIBILITY_MODE`` ``AnyNewerVersion``, ``SameMajorVersion`` and 181 ``SameMinorVersion`` handle the version range if any is specified 182 (see :command:`find_package` command for the details). 183 ``ExactVersion`` mode is incompatible with version ranges and will display an 184 author warning if one is specified. 185 186Internally, this macro executes :command:`configure_file()` to create the 187resulting version file. Depending on the ``COMPATIBILITY``, the corresponding 188``BasicConfigVersion-<COMPATIBILITY>.cmake.in`` file is used. 189Please note that these files are internal to CMake and you should not call 190:command:`configure_file()` on them yourself, but they can be used as starting 191point to create more sophisticted custom ``ConfigVersion.cmake`` files. 192 193Example Generating Package Files 194^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 195 196Example using both :command:`configure_package_config_file` and 197``write_basic_package_version_file()``: 198 199``CMakeLists.txt``: 200 201.. code-block:: cmake 202 203 set(INCLUDE_INSTALL_DIR include/ ... CACHE ) 204 set(LIB_INSTALL_DIR lib/ ... CACHE ) 205 set(SYSCONFIG_INSTALL_DIR etc/foo/ ... CACHE ) 206 #... 207 include(CMakePackageConfigHelpers) 208 configure_package_config_file(FooConfig.cmake.in 209 ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake 210 INSTALL_DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake 211 PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR) 212 write_basic_package_version_file( 213 ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake 214 VERSION 1.2.3 215 COMPATIBILITY SameMajorVersion ) 216 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake 217 ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake 218 DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake ) 219 220``FooConfig.cmake.in``: 221 222:: 223 224 set(FOO_VERSION x.y.z) 225 ... 226 @PACKAGE_INIT@ 227 ... 228 set_and_check(FOO_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") 229 set_and_check(FOO_SYSCONFIG_DIR "@PACKAGE_SYSCONFIG_INSTALL_DIR@") 230 231 check_required_components(Foo) 232#]=======================================================================] 233 234include(WriteBasicConfigVersionFile) 235 236macro(WRITE_BASIC_PACKAGE_VERSION_FILE) 237 write_basic_config_version_file(${ARGN}) 238endmacro() 239 240function(CONFIGURE_PACKAGE_CONFIG_FILE _inputFile _outputFile) 241 set(options NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO) 242 set(oneValueArgs INSTALL_DESTINATION INSTALL_PREFIX) 243 set(multiValueArgs PATH_VARS ) 244 245 cmake_parse_arguments(CCF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 246 247 if(CCF_UNPARSED_ARGUMENTS) 248 message(FATAL_ERROR "Unknown keywords given to CONFIGURE_PACKAGE_CONFIG_FILE(): \"${CCF_UNPARSED_ARGUMENTS}\"") 249 endif() 250 251 if(NOT CCF_INSTALL_DESTINATION) 252 message(FATAL_ERROR "No INSTALL_DESTINATION given to CONFIGURE_PACKAGE_CONFIG_FILE()") 253 endif() 254 255 if(DEFINED CCF_INSTALL_PREFIX) 256 if(IS_ABSOLUTE "${CCF_INSTALL_PREFIX}") 257 set(installPrefix "${CCF_INSTALL_PREFIX}") 258 else() 259 message(FATAL_ERROR "INSTALL_PREFIX must be an absolute path") 260 endif() 261 elseif(IS_ABSOLUTE "${CMAKE_INSTALL_PREFIX}") 262 set(installPrefix "${CMAKE_INSTALL_PREFIX}") 263 else() 264 get_filename_component(installPrefix "${CMAKE_INSTALL_PREFIX}" ABSOLUTE) 265 endif() 266 267 if(IS_ABSOLUTE "${CCF_INSTALL_DESTINATION}") 268 set(absInstallDir "${CCF_INSTALL_DESTINATION}") 269 else() 270 set(absInstallDir "${installPrefix}/${CCF_INSTALL_DESTINATION}") 271 endif() 272 273 file(RELATIVE_PATH PACKAGE_RELATIVE_PATH "${absInstallDir}" "${installPrefix}" ) 274 275 foreach(var ${CCF_PATH_VARS}) 276 if(NOT DEFINED ${var}) 277 message(FATAL_ERROR "Variable ${var} does not exist") 278 else() 279 if(IS_ABSOLUTE "${${var}}") 280 string(REPLACE "${installPrefix}" "\${PACKAGE_PREFIX_DIR}" 281 PACKAGE_${var} "${${var}}") 282 else() 283 set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}") 284 endif() 285 endif() 286 endforeach() 287 288 get_filename_component(inputFileName "${_inputFile}" NAME) 289 290 set(PACKAGE_INIT " 291####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### 292####### Any changes to this file will be overwritten by the next CMake run #### 293####### The input file was ${inputFileName} ######## 294 295get_filename_component(PACKAGE_PREFIX_DIR \"\${CMAKE_CURRENT_LIST_DIR}/${PACKAGE_RELATIVE_PATH}\" ABSOLUTE) 296") 297 298 if("${absInstallDir}" MATCHES "^(/usr)?/lib(64)?/.+") 299 # Handle "/usr move" symlinks created by some Linux distros. 300 string(APPEND PACKAGE_INIT " 301# Use original install prefix when loaded through a \"/usr move\" 302# cross-prefix symbolic link such as /lib -> /usr/lib. 303get_filename_component(_realCurr \"\${CMAKE_CURRENT_LIST_DIR}\" REALPATH) 304get_filename_component(_realOrig \"${absInstallDir}\" REALPATH) 305if(_realCurr STREQUAL _realOrig) 306 set(PACKAGE_PREFIX_DIR \"${installPrefix}\") 307endif() 308unset(_realOrig) 309unset(_realCurr) 310") 311 endif() 312 313 if(NOT CCF_NO_SET_AND_CHECK_MACRO) 314 string(APPEND PACKAGE_INIT " 315macro(set_and_check _var _file) 316 set(\${_var} \"\${_file}\") 317 if(NOT EXISTS \"\${_file}\") 318 message(FATAL_ERROR \"File or directory \${_file} referenced by variable \${_var} does not exist !\") 319 endif() 320endmacro() 321") 322 endif() 323 324 325 if(NOT CCF_NO_CHECK_REQUIRED_COMPONENTS_MACRO) 326 string(APPEND PACKAGE_INIT " 327macro(check_required_components _NAME) 328 foreach(comp \${\${_NAME}_FIND_COMPONENTS}) 329 if(NOT \${_NAME}_\${comp}_FOUND) 330 if(\${_NAME}_FIND_REQUIRED_\${comp}) 331 set(\${_NAME}_FOUND FALSE) 332 endif() 333 endif() 334 endforeach() 335endmacro() 336") 337 endif() 338 339 string(APPEND PACKAGE_INIT " 340####################################################################################") 341 342 configure_file("${_inputFile}" "${_outputFile}" @ONLY) 343 344endfunction() 345