diff --git a/cmake/AddInstallRPATHSupport.cmake b/cmake/AddInstallRPATHSupport.cmake index a2465225..e14b1e9a 100644 --- a/cmake/AddInstallRPATHSupport.cmake +++ b/cmake/AddInstallRPATHSupport.cmake @@ -1,95 +1,132 @@ -#.rst: -# AddInstallRPATHSupport -# ---------------------- -# -# Add support to RPATH during installation to your project:: -# -# add_install_rpath_support([BIN_DIRS dir [dir]] -# [LIB_DIRS dir [dir]] -# [INSTALL_NAME_DIR [dir]] -# [DEPENDS condition [condition]] -# [USE_LINK_PATH]) -# -# Normally (depending on the platform) when you install a shared -# library you can either specify its absolute path as the install name, -# or leave just the library name itself. In the former case the library -# will be correctly linked during run time by all executables and other -# shared libraries, but it must not change its install location. This -# is often the case for libraries installed in the system default -# library directory (e.g. ``/usr/lib``). -# In the latter case, instead, the library can be moved anywhere in the -# file system but at run time the dynamic linker must be able to find -# it. This is often accomplished by setting environmental variables -# (i.e. ``LD_LIBRARY_PATH`` on Linux). -# This procedure is usually not desirable for two main reasons: -# -# - by setting the variable you are changing the default behaviour -# of the dynamic linker thus potentially breaking executables (not as -# destructive as ``LD_PRELOAD``) -# - the variable will be used only by applications spawned by the shell -# and not by other processes. -# -# RPATH is aimed to solve the issues introduced by the second -# installation method. Using run-path dependent libraries you can -# create a directory structure containing executables and dependent -# libraries that users can relocate without breaking it. -# A run-path dependent library is a dependent library whose complete -# install name is not known when the library is created. -# Instead, the library specifies that the dynamic loader must resolve -# the library’s install name when it loads the executable that depends -# on the library. The executable or the other shared library will -# hardcode in the binary itself the additional search directories -# to be passed to the dynamic linker. This works great in conjunction -# with relative paths. -# This command will enable support to RPATH to your project. -# It will enable the following things: -# -# - If the project builds shared libraries it will generate a run-path -# enabled shared library, i.e. its install name will be resolved -# only at run time. -# - In all cases (building executables and/or shared libraries) -# dependent shared libraries with RPATH support will be properly -# -# The command has the following parameters: -# -# Options: -# - ``USE_LINK_PATH``: if passed the command will automatically adds to -# the RPATH the path to all the dependent libraries. -# -# Arguments: -# - ``BIN_DIRS`` list of directories when the targets (executable and -# plugins) will be installed. -# - ``LIB_DIRS`` list of directories to be added to the RPATH. These -# directories will be added "relative" w.r.t. the ``BIN_DIRS`` and -# ``LIB_DIRS``. -# - ``INSTALL_NAME_DIR`` directory where the libraries will be installed. -# This variable will be used only if ``CMAKE_SKIP_RPATH`` or -# ``CMAKE_SKIP_INSTALL_RPATH`` is set to ``TRUE`` as it will set the -# ``INSTALL_NAME_DIR`` on all targets -# - ``DEPENDS`` list of conditions that should be ``TRUE`` to enable -# RPATH, for example ``FOO; NOT BAR``. -# -# Note: see https://gitlab.kitware.com/cmake/cmake/issues/16589 for further -# details. - -#======================================================================= -# Copyright 2014 Istituto Italiano di Tecnologia (IIT) -# @author Francesco Romano -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#======================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - +# SPDX-FileCopyrightText: 2012-2021 Istituto Italiano di Tecnologia (IIT) +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +AddInstallRPATHSupport +---------------------- + +Add support to RPATH during installation to the project and the targets + +.. command:: add_install_rpath_support + + Add support to RPATH during installation to the project:: + +.. code-block:: cmake + add_install_rpath_support([BIN_DIRS dir [dir]] + [LIB_DIRS dir [dir]] + [INSTALL_NAME_DIR [dir]] + [DEPENDS condition [condition]] + [USE_LINK_PATH]) + + Normally (depending on the platform) when you install a shared + library you can either specify its absolute path as the install name, + or leave just the library name itself. In the former case the library + will be correctly linked during run time by all executables and other + shared libraries, but it must not change its install location. This + is often the case for libraries installed in the system default + library directory (e.g. ``/usr/lib``). + In the latter case, instead, the library can be moved anywhere in the + file system but at run time the dynamic linker must be able to find + it. This is often accomplished by setting environmental variables + (i.e. ``LD_LIBRARY_PATH`` on Linux). + This procedure is usually not desirable for two main reasons: + + - by setting the variable you are changing the default behaviour + of the dynamic linker thus potentially breaking executables (not as + destructive as ``LD_PRELOAD``) + - the variable will be used only by applications spawned by the shell + and not by other processes. + + RPATH aims in solving the issues introduced by the second + installation method. Using run-path dependent libraries you can + create a directory structure containing executables and dependent + libraries that users can relocate without breaking it. + A run-path dependent library is a dependent library whose complete + install name is not known when the library is created. + Instead, the library specifies that the dynamic loader must resolve + the library’s install name when it loads the executable that depends + on the library. The executable or the other shared library will + hardcode in the binary itself the additional search directories + to be passed to the dynamic linker. This works great in conjunction + with relative paths. + This command will enable support to RPATH to your project. + It will enable the following things: + + - If the project builds shared libraries it will generate a run-path + enabled shared library, i.e. its install name will be resolved + only at run time. + - In all cases (building executables and/or shared libraries) + dependent shared libraries with RPATH support will have their name + resolved only at run time, by embedding the search path directly + into the built binary. + + The command has the following parameters: + + Options: + - ``USE_LINK_PATH``: if passed the command will automatically adds to + the RPATH the path to all the dependent libraries. + + Arguments: + - ``BIN_DIRS`` list of directories when the targets (executable and + plugins) will be installed. + - ``LIB_DIRS`` list of directories to be added to the RPATH. These + directories will be added "relative" w.r.t. the ``BIN_DIRS`` and + ``LIB_DIRS``. + - ``INSTALL_NAME_DIR`` directory where the libraries will be installed. + This variable will be used only if ``CMAKE_SKIP_RPATH`` or + ``CMAKE_SKIP_INSTALL_RPATH`` is set to ``TRUE`` as it will set the + ``INSTALL_NAME_DIR`` on all targets + - ``DEPENDS`` list of conditions that should be ``TRUE`` to enable + RPATH, for example ``FOO; NOT BAR``. + + Note: see https://gitlab.kitware.com/cmake/cmake/issues/16589 for further + details. + +.. command:: target_append_install_rpath + + Add extra paths to RPATH for a specific target:: + +.. code-block:: cmake + + target_append_install_rpath( + + [LIB_DIRS dir [dir]] + [DEPENDS condition [condition]]) + + Arguments: + - ``INSTALL_DESTINATION`` path where the target will be installed. + - ``LIB_DIRS`` list of directories to be added to the RPATH. These + directories will be added "relative" w.r.t. the ``INSTALL_DESTINATION``. + - ``DEPENDS`` list of conditions that should be ``TRUE`` to enable + RPATH, for example ``FOO; NOT BAR``. +#]=======================================================================] include(CMakeParseArguments) +macro(__AddInstallRPATHSupport_GET_SYSTEM_LIB_DIRS _var) + # Find system implicit lib directories + set(${_var} ${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES}) + if(EXISTS "/etc/debian_version") # is this a debian system ? + if(CMAKE_LIBRARY_ARCHITECTURE) + list(APPEND ${_var} "/lib/${CMAKE_LIBRARY_ARCHITECTURE}" + "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}") + endif() + endif() +endmacro() + + +macro(__AddInstallRPATHSupport_APPEND_RELATIVE_RPATH _var _bin_dir _lib_dir) + file(RELATIVE_PATH _rel_path ${_bin_dir} ${_lib_dir}) + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + list(APPEND ${_var} "@loader_path/${_rel_path}") + else() + list(APPEND ${_var} "\$ORIGIN/${_rel_path}") + endif() +endmacro() + + + function(ADD_INSTALL_RPATH_SUPPORT) set(_options USE_LINK_PATH) @@ -131,25 +168,14 @@ function(ADD_INSTALL_RPATH_SUPPORT) # Enable RPATH on OSX. set(CMAKE_MACOSX_RPATH TRUE PARENT_SCOPE) - # Find system implicit lib directories - set(_system_lib_dirs ${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES}) - if(EXISTS "/etc/debian_version") # is this a debian system ? - if(CMAKE_LIBRARY_ARCHITECTURE) - list(APPEND _system_lib_dirs "/lib/${CMAKE_LIBRARY_ARCHITECTURE}" - "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}") - endif() - endif() + __AddInstallRPATHSupport_get_system_lib_dirs(_system_lib_dirs) + # This is relative RPATH for libraries built in the same project foreach(lib_dir ${_ARS_LIB_DIRS}) list(FIND _system_lib_dirs "${lib_dir}" isSystemDir) if("${isSystemDir}" STREQUAL "-1") foreach(bin_dir ${_ARS_LIB_DIRS} ${_ARS_BIN_DIRS}) - file(RELATIVE_PATH _rel_path ${bin_dir} ${lib_dir}) - if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - list(APPEND CMAKE_INSTALL_RPATH "@loader_path/${_rel_path}") - else() - list(APPEND CMAKE_INSTALL_RPATH "\$ORIGIN/${_rel_path}") - endif() + __AddInstallRPATHSupport_append_relative_rpath(CMAKE_INSTALL_RPATH ${bin_dir} ${lib_dir}) endforeach() endif() endforeach() @@ -165,3 +191,45 @@ function(ADD_INSTALL_RPATH_SUPPORT) endif() endfunction() + + +function(TARGET_APPEND_INSTALL_RPATH _target) + set(_options ) + set(_oneValueArgs INSTALL_DESTINATION) + set(_multiValueArgs LIB_DIRS + DEPENDS) + + if (CMAKE_SKIP_RPATH OR (CMAKE_SKIP_INSTALL_RPATH AND CMAKE_SKIP_BUILD_RPATH)) + return() + endif() + + cmake_parse_arguments(_ARS "${_options}" + "${_oneValueArgs}" + "${_multiValueArgs}" + "${ARGN}") + + set(_rpath_available 1) + if(DEFINED _ARS_DEPENDS) + foreach(_dep ${_ARS_DEPENDS}) + string(REGEX REPLACE " +" ";" _dep "${_dep}") + if(NOT (${_dep})) + set(_rpath_available 0) + endif() + endforeach() + endif() + + if(_rpath_available) + + __AddInstallRPATHSupport_get_system_lib_dirs(_system_lib_dirs) + + get_target_property(_current_rpath ${_target} INSTALL_RPATH) + foreach(lib_dir ${_ARS_LIB_DIRS}) + list(FIND _system_lib_dirs "${lib_dir}" isSystemDir) + if("${isSystemDir}" STREQUAL "-1") + __AddInstallRPATHSupport_append_relative_rpath(_current_rpath ${_ARS_INSTALL_DESTINATION} ${lib_dir}) + endif() + endforeach() + set_target_properties(${_target} PROPERTIES INSTALL_RPATH "${_current_rpath}") + endif() + +endfunction() diff --git a/cmake/AddUninstallTarget.cmake b/cmake/AddUninstallTarget.cmake index fefef2d1..63b3fce8 100644 --- a/cmake/AddUninstallTarget.cmake +++ b/cmake/AddUninstallTarget.cmake @@ -1,44 +1,58 @@ -#.rst: -# AddUninstallTarget -# ------------------ -# -# Add the "uninstall" target for your project:: -# -# include(AddUninstallTarget) -# -# -# will create a file cmake_uninstall.cmake in the build directory and add a -# custom target uninstall that will remove the files installed by your package -# (using install_manifest.txt) - -#============================================================================= -# Copyright 2008-2013 Kitware, Inc. -# Copyright 2013 Istituto Italiano di Tecnologia (IIT) -# Authors: Daniele E. Domenichelli -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - - -if(DEFINED __ADD_UNINSTALL_TARGET_INCLUDED) +# SPDX-FileCopyrightText: 2012-2021 Istituto Italiano di Tecnologia (IIT) +# SPDX-FileCopyrightText: 2008-2013 Kitware Inc. +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +AddUninstallTarget +------------------ + +Add the "uninstall" target for your project:: + + include(AddUninstallTarget) + + +will create a file ``cmake_uninstall.cmake`` in the build directory and add a +custom target ``uninstall`` (or ``UNINSTALL`` on Visual Studio and Xcode) that +will remove the files installed by your package (using +``install_manifest.txt``). +See also +https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake + +The :module:`AddUninstallTarget` module must be included in your main +``CMakeLists.txt``. If included in a subdirectory it does nothing. +This allows you to use it safely in your main ``CMakeLists.txt`` and include +your project using ``add_subdirectory`` (for example when using it with +:cmake:module:`FetchContent`). + +If the ``uninstall`` target already exists, the module does nothing. +#]=======================================================================] + + +# AddUninstallTarget works only when included in the main CMakeLists.txt +if(NOT "${CMAKE_CURRENT_BINARY_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") return() endif() -set(__ADD_UNINSTALL_TARGET_INCLUDED TRUE) +# The name of the target is uppercase in MSVC and Xcode (for coherence with the +# other standard targets) +if("${CMAKE_GENERATOR}" MATCHES "^(Visual Studio|Xcode)") + set(_uninstall "UNINSTALL") +else() + set(_uninstall "uninstall") +endif() + +# If target is already defined don't do anything +if(TARGET ${_uninstall}) + return() +endif() -set(_filename ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) -file(WRITE ${_filename} +set(_filename cmake_uninstall.cmake) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_filename}" "if(NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\") - message(WARNING \"Cannot find install manifest: \\\"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\\\"\") - return() + message(WARNING \"Cannot find install manifest: \\\"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\\\"\") + return() endif() file(READ \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\" files) @@ -46,25 +60,33 @@ string(STRIP \"\${files}\" files) string(REGEX REPLACE \"\\n\" \";\" files \"\${files}\") list(REVERSE files) foreach(file \${files}) + if(IS_SYMLINK \"\$ENV{DESTDIR}\${file}\" OR EXISTS \"\$ENV{DESTDIR}\${file}\") message(STATUS \"Uninstalling: \$ENV{DESTDIR}\${file}\") - if(EXISTS \"\$ENV{DESTDIR}\${file}\") - execute_process( - COMMAND \${CMAKE_COMMAND} -E remove \"\$ENV{DESTDIR}\${file}\" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_retval) - if(NOT \"\${rm_retval}\" EQUAL 0) - message(FATAL_ERROR \"Problem when removing \\\"\$ENV{DESTDIR}\${file}\\\"\") - endif() - else() - message(STATUS \"File \\\"\$ENV{DESTDIR}\${file}\\\" does not exist.\") + execute_process( + COMMAND \${CMAKE_COMMAND} -E remove \"\$ENV{DESTDIR}\${file}\" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval) + if(NOT \"\${rm_retval}\" EQUAL 0) + message(FATAL_ERROR \"Problem when removing \\\"\$ENV{DESTDIR}\${file}\\\"\") endif() + else() + message(STATUS \"Not-found: \$ENV{DESTDIR}\${file}\") + endif() endforeach(file) ") -if("${CMAKE_GENERATOR}" MATCHES "^(Visual Studio|Xcode)") - set(_uninstall "UNINSTALL") +set(_desc "Uninstall the project...") +if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") + set(_comment COMMAND \$\(CMAKE_COMMAND\) -E cmake_echo_color --switch=$\(COLOR\) --cyan "${_desc}") else() - set(_uninstall "uninstall") + set(_comment COMMENT "${_desc}") endif() -add_custom_target(${_uninstall} COMMAND "${CMAKE_COMMAND}" -P "${_filename}") +add_custom_target(${_uninstall} + ${_comment} + COMMAND ${CMAKE_COMMAND} -P ${_filename} + USES_TERMINAL + BYPRODUCTS uninstall_byproduct + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") +set_property(SOURCE uninstall_byproduct PROPERTY SYMBOLIC 1) + set_property(TARGET ${_uninstall} PROPERTY FOLDER "CMakePredefinedTargets") diff --git a/cmake/InstallBasicPackageFiles.cmake b/cmake/InstallBasicPackageFiles.cmake index b3d4fe14..077b95d5 100644 --- a/cmake/InstallBasicPackageFiles.cmake +++ b/cmake/InstallBasicPackageFiles.cmake @@ -1,200 +1,216 @@ -#.rst: -# InstallBasicPackageFiles -# ------------------------ -# -# A helper module to make your package easier to be found by other -# projects. -# -# -# .. command:: install_basic_package_files -# -# Create and install a basic version of cmake config files for your -# project:: -# -# install_basic_package_files( -# VERSION -# COMPATIBILITY -# TARGETS -# TARGETS_PROPERTY -# TARGETS_PROPERTIES -# [NO_SET_AND_CHECK_MACRO] -# [NO_CHECK_REQUIRED_COMPONENTS_MACRO] -# [VARS_PREFIX ] # (default = "") -# [DESTINATION ] -# [NAMESPACE ] # (default = "::") -# [EXTRA_PATH_VARS_SUFFIX path1 [path2 ...]] -# [CONFIG_TEMPLATE ] -# [UPPERCASE_FILENAMES | LOWERCASE_FILENAMES] -# [DEPENDENCIES ] -# [NO_COMPATIBILITY_VARS] -# ) -# -# Depending on UPPERCASE_FILENAMES and LOWERCASE_FILENAMES, this -# function generates 3 files: -# -# - ``ConfigVersion.cmake`` or ``-config-version.cmake`` -# - ``Config.cmake`` or ``-config.cmake`` -# - ``Targets.cmake`` or ``-targets.cmake`` -# -# If neither ``UPPERCASE_FILENAMES`` nor ``LOWERCASE_FILENAMES`` is -# set, a file ``ConfigVersion.cmake.in`` or -# ``-config-version.cmake.in`` is searched, and the convention -# is chosed according to the file found. If no file was found, the -# uppercase convention is used. -# -# The ``DEPENDENCIES`` flag can be used to set a list of dependencies -# that will be searched using the :command:`find_dependency` command -# from the :module:`CMakeFindDependencyMacro` module. -# When using a custom template file, the ``@PACKAGE_DEPENDENCIES@`` -# string is replaced with the code checking for the dependencies -# specified by this argument. -# -# Each file is generated twice, one for the build directory and one for -# the installation directory. The ``DESTINATION`` argument can be -# passed to install the files in a location different from the default -# one (``CMake`` on Windows, ``${CMAKE_INSTALL_LIBDIR}/cmake/${name}`` -# on other platforms. -# -# -# The ``ConfigVersion.cmake`` is generated using -# ``write_basic_package_version_file``. The ``VERSION``, -# ``COMPATIBILITY``, ``NO_SET_AND_CHECK_MACRO``, and -# ``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` are passed to this function -# and are used internally by :module:`CMakePackageConfigHelpers` module. -# -# ``VERSION`` shall be in the form ``[.[.[.]]]]``. -# If no ``VERSION`` is given, the ``PROJECT_VERSION`` variable is used. -# If this hasn’t been set, it errors out. The ``VERSION`` argument is also used -# to replace the ``@PACKAGE_VERSION@`` string in the configuration file. -# -# ``COMPATIBILITY`` shall be any of ````. -# The ``COMPATIBILITY`` mode ``AnyNewerVersion`` means that the installed -# package version will be considered compatible if it is newer or exactly the -# same as the requested version. This mode should be used for packages which are -# fully backward compatible, also across major versions. -# If ``SameMajorVersion`` is used instead, then the behaviour differs from -# ``AnyNewerVersion`` in that the major version number must be the same as -# requested, e.g. version 2.0 will not be considered compatible if 1.0 is -# requested. This mode should be used for packages which guarantee backward -# compatibility within the same major version. If ``ExactVersion`` is used, then -# the package is only considered compatible if the requested version matches -# exactly its own version number (not considering the tweak version). For -# example, version 1.2.3 of a package is only considered compatible to requested -# version 1.2.3. This mode is for packages without compatibility guarantees. If -# your project has more elaborated version matching rules, you will need to -# write your own custom ConfigVersion.cmake file instead of using this macro. -# -# By default ``install_basic_package_files`` also generates the two helper -# macros ``set_and_check()`` and ``check_required_components()`` into the -# ``Config.cmake`` file. ``set_and_check()`` should be used instead of the -# normal set() command for setting directories and file locations. Additionally -# to setting the variable it also checks that the referenced file or directory -# actually exists and fails with a ``FATAL_ERROR`` otherwise. This makes sure -# that the created ``Config.cmake`` file does not contain wrong -# references. When using the ``NO_SET_AND_CHECK_MACRO, this macro is not -# generated into the ``Config.cmake`` file. -# -# By default, ``install_basic_package_files`` append a call to -# ``check_required_components()`` in Config.cmake file if the -# package supports components. This macro checks whether all requested, -# non-optional components have been found, and if this is not the case, sets the -# ``_FOUND`` variable to ``FALSE``, so that the package is considered to -# be not found. It does that by testing the ``__FOUND`` -# variables for all requested required components. When using the -# ``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` option, this macro is not generated -# into the Config.cmake file. -# -# Finally, the files in the build and install directory are exactly the same. -# -# See the documentation of :module:`CMakePackageConfigHelpers` module for -# further information and references therein. -# -# -# The ``Config.cmake`` is generated using -# ``configure_package_config_file``. See the documentation for the -# :module:`CMakePackageConfigHelpers` module for further information. -# If the ``CONFIG_TEMPLATE`` argument is passed, the specified file -# is used as template for generating the configuration file, otherwise -# this module expects to find a ``Config.cmake.in`` or -# ``-config.cmake.in`` file either in the root directory of the -# project or in current source directory. -# If the file does not exist, a very basic file is created. -# -# A set of variables are checked and passed to -# ``configure_package_config_file`` as ``PATH_VARS``. For each of the -# ``SUFFIX`` considered, if one of the variables:: -# -# _(BUILD|INSTALL)_ -# (BUILD|INSTALL)__ -# -# is defined, the ``_`` variable will be defined -# before configuring the package. In order to use that variable in the -# config file, you have to add a line:: -# -# set_and_check(_ \"@PACKAGE__@\") -# -# if the path must exist or just:: -# -# set(_ \"@PACKAGE__@\") -# -# if the path could be missing. -# -# These variable will have different values whether you are using the -# package from the build tree or from the install directory. Also these -# files will contain only relative paths, meaning that you can move the -# whole installation and the CMake files will still work. -# -# Default ``PATH_VARS`` suffixes are:: -# -# BINDIR BIN_DIR -# SBINDIR SBIN_DIR -# LIBEXECDIR LIBEXEC_DIR -# SYSCONFDIR SYSCONF_DIR -# SHAREDSTATEDIR SHAREDSTATE_DIR -# LOCALSTATEDIR LOCALSTATE_DIR -# LIBDIR LIB_DIR -# INCLUDEDIR INCLUDE_DIR -# OLDINCLUDEDIR OLDINCLUDE_DIR -# DATAROOTDIR DATAROOT_DIR -# DATADIR DATA_DIR -# INFODIR INFO_DIR -# LOCALEDIR LOCALE_DIR -# MANDIR MAN_DIR -# DOCDIR DOC_DIR -# -# more suffixes can be added using the ``EXTRA_PATH_VARS_SUFFIX`` -# argument. -# -# -# The ``Targets.cmake`` is generated using -# :command:`export(TARGETS)` in the build tree and -# :command:`install(EXPORT)` in the installation directory. -# The targets are exported using the value for the ``NAMESPACE`` -# argument as namespace. -# The targets can be passed using the `TARGETS` argument or using a global -# property, that can be passed to the function using the ``TARGETS_PROPERTY`` -# argument -# -# If the ``NO_COMPATIBILITY_VARS`` argument is not set, the compatibility -# variables ``_LIBRARIES`` and ``_INCLUDE_DIRS`` -# are set, trying to guess their correct values from the variables set or -# from the arguments passed to this command. This argument is ignored if -# the template file is not generated by this command. - -#============================================================================= -# Copyright 2013 Istituto Italiano di Tecnologia (IIT) -# Authors: Daniele E. Domenichelli -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) +# SPDX-FileCopyrightText: 2012-2021 Istituto Italiano di Tecnologia (IIT) +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +InstallBasicPackageFiles +------------------------ + +A helper module to make your package easier to be found by other +projects. + + +.. command:: install_basic_package_files + +Create and install a basic version of cmake config files for your +project:: + + install_basic_package_files( + COMPATIBILITY + [VERSION ] + [ARCH_INDEPENDENT] + [NO_EXPORT | EXPORT ] # (default = "EXPORT ") + [NO_SET_AND_CHECK_MACRO] + [NO_CHECK_REQUIRED_COMPONENTS_MACRO] + [VARS_PREFIX ] # (default = "") + [EXPORT_DESTINATION ] + [INSTALL_DESTINATION ] + [NAMESPACE ] # (default = "::") + [EXTRA_PATH_VARS_SUFFIX path1 [path2 ...]] + [CONFIG_TEMPLATE ] + [UPPERCASE_FILENAMES | LOWERCASE_FILENAMES] + [DEPENDENCIES " [...]" ...] + [PRIVATE_DEPENDENCIES " [...]" ...] + [INCLUDE_FILE | INCLUDE_CONTENT ] + [COMPONENT ] # (default = "") + ) + +Depending on ``UPPERCASE_FILENAMES`` and ``LOWERCASE_FILENAMES``, this +function generates 3 files: + + - ``ConfigVersion.cmake`` or ``-config-version.cmake`` + - ``Config.cmake`` or ``-config.cmake`` + - ``Targets.cmake`` or ``-targets.cmake`` + +If neither ``UPPERCASE_FILENAMES`` nor ``LOWERCASE_FILENAMES`` is +set, a file ``Config.cmake.in`` or +``-config.cmake.in`` is searched, and the convention +is chosed according to the file found. If no file was found, the +uppercase convention is used. + +The ``DEPENDENCIES`` argument can be used to set a list of dependencies +that will be searched using the :cmake:command:`find_dependency` command +from the :module:`CMakeFindDependencyMacro` module. +Dependencies can be followed by any of the possible +:cmake:command:`find_dependency` argument. +In this case, all the arguments must be specified within double quotes (e.g. +``" 1.0.0 EXACT"``, or ``" CONFIG"``). +The ``PRIVATE_DEPENDENCIES`` argument is similar to ``DEPENDENCIES``, but +these dependencies are included only when :variable:`BUILD_SHARED_LIBS` is +``OFF``. +If a libraries is declared ``STATIC``, ``OBJECT`` or ``INTERFACE``, and they +link to some dependency, these should be added using the ``DEPENDENCIES`` +argument, since the ``PRIVATE_DEPENDENCIES`` argument would work only when +:variable:`BUILD_SHARED_LIBS` is disabled. + +When using a custom template file, the ``@PACKAGE_DEPENDENCIES@`` +string is replaced with the code checking for the dependencies +specified by these two argument. + +If the ``ARCH_INDEPENDENT`` option is enabled, the installed package version +will be considered compatible even if it was built for a different +architecture than the requested architecture. + +Each file is generated twice, one for the build directory and one for +the installation directory. The ``INSTALL_DESTINATION`` argument can be +passed to install the files in a location different from the default +one (``${CMAKE_INSTALL_DATADIR}/cmake/${Name}`` if the ``ARCH_INDEPENDENT`` +option is enabled, ``${CMAKE_INSTALL_LIBDIR}/cmake/${Name}`` otherwise). +The ``EXPORT_DESTINATION`` argument can be passed to +generate the files in the build tree in a location different from the default +one (``CMAKE_BINARY_DIR``). If this is a relative path, it is +considered relative to the ``CMAKE_CURRENT_BINARY_DIR`` directory. + +The build directory is exported to the CMake user package registry if the +build option ``CMAKE_EXPORT_PACKAGE_REGISTRY`` is set. + +The ``ConfigVersion.cmake`` file is generated using +:cmake:command:`write_basic_package_version_file`. The ``VERSION``, +``COMPATIBILITY``, and ``ARCH_INDEPENDENT``arguments are passed to this +function. + +``VERSION`` shall be in the form ``[.[.[.]]]]``. +If no ``VERSION`` is given, the ``PROJECT_VERSION`` variable is used. +If this hasn’t been set, it errors out. The ``VERSION`` argument is also used +to replace the ``@PACKAGE_VERSION@`` string in the configuration file. + +``COMPATIBILITY`` shall be any of the options accepted by the +:cmake:command:`write_basic_package_version_file` command +(``AnyNewerVersion``, ``SameMajorVersion``, ``SameMinorVersion`` [CMake 3.11], +or ``ExactVersion``). +These options are explained in :cmake:command:`write_basic_package_version_file` +command documentation. +If your project has more elaborate version matching rules, you will need to +write your own custom ConfigVersion.cmake file instead of using this macro. + +The ``Config.cmake`` file is generated using +:cmake:command:`configure_package_config_file`. The +``NO_SET_AND_CHECK_MACRO``, ``NO_CHECK_REQUIRED_COMPONENTS_MACRO``, and +arguments are passed to this function. + +By default :command:`install_basic_package_files` also generates the two helper +macros ``set_and_check()`` and ``check_required_components()`` into the +``Config.cmake`` file. ``set_and_check()`` should be used instead of the +normal :cmake:command:`set()` command for setting directories and file locations. +Additionally to setting the variable it also checks that the referenced file +or directory actually exists and fails with a ``FATAL_ERROR`` otherwise. +This makes sure that the created ``Config.cmake`` file does not contain +wrong references. +When using the ``NO_SET_AND_CHECK_MACRO, this macro is not generated into the +``Config.cmake`` file. + +By default, :command:`install_basic_package_files` append a call to +``check_required_components()`` in ``Config.cmake`` file if the +package supports components. This macro checks whether all requested, +non-optional components have been found, and if this is not the case, sets the +``_FOUND`` variable to ``FALSE``, so that the package is considered to +be not found. It does that by testing the ``__FOUND`` +variables for all requested required components. When using the +``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` option, this macro is not generated +into the ``Config.cmake`` file. + +Finally, the files in the build and install directory are exactly the same. + +See the documentation of :module:`CMakePackageConfigHelpers` module for +further information and references therein. + +If the ``CONFIG_TEMPLATE`` argument is passed, the specified file +is used as template for generating the configuration file, otherwise +this module expects to find a ``Config.cmake.in`` or +``-config.cmake.in`` file either in current source directory. +If the file does not exist, a very basic file is created. + +A set of variables are checked and passed to +:cmake:command:`configure_package_config_file` as ``PATH_VARS``. For each of the +``SUFFIX`` considered, if one of the variables:: + + _(BUILD|INSTALL)_ + (BUILD|INSTALL)__ + +is defined, the ``_`` variable will be defined +before configuring the package. In order to use that variable in the +config file, you have to add a line:: + + set_and_check(_ \"@PACKAGE__@\") + +if the path must exist or just:: + + set(_ \"@PACKAGE__@\") + +if the path could be missing. + +These variable will have different values whether you are using the +package from the build tree or from the install directory. Also these +files will contain only relative paths, meaning that you can move the +whole installation and the CMake files will still work. + +Default ``PATH_VARS`` suffixes are:: + + BINDIR BIN_DIR + SBINDIR SBIN_DIR + LIBEXECDIR LIBEXEC_DIR + SYSCONFDIR SYSCONF_DIR + SHAREDSTATEDIR SHAREDSTATE_DIR + LOCALSTATEDIR LOCALSTATE_DIR + LIBDIR LIB_DIR + INCLUDEDIR INCLUDE_DIR + OLDINCLUDEDIR OLDINCLUDE_DIR + DATAROOTDIR DATAROOT_DIR + DATADIR DATA_DIR + INFODIR INFO_DIR + LOCALEDIR LOCALE_DIR + MANDIR MAN_DIR + DOCDIR DOC_DIR + +more suffixes can be added using the ``EXTRA_PATH_VARS_SUFFIX`` +argument. + + +The ``Targets.cmake`` is generated using :cmake:command:`export(EXPORT)` +in the build tree and :cmake:command:`install(EXPORT)` in the installation +directory. The targets are exported using the value for the ``NAMESPACE`` +argument as namespace. +The export can be passed using the ``EXPORT`` argument. If no export is +used (e.g. for a CMake script library), pass ``NO_EXPORT``. + +If the ``INCLUDE_FILE`` argument is passed, the content of the specified file +(which might contain ``@variables@``) is appended to the generated +``Config.cmake`` file. +If the ``INCLUDE_CONTENT`` argument is passed, the specified content +(which might contain ``@variables@``) is appended to the generated +``Config.cmake`` file. +When a ``CONFIG_TEMPLATE`` is passed, or a ``ConfigVersion.cmake.in`` or +a ``-config-version.cmake.in file is available, these 2 arguments are +used to replace the ``@INCLUDED_CONTENT@`` string in this file. +This allows one to inject custom code to this file, useful e.g. to set +additional variables which are loaded by downstream projects. + +Note that content specified with ``INCLUDE_FILE`` or ``INCLUDE_CONTENT`` +cannot reference any of the ``PATH_VARS`` because this content is not +expanded by :cmake:command:`configure_package_config_file`. + +If the ``COMPONENT`` argument is passed, it is forwarded to the +:cmake:command:`install` commands, otherwise ```` is used. +#]=======================================================================] if(COMMAND install_basic_package_files) @@ -209,24 +225,33 @@ include(CMakeParseArguments) function(INSTALL_BASIC_PACKAGE_FILES _Name) - # TODO check that _Name does not contain "-" characters - - set(_options NO_SET_AND_CHECK_MACRO + set(_options ARCH_INDEPENDENT + NO_EXPORT + NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO UPPERCASE_FILENAMES LOWERCASE_FILENAMES - NO_COMPATIBILITY_VARS) + NO_COMPATIBILITY_VARS # Deprecated + ENABLE_COMPATIBILITY_VARS) # Deprecated set(_oneValueArgs VERSION COMPATIBILITY - TARGETS_PROPERTY + EXPORT + FIRST_TARGET # Deprecated + TARGETS_PROPERTY # Deprecated VARS_PREFIX - DESTINATION + EXPORT_DESTINATION + INSTALL_DESTINATION + DESTINATION # Deprecated NAMESPACE - CONFIG_TEMPLATE) + CONFIG_TEMPLATE + INCLUDE_FILE + INCLUDE_CONTENT + COMPONENT) set(_multiValueArgs EXTRA_PATH_VARS_SUFFIX - TARGETS - TARGETS_PROPERTIES - DEPENDENCIES) + TARGETS # Deprecated + TARGETS_PROPERTIES # Deprecated + DEPENDENCIES + PRIVATE_DEPENDENCIES) cmake_parse_arguments(_IBPF "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" "${ARGN}") if(NOT DEFINED _IBPF_VARS_PREFIX) @@ -234,41 +259,136 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name) endif() if(NOT DEFINED _IBPF_VERSION) - message(FATAL_ERROR "VERSION argument is required") + if(NOT DEFINED PROJECT_VERSION) + message(FATAL_ERROR "VERSION argument is required (PROJECT_VERSION is not defined)") + endif() + set(_IBPF_VERSION ${PROJECT_VERSION}) endif() if(NOT DEFINED _IBPF_COMPATIBILITY) message(FATAL_ERROR "COMPATIBILITY argument is required") endif() - if(NOT DEFINED _IBPF_TARGETS AND - NOT DEFINED _IBPF_TARGETS_PROPERTY AND - NOT DEFINED _IBPF_TARGETS_PROPERTIES) - message(FATAL_ERROR "TARGETS_PROPERTY or TARGET_PROPERTIES argument is required") - endif() - - if((DEFINED _IBPF_TARGETS AND (DEFINED _IBPF_TARGETS_PROPERTY OR DEFINED _IBPF_TARGETS_PROPERTIES)) OR - (DEFINED _IBPF_TARGETS_PROPERTY AND DEFINED _IBPF_TARGETS_PROPERTIES)) - message(FATAL_ERROR "Only one argument between TARGETS, TARGETS_PROPERTY, and TARGET_PROPERTIES can be used") + unset(_arch_independent) + if(_IBPF_ARCH_INDEPENDENT) + set(_arch_independent ARCH_INDEPENDENT) endif() if(_IBPF_UPPERCASE_FILENAMES AND _IBPF_LOWERCASE_FILENAMES) message(FATAL_ERROR "UPPERCASE_FILENAMES and LOWERCASE_FILENAMES arguments cannot be used together") endif() + if(DEFINED _IBPF_INCLUDE_FILE AND DEFINED _IBPF_INCLUDE_CONTENT) + message(FATAL_ERROR "INCLUDE_FILE and INCLUDE_CONTENT arguments cannot be used together") + endif() + + # Prepare install and export commands + unset(_targets) + set(_install_cmd EXPORT ${_Name}) + set(_export_cmd EXPORT ${_Name}) + + if(DEFINED _IBPF_EXPORT) + if(_IBPF_NO_EXPORT OR DEFINED _IBPF_TARGETS OR DEFINED _IBPF_TARGETS_PROPERTIES OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "EXPORT cannot be used with NO_EXPORT, TARGETS, TARGETS_PROPERTY, or TARGETS_PROPERTIES") + endif() + + set(_export_cmd EXPORT ${_IBPF_EXPORT}) + set(_install_cmd EXPORT ${_IBPF_EXPORT}) + + elseif(_IBPF_NO_EXPORT) + if(DEFINED _IBPF_TARGETS OR DEFINED _IBPF_TARGETS_PROPERTIES OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "NO_EXPORT cannot be used with TARGETS, TARGETS_PROPERTY, or TARGETS_PROPERTIES") + endif() + + elseif(DEFINED _IBPF_TARGETS) + message(DEPRECATION "TARGETS is deprecated. Use EXPORT instead") + + if(DEFINED _IBPF_TARGETS_PROPERTY OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "TARGETS cannot be used with TARGETS_PROPERTY or TARGETS_PROPERTIES") + endif() + + set(_targets ${_IBPF_TARGETS}) + set(_export_cmd TARGETS ${_IBPF_TARGETS}) + + elseif(DEFINED _IBPF_TARGETS_PROPERTY) + message(DEPRECATION "TARGETS_PROPERTY is deprecated. Use EXPORT instead") + + if(DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "TARGETS_PROPERTIES cannot be used with TARGETS_PROPERTIES") + endif() + + get_property(_targets GLOBAL PROPERTY ${_IBPF_TARGETS_PROPERTY}) + set(_export_cmd TARGETS ${_targets}) + + elseif(DEFINED _IBPF_TARGETS_PROPERTIES) + message(DEPRECATION "TARGETS_PROPERTIES is deprecated. Use EXPORT instead") + + set(_targets "") # Defined but empty + foreach(_prop ${_IBPF_TARGETS_PROPERTIES}) + get_property(_prop_val GLOBAL PROPERTY ${_prop}) + list(APPEND _targets ${_prop_val}) + endforeach() + set(_export_cmd TARGETS ${_targets}) + + endif() + # Path for installed cmake files - if(NOT DEFINED _IBPF_DESTINATION) - if(WIN32 AND NOT CYGWIN) - set(_IBPF_DESTINATION CMake) + if(DEFINED _IBPF_DESTINATION) + message(DEPRECATION "DESTINATION is deprecated. Use INSTALL_DESTINATION instead") + if(NOT DEFINED _IBPF_INSTALL_DESTINATION) + set(_IBPF_INSTALL_DESTINATION ${_IBPF_DESTINATION}) + endif() + endif() + + # If not set by the user, choose an adequate destination + if(NOT DEFINED _IBPF_INSTALL_DESTINATION) + if(_IBPF_ARCH_INDEPENDENT) + set(_IBPF_INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/${_Name}) else() - set(_IBPF_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${_Name}) + set(_IBPF_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${_Name}) endif() endif() + # FIRST_TARGET is no longer used + if(DEFINED _IBPF_FIRST_TARGET) + message(DEPRECATION "FIRST_TARGET is deprecated.") + endif() + + # NO_COMPATIBILITY_VARS and ENABLE_COMPATIBILITY_VARS cannot be used together + if(_IBPF_NO_COMPATIBILITY_VARS AND _ENABLE_COMPATIBILITY_VARS) + message(FATAL_ERROR "NO_COMPATIBILITY_VARS and ENABLE_COMPATIBILITY_VARS cannot be used together") + endif() + # NO_COMPATIBILITY_VARS is deprecated + if(_IBPF_NO_COMPATIBILITY_VARS) + message(DEPRECATION "NO_COMPATIBILITY_VARS is deprecated.") + endif() + # ENABLE_COMPATIBILITY_VARS is deprecated + if(_IBPF_ENABLE_COMPATIBILITY_VARS) + message(DEPRECATION "ENABLE_COMPATIBILITY_VARS is deprecated.") + endif() + # ENABLE_COMPATIBILITY_VARS does not work with EXPORT + if(NOT DEFINED _targets AND _IBPF_ENABLE_COMPATIBILITY_VARS) + message(FATAL_ERROR "ENABLE_COMPATIBILITY_VARS does not work with EXPORT") + endif() + # ENABLE_COMPATIBILITY_VARS can be enabled for projects still using targets + if(DEFINED _targets AND NOT _IBPF_NO_COMPATIBILITY_VARS AND NOT _IBPF_ENABLE_COMPATIBILITY_VARS) + message(DEPRECATION "Compatibility variables are no longer generated. Use ENABLE_COMPATIBILITY_VARS to re-enable them (deprecated) or define them using either INCLUDE_FILE or INCLUDE_CONTENT (recommended).") + endif() + + if(NOT DEFINED _IBPF_EXPORT_DESTINATION) + set(_IBPF_EXPORT_DESTINATION "${CMAKE_BINARY_DIR}") + elseif(NOT IS_ABSOLUTE "${_IBPF_EXPORT_DESTINATION}") + set(_IBPF_EXPORT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${_IBPF_EXPORT_DESTINATION}") + endif() + if(NOT DEFINED _IBPF_NAMESPACE) set(_IBPF_NAMESPACE "${_Name}::") endif() + if(NOT DEFINED _IBPF_COMPONENT) + set(_IBPF_COMPONENT "${_Name}") + endif() + if(_IBPF_NO_SET_AND_CHECK_MACRO) list(APPEND configure_package_config_file_extra_args NO_SET_AND_CHECK_MACRO) endif() @@ -278,21 +398,6 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name) endif() - # Get targets from TARGETS argument or from GLOBAL PROPERTY/PROPERTIES set - # in TARGETS_PROPERTY or TARGETS_PROPERTIES arguments - if(DEFINED _IBPF_TARGETS) - set(_targets ${_IBPF_TARGETS}) - elseif(DEFINED _IBPF_TARGETS_PROPERTY) - get_property(_targets GLOBAL PROPERTY ${_IBPF_TARGETS_PROPERTY}) - else() - set(_targets) - foreach(_prop ${_IBPF_TARGETS_PROPERTIES}) - get_property(_prop_val GLOBAL PROPERTY ${_prop}) - list(APPEND _targets ${_prop_val}) - endforeach() - endif() - list(GET _targets 0 _first_target) - # Set input file for config, and ensure that _IBPF_UPPERCASE_FILENAMES # and _IBPF_LOWERCASE_FILENAMES are set correctly @@ -314,17 +419,7 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name) endif() else() string(TOLOWER "${_Name}" _name) - if(EXISTS "${CMAKE_SOURCE_DIR}/${_Name}Config.cmake.in") - set(_config_cmake_in "${CMAKE_SOURCE_DIR}/${_Name}Config.cmake.in") - if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) - set(_IBPF_UPPERCASE_FILENAMES 1) - endif() - elseif(EXISTS "${CMAKE_SOURCE_DIR}/${_name}-config.cmake.in") - set(_config_cmake_in "${CMAKE_SOURCE_DIR}/${_name}-config.cmake.in") - if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) - set(_IBPF_LOWERCASE_FILENAMES 1) - endif() - elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in") set(_config_cmake_in "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in") if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) set(_IBPF_UPPERCASE_FILENAMES 1) @@ -337,7 +432,7 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name) else() set(_generate_file 1) if(_IBPF_LOWERCASE_FILENAMES) - set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_name}-config.cmake") + set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_name}-config.cmake.in") else() set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_Name}Config.cmake.in") set(_IBPF_UPPERCASE_FILENAMES 1) @@ -345,6 +440,40 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name) endif() endif() + # Set input file containing user variables + if(DEFINED _IBPF_INCLUDE_FILE) + if(NOT IS_ABSOLUTE "${_IBPF_INCLUDE_FILE}") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_IBPF_INCLUDE_FILE}") + set(_IBPF_INCLUDE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${_IBPF_INCLUDE_FILE}") + endif() + endif() + if(NOT EXISTS "${_IBPF_INCLUDE_FILE}") + message(FATAL_ERROR "File \"${_IBPF_INCLUDE_FILE}\" not found") + endif() + file(READ ${_IBPF_INCLUDE_FILE} _IBPF_INCLUDE_CONTENT) + endif() + + if(DEFINED _IBPF_INCLUDE_CONTENT) + string(CONFIGURE ${_IBPF_INCLUDE_CONTENT} + _IBPF_INCLUDE_CONTENT + @ONLY) + set(INCLUDED_CONTENT +"#### Expanded from INCLUDE_FILE/INCLUDE_CONTENT by install_basic_package_files() #### + +${_IBPF_INCLUDE_CONTENT} + +##################################################################################### +") + endif() + + # Backwards compatibility + if(NOT _generate_file AND DEFINED _IBPF_INCLUDE_FILE) + file(READ ${_config_cmake_in} _config_cmake_in_content) + if("${_config_cmake_in_content}" MATCHES "@INCLUDED_FILE_CONTENT@") + message(DEPRECATION "The @INCLUDED_FILE_CONTENT@ variable is deprecated in favour of @INCLUDED_CONTENT@") + set(INCLUDED_FILE_CONTENT "${INCLUDED_CONTENT}") + endif() + endif() # Select output file names if(_IBPF_UPPERCASE_FILENAMES) @@ -362,7 +491,7 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name) if(_generate_file) # Generate the compatibility code unset(_compatibility_vars) - if(NOT _IBPF_NO_COMPATIBILITY_VARS) + if(_IBPF_ENABLE_COMPATIBILITY_VARS) unset(_get_include_dir_code) unset(_set_include_dir_code) unset(_target_list) @@ -373,25 +502,34 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name) DEFINED BUILD_${_IBPF_VARS_PREFIX}_INCLUDEDIR OR DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_INCLUDEDIR OR DEFINED INSTALL_${_IBPF_VARS_PREFIX}_INCLUDEDIR) - set(_get_include_dir "set(${_IBPF_VARS_PREFIX}_INCLUDEDIR \"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDEDIR\@\")\n") - set(_set_include_dir "set(${_Name}_INCLUDE_DIRS \"\${${_IBPF_VARS_PREFIX}_INCLUDEDIR}\")") + list(APPEND _include_dir_list "\"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDEDIR\@\"") elseif(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_INCLUDE_DIR OR DEFINED BUILD_${_IBPF_VARS_PREFIX}_INCLUDE_DIR OR DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_INCLUDE_DIR OR DEFINED INSTALL_${_IBPF_VARS_PREFIX}_INCLUDE_DIR) - set(_get_include_dir "set(${_IBPF_VARS_PREFIX}_INCLUDE_DIR \"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDE_DIR\@\")\n") - set(_set_include_dir "set(${_Name}_INCLUDE_DIRS \"\${${_IBPF_VARS_PREFIX}_INCLUDE_DIR}\")") + list(APPEND _include_dir_list "\"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDE_DIR\@\"") else() unset(_include_dir_list) foreach(_target ${_targets}) - set(_get_include_dir "${_get_include_dir}get_property(${_IBPF_VARS_PREFIX}_${_target}_INCLUDE_DIR TARGET ${_IBPF_NAMESPACE}${_target} PROPERTY INTERFACE_INCLUDE_DIRECTORIES)\n") - list(APPEND _include_dir_list "\"\${${_IBPF_VARS_PREFIX}_${_target}_INCLUDE_DIR}\"") + list(APPEND _include_dir_list "\$") endforeach() string(REPLACE ";" " " _include_dir_list "${_include_dir_list}") string(REPLACE ";" " " _target_list "${_target_list}") - set(_set_include_dir "set(${_Name}_INCLUDE_DIRS ${_include_dir_list})\nlist(REMOVE_DUPLICATES ${_Name}_INCLUDE_DIRS)") + set(_set_include_dir "") endif() - set(_compatibility_vars "# Compatibility\n${_get_include_dir}\nset(${_Name}_LIBRARIES ${_target_list})\n${_set_include_dir}") + set(_compatibility_vars +"# Compatibility\nset(${_Name}_LIBRARIES ${_target_list}) +set(${_Name}_INCLUDE_DIRS ${_include_dir_list}) +if(NOT \"\${${_Name}_INCLUDE_DIRS}\" STREQUAL \"\") + list(REMOVE_DUPLICATES ${_Name}_INCLUDE_DIRS) +endif() +") + endif() + + if(_IBPF_NO_EXPORT) + set(_include_targets_cmd "") + else() + set(_include_targets_cmd "include(\"\${CMAKE_CURRENT_LIST_DIR}/${_targets_filename}\")") endif() # Write the file @@ -402,11 +540,11 @@ function(INSTALL_BASIC_PACKAGE_FILES _Name) \@PACKAGE_DEPENDENCIES\@ -if(NOT TARGET ${_IBPF_NAMESPACE}${_first_target}) - include(\"\${CMAKE_CURRENT_LIST_DIR}/${_targets_filename}\") -endif() +${_include_targets_cmd} ${_compatibility_vars} + +\@INCLUDED_CONTENT\@ ") endif() @@ -447,28 +585,43 @@ ${_compatibility_vars} endforeach() - # ConfigVersion.cmake file (same for build tree and intall) - write_basic_package_version_file("${CMAKE_BINARY_DIR}/${_version_filename}" + # ConfigVersion.cmake file (same for build tree and intall) + write_basic_package_version_file("${_IBPF_EXPORT_DESTINATION}/${_version_filename}" VERSION ${_IBPF_VERSION} - COMPATIBILITY ${_IBPF_COMPATIBILITY}) - install(FILES "${CMAKE_BINARY_DIR}/${_version_filename}" - DESTINATION ${_IBPF_DESTINATION}) + COMPATIBILITY ${_IBPF_COMPATIBILITY} + ${_arch_independent}) + install(FILES "${_IBPF_EXPORT_DESTINATION}/${_version_filename}" + DESTINATION ${_IBPF_INSTALL_DESTINATION} + COMPONENT ${_IBPF_COMPONENT}) # Prepare PACKAGE_DEPENDENCIES variable + set(_need_private_deps 0) + if(NOT BUILD_SHARED_LIBS) + set(_need_private_deps 1) + endif() + unset(PACKAGE_DEPENDENCIES) - if(DEFINED _IBPF_DEPENDENCIES) + if(DEFINED _IBPF_DEPENDENCIES OR (DEFINED _IBPF_PRIVATE_DEPENDENCIES AND _need_private_deps)) set(PACKAGE_DEPENDENCIES "#### Expanded from @PACKAGE_DEPENDENCIES@ by install_basic_package_files() ####\n\ninclude(CMakeFindDependencyMacro)\n") + foreach(_dep ${_IBPF_DEPENDENCIES}) - set(PACKAGE_DEPENDENCIES "${PACKAGE_DEPENDENCIES}find_dependency(${_dep})\n") + string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n") endforeach() - set(PACKAGE_DEPENDENCIES "${PACKAGE_DEPENDENCIES}\n###############################################################################\n") + + if(_need_private_deps) + foreach(_dep ${_IBPF_PRIVATE_DEPENDENCIES}) + string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n") + endforeach() + endif() + + string(APPEND PACKAGE_DEPENDENCIES "\n###############################################################################\n") endif() # Prepare PACKAGE_VERSION variable set(PACKAGE_VERSION ${_IBPF_VERSION}) - # Config.cmake (build tree) + # Config.cmake (build tree) foreach(p ${_build_path_vars_suffix}) if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_${p}) set(${_IBPF_VARS_PREFIX}_${p} "${${_IBPF_VARS_PREFIX}_BUILD_${p}}") @@ -477,13 +630,13 @@ ${_compatibility_vars} endif() endforeach() configure_package_config_file("${_config_cmake_in}" - "${CMAKE_BINARY_DIR}/${_config_filename}" - INSTALL_DESTINATION ${CMAKE_BINARY_DIR} + "${_IBPF_EXPORT_DESTINATION}/${_config_filename}" + INSTALL_DESTINATION ${_IBPF_EXPORT_DESTINATION} PATH_VARS ${_build_path_vars} ${configure_package_config_file_extra_args} INSTALL_PREFIX ${CMAKE_BINARY_DIR}) - # Config.cmake (installed) + # Config.cmake (installed) foreach(p ${_install_path_vars_suffix}) if(DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_${p}) set(${_IBPF_VARS_PREFIX}_${p} "${${_IBPF_VARS_PREFIX}_INSTALL_${p}}") @@ -492,23 +645,40 @@ ${_compatibility_vars} endif() endforeach() configure_package_config_file("${_config_cmake_in}" - "${CMAKE_CURRENT_BINARY_DIR}/${_config_filename}.install" - INSTALL_DESTINATION ${_IBPF_DESTINATION} + "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_config_filename}.install" + INSTALL_DESTINATION ${_IBPF_INSTALL_DESTINATION} PATH_VARS ${_install_path_vars} ${configure_package_config_file_extra_args}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${_config_filename}.install" - DESTINATION ${_IBPF_DESTINATION} - RENAME ${_config_filename}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_config_filename}.install" + DESTINATION ${_IBPF_INSTALL_DESTINATION} + RENAME ${_config_filename} + COMPONENT ${_IBPF_COMPONENT}) - # Targets.cmake (build tree) - export(TARGETS ${_targets} - NAMESPACE ${_IBPF_NAMESPACE} - FILE "${CMAKE_BINARY_DIR}/${_targets_filename}") + # Targets.cmake (build tree) + if(NOT _IBPF_NO_EXPORT) + export(${_export_cmd} + NAMESPACE ${_IBPF_NAMESPACE} + FILE "${_IBPF_EXPORT_DESTINATION}/${_targets_filename}") + endif() - # Targets.cmake (installed) - install(EXPORT ${_Name} - NAMESPACE ${_IBPF_NAMESPACE} - DESTINATION ${_IBPF_DESTINATION} - FILE "${_targets_filename}") + # Export build directory if CMAKE_EXPORT_PACKAGE_REGISTRY is set. + # CMake >= 3.15 already checks for CMAKE_EXPORT_PACKAGE_REGISTRY in `export(PACKAGE)` (cf. + # cf. https://cmake.org/cmake/help/latest/policy/CMP0090.html), and we effectively back-port + # this behavior to earlier versions. + # Note that even never CMake versions may apply old policy behaviors if the consuming project + # requires a lower version of CMake (e.g. `cmake_minimum_required(VERSION 3.14)`), so the + # check for `CMAKE_EXPORT_PACKAGE_REGISTRY` is necessary for CMake >= 3.15 as well. + if(CMAKE_EXPORT_PACKAGE_REGISTRY) + export(PACKAGE ${_Name}) + endif() + + # Targets.cmake (installed) + if(NOT _IBPF_NO_EXPORT) + install(${_install_cmd} + NAMESPACE ${_IBPF_NAMESPACE} + DESTINATION ${_IBPF_INSTALL_DESTINATION} + FILE "${_targets_filename}" + COMPONENT ${_IBPF_COMPONENT}) + endif() endfunction()