summaryrefslogtreecommitdiffstats
path: root/Tests/InstallMode
diff options
context:
space:
mode:
authorFelix Lelchuk <felix.lelchuk@gmx.de>2021-08-02 17:42:26 (GMT)
committerFelix Lelchuk <felix.lelchuk@gmx.de>2021-08-02 17:42:26 (GMT)
commit58d10cf6f13493db124af18e3cac127b2164ea59 (patch)
tree593dc156eae14ffe6584fa1a31e17f9a18d88a2f /Tests/InstallMode
parentc15bb6f8b8c2eac691138e35d96570d537cc6d69 (diff)
downloadCMake-58d10cf6f13493db124af18e3cac127b2164ea59.zip
CMake-58d10cf6f13493db124af18e3cac127b2164ea59.tar.gz
CMake-58d10cf6f13493db124af18e3cac127b2164ea59.tar.bz2
Alternative symlink-creating mode for file(INSTALL ...)
An new environment variable 'CMAKE_INSTALL_MODE' is introduced, which can be used to ask CMake to create symbolic links instead of copying files during a file(INSTALL ...). The operation is at the file level only, directory trees are still created using actual directories, not links. Signed-off-by: Felix Lelchuk <felix.lelchuk@gmx.de>
Diffstat (limited to 'Tests/InstallMode')
-rw-r--r--Tests/InstallMode/CMakeLists.txt124
-rw-r--r--Tests/InstallMode/README.txt43
-rw-r--r--Tests/InstallMode/Subproject.cmake76
-rw-r--r--Tests/InstallMode/Test.cmake38
-rw-r--r--Tests/InstallMode/subpro_a_static_lib/CMakeLists.txt60
-rw-r--r--Tests/InstallMode/subpro_a_static_lib/cmake/PackageConfig.cmake.in8
-rw-r--r--Tests/InstallMode/subpro_a_static_lib/include/static_lib.h3
-rw-r--r--Tests/InstallMode/subpro_a_static_lib/src/static_lib.cpp10
-rw-r--r--Tests/InstallMode/subpro_b_shared_lib/CMakeLists.txt66
-rw-r--r--Tests/InstallMode/subpro_b_shared_lib/cmake/PackageConfig.cmake.in8
-rw-r--r--Tests/InstallMode/subpro_b_shared_lib/include/shared_lib.h3
-rw-r--r--Tests/InstallMode/subpro_b_shared_lib/src/shared_lib.cpp10
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/CMakeLists.txt10
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/CMakeLists.txt61
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/cmake/PackageConfig.cmake.in8
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/include/c1_lib.h3
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/src/c1_lib.cpp10
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/CMakeLists.txt68
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/cmake/PackageConfig.cmake.in11
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/include/c2_lib.h3
-rw-r--r--Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/src/c2_lib.cpp12
-rw-r--r--Tests/InstallMode/subpro_d_executable/CMakeLists.txt24
-rw-r--r--Tests/InstallMode/subpro_d_executable/src/main.cpp13
-rw-r--r--Tests/InstallMode/superpro/CMakeLists.txt29
-rw-r--r--Tests/InstallMode/superpro/file_copy.txt1
-rw-r--r--Tests/InstallMode/superpro/file_copy_file.txt1
-rw-r--r--Tests/InstallMode/superpro/file_create_link_symbolic.txt2
-rw-r--r--Tests/InstallMode/superpro/file_install.txt6
28 files changed, 711 insertions, 0 deletions
diff --git a/Tests/InstallMode/CMakeLists.txt b/Tests/InstallMode/CMakeLists.txt
new file mode 100644
index 0000000..96c83a0
--- /dev/null
+++ b/Tests/InstallMode/CMakeLists.txt
@@ -0,0 +1,124 @@
+cmake_minimum_required(VERSION 3.20.0)
+
+project(superpro LANGUAGES NONE)
+
+add_subdirectory(superpro)
+
+include(Subproject.cmake)
+add_subproject(static_lib DIR subpro_a_static_lib)
+add_subproject(shared_lib DIR subpro_b_shared_lib)
+add_subproject(nested_lib DIR subpro_c_nested_lib NO_INSTALL)
+add_subproject(executable DIR subpro_d_executable
+ DEPENDS
+ static_lib
+ shared_lib
+ nested_lib
+)
+
+include(CTest)
+if(BUILD_TESTING)
+ enable_language(CXX) # required by GNUInstallDirs
+ include(GNUInstallDirs)
+
+ macro(testme _name _path _symlink)
+ add_test(
+ NAME "${_name}"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMAND
+ "${CMAKE_COMMAND}"
+ "-DFILE_PATH=${CMAKE_INSTALL_PREFIX}/${_path}"
+ "-DEXPECT_SYMLINK:BOOL=${_symlink}"
+ "-DEXPECT_ABSOLUTE:BOOL=${ARGN}"
+ "-P" "${CMAKE_SOURCE_DIR}/Test.cmake"
+ )
+ endmacro()
+
+ set(_mode $ENV{CMAKE_INSTALL_MODE})
+ if(NOT "${_mode}" OR "${_mode}" STREQUAL "COPY")
+ set(expect_symlink NO)
+ elseif("${_mode}" MATCHES "(REL_)?SYMLINK(_OR_COPY)?")
+ set(expect_symlink YES)
+ set(expect_absolute NO)
+ elseif("${_mode}" MATCHES "ABS_SYMLINK(_OR_COPY)?")
+ set(expect_symlink YES)
+ set(expect_absolute YES)
+ endif()
+
+ # toplevel project should respect CMAKE_INSTALL_MODE
+
+ testme(superproj_file_copy
+ "file_copy.txt" NO)
+ testme(superproj_file_copy_file
+ "file_copy_file.txt" NO)
+ testme(superproj_file_install
+ "file_install.txt"
+ ${expect_symlink}
+ ${expect_absolute})
+ testme(superproj_file_create_link_symbolic
+ "file_create_link_symbolic.txt" YES YES)
+
+ # subprojects should receive and respect CMAKE_INSTALL_MODE too
+
+ testme(subpro_a_static_lib_header
+ "${CMAKE_INSTALL_INCLUDEDIR}/static_lib.h"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+ testme(subpro_a_static_lib_libfile
+ "${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}the_static_lib${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+
+ testme(subpro_b_shared_lib_header
+ "${CMAKE_INSTALL_INCLUDEDIR}/shared_lib.h"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+
+ if(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG AND
+ "${CMAKE_CXX_CREATE_SHARED_MODULE}" MATCHES "SONAME_FLAG")
+ # due to semver, this is always a link
+ testme(subpro_b_shared_lib_libfile
+ "${CMAKE_INSTALL_LIBDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}the_shared_lib${CMAKE_SHARED_LIBRARY_SUFFIX}"
+ YES
+ ${expect_absolute}
+ )
+ # this is the actual shared lib, so should follow CMAKE_INSTALL_MODE rules
+ testme(subpro_b_shared_lib_libfile_versuffix
+ "${CMAKE_INSTALL_LIBDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}the_shared_lib${CMAKE_SHARED_LIBRARY_SUFFIX}.2.3.4"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+ endif()
+
+ testme(subpro_d_executable_exefile
+ "${CMAKE_INSTALL_BINDIR}/the_executable${CMAKE_EXECUTABLE_SUFFIX}"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+
+ # nested subprojects should receive and respect CMAKE_INSTALL_MODE too
+
+ testme(subsubpro_c1_header
+ "${CMAKE_INSTALL_INCLUDEDIR}/c1_lib.h"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+ testme(subsubpro_c1_libfile
+ "${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}the_c1_lib${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+
+ testme(subsubpro_c2_header
+ "${CMAKE_INSTALL_INCLUDEDIR}/c2_lib.h"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+ testme(subsubpro_c2_libfile
+ "${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}the_c2_lib${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ ${expect_symlink}
+ ${expect_absolute}
+ )
+endif()
diff --git a/Tests/InstallMode/README.txt b/Tests/InstallMode/README.txt
new file mode 100644
index 0000000..a4316eb
--- /dev/null
+++ b/Tests/InstallMode/README.txt
@@ -0,0 +1,43 @@
+This is an example superbuild project to demonstrate the use of the
+CMAKE_INSTALL_MODE environment variable on.
+
+The project hierarchy is like (B = Builds / D = Link Dependency):
+
++---------------------------------------------------------------------+
+| Superbuild (Top) |
++---------------------------------------------------------------------+
+ | | | |
+ | | | |
+ (B) (B) (B) (B)
+ | | | |
+ v v v v
++---------------+ +---------------+ +---------------+ +---------------+
+| A: Static Lib | | B: Shared Lib | | C: Nested | | D: Executable |
+| Project | | Project | | Superbuild | | Project |
++---------------+ +---------------+ +---------------+ +---------------+
+ ^ ^ | | | | |
+ | | (B) (B) | | |
+ | | | | | | |
+ | | v | | | |
+ | | +----------------+ | | | |
+ | | | C1: Static Lib | | | | |
+ | | | Project | | (D) (D) (D)
+ | | +----------------+ | | | |
+ | | ^ | | | |
+ | | | v | | |
+ | | (D) +----------------+ | | |
+ | | | | C2: Static Lib |<---+ | |
+ | | +--| Project | | |
+ | | +----------------+ | |
+ | | | |
+ | +------------------------------------+ |
+ | |
+ +--------------------------------------------------------+
+
+The superbuild system is built on top of ExternalProject_Add().
+
+NOTE that the subprojects will configure, build and install
+during the build phase ('make') of the top-level project.
+There is no install target in the top-level project!
+The CMAKE_INSTALL_PREFIX is therefore populated during the build
+phase already.
diff --git a/Tests/InstallMode/Subproject.cmake b/Tests/InstallMode/Subproject.cmake
new file mode 100644
index 0000000..e4354d6
--- /dev/null
+++ b/Tests/InstallMode/Subproject.cmake
@@ -0,0 +1,76 @@
+include(ExternalProject)
+
+# add_subproject(<name> [NO_INSTALL] [DIR <dirname>] [DEPENDS [subpro_dep ...]])
+function(add_subproject _name)
+ cmake_parse_arguments(_arg "NO_INSTALL" "DIR" "DEPENDS" ${ARGN})
+
+ if(_arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "There are unparsed arguments")
+ endif()
+
+ set(_maybe_NO_INSTALL)
+ if(_arg_NO_INSTALL)
+ set(_maybe_NO_INSTALL "INSTALL_COMMAND")
+ else()
+ # This is a trick to get a valid call.
+ # Since we set UPDATE_COMMAND to ""
+ # explicitly below, this won't harm.
+ set(_maybe_NO_INSTALL "UPDATE_COMMAND")
+ endif()
+
+ if(CMAKE_GENERATOR MATCHES "Ninja Multi-Config")
+ # Replace list separator before passing on to ExternalProject_Add
+ string(REPLACE ";" "|" _CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}")
+ string(REPLACE ";" "|" _CROSS_CONFIGS "${CMAKE_CROSS_CONFIGS}")
+ string(REPLACE ";" "|" _DEFAULT_CONFIGS "${CMAKE_DEFAULT_CONFIGS}")
+
+ set(_maybe_NINJA_MULTICONFIG_ARGS
+ "-DCMAKE_CONFIGURATION_TYPES:STRINGS=${_CONFIGURATION_TYPES}"
+ "-DCMAKE_CROSS_CONFIGS:STRINGS=${_CROSS_CONFIGS}"
+ "-DCMAKE_DEFAULT_BUILD_TYPE:STRING=${CMAKE_DEFAULT_BUILD_TYPE}"
+ "-DCMAKE_DEFAULT_CONFIGS:STRINGS=${_DEFAULT_CONFIGS}"
+ )
+ endif()
+
+ ExternalProject_Add("${_name}"
+ DOWNLOAD_COMMAND ""
+ UPDATE_COMMAND ""
+ ${_maybe_NO_INSTALL} ""
+
+ BUILD_ALWAYS ON
+
+ LOG_DOWNLOAD OFF
+ LOG_UPDATE OFF
+ LOG_PATCH OFF
+ LOG_CONFIGURE OFF
+ LOG_BUILD OFF
+ LOG_INSTALL OFF
+
+ SOURCE_DIR "${PROJECT_SOURCE_DIR}/${_arg_DIR}"
+
+ # Private build directory per subproject
+ BINARY_DIR "${PROJECT_BINARY_DIR}/subproject/${_arg_DIR}"
+
+ # Common install directory, populated immediately
+ # during build (during build - not install - of superproject)
+ INSTALL_DIR "${CMAKE_INSTALL_PREFIX}"
+
+ DEPENDS
+ ${_arg_DEPENDS}
+
+ LIST_SEPARATOR "|"
+ CMAKE_ARGS
+ "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>"
+
+ # We can rely on ExternalProject to pick the right
+ # generator (and architecture/toolset where applicable),
+ # however, we need to explicitly inherit other parent
+ # project's build settings.
+ "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
+ ${_maybe_NINJA_MULTICONFIG_ARGS}
+
+ # Subproject progress reports clutter up the output, disable
+ "-DCMAKE_TARGET_MESSAGES:BOOL=OFF"
+ "-DCMAKE_RULE_MESSAGES:BOOL=OFF"
+ )
+endfunction()
diff --git a/Tests/InstallMode/Test.cmake b/Tests/InstallMode/Test.cmake
new file mode 100644
index 0000000..46c8fa1
--- /dev/null
+++ b/Tests/InstallMode/Test.cmake
@@ -0,0 +1,38 @@
+message("Testing...")
+message("FILE_PATH = ${FILE_PATH}")
+message("EXPECT_SYMLINK = ${EXPECT_SYMLINK}")
+message("EXPECT_ABSOLUTE = ${EXPECT_ABSOLUTE}")
+
+if(NOT DEFINED FILE_PATH)
+ message(FATAL_ERROR "FILE_PATH variable must be defined")
+endif()
+
+if(NOT EXISTS "${FILE_PATH}")
+ message(FATAL_ERROR "File ${FILE_PATH} does not exist")
+endif()
+
+if(NOT DEFINED EXPECT_SYMLINK)
+ message(FATAL_ERROR "EXPECT_SYMLINK must be defined")
+endif()
+
+if(EXPECT_SYMLINK)
+ if(NOT DEFINED EXPECT_ABSOLUTE)
+ message(FATAL_ERROR "EXPECT_ABSOLUTE variable must be defined")
+ endif()
+
+ if(NOT IS_SYMLINK "${FILE_PATH}")
+ message(FATAL_ERROR "${FILE_PATH} must be a symlink")
+ endif()
+
+ file(READ_SYMLINK "${FILE_PATH}" TARGET_PATH)
+
+ if(EXPECT_ABSOLUTE AND NOT IS_ABSOLUTE "${TARGET_PATH}")
+ message(FATAL_ERROR "${FILE_PATH} must be an absolute symlink")
+ elseif(NOT EXPECT_ABSOLUTE AND IS_ABSOLUTE "${TARGET_PATH}")
+ message(FATAL_ERROR "${FILE_PATH} must be a relative symlink")
+ endif()
+else()
+ if(IS_SYMLINK "${FILE_PATH}")
+ message(FATAL_ERROR "${FILE_PATH} must NOT be a symlink")
+ endif()
+endif()
diff --git a/Tests/InstallMode/subpro_a_static_lib/CMakeLists.txt b/Tests/InstallMode/subpro_a_static_lib/CMakeLists.txt
new file mode 100644
index 0000000..7cd32cc
--- /dev/null
+++ b/Tests/InstallMode/subpro_a_static_lib/CMakeLists.txt
@@ -0,0 +1,60 @@
+# This CMakeLists.txt is part of the subproject A (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(static_lib_project VERSION 1.2.3 LANGUAGES CXX)
+
+include(GNUInstallDirs)
+
+add_library(the_static_lib STATIC
+ "include/static_lib.h"
+ "src/static_lib.cpp"
+)
+
+target_include_directories(the_static_lib PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+install(
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+install(
+ TARGETS
+ the_static_lib
+ EXPORT main
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+ "cmake/PackageConfig.cmake.in"
+ "${PROJECT_NAME}Config.cmake"
+ INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
+ PATH_VARS
+ CMAKE_INSTALL_INCLUDEDIR
+ CMAKE_INSTALL_LIBDIR
+)
+
+write_basic_package_version_file("${PROJECT_NAME}Version.cmake"
+ VERSION "${PROJECT_VERSION}"
+ COMPATIBILITY SameMajorVersion
+)
+
+install(
+ EXPORT main
+ FILE "${PROJECT_NAME}Targets.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+)
+
+install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Version.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+)
diff --git a/Tests/InstallMode/subpro_a_static_lib/cmake/PackageConfig.cmake.in b/Tests/InstallMode/subpro_a_static_lib/cmake/PackageConfig.cmake.in
new file mode 100644
index 0000000..0fe72c9
--- /dev/null
+++ b/Tests/InstallMode/subpro_a_static_lib/cmake/PackageConfig.cmake.in
@@ -0,0 +1,8 @@
+set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set_and_check(@PROJECT_NAME@_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(@PROJECT_NAME@_LIB_DIR "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
diff --git a/Tests/InstallMode/subpro_a_static_lib/include/static_lib.h b/Tests/InstallMode/subpro_a_static_lib/include/static_lib.h
new file mode 100644
index 0000000..bd82d2e
--- /dev/null
+++ b/Tests/InstallMode/subpro_a_static_lib/include/static_lib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void static_hello();
diff --git a/Tests/InstallMode/subpro_a_static_lib/src/static_lib.cpp b/Tests/InstallMode/subpro_a_static_lib/src/static_lib.cpp
new file mode 100644
index 0000000..fe1cd85
--- /dev/null
+++ b/Tests/InstallMode/subpro_a_static_lib/src/static_lib.cpp
@@ -0,0 +1,10 @@
+#include <iostream>
+
+#include <static_lib.h>
+
+using namespace std;
+
+void static_hello()
+{
+ cout << "Hello from static_lib" << endl;
+}
diff --git a/Tests/InstallMode/subpro_b_shared_lib/CMakeLists.txt b/Tests/InstallMode/subpro_b_shared_lib/CMakeLists.txt
new file mode 100644
index 0000000..eb118c9
--- /dev/null
+++ b/Tests/InstallMode/subpro_b_shared_lib/CMakeLists.txt
@@ -0,0 +1,66 @@
+# This CMakeLists.txt is part of the subproject B (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(shared_lib_project VERSION 2.3.4 LANGUAGES CXX)
+
+include(GNUInstallDirs)
+
+add_library(the_shared_lib SHARED
+ "include/shared_lib.h"
+ "src/shared_lib.cpp"
+)
+
+set_target_properties(the_shared_lib
+ PROPERTIES
+ VERSION "${PROJECT_VERSION}"
+ SOVERSION "${PROJECT_VERSION}"
+)
+
+target_include_directories(the_shared_lib PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+install(
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+install(
+ TARGETS
+ the_shared_lib
+ EXPORT main
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+ "cmake/PackageConfig.cmake.in"
+ "${PROJECT_NAME}Config.cmake"
+ INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
+ PATH_VARS
+ CMAKE_INSTALL_INCLUDEDIR
+ CMAKE_INSTALL_LIBDIR
+)
+
+write_basic_package_version_file("${PROJECT_NAME}Version.cmake"
+ VERSION "${PROJECT_VERSION}"
+ COMPATIBILITY SameMajorVersion
+)
+
+install(
+ EXPORT main
+ FILE "${PROJECT_NAME}Targets.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+)
+
+install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Version.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+)
diff --git a/Tests/InstallMode/subpro_b_shared_lib/cmake/PackageConfig.cmake.in b/Tests/InstallMode/subpro_b_shared_lib/cmake/PackageConfig.cmake.in
new file mode 100644
index 0000000..0fe72c9
--- /dev/null
+++ b/Tests/InstallMode/subpro_b_shared_lib/cmake/PackageConfig.cmake.in
@@ -0,0 +1,8 @@
+set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set_and_check(@PROJECT_NAME@_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(@PROJECT_NAME@_LIB_DIR "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
diff --git a/Tests/InstallMode/subpro_b_shared_lib/include/shared_lib.h b/Tests/InstallMode/subpro_b_shared_lib/include/shared_lib.h
new file mode 100644
index 0000000..fd960db
--- /dev/null
+++ b/Tests/InstallMode/subpro_b_shared_lib/include/shared_lib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void shared_hello();
diff --git a/Tests/InstallMode/subpro_b_shared_lib/src/shared_lib.cpp b/Tests/InstallMode/subpro_b_shared_lib/src/shared_lib.cpp
new file mode 100644
index 0000000..2820d5d
--- /dev/null
+++ b/Tests/InstallMode/subpro_b_shared_lib/src/shared_lib.cpp
@@ -0,0 +1,10 @@
+#include <iostream>
+
+#include <shared_lib.h>
+
+using namespace std;
+
+void shared_hello()
+{
+ cout << "Hello from shared_lib" << endl;
+}
diff --git a/Tests/InstallMode/subpro_c_nested_lib/CMakeLists.txt b/Tests/InstallMode/subpro_c_nested_lib/CMakeLists.txt
new file mode 100644
index 0000000..e397c02
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.20.0)
+
+project(subpro_c_nested_lib LANGUAGES NONE)
+
+include(../Subproject.cmake)
+add_subproject(c1_lib DIR subsubpro_c1_lib)
+add_subproject(c2_lib DIR subsubpro_c2_lib
+ DEPENDS
+ c1_lib
+)
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/CMakeLists.txt b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/CMakeLists.txt
new file mode 100644
index 0000000..89f3755
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/CMakeLists.txt
@@ -0,0 +1,61 @@
+# This CMakeLists.txt is a nested subproject of the
+# subproject C (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(c1_lib_project VERSION 1.2.3 LANGUAGES CXX)
+
+include(GNUInstallDirs)
+
+add_library(the_c1_lib STATIC
+ "include/c1_lib.h"
+ "src/c1_lib.cpp"
+)
+
+target_include_directories(the_c1_lib PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+install(
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+install(
+ TARGETS
+ the_c1_lib
+ EXPORT main
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+ "cmake/PackageConfig.cmake.in"
+ "${PROJECT_NAME}Config.cmake"
+ INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
+ PATH_VARS
+ CMAKE_INSTALL_INCLUDEDIR
+ CMAKE_INSTALL_LIBDIR
+)
+
+write_basic_package_version_file("${PROJECT_NAME}Version.cmake"
+ VERSION "${PROJECT_VERSION}"
+ COMPATIBILITY SameMajorVersion
+)
+
+install(
+ EXPORT main
+ FILE "${PROJECT_NAME}Targets.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+)
+
+install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Version.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+)
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/cmake/PackageConfig.cmake.in b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/cmake/PackageConfig.cmake.in
new file mode 100644
index 0000000..0fe72c9
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/cmake/PackageConfig.cmake.in
@@ -0,0 +1,8 @@
+set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set_and_check(@PROJECT_NAME@_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(@PROJECT_NAME@_LIB_DIR "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/include/c1_lib.h b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/include/c1_lib.h
new file mode 100644
index 0000000..245f9d4
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/include/c1_lib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void c1_hello();
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/src/c1_lib.cpp b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/src/c1_lib.cpp
new file mode 100644
index 0000000..c405056
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/src/c1_lib.cpp
@@ -0,0 +1,10 @@
+#include <iostream>
+
+#include <c1_lib.h>
+
+using namespace std;
+
+void c1_hello()
+{
+ cout << "Hello from c1_lib" << endl;
+}
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/CMakeLists.txt b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/CMakeLists.txt
new file mode 100644
index 0000000..e139446
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/CMakeLists.txt
@@ -0,0 +1,68 @@
+# This CMakeLists.txt is a nested subproject of the
+# subproject C (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(c2_lib_project VERSION 1.2.3 LANGUAGES CXX)
+
+find_package(c1_lib_project REQUIRED)
+
+include(GNUInstallDirs)
+
+add_library(the_c2_lib STATIC
+ "include/c2_lib.h"
+ "src/c2_lib.cpp"
+)
+
+target_link_libraries(the_c2_lib
+ PUBLIC
+ the_c1_lib
+)
+
+target_include_directories(the_c2_lib PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+install(
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+install(
+ TARGETS
+ the_c2_lib
+ EXPORT main
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+ "cmake/PackageConfig.cmake.in"
+ "${PROJECT_NAME}Config.cmake"
+ INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
+ PATH_VARS
+ CMAKE_INSTALL_INCLUDEDIR
+ CMAKE_INSTALL_LIBDIR
+)
+
+write_basic_package_version_file("${PROJECT_NAME}Version.cmake"
+ VERSION "${PROJECT_VERSION}"
+ COMPATIBILITY SameMajorVersion
+)
+
+install(
+ EXPORT main
+ FILE "${PROJECT_NAME}Targets.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+)
+
+install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Version.cmake"
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+)
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/cmake/PackageConfig.cmake.in b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/cmake/PackageConfig.cmake.in
new file mode 100644
index 0000000..45a177a
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/cmake/PackageConfig.cmake.in
@@ -0,0 +1,11 @@
+set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set_and_check(@PROJECT_NAME@_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(@PROJECT_NAME@_LIB_DIR "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
+
+include(CMakeFindDependencyMacro)
+find_dependency(c1_lib_project REQUIRED)
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/include/c2_lib.h b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/include/c2_lib.h
new file mode 100644
index 0000000..5056814
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/include/c2_lib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void c2_hello();
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/src/c2_lib.cpp b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/src/c2_lib.cpp
new file mode 100644
index 0000000..cd2c932
--- /dev/null
+++ b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/src/c2_lib.cpp
@@ -0,0 +1,12 @@
+#include <iostream>
+
+#include <c1_lib.h>
+#include <c2_lib.h>
+
+using namespace std;
+
+void c2_hello()
+{
+ cout << "Hello from c2_lib and also..." << endl;
+ c1_hello();
+}
diff --git a/Tests/InstallMode/subpro_d_executable/CMakeLists.txt b/Tests/InstallMode/subpro_d_executable/CMakeLists.txt
new file mode 100644
index 0000000..9847227
--- /dev/null
+++ b/Tests/InstallMode/subpro_d_executable/CMakeLists.txt
@@ -0,0 +1,24 @@
+# This CMakeLists.txt is part of the subproject B (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(subpro_d_executable LANGUAGES CXX)
+
+find_package(static_lib_project REQUIRED)
+find_package(shared_lib_project REQUIRED)
+find_package(c2_lib_project REQUIRED)
+
+add_executable(the_executable
+ "src/main.cpp"
+)
+
+target_link_libraries(the_executable PRIVATE
+ the_static_lib
+ the_shared_lib
+ the_c2_lib
+)
+
+install(
+ TARGETS
+ the_executable
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+)
diff --git a/Tests/InstallMode/subpro_d_executable/src/main.cpp b/Tests/InstallMode/subpro_d_executable/src/main.cpp
new file mode 100644
index 0000000..ec12004
--- /dev/null
+++ b/Tests/InstallMode/subpro_d_executable/src/main.cpp
@@ -0,0 +1,13 @@
+#include <cstdlib>
+
+#include <c2_lib.h>
+#include <shared_lib.h>
+#include <static_lib.h>
+
+int main()
+{
+ static_hello();
+ shared_hello();
+ c2_hello();
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/InstallMode/superpro/CMakeLists.txt b/Tests/InstallMode/superpro/CMakeLists.txt
new file mode 100644
index 0000000..ae4d25c
--- /dev/null
+++ b/Tests/InstallMode/superpro/CMakeLists.txt
@@ -0,0 +1,29 @@
+# This CMakeLists.txt is part of the superproject (add_subdirectory).
+
+# Below file transfers are executed at configuration time!
+
+file(
+ COPY
+ "file_copy.txt"
+ DESTINATION
+ "${CMAKE_INSTALL_PREFIX}"
+)
+
+file(COPY_FILE
+ "${CMAKE_CURRENT_SOURCE_DIR}/file_copy_file.txt"
+ "${CMAKE_INSTALL_PREFIX}/file_copy_file.txt"
+)
+
+file(
+ INSTALL
+ "file_install.txt"
+ DESTINATION
+ "${CMAKE_INSTALL_PREFIX}"
+)
+
+file(
+ CREATE_LINK
+ "${CMAKE_CURRENT_SOURCE_DIR}/file_create_link_symbolic.txt"
+ "${CMAKE_INSTALL_PREFIX}/file_create_link_symbolic.txt"
+ SYMBOLIC
+)
diff --git a/Tests/InstallMode/superpro/file_copy.txt b/Tests/InstallMode/superpro/file_copy.txt
new file mode 100644
index 0000000..aacbb96
--- /dev/null
+++ b/Tests/InstallMode/superpro/file_copy.txt
@@ -0,0 +1 @@
+This file should always be copied into CMAKE_INSTALL_PREFIX.
diff --git a/Tests/InstallMode/superpro/file_copy_file.txt b/Tests/InstallMode/superpro/file_copy_file.txt
new file mode 100644
index 0000000..aacbb96
--- /dev/null
+++ b/Tests/InstallMode/superpro/file_copy_file.txt
@@ -0,0 +1 @@
+This file should always be copied into CMAKE_INSTALL_PREFIX.
diff --git a/Tests/InstallMode/superpro/file_create_link_symbolic.txt b/Tests/InstallMode/superpro/file_create_link_symbolic.txt
new file mode 100644
index 0000000..16a481b
--- /dev/null
+++ b/Tests/InstallMode/superpro/file_create_link_symbolic.txt
@@ -0,0 +1,2 @@
+This file should always be installed into CMAKE_INSTALL_PREFIX
+as a symbolic link to the original file.
diff --git a/Tests/InstallMode/superpro/file_install.txt b/Tests/InstallMode/superpro/file_install.txt
new file mode 100644
index 0000000..eac9782
--- /dev/null
+++ b/Tests/InstallMode/superpro/file_install.txt
@@ -0,0 +1,6 @@
+This file should be placed in CMAKE_INSTALL_PREFIX
+as a copy if the CMAKE_INSTALL_MODE environment variable
+is unset or equals "COPY".
+If the variable's value is "SYMLINK" or "SYMLINK_OR_COPY",
+the CMAKE_INSTALL_PREFIX should rather receive a symbolic
+link to this file.