summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2021-06-08 12:08:57 (GMT)
committerKitware Robot <kwrobot@kitware.com>2021-06-08 12:09:04 (GMT)
commitacb25d50d9d37e93cafcbbc4401e1b45029b6461 (patch)
tree078d3f511f584e4f924a9380f9539aa122a2263e
parent3653dc60690e6fc33d9e7bf44186b82587cf21a7 (diff)
parent8d898cb3e10d6ad44bbe542b7b219a0b788b2a0d (diff)
downloadCMake-acb25d50d9d37e93cafcbbc4401e1b45029b6461.zip
CMake-acb25d50d9d37e93cafcbbc4401e1b45029b6461.tar.gz
CMake-acb25d50d9d37e93cafcbbc4401e1b45029b6461.tar.bz2
Merge topic 'install-with-runtime-dependencies'
8d898cb3e1 FileAPI: Add integration for runtime dependency installers 72f2448e82 Help: Add documentation for runtime dependency installation 0c3c6acaff Tests: Add tests for new options 4910132d8c install: Add RUNTIME_DEPENDENCY_SET mode bc8a4a06a4 install(IMPORTED_RUNTIME_ARTIFACTS): Add RUNTIME_DEPENDENCY_SET option 3e7d3c252a install(TARGETS): Add RUNTIME_DEPENDENCY_SET argument ed3633d88c install(TARGETS): Add RUNTIME_DEPENDENCIES option f2617cf8e6 Source: Add cmInstallRuntimeDependencySet ... Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !6186
-rw-r--r--Help/command/install.rst108
-rw-r--r--Help/manual/cmake-file-api.7.rst24
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst5
-rw-r--r--Help/release/dev/install-runtime-dependencies.rst9
-rw-r--r--Source/CMakeLists.txt6
-rw-r--r--Source/cmBinUtilsMacOSMachOLinker.cxx22
-rw-r--r--Source/cmBinUtilsMacOSMachOLinker.h2
-rw-r--r--Source/cmFileAPICodemodel.cxx28
-rw-r--r--Source/cmFileCommand.cxx211
-rw-r--r--Source/cmGlobalGenerator.cxx24
-rw-r--r--Source/cmGlobalGenerator.h11
-rw-r--r--Source/cmInstallCommand.cxx361
-rw-r--r--Source/cmInstallGenerator.cxx51
-rw-r--r--Source/cmInstallGenerator.h3
-rw-r--r--Source/cmInstallGetRuntimeDependenciesGenerator.cxx206
-rw-r--r--Source/cmInstallGetRuntimeDependenciesGenerator.h56
-rw-r--r--Source/cmInstallRuntimeDependencySet.cxx95
-rw-r--r--Source/cmInstallRuntimeDependencySet.h163
-rw-r--r--Source/cmInstallRuntimeDependencySetGenerator.cxx276
-rw-r--r--Source/cmInstallRuntimeDependencySetGenerator.h74
-rw-r--r--Source/cmRuntimeDependencyArchive.cxx39
-rw-r--r--Source/cmRuntimeDependencyArchive.h26
-rw-r--r--Source/cmSystemTools.cxx210
-rw-r--r--Source/cmSystemTools.h6
-rw-r--r--Tests/CMakeLists.txt1
-rw-r--r--Tests/ExportImport/CMakeLists.txt36
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt2
-rw-r--r--Tests/ExportImport/Export/install-RUNTIME_DEPENDENCY_SET/CMakeLists.txt42
-rw-r--r--Tests/ExportImport/Export/install-RUNTIME_DEPENDENCY_SET/deplib.c12
-rw-r--r--Tests/ExportImport/Import/CMakeLists.txt6
-rw-r--r--Tests/ExportImport/Import/check_installed.cmake20
-rw-r--r--Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake21
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt74
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/check_installed.cmake11
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/lib.c12
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/main.c31
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/mod.c12
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/sublib1.c12
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/sublib2.c12
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/CMakeLists.txt33
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/check_installed.cmake11
-rw-r--r--Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/main.c15
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-check.py16
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json163
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json17
-rw-r--r--Tests/RunCMake/FileAPI/cxx/CMakeLists.txt15
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-rpath.cmake35
-rw-r--r--Tests/RunCMake/file-RPATH/Common.cmake37
-rw-r--r--Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported-result.txt1
-rw-r--r--Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt6
-rw-r--r--Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported.cmake2
-rw-r--r--Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported-result.txt1
-rw-r--r--Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt5
-rw-r--r--Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported.cmake1
-rw-r--r--Tests/RunCMake/install/RunCMakeTest.cmake22
-rw-r--r--Tests/RunCMake/install/RuntimeDependencies-COMPONENTS.cmake39
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake9
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake10
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake9
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt5
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict-stderr.txt5
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict.cmake7
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt5
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported.cmake4
-rwxr-xr-xbootstrap3
80 files changed, 2585 insertions, 244 deletions
diff --git a/Help/command/install.rst b/Help/command/install.rst
index 4d41fb3..acfaa48 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -15,6 +15,7 @@ Synopsis
install(`SCRIPT`_ <file> [...])
install(`CODE`_ <code> [...])
install(`EXPORT`_ <export-name> [...])
+ install(`RUNTIME_DEPENDENCY_SET`_ <set-name> [...])
Introduction
^^^^^^^^^^^^
@@ -125,6 +126,7 @@ Installing Targets
.. code-block:: cmake
install(TARGETS targets... [EXPORT <export-name>]
+ [RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>]
[[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
@@ -339,6 +341,34 @@ top level:
relative path is specified, it is treated as relative to the
``$<INSTALL_PREFIX>``.
+``RUNTIME_DEPENDENCY_SET``
+ .. versionadded:: 3.21
+
+ This option causes all runtime dependencies of installed executable, shared
+ library, and module targets to be added to the specified runtime dependency
+ set. This set can then be installed later on with an
+ `install(RUNTIME_DEPENDENCY_SET)`_ command.
+
+ This argument and the ``RUNTIME_DEPENDENCIES`` argument are mutually
+ exclusive.
+
+``RUNTIME_DEPENDENCIES``
+ .. versionadded:: 3.21
+
+ This option causes all runtime dependencies of installed executable, shared
+ library, and module targets to be installed along with the targets
+ themselves. The ``RUNTIME``, ``LIBRARY``, ``FRAMEWORK``, and generic
+ arguments are used to determine the properties (``DESTINATION``,
+ ``COMPONENT``, etc.) of the installation of these dependencies.
+
+ ``RUNTIME_DEPENDENCIES`` is semantically equivalent to calling
+ ``install(TARGETS ... RUNTIME_DEPENDENCY_SET)`` and then
+ `install(RUNTIME_DEPENDENCY_SET)`_ with a randomly generated name. It accepts
+ all of the same options as `install(RUNTIME_DEPENDENCY_SET)`_.
+
+ This argument and the ``RUNTIME_DEPENDENCY_SET`` argument are mutually
+ exclusive.
+
One or more groups of properties may be specified in a single call to
the ``TARGETS`` form of this command. A target may be installed more than
once to different locations. Consider hypothetical targets ``myExe``,
@@ -394,6 +424,7 @@ Installing Imported Runtime Artifacts
.. code-block:: cmake
install(IMPORTED_RUNTIME_ARTIFACTS targets...
+ [RUNTIME_DEPENDENCY_SET <set-name>]
[[LIBRARY|RUNTIME|FRAMEWORK|BUNDLE]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
@@ -415,6 +446,15 @@ not installed. In the case of :prop_tgt:`FRAMEWORK` libraries,
:prop_tgt:`MACOSX_BUNDLE` executables, and :prop_tgt:`BUNDLE` CFBundles, the
entire directory is installed.
+``IMPORTED_RUNTIME_ARTIFACTS`` accepts the following additional arguments:
+
+``RUNTIME_DEPENDENCY_SET``
+
+ This option causes all runtime dependencies of installed executable, shared
+ library, and module targets to be added to the specified runtime dependency
+ set. This set can then be installed later on with an
+ `install(RUNTIME_DEPENDENCY_SET)`_ command.
+
Installing Files
^^^^^^^^^^^^^^^^
@@ -773,6 +813,74 @@ executable from the installation tree using the imported target name
:command:`install_files`, and :command:`install_programs` commands
is not defined.
+Installing Runtime Dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. _`install(RUNTIME_DEPENDENCY_SET)`:
+.. _RUNTIME_DEPENDENCY_SET:
+
+.. versionadded:: 3.21
+
+.. code-block:: cmake
+
+ install(RUNTIME_DEPENDENCY_SET <set-name>
+ [[LIBRARY|RUNTIME|FRAMEWORK]
+ [DESTINATION <dir>]
+ [PERMISSIONS permissions...]
+ [CONFIGURATIONS [Debug|Release|...]]
+ [COMPONENT <component>]
+ [NAMELINK_COMPONENT <component>]
+ [OPTIONAL] [EXCLUDE_FROM_ALL]
+ ] [...]
+ [PRE_INCLUDE_REGEXES regexes...]
+ [PRE_EXCLUDE_REGEXES regexes...]
+ [POST_INCLUDE_REGEXES regexes...]
+ [POST_EXCLUDE_REGEXES regexes...]
+ [DIRECTORIES directories...]
+ )
+
+Installs a runtime dependency set created by one or more
+`install(TARGETS)`_ or `install(IMPORTED_RUNTIME_ARTIFACTS)`_ commands. The
+dependencies of targets belonging to a runtime dependency set are installed in
+the ``RUNTIME`` destination and component on DLL platforms, and in the
+``LIBRARY`` destination and component on non-DLL platforms. macOS frameworks
+are installed in the ``FRAMEWORK`` destination and component. The generated
+install script calls :command:`file(GET_RUNTIME_DEPENDENCIES)` on the
+build-tree files to calculate the runtime dependencies, with the build-tree
+executable files as the ``EXECUTABLES`` argument, the build-tree shared
+libraries as the ``LIBRARIES`` argument, and the build-tree modules as the
+``MODULES`` argument. If one of the executables is a :prop_tgt:`MACOSX_BUNDLE`
+executable on a macOS platform, that executable is passed as the
+``BUNDLE_EXECUTABLE`` argument. If ``RUNTIME_DEPENDENCY_SET`` is specified on
+a macOS platform, at most one :prop_tgt:`MACOSX_BUNDLE` executable may be in
+the runtime dependency set. The :prop_tgt:`MACOSX_BUNDLE` property has no
+effect on non-macOS platforms. Targets built within the build tree will never
+be installed as runtime dependencies, nor will their own dependencies, unless
+the targets themselves are installed with `install(TARGETS)`_.
+
+This argument accepts the following sub-arguments:
+
+``DIRECTORIES <directories>``
+ List of directories to be passed as the ``DIRECTORIES`` argument of
+ :command:`file(GET_RUNTIME_DEPENDENCIES)`. This argument supports
+ :manual:`generator expressions <cmake-generator-expressions(7)>`. If a
+ ``DIRECTORIES`` argument evaluates to an empty string, it is not passed to
+ :command:`file(GET_RUNTIME_DEPENDENCIES)`.
+
+``PRE_INCLUDE_REGEXES <regexes>``, ``PRE_EXCLUDE_REGEXES <regexes>``, ``POST_INCLUDE_REGEXES <regexes>``, ``POST_EXCLUDE_REGEXES <regexes>``
+ List of regular expressions to be passed as their respective arguments to
+ :command:`file(GET_RUNTIME_DEPENDENCIES)`. These arguments support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`. If an
+ argument evaluates to an empty string, it is not passed to
+ :command:`file(GET_RUNTIME_DEPENDENCIES)`.
+
+``POST_INCLUDE_FILES <files>``, ``POST_EXCLUDE_FILES <files>``
+ List of files to be passed as their respective arguments to
+ :command:`file(GET_RUNTIME_DEPENDENCIES)`. These arguments support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`. If an
+ argument evaluates to an empty string, it is not passed to
+ :command:`file(GET_RUNTIME_DEPENDENCIES)`.
+
Generated Installation Script
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index e7d78c3..5e22ea9 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -752,6 +752,12 @@ with members:
The ``destination`` member is populated. The ``isOptional`` member may
exist. This type has no additional members.
+ ``runtimeDependencySet``
+ An :command:`install(RUNTIME_DEPENDENCY_SET)` call or an
+ :command:`install(TARGETS)` call with ``RUNTIME_DEPENDENCIES``. The
+ ``destination`` member is populated. This type has additional members
+ ``runtimeDependencySetName`` and ``runtimeDependencySetType``.
+
``isExcludeFromAll``
Optional member that is present with boolean value ``true`` when
:command:`install` is called with the ``EXCLUDE_FROM_ALL`` option.
@@ -811,6 +817,24 @@ with members:
An unsigned integer 0-based index into the main "codemodel"
object's ``targets`` array for the target.
+ ``runtimeDependencySetName``
+ Optional member that is present when ``type`` is ``runtimeDependencySet``
+ and the installer was created by an
+ :command:`install(RUNTIME_DEPENDENCY_SET)` call. The value is a string
+ specifying the name of the runtime dependency set that was installed.
+
+ ``runtimeDependencySetType``
+ Optional member that is present when ``type`` is ``runtimeDependencySet``.
+ The value is a string with one of the following values:
+
+ ``library``
+ Indicates that this installer installs dependencies that are not macOS
+ frameworks.
+
+ ``framework``
+ Indicates that this installer installs dependencies that are macOS
+ frameworks.
+
``scriptFile``
Optional member that is present when ``type`` is ``script``.
The value is a string specifying the path to the script file on disk,
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 775067a..0ba41c8 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -966,8 +966,9 @@ which is just the string ``tgt``.
.. genex:: $<INSTALL_PREFIX>
Content of the install prefix when the target is exported via
- :command:`install(EXPORT)`, or when evaluated in
- :prop_tgt:`INSTALL_NAME_DIR`, and empty otherwise.
+ :command:`install(EXPORT)`, or when evaluated in the
+ :prop_tgt:`INSTALL_NAME_DIR` property or the ``INSTALL_NAME_DIR`` argument of
+ :command:`install(RUNTIME_DEPENDENCY_SET)`, and empty otherwise.
Output-Related Expressions
--------------------------
diff --git a/Help/release/dev/install-runtime-dependencies.rst b/Help/release/dev/install-runtime-dependencies.rst
new file mode 100644
index 0000000..58c92e6
--- /dev/null
+++ b/Help/release/dev/install-runtime-dependencies.rst
@@ -0,0 +1,9 @@
+install-runtime-dependencies
+----------------------------
+
+* The :command:`install(TARGETS)` command gained new ``RUNTIME_DEPENDENCIES``
+ and ``RUNTIME_DEPENDENCY_SET`` arguments, which can be used to install
+ runtime dependencies using :command:`file(GET_RUNTIME_DEPENDENCIES)`.
+* The :command:`install` command gained a new ``RUNTIME_DEPENDENCY_SET`` mode,
+ which can be used to install runtime dependencies using
+ :command:`file(GET_RUNTIME_DEPENDENCIES)`.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 844a2ee..9a18184 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -345,6 +345,8 @@ set(SRCS
cmGraphVizWriter.h
cmInstallGenerator.h
cmInstallGenerator.cxx
+ cmInstallGetRuntimeDependenciesGenerator.h
+ cmInstallGetRuntimeDependenciesGenerator.cxx
cmInstallExportGenerator.cxx
cmInstalledFile.h
cmInstalledFile.cxx
@@ -352,6 +354,10 @@ set(SRCS
cmInstallFilesGenerator.cxx
cmInstallImportedRuntimeArtifactsGenerator.h
cmInstallImportedRuntimeArtifactsGenerator.cxx
+ cmInstallRuntimeDependencySet.h
+ cmInstallRuntimeDependencySet.cxx
+ cmInstallRuntimeDependencySetGenerator.h
+ cmInstallRuntimeDependencySetGenerator.cxx
cmInstallScriptGenerator.h
cmInstallScriptGenerator.cxx
cmInstallSubdirectoryGenerator.h
diff --git a/Source/cmBinUtilsMacOSMachOLinker.cxx b/Source/cmBinUtilsMacOSMachOLinker.cxx
index 0f47146..47f77d8 100644
--- a/Source/cmBinUtilsMacOSMachOLinker.cxx
+++ b/Source/cmBinUtilsMacOSMachOLinker.cxx
@@ -65,18 +65,18 @@ bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
if (!executableFile.empty()) {
executablePath = cmSystemTools::GetFilenamePath(executableFile);
}
- return this->ScanDependencies(file, executablePath);
-}
-
-bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
- std::string const& file, std::string const& executablePath)
-{
std::vector<std::string> libs;
std::vector<std::string> rpaths;
if (!this->Tool->GetFileInfo(file, libs, rpaths)) {
return false;
}
+ return this->ScanDependencies(file, libs, rpaths, executablePath);
+}
+bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
+ std::string const& file, std::vector<std::string> const& libs,
+ std::vector<std::string> const& rpaths, std::string const& executablePath)
+{
std::string loaderPath = cmSystemTools::GetFilenamePath(file);
return this->GetFileDependencies(libs, executablePath, loaderPath, rpaths);
}
@@ -98,8 +98,14 @@ bool cmBinUtilsMacOSMachOLinker::GetFileDependencies(
!IsMissingSystemDylib(path)) {
auto filename = cmSystemTools::GetFilenameName(path);
bool unique;
- this->Archive->AddResolvedPath(filename, path, unique);
- if (unique && !this->ScanDependencies(path, executablePath)) {
+ std::vector<std::string> libs;
+ std::vector<std::string> depRpaths;
+ if (!this->Tool->GetFileInfo(path, libs, depRpaths)) {
+ return false;
+ }
+ this->Archive->AddResolvedPath(filename, path, unique, depRpaths);
+ if (unique &&
+ !this->ScanDependencies(path, libs, depRpaths, executablePath)) {
return false;
}
}
diff --git a/Source/cmBinUtilsMacOSMachOLinker.h b/Source/cmBinUtilsMacOSMachOLinker.h
index 1c4a5fc..eae23cc 100644
--- a/Source/cmBinUtilsMacOSMachOLinker.h
+++ b/Source/cmBinUtilsMacOSMachOLinker.h
@@ -27,6 +27,8 @@ private:
std::unique_ptr<cmBinUtilsMacOSMachOGetRuntimeDependenciesTool> Tool;
bool ScanDependencies(std::string const& file,
+ std::vector<std::string> const& libs,
+ std::vector<std::string> const& rpaths,
std::string const& executablePath);
bool GetFileDependencies(std::vector<std::string> const& names,
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index efe1ab6..2d6745c 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -15,6 +15,7 @@
#include <utility>
#include <vector>
+#include <cm/string_view>
#include <cmext/algorithm>
#include <cm3p/json/value.h>
@@ -29,7 +30,10 @@
#include "cmInstallExportGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
+#include "cmInstallGetRuntimeDependenciesGenerator.h"
#include "cmInstallImportedRuntimeArtifactsGenerator.h"
+#include "cmInstallRuntimeDependencySet.h"
+#include "cmInstallRuntimeDependencySetGenerator.h"
#include "cmInstallScriptGenerator.h"
#include "cmInstallSubdirectoryGenerator.h"
#include "cmInstallTargetGenerator.h"
@@ -877,8 +881,10 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
assert(gen);
Json::Value installer = Json::objectValue;
- // Exclude subdirectory installers. They are implementation details.
- if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen)) {
+ // Exclude subdirectory installers and file(GET_RUNTIME_DEPENDENCIES)
+ // installers. They are implementation details.
+ if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen) ||
+ dynamic_cast<cmInstallGetRuntimeDependenciesGenerator*>(gen)) {
return installer;
}
@@ -1020,6 +1026,24 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
if (installImportedRuntimeArtifacts->GetOptional()) {
installer["isOptional"] = true;
}
+ } else if (auto* installRuntimeDependencySet =
+ dynamic_cast<cmInstallRuntimeDependencySetGenerator*>(gen)) {
+ installer["type"] = "runtimeDependencySet";
+ installer["destination"] =
+ installRuntimeDependencySet->GetDestination(this->Config);
+ std::string name(
+ installRuntimeDependencySet->GetRuntimeDependencySet()->GetName());
+ if (!name.empty()) {
+ installer["runtimeDependencySetName"] = name;
+ }
+ switch (installRuntimeDependencySet->GetDependencyType()) {
+ case cmInstallRuntimeDependencySetGenerator::DependencyType::Framework:
+ installer["runtimeDependencySetType"] = "framework";
+ break;
+ case cmInstallRuntimeDependencySetGenerator::DependencyType::Library:
+ installer["runtimeDependencySetType"] = "library";
+ break;
+ }
}
// Add fields common to all install generators.
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index f2d4cda..0ad59c7 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -990,50 +990,42 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- const char* oldRPath = nullptr;
- const char* newRPath = nullptr;
+ std::string oldRPath;
+ std::string newRPath;
bool removeEnvironmentRPath = false;
- enum Doing
- {
- DoingNone,
- DoingFile,
- DoingOld,
- DoingNew
- };
- Doing doing = DoingNone;
- for (unsigned int i = 1; i < args.size(); ++i) {
- if (args[i] == "OLD_RPATH") {
- doing = DoingOld;
- } else if (args[i] == "NEW_RPATH") {
- doing = DoingNew;
- } else if (args[i] == "FILE") {
- doing = DoingFile;
- } else if (args[i] == "INSTALL_REMOVE_ENVIRONMENT_RPATH") {
- removeEnvironmentRPath = true;
- } else if (doing == DoingFile) {
- file = args[i];
- doing = DoingNone;
- } else if (doing == DoingOld) {
- oldRPath = args[i].c_str();
- doing = DoingNone;
- } else if (doing == DoingNew) {
- newRPath = args[i].c_str();
- doing = DoingNone;
- } else {
- status.SetError(
- cmStrCat("RPATH_CHANGE given unknown argument ", args[i]));
- return false;
- }
+ cmArgumentParser<void> parser;
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> missingArgs;
+ std::vector<std::string> parsedArgs;
+ parser.Bind("FILE"_s, file)
+ .Bind("OLD_RPATH"_s, oldRPath)
+ .Bind("NEW_RPATH"_s, newRPath)
+ .Bind("INSTALL_REMOVE_ENVIRONMENT_RPATH"_s, removeEnvironmentRPath);
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
+ &parsedArgs);
+ if (!unknownArgs.empty()) {
+ status.SetError(
+ cmStrCat("RPATH_CHANGE given unknown argument ", unknownArgs.front()));
+ return false;
+ }
+ if (!missingArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_CHANGE \"", missingArgs.front(),
+ "\" argument not given value."));
+ return false;
}
if (file.empty()) {
status.SetError("RPATH_CHANGE not given FILE option.");
return false;
}
- if (!oldRPath) {
+ if (oldRPath.empty() &&
+ std::find(parsedArgs.begin(), parsedArgs.end(), "OLD_RPATH") ==
+ parsedArgs.end()) {
status.SetError("RPATH_CHANGE not given OLD_RPATH option.");
return false;
}
- if (!newRPath) {
+ if (newRPath.empty() &&
+ std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") ==
+ parsedArgs.end()) {
status.SetError("RPATH_CHANGE not given NEW_RPATH option.");
return false;
}
@@ -1065,28 +1057,85 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args,
return success;
}
+bool HandleRPathSetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Evaluate arguments.
+ std::string file;
+ std::string newRPath;
+ cmArgumentParser<void> parser;
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> missingArgs;
+ std::vector<std::string> parsedArgs;
+ parser.Bind("FILE"_s, file).Bind("NEW_RPATH"_s, newRPath);
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
+ &parsedArgs);
+ if (!unknownArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_SET given unrecognized argument \"",
+ unknownArgs.front(), "\"."));
+ return false;
+ }
+ if (!missingArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_SET \"", missingArgs.front(),
+ "\" argument not given value."));
+ return false;
+ }
+ if (file.empty()) {
+ status.SetError("RPATH_SET not given FILE option.");
+ return false;
+ }
+ if (newRPath.empty() &&
+ std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") ==
+ parsedArgs.end()) {
+ status.SetError("RPATH_SET not given NEW_RPATH option.");
+ return false;
+ }
+ if (!cmSystemTools::FileExists(file, true)) {
+ status.SetError(
+ cmStrCat("RPATH_SET given FILE \"", file, "\" that does not exist."));
+ return false;
+ }
+ bool success = true;
+ cmFileTimes const ft(file);
+ std::string emsg;
+ bool changed;
+
+ if (!cmSystemTools::SetRPath(file, newRPath, &emsg, &changed)) {
+ status.SetError(cmStrCat("RPATH_SET could not write new RPATH:\n ",
+ newRPath, "\nto the file:\n ", file, "\n",
+ emsg));
+ success = false;
+ }
+ if (success) {
+ if (changed) {
+ std::string message =
+ cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"');
+ status.GetMakefile().DisplayStatus(message, -1);
+ }
+ ft.Store(file);
+ }
+ return success;
+}
+
bool HandleRPathRemoveCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
// Evaluate arguments.
std::string file;
- enum Doing
- {
- DoingNone,
- DoingFile
- };
- Doing doing = DoingNone;
- for (unsigned int i = 1; i < args.size(); ++i) {
- if (args[i] == "FILE") {
- doing = DoingFile;
- } else if (doing == DoingFile) {
- file = args[i];
- doing = DoingNone;
- } else {
- status.SetError(
- cmStrCat("RPATH_REMOVE given unknown argument ", args[i]));
- return false;
- }
+ cmArgumentParser<void> parser;
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> missingArgs;
+ parser.Bind("FILE"_s, file);
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs);
+ if (!unknownArgs.empty()) {
+ status.SetError(
+ cmStrCat("RPATH_REMOVE given unknown argument ", unknownArgs.front()));
+ return false;
+ }
+ if (!missingArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_REMOVE \"", missingArgs.front(),
+ "\" argument not given value."));
+ return false;
}
if (file.empty()) {
status.SetError("RPATH_REMOVE not given FILE option.");
@@ -1123,36 +1172,31 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- const char* rpath = nullptr;
- enum Doing
- {
- DoingNone,
- DoingFile,
- DoingRPath
- };
- Doing doing = DoingNone;
- for (unsigned int i = 1; i < args.size(); ++i) {
- if (args[i] == "RPATH") {
- doing = DoingRPath;
- } else if (args[i] == "FILE") {
- doing = DoingFile;
- } else if (doing == DoingFile) {
- file = args[i];
- doing = DoingNone;
- } else if (doing == DoingRPath) {
- rpath = args[i].c_str();
- doing = DoingNone;
- } else {
- status.SetError(
- cmStrCat("RPATH_CHECK given unknown argument ", args[i]));
- return false;
- }
+ std::string rpath;
+ cmArgumentParser<void> parser;
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> missingArgs;
+ std::vector<std::string> parsedArgs;
+ parser.Bind("FILE"_s, file).Bind("RPATH"_s, rpath);
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
+ &parsedArgs);
+ if (!unknownArgs.empty()) {
+ status.SetError(
+ cmStrCat("RPATH_CHECK given unknown argument ", unknownArgs.front()));
+ return false;
+ }
+ if (!missingArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_CHECK \"", missingArgs.front(),
+ "\" argument not given value."));
+ return false;
}
if (file.empty()) {
status.SetError("RPATH_CHECK not given FILE option.");
return false;
}
- if (!rpath) {
+ if (rpath.empty() &&
+ std::find(parsedArgs.begin(), parsedArgs.end(), "RPATH") ==
+ parsedArgs.end()) {
status.SetError("RPATH_CHECK not given RPATH option.");
return false;
}
@@ -3000,11 +3044,10 @@ bool HandleCreateLinkCommand(std::vector<std::string> const& args,
bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
- "Darwin" };
std::string platform =
status.GetMakefile().GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
- if (!supportedPlatforms.count(platform)) {
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ platform)) {
status.SetError(
cmStrCat("GET_RUNTIME_DEPENDENCIES is not supported on system \"",
platform, "\""));
@@ -3032,6 +3075,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
std::string ResolvedDependenciesVar;
std::string UnresolvedDependenciesVar;
std::string ConflictingDependenciesPrefix;
+ std::string RPathPrefix;
std::string BundleExecutable;
std::vector<std::string> Executables;
std::vector<std::string> Libraries;
@@ -3053,6 +3097,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
&Arguments::UnresolvedDependenciesVar)
.Bind("CONFLICTING_DEPENDENCIES_PREFIX"_s,
&Arguments::ConflictingDependenciesPrefix)
+ .Bind("RPATH_PREFIX"_s, &Arguments::RPathPrefix)
.Bind("BUNDLE_EXECUTABLE"_s, &Arguments::BundleExecutable)
.Bind("EXECUTABLES"_s, &Arguments::Executables)
.Bind("LIBRARIES"_s, &Arguments::Libraries)
@@ -3135,6 +3180,11 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
if (unique) {
deps.push_back(firstPath);
+ if (!parsedArgs.RPathPrefix.empty()) {
+ status.GetMakefile().AddDefinition(
+ parsedArgs.RPathPrefix + "_" + firstPath,
+ cmJoin(archive.GetRPaths().at(firstPath), ";"));
+ }
} else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
conflictingDeps.push_back(val.first);
std::vector<std::string> paths;
@@ -3741,6 +3791,7 @@ bool cmFileCommand(std::vector<std::string> const& args,
{ "DIFFERENT"_s, HandleDifferentCommand },
{ "RPATH_CHANGE"_s, HandleRPathChangeCommand },
{ "CHRPATH"_s, HandleRPathChangeCommand },
+ { "RPATH_SET"_s, HandleRPathSetCommand },
{ "RPATH_CHECK"_s, HandleRPathCheckCommand },
{ "RPATH_REMOVE"_s, HandleRPathRemoveCommand },
{ "READ_ELF"_s, HandleReadElfCommand },
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index d7da0d3..9193778 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -36,6 +36,7 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmInstallGenerator.h"
+#include "cmInstallRuntimeDependencySet.h"
#include "cmLinkLineComputer.h"
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
@@ -3332,3 +3333,26 @@ bool cmGlobalGenerator::GenerateCPackPropertiesFile()
return true;
}
+
+cmInstallRuntimeDependencySet*
+cmGlobalGenerator::CreateAnonymousRuntimeDependencySet()
+{
+ auto set = cm::make_unique<cmInstallRuntimeDependencySet>();
+ auto* retval = set.get();
+ this->RuntimeDependencySets.push_back(std::move(set));
+ return retval;
+}
+
+cmInstallRuntimeDependencySet* cmGlobalGenerator::GetNamedRuntimeDependencySet(
+ const std::string& name)
+{
+ auto it = this->RuntimeDependencySetsByName.find(name);
+ if (it == this->RuntimeDependencySetsByName.end()) {
+ auto set = cm::make_unique<cmInstallRuntimeDependencySet>(name);
+ it =
+ this->RuntimeDependencySetsByName.insert(std::make_pair(name, set.get()))
+ .first;
+ this->RuntimeDependencySets.push_back(std::move(set));
+ }
+ return it->second;
+}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index fee0359..147146e 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -42,6 +42,7 @@ class cmDirectoryId;
class cmExportBuildFileGenerator;
class cmExternalMakefileProjectGenerator;
class cmGeneratorTarget;
+class cmInstallRuntimeDependencySet;
class cmLinkLineComputer;
class cmLocalGenerator;
class cmMakefile;
@@ -528,6 +529,11 @@ public:
std::string NewDeferId();
+ cmInstallRuntimeDependencySet* CreateAnonymousRuntimeDependencySet();
+
+ cmInstallRuntimeDependencySet* GetNamedRuntimeDependencySet(
+ const std::string& name);
+
protected:
// for a project collect all its targets by following depend
// information, and also collect all the targets
@@ -747,6 +753,11 @@ private:
std::unordered_set<std::string> GeneratedFiles;
+ std::vector<std::unique_ptr<cmInstallRuntimeDependencySet>>
+ RuntimeDependencySets;
+ std::map<std::string, cmInstallRuntimeDependencySet*>
+ RuntimeDependencySetsByName;
+
#if !defined(CMAKE_BOOTSTRAP)
// Pool of file locks
cmFileLockPool FileLockPool;
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index c9bb467..79109b5 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -2,8 +2,10 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallCommand.h"
+#include <algorithm>
#include <cassert>
#include <cstddef>
+#include <iterator>
#include <set>
#include <sstream>
#include <utility>
@@ -23,7 +25,10 @@
#include "cmInstallExportGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
+#include "cmInstallGetRuntimeDependenciesGenerator.h"
#include "cmInstallImportedRuntimeArtifactsGenerator.h"
+#include "cmInstallRuntimeDependencySet.h"
+#include "cmInstallRuntimeDependencySetGenerator.h"
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmListFileCache.h"
@@ -31,6 +36,7 @@
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmProperty.h"
+#include "cmRuntimeDependencyArchive.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSubcommandTable.h"
@@ -40,6 +46,29 @@
namespace {
+struct RuntimeDependenciesArgs
+{
+ std::vector<std::string> Directories;
+ std::vector<std::string> PreIncludeRegexes;
+ std::vector<std::string> PreExcludeRegexes;
+ std::vector<std::string> PostIncludeRegexes;
+ std::vector<std::string> PostExcludeRegexes;
+ std::vector<std::string> PostIncludeFiles;
+ std::vector<std::string> PostExcludeFiles;
+};
+
+auto const RuntimeDependenciesArgHelper =
+ cmArgumentParser<RuntimeDependenciesArgs>{}
+ .Bind("DIRECTORIES"_s, &RuntimeDependenciesArgs::Directories)
+ .Bind("PRE_INCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreIncludeRegexes)
+ .Bind("PRE_EXCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreExcludeRegexes)
+ .Bind("POST_INCLUDE_REGEXES"_s,
+ &RuntimeDependenciesArgs::PostIncludeRegexes)
+ .Bind("POST_EXCLUDE_REGEXES"_s,
+ &RuntimeDependenciesArgs::PostExcludeRegexes)
+ .Bind("POST_INCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostIncludeFiles)
+ .Bind("POST_EXCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostExcludeFiles);
+
class Helper
{
public:
@@ -147,12 +176,106 @@ std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
args.GetDestination());
}
+void AddInstallRuntimeDependenciesGenerator(
+ Helper& helper, cmInstallRuntimeDependencySet* runtimeDependencySet,
+ const cmInstallCommandArguments& runtimeArgs,
+ const cmInstallCommandArguments& libraryArgs,
+ const cmInstallCommandArguments& frameworkArgs,
+ RuntimeDependenciesArgs runtimeDependenciesArgs, bool& installsRuntime,
+ bool& installsLibrary, bool& installsFramework)
+{
+ bool dllPlatform =
+ !helper.Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
+ bool apple =
+ helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") == "Darwin";
+ auto const& runtimeDependenciesArgsRef =
+ dllPlatform ? runtimeArgs : libraryArgs;
+ std::vector<std::string> configurations =
+ runtimeDependenciesArgsRef.GetConfigurations();
+ if (apple) {
+ std::copy(frameworkArgs.GetConfigurations().begin(),
+ frameworkArgs.GetConfigurations().end(),
+ std::back_inserter(configurations));
+ }
+
+ // Create file(GET_RUNTIME_DEPENDENCIES) generator.
+ auto getRuntimeDependenciesGenerator =
+ cm::make_unique<cmInstallGetRuntimeDependenciesGenerator>(
+ runtimeDependencySet, std::move(runtimeDependenciesArgs.Directories),
+ std::move(runtimeDependenciesArgs.PreIncludeRegexes),
+ std::move(runtimeDependenciesArgs.PreExcludeRegexes),
+ std::move(runtimeDependenciesArgs.PostIncludeRegexes),
+ std::move(runtimeDependenciesArgs.PostExcludeRegexes),
+ std::move(runtimeDependenciesArgs.PostIncludeFiles),
+ std::move(runtimeDependenciesArgs.PostExcludeFiles),
+ runtimeDependenciesArgsRef.GetComponent(),
+ apple ? frameworkArgs.GetComponent() : "", true, "_CMAKE_DEPS",
+ "_CMAKE_RPATH", configurations,
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile),
+ runtimeDependenciesArgsRef.GetExcludeFromAll() &&
+ (apple ? frameworkArgs.GetExcludeFromAll() : true),
+ helper.Makefile->GetBacktrace());
+ helper.Makefile->AddInstallGenerator(
+ std::move(getRuntimeDependenciesGenerator));
+
+ // Create the library dependencies generator.
+ auto libraryRuntimeDependenciesGenerator =
+ cm::make_unique<cmInstallRuntimeDependencySetGenerator>(
+ cmInstallRuntimeDependencySetGenerator::DependencyType::Library,
+ runtimeDependencySet, std::vector<std::string>{}, true, std::string{},
+ true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP",
+ dllPlatform ? helper.GetRuntimeDestination(&runtimeArgs)
+ : helper.GetLibraryDestination(&libraryArgs),
+ runtimeDependenciesArgsRef.GetConfigurations(),
+ runtimeDependenciesArgsRef.GetComponent(),
+ runtimeDependenciesArgsRef.GetPermissions(),
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile),
+ runtimeDependenciesArgsRef.GetExcludeFromAll(),
+ helper.Makefile->GetBacktrace());
+ helper.Makefile->AddInstallGenerator(
+ std::move(libraryRuntimeDependenciesGenerator));
+ if (dllPlatform) {
+ installsRuntime = true;
+ } else {
+ installsLibrary = true;
+ }
+
+ if (apple) {
+ // Create the framework dependencies generator.
+ auto frameworkRuntimeDependenciesGenerator =
+ cm::make_unique<cmInstallRuntimeDependencySetGenerator>(
+ cmInstallRuntimeDependencySetGenerator::DependencyType::Framework,
+ runtimeDependencySet, std::vector<std::string>{}, true, std::string{},
+ true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP",
+ frameworkArgs.GetDestination(), frameworkArgs.GetConfigurations(),
+ frameworkArgs.GetComponent(), frameworkArgs.GetPermissions(),
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile),
+ frameworkArgs.GetExcludeFromAll(), helper.Makefile->GetBacktrace());
+ helper.Makefile->AddInstallGenerator(
+ std::move(frameworkRuntimeDependenciesGenerator));
+ installsFramework = true;
+ }
+}
+
std::set<std::string> const allowedTypes{
"BIN", "SBIN", "LIB", "INCLUDE", "SYSCONF",
"SHAREDSTATE", "LOCALSTATE", "RUNSTATE", "DATA", "INFO",
"LOCALE", "MAN", "DOC",
};
+template <typename T>
+bool AddBundleExecutable(Helper& helper,
+ cmInstallRuntimeDependencySet* runtimeDependencySet,
+ T&& bundleExecutable)
+{
+ if (!runtimeDependencySet->AddBundleExecutable(bundleExecutable)) {
+ helper.SetError(
+ "A runtime dependency set may only have one bundle executable.");
+ return false;
+ }
+ return true;
+}
+
bool HandleScriptMode(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -289,13 +412,25 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
// These generic args also contain the targets and the export stuff
std::vector<std::string> targetList;
std::string exports;
+ std::vector<std::string> runtimeDependenciesArgVector;
+ std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
+ std::vector<std::string> parsedArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
genericArgs.Bind("TARGETS"_s, targetList);
genericArgs.Bind("EXPORT"_s, exports);
- genericArgs.Parse(genericArgVector, &unknownArgs);
+ genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector);
+ genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
+ genericArgs.Parse(genericArgVector, &unknownArgs, nullptr, &parsedArgs);
bool success = genericArgs.Finalize();
+ bool withRuntimeDependencies =
+ std::find(parsedArgs.begin(), parsedArgs.end(), "RUNTIME_DEPENDENCIES") !=
+ parsedArgs.end();
+ RuntimeDependenciesArgs runtimeDependenciesArgs =
+ RuntimeDependenciesArgHelper.Parse(runtimeDependenciesArgVector,
+ &unknownArgs);
+
cmInstallCommandArguments archiveArgs(helper.DefaultComponentName);
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
@@ -402,6 +537,49 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
return false;
}
+ cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
+ if (withRuntimeDependencies) {
+ if (!runtimeDependencySetArg.empty()) {
+ status.SetError("TARGETS cannot have both RUNTIME_DEPENDENCIES and "
+ "RUNTIME_DEPENDENCY_SET.");
+ return false;
+ }
+ auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ system)) {
+ status.SetError(
+ cmStrCat("TARGETS RUNTIME_DEPENDENCIES is not supported on system \"",
+ system, '"'));
+ return false;
+ }
+ if (helper.Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
+ status.SetError("TARGETS RUNTIME_DEPENDENCIES is not supported "
+ "when cross-compiling.");
+ return false;
+ }
+ if (helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") ==
+ "Darwin" &&
+ frameworkArgs.GetDestination().empty()) {
+ status.SetError(
+ "TARGETS RUNTIME_DEPENDENCIES given no FRAMEWORK DESTINATION");
+ return false;
+ }
+ runtimeDependencySet = helper.Makefile->GetGlobalGenerator()
+ ->CreateAnonymousRuntimeDependencySet();
+ } else if (!runtimeDependencySetArg.empty()) {
+ auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ system)) {
+ status.SetError(cmStrCat(
+ "TARGETS RUNTIME_DEPENDENCY_SET is not supported on system \"", system,
+ '"'));
+ return false;
+ }
+ runtimeDependencySet =
+ helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
+ runtimeDependencySetArg);
+ }
+
// Select the mode for installing symlinks to versioned shared libraries.
cmInstallTargetGenerator::NamelinkModeType namelinkMode =
cmInstallTargetGenerator::NamelinkModeNone;
@@ -546,6 +724,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
helper.GetRuntimeDestination(nullptr));
}
+ if (runtimeDependencySet && runtimeGenerator) {
+ runtimeDependencySet->AddLibrary(runtimeGenerator.get());
+ }
} else {
// This is a non-DLL platform.
// If it is marked with FRAMEWORK property use the FRAMEWORK set of
@@ -591,6 +772,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
namelinkOnly =
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
}
+ if (runtimeDependencySet && libraryGenerator) {
+ runtimeDependencySet->AddLibrary(libraryGenerator.get());
+ }
}
} break;
case cmStateEnums::STATIC_LIBRARY: {
@@ -633,6 +817,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
libraryGenerator->SetNamelinkMode(namelinkMode);
namelinkOnly =
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddModule(libraryGenerator.get());
+ }
} else {
status.SetError(
cmStrCat("TARGETS given no LIBRARY DESTINATION for module "
@@ -685,6 +872,12 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
target.GetName(), "\"."));
return false;
}
+ if (runtimeDependencySet) {
+ if (!AddBundleExecutable(helper, runtimeDependencySet,
+ bundleGenerator.get())) {
+ return false;
+ }
+ }
} else {
// Executables use the RUNTIME properties.
if (!runtimeArgs.GetDestination().empty()) {
@@ -693,6 +886,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
runtimeGenerator = CreateInstallTargetGenerator(
target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
helper.GetRuntimeDestination(&runtimeArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddExecutable(runtimeGenerator.get());
+ }
}
// On DLL platforms an executable may also have an import
@@ -821,6 +1017,13 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
helper.Makefile->AddInstallGenerator(std::move(resourceGenerator));
}
+ if (withRuntimeDependencies && !runtimeDependencySet->Empty()) {
+ AddInstallRuntimeDependenciesGenerator(
+ helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs,
+ std::move(runtimeDependenciesArgs), installsRuntime, installsLibrary,
+ installsFramework);
+ }
+
// Tell the global generator about any installation component names
// specified
if (installsArchive) {
@@ -895,9 +1098,11 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
// now parse the generic args (i.e. the ones not specialized on LIBRARY,
// RUNTIME etc. (see above)
std::vector<std::string> targetList;
+ std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
- genericArgs.Bind("IMPORTED_RUNTIME_ARTIFACTS"_s, targetList);
+ genericArgs.Bind("IMPORTED_RUNTIME_ARTIFACTS"_s, targetList)
+ .Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
genericArgs.Parse(genericArgVector, &unknownArgs);
bool success = genericArgs.Finalize();
@@ -936,6 +1141,22 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
return false;
}
+ cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
+ if (!runtimeDependencySetArg.empty()) {
+ auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ system)) {
+ status.SetError(
+ cmStrCat("IMPORTED_RUNTIME_ARTIFACTS RUNTIME_DEPENDENCY_SET is not "
+ "supported on system \"",
+ system, '"'));
+ return false;
+ }
+ runtimeDependencySet =
+ helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
+ runtimeDependencySetArg);
+ }
+
// Check if there is something to do.
if (targetList.empty()) {
return true;
@@ -1014,6 +1235,9 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
if (target.IsDLLPlatform()) {
runtimeGenerator = createInstallGenerator(
target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddLibrary(runtimeGenerator.get());
+ }
} else if (target.IsFrameworkOnApple()) {
if (frameworkArgs.GetDestination().empty()) {
status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given no "
@@ -1024,14 +1248,23 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
}
frameworkGenerator = createInstallGenerator(
target, frameworkArgs, frameworkArgs.GetDestination());
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddLibrary(frameworkGenerator.get());
+ }
} else {
libraryGenerator = createInstallGenerator(
target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddLibrary(libraryGenerator.get());
+ }
}
break;
case cmStateEnums::MODULE_LIBRARY:
libraryGenerator = createInstallGenerator(
target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddModule(libraryGenerator.get());
+ }
break;
case cmStateEnums::EXECUTABLE:
if (target.IsAppBundleOnApple()) {
@@ -1044,9 +1277,18 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
}
bundleGenerator = createInstallGenerator(
target, bundleArgs, bundleArgs.GetDestination());
+ if (runtimeDependencySet) {
+ if (!AddBundleExecutable(helper, runtimeDependencySet,
+ bundleGenerator.get())) {
+ return false;
+ }
+ }
} else {
runtimeGenerator = createInstallGenerator(
target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddExecutable(runtimeGenerator.get());
+ }
}
break;
default:
@@ -1700,6 +1942,120 @@ bool HandleExportMode(std::vector<std::string> const& args,
return true;
}
+bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ system)) {
+ status.SetError(cmStrCat(
+ "RUNTIME_DEPENDENCY_SET is not supported on system \"", system, '"'));
+ return false;
+ }
+
+ // This is the RUNTIME_DEPENDENCY_SET mode.
+ cmInstallRuntimeDependencySet* runtimeDependencySet;
+
+ struct ArgVectors
+ {
+ std::vector<std::string> Library;
+ std::vector<std::string> Runtime;
+ std::vector<std::string> Framework;
+ };
+
+ static auto const argHelper = cmArgumentParser<ArgVectors>{}
+ .Bind("LIBRARY"_s, &ArgVectors::Library)
+ .Bind("RUNTIME"_s, &ArgVectors::Runtime)
+ .Bind("FRAMEWORK"_s, &ArgVectors::Framework);
+
+ std::vector<std::string> genericArgVector;
+ ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
+
+ // now parse the generic args (i.e. the ones not specialized on LIBRARY,
+ // RUNTIME, FRAMEWORK etc. (see above)
+ // These generic args also contain the runtime dependency set
+ std::string runtimeDependencySetArg;
+ std::vector<std::string> runtimeDependencyArgVector;
+ std::vector<std::string> parsedArgs;
+ cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
+ genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
+ genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector, nullptr,
+ &parsedArgs);
+ bool success = genericArgs.Finalize();
+
+ cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
+
+ // Now also parse the file(GET_RUNTIME_DEPENDENCY) args
+ std::vector<std::string> unknownArgs;
+ auto runtimeDependencyArgs = RuntimeDependenciesArgHelper.Parse(
+ runtimeDependencyArgVector, &unknownArgs);
+
+ // now parse the args for specific parts of the target (e.g. LIBRARY,
+ // RUNTIME, FRAMEWORK etc.
+ libraryArgs.Parse(argVectors.Library, &unknownArgs);
+ runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
+ frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
+
+ libraryArgs.SetGenericArguments(&genericArgs);
+ runtimeArgs.SetGenericArguments(&genericArgs);
+ frameworkArgs.SetGenericArguments(&genericArgs);
+
+ success = success && libraryArgs.Finalize();
+ success = success && runtimeArgs.Finalize();
+ success = success && frameworkArgs.Finalize();
+
+ if (!success) {
+ return false;
+ }
+
+ if (!unknownArgs.empty()) {
+ helper.SetError(
+ cmStrCat("RUNTIME_DEPENDENCY_SET given unknown argument \"",
+ unknownArgs.front(), "\"."));
+ return false;
+ }
+
+ if (runtimeDependencySetArg.empty()) {
+ helper.SetError(
+ "RUNTIME_DEPENDENCY_SET not given a runtime dependency set.");
+ return false;
+ }
+
+ runtimeDependencySet =
+ helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
+ runtimeDependencySetArg);
+
+ bool installsRuntime = false;
+ bool installsLibrary = false;
+ bool installsFramework = false;
+
+ AddInstallRuntimeDependenciesGenerator(
+ helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs,
+ std::move(runtimeDependencyArgs), installsRuntime, installsLibrary,
+ installsFramework);
+
+ // Tell the global generator about any installation component names
+ // specified
+ if (installsLibrary) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ libraryArgs.GetComponent());
+ }
+ if (installsRuntime) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ runtimeArgs.GetComponent());
+ }
+ if (installsFramework) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ frameworkArgs.GetComponent());
+ }
+
+ return true;
+}
+
bool Helper::MakeFilesFullPath(const char* modeName,
const std::vector<std::string>& relFiles,
std::vector<std::string>& absFiles)
@@ -1934,6 +2290,7 @@ bool cmInstallCommand(std::vector<std::string> const& args,
{ "DIRECTORY"_s, HandleDirectoryMode },
{ "EXPORT"_s, HandleExportMode },
{ "EXPORT_ANDROID_MK"_s, HandleExportAndroidMKMode },
+ { "RUNTIME_DEPENDENCY_SET"_s, HandleRuntimeDependencySetMode },
};
return subcommand(args[0], args, status);
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index 9f0d119..4cfeb47 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -43,7 +43,8 @@ void cmInstallGenerator::AddInstallRule(
std::vector<std::string> const& files, bool optional /* = false */,
const char* permissions_file /* = 0 */,
const char* permissions_dir /* = 0 */, const char* rename /* = 0 */,
- const char* literal_args /* = 0 */, Indent indent)
+ const char* literal_args /* = 0 */, Indent indent,
+ const char* files_var /* = 0 */)
{
// Use the FILE command to install the file.
std::string stype;
@@ -70,37 +71,46 @@ void cmInstallGenerator::AddInstallRule(
stype = "FILE";
break;
}
- os << indent;
if (cmSystemTools::FileIsFullPath(dest)) {
- os << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
- os << indent << " \"";
- bool firstIteration = true;
- for (std::string const& file : files) {
- if (!firstIteration) {
- os << ";";
+ if (!files.empty()) {
+ os << indent << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
+ os << indent << " \"";
+ bool firstIteration = true;
+ for (std::string const& file : files) {
+ if (!firstIteration) {
+ os << ";";
+ }
+ os << dest << "/";
+ if (rename && *rename) {
+ os << rename;
+ } else {
+ os << cmSystemTools::GetFilenameName(file);
+ }
+ firstIteration = false;
}
- os << dest << "/";
- if (rename && *rename) {
- os << rename;
- } else {
- os << cmSystemTools::GetFilenameName(file);
- }
- firstIteration = false;
+ os << "\")\n";
+ }
+ if (files_var) {
+ os << indent << "foreach(_f IN LISTS " << files_var << ")\n";
+ os << indent.Next() << "get_filename_component(_fn \"${_f}\" NAME)\n";
+ os << indent.Next() << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES \""
+ << dest << "/${_fn}\")\n";
+ os << indent << "endforeach()\n";
}
- os << "\")\n";
os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
- os << indent << indent << "message(WARNING \"ABSOLUTE path INSTALL "
+ os << indent.Next() << "message(WARNING \"ABSOLUTE path INSTALL "
<< "DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
os << indent << "endif()\n";
os << indent << "if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
- os << indent << indent << "message(FATAL_ERROR \"ABSOLUTE path INSTALL "
+ os << indent.Next() << "message(FATAL_ERROR \"ABSOLUTE path INSTALL "
<< "DESTINATION forbidden (by caller): "
<< "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
os << indent << "endif()\n";
}
std::string absDest = ConvertToAbsoluteDestination(dest);
- os << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " << stype;
+ os << indent << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE "
+ << stype;
if (optional) {
os << " OPTIONAL";
}
@@ -133,6 +143,9 @@ void cmInstallGenerator::AddInstallRule(
for (std::string const& f : files) {
os << "\n" << indent << " \"" << f << "\"";
}
+ if (files_var) {
+ os << " ${" << files_var << "}";
+ }
os << "\n" << indent << " ";
if (!(literal_args && *literal_args)) {
os << " ";
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index 97acb88..d342c99 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -50,7 +50,8 @@ public:
std::vector<std::string> const& files, bool optional = false,
const char* permissions_file = nullptr,
const char* permissions_dir = nullptr, const char* rename = nullptr,
- const char* literal_args = nullptr, Indent indent = Indent());
+ const char* literal_args = nullptr, Indent indent = Indent(),
+ const char* files_var = nullptr);
/** Get the install destination as it should appear in the
installation script. */
diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.cxx b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
new file mode 100644
index 0000000..4d585ce
--- /dev/null
+++ b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
@@ -0,0 +1,206 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallGetRuntimeDependenciesGenerator.h"
+
+#include <memory>
+#include <ostream>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmGeneratorExpression.h"
+#include "cmInstallRuntimeDependencySet.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmStringAlgorithms.h"
+
+namespace {
+template <typename T, typename F>
+void WriteMultiArgument(std::ostream& os, const cm::string_view& keyword,
+ const std::vector<T>& list,
+ cmScriptGeneratorIndent indent, F transform)
+{
+ bool first = true;
+ for (auto const& item : list) {
+ cm::optional<std::string> result = transform(item);
+ if (result) {
+ if (first) {
+ os << indent << " " << keyword << "\n";
+ first = false;
+ }
+ os << indent << " " << *result << "\n";
+ }
+ }
+}
+
+void WriteFilesArgument(
+ std::ostream& os, const cm::string_view& keyword,
+ const std::vector<std::unique_ptr<cmInstallRuntimeDependencySet::Item>>&
+ items,
+ const std::string& config, cmScriptGeneratorIndent indent)
+{
+ WriteMultiArgument(
+ os, keyword, items, indent,
+ [config](const std::unique_ptr<cmInstallRuntimeDependencySet::Item>& i)
+ -> std::string { return cmStrCat('"', i->GetItemPath(config), '"'); });
+}
+
+void WriteGenexEvaluatorArgument(std::ostream& os,
+ const cm::string_view& keyword,
+ const std::vector<std::string>& genexes,
+ const std::string& config,
+ cmLocalGenerator* lg,
+ cmScriptGeneratorIndent indent)
+{
+ WriteMultiArgument(
+ os, keyword, genexes, indent,
+ [config, lg](const std::string& genex) -> cm::optional<std::string> {
+ std::string result = cmGeneratorExpression::Evaluate(genex, lg, config);
+ if (result.empty()) {
+ return cm::nullopt;
+ }
+ return cmOutputConverter::EscapeForCMake(result);
+ });
+}
+}
+
+cmInstallGetRuntimeDependenciesGenerator::
+ cmInstallGetRuntimeDependenciesGenerator(
+ cmInstallRuntimeDependencySet* runtimeDependencySet,
+ std::vector<std::string> directories,
+ std::vector<std::string> preIncludeRegexes,
+ std::vector<std::string> preExcludeRegexes,
+ std::vector<std::string> postIncludeRegexes,
+ std::vector<std::string> postExcludeRegexes,
+ std::vector<std::string> postIncludeFiles,
+ std::vector<std::string> postExcludeFiles, std::string libraryComponent,
+ std::string frameworkComponent, bool noInstallRPath, const char* depsVar,
+ const char* rpathPrefix, std::vector<std::string> const& configurations,
+ MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace)
+ : cmInstallGenerator("", configurations, "", message, exclude_from_all,
+ false, std::move(backtrace))
+ , RuntimeDependencySet(runtimeDependencySet)
+ , Directories(std::move(directories))
+ , PreIncludeRegexes(std::move(preIncludeRegexes))
+ , PreExcludeRegexes(std::move(preExcludeRegexes))
+ , PostIncludeRegexes(std::move(postIncludeRegexes))
+ , PostExcludeRegexes(std::move(postExcludeRegexes))
+ , PostIncludeFiles(std::move(postIncludeFiles))
+ , PostExcludeFiles(std::move(postExcludeFiles))
+ , LibraryComponent(std::move(libraryComponent))
+ , FrameworkComponent(std::move(frameworkComponent))
+ , NoInstallRPath(noInstallRPath)
+ , DepsVar(depsVar)
+ , RPathPrefix(rpathPrefix)
+{
+ this->ActionsPerConfig = true;
+}
+
+bool cmInstallGetRuntimeDependenciesGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ return true;
+}
+
+void cmInstallGetRuntimeDependenciesGenerator::GenerateScript(std::ostream& os)
+{
+ // Track indentation.
+ Indent indent;
+
+ // Begin this block of installation.
+ os << indent << "if(";
+ if (this->FrameworkComponent.empty() ||
+ this->FrameworkComponent == this->LibraryComponent) {
+ os << this->CreateComponentTest(this->LibraryComponent,
+ this->ExcludeFromAll);
+ } else {
+ os << this->CreateComponentTest(this->LibraryComponent, true) << " OR "
+ << this->CreateComponentTest(this->FrameworkComponent,
+ this->ExcludeFromAll);
+ }
+ os << ")\n";
+
+ // Generate the script possibly with per-configuration code.
+ this->GenerateScriptConfigs(os, indent.Next());
+
+ // End this block of installation.
+ os << indent << "endif()\n\n";
+}
+
+void cmInstallGetRuntimeDependenciesGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ std::string installNameTool =
+ this->LocalGenerator->GetMakefile()->GetSafeDefinition(
+ "CMAKE_INSTALL_NAME_TOOL");
+
+ os << indent << "file(GET_RUNTIME_DEPENDENCIES\n"
+ << indent << " RESOLVED_DEPENDENCIES_VAR " << this->DepsVar << '\n';
+ WriteFilesArgument(os, "EXECUTABLES"_s,
+ this->RuntimeDependencySet->GetExecutables(), config,
+ indent);
+ WriteFilesArgument(os, "LIBRARIES"_s,
+ this->RuntimeDependencySet->GetLibraries(), config,
+ indent);
+ WriteFilesArgument(os, "MODULES"_s, this->RuntimeDependencySet->GetModules(),
+ config, indent);
+ if (this->RuntimeDependencySet->GetBundleExecutable()) {
+ os << indent << " BUNDLE_EXECUTABLE \""
+ << this->RuntimeDependencySet->GetBundleExecutable()->GetItemPath(
+ config)
+ << "\"\n";
+ }
+ WriteGenexEvaluatorArgument(os, "DIRECTORIES"_s, this->Directories, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "PRE_INCLUDE_REGEXES"_s,
+ this->PreIncludeRegexes, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "PRE_EXCLUDE_REGEXES"_s,
+ this->PreExcludeRegexes, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "POST_INCLUDE_REGEXES"_s,
+ this->PostIncludeRegexes, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "POST_EXCLUDE_REGEXES"_s,
+ this->PostExcludeRegexes, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "POST_INCLUDE_FILES"_s,
+ this->PostIncludeFiles, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "POST_EXCLUDE_FILES"_s,
+ this->PostExcludeFiles, config,
+ this->LocalGenerator, indent);
+
+ std::set<std::string> postExcludeFiles;
+ auto const addPostExclude =
+ [config, &postExcludeFiles, this](
+ const std::vector<std::unique_ptr<cmInstallRuntimeDependencySet::Item>>&
+ tgts) {
+ for (auto const& item : tgts) {
+ item->AddPostExcludeFiles(config, postExcludeFiles,
+ this->RuntimeDependencySet);
+ }
+ };
+ addPostExclude(this->RuntimeDependencySet->GetExecutables());
+ addPostExclude(this->RuntimeDependencySet->GetLibraries());
+ addPostExclude(this->RuntimeDependencySet->GetModules());
+ bool first = true;
+ for (auto const& file : postExcludeFiles) {
+ if (first) {
+ os << indent << " POST_EXCLUDE_FILES_STRICT\n";
+ first = false;
+ }
+ os << indent << " \"" << file << "\"\n";
+ }
+
+ if (!installNameTool.empty() && !this->NoInstallRPath) {
+ os << indent << " RPATH_PREFIX " << this->RPathPrefix << '\n';
+ }
+ os << indent << " )\n";
+}
diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.h b/Source/cmInstallGetRuntimeDependenciesGenerator.h
new file mode 100644
index 0000000..19f6cc6
--- /dev/null
+++ b/Source/cmInstallGetRuntimeDependenciesGenerator.h
@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmLocalGenerator;
+class cmInstallRuntimeDependencySet;
+
+class cmInstallGetRuntimeDependenciesGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallGetRuntimeDependenciesGenerator(
+ cmInstallRuntimeDependencySet* runtimeDependencySet,
+ std::vector<std::string> directories,
+ std::vector<std::string> preIncludeRegexes,
+ std::vector<std::string> preExcludeRegexes,
+ std::vector<std::string> postIncludeRegexes,
+ std::vector<std::string> postExcludeRegexes,
+ std::vector<std::string> postIncludeFiles,
+ std::vector<std::string> postExcludeFiles, std::string libraryComponent,
+ std::string frameworkComponent, bool noInstallRPath, const char* depsVar,
+ const char* rpathPrefix, std::vector<std::string> const& configurations,
+ MessageLevel message, bool exclude_from_all,
+ cmListFileBacktrace backtrace);
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+protected:
+ void GenerateScript(std::ostream& os) override;
+
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+private:
+ cmInstallRuntimeDependencySet* RuntimeDependencySet;
+ std::vector<std::string> Directories;
+ std::vector<std::string> PreIncludeRegexes;
+ std::vector<std::string> PreExcludeRegexes;
+ std::vector<std::string> PostIncludeRegexes;
+ std::vector<std::string> PostExcludeRegexes;
+ std::vector<std::string> PostIncludeFiles;
+ std::vector<std::string> PostExcludeFiles;
+ std::string LibraryComponent;
+ std::string FrameworkComponent;
+ bool NoInstallRPath;
+ const char* DepsVar;
+ const char* RPathPrefix;
+ cmLocalGenerator* LocalGenerator = nullptr;
+};
diff --git a/Source/cmInstallRuntimeDependencySet.cxx b/Source/cmInstallRuntimeDependencySet.cxx
new file mode 100644
index 0000000..0cef49a
--- /dev/null
+++ b/Source/cmInstallRuntimeDependencySet.cxx
@@ -0,0 +1,95 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallRuntimeDependencySet.h"
+
+#include <set>
+#include <string>
+#include <utility>
+
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallImportedRuntimeArtifactsGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmStateTypes.h"
+#include "cmTargetDepend.h"
+
+cmInstallRuntimeDependencySet::cmInstallRuntimeDependencySet(std::string name)
+ : Name(std::move(name))
+{
+}
+
+void cmInstallRuntimeDependencySet::AddExecutable(
+ std::unique_ptr<Item> executable)
+{
+ this->Executables.push_back(std::move(executable));
+}
+
+void cmInstallRuntimeDependencySet::AddLibrary(std::unique_ptr<Item> library)
+{
+ this->Libraries.push_back(std::move(library));
+}
+
+void cmInstallRuntimeDependencySet::AddModule(std::unique_ptr<Item> module)
+{
+ this->Modules.push_back(std::move(module));
+}
+
+bool cmInstallRuntimeDependencySet::AddBundleExecutable(
+ std::unique_ptr<Item> bundleExecutable)
+{
+ if (this->BundleExecutable) {
+ return false;
+ }
+ this->BundleExecutable = bundleExecutable.get();
+ this->AddExecutable(std::move(bundleExecutable));
+ return true;
+}
+
+std::string cmInstallRuntimeDependencySet::TargetItem::GetItemPath(
+ const std::string& config) const
+{
+ return this->Target->GetTarget()->GetFullPath(config);
+}
+
+namespace {
+const std::set<const cmGeneratorTarget*>& GetTargetDependsClosure(
+ std::map<const cmGeneratorTarget*, std::set<const cmGeneratorTarget*>>&
+ targetDepends,
+ const cmGeneratorTarget* tgt)
+{
+ auto it = targetDepends.insert({ tgt, {} });
+ auto& retval = it.first->second;
+ if (it.second) {
+ auto const& deps = tgt->GetGlobalGenerator()->GetTargetDirectDepends(tgt);
+ for (auto const& dep : deps) {
+ if (!dep.IsCross() && dep.IsLink()) {
+ auto type = dep->GetType();
+ if (type == cmStateEnums::EXECUTABLE ||
+ type == cmStateEnums::SHARED_LIBRARY ||
+ type == cmStateEnums::MODULE_LIBRARY) {
+ retval.insert(dep);
+ }
+ auto const& depDeps = GetTargetDependsClosure(targetDepends, dep);
+ retval.insert(depDeps.begin(), depDeps.end());
+ }
+ }
+ }
+ return retval;
+}
+}
+
+void cmInstallRuntimeDependencySet::TargetItem::AddPostExcludeFiles(
+ const std::string& config, std::set<std::string>& files,
+ cmInstallRuntimeDependencySet* set) const
+{
+ for (auto const* dep : GetTargetDependsClosure(set->TargetDepends,
+ this->Target->GetTarget())) {
+ files.insert(dep->GetFullPath(config));
+ }
+}
+
+std::string cmInstallRuntimeDependencySet::ImportedTargetItem::GetItemPath(
+ const std::string& config) const
+{
+ return this->Target->GetTarget()->GetFullPath(config);
+}
diff --git a/Source/cmInstallRuntimeDependencySet.h b/Source/cmInstallRuntimeDependencySet.h
new file mode 100644
index 0000000..7f51624
--- /dev/null
+++ b/Source/cmInstallRuntimeDependencySet.h
@@ -0,0 +1,163 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+class cmGeneratorTarget;
+class cmInstallImportedRuntimeArtifactsGenerator;
+class cmInstallTargetGenerator;
+
+class cmInstallRuntimeDependencySet
+{
+public:
+ cmInstallRuntimeDependencySet(std::string name = "");
+
+ cmInstallRuntimeDependencySet(const cmInstallRuntimeDependencySet&) = delete;
+ cmInstallRuntimeDependencySet& operator=(
+ const cmInstallRuntimeDependencySet&) = delete;
+
+ cm::string_view GetName() const { return this->Name; }
+
+ cm::string_view GetDisplayName() const
+ {
+ if (this->Name.empty()) {
+ return "<anonymous>"_s;
+ }
+ return this->Name;
+ }
+
+ class Item
+ {
+ public:
+ virtual ~Item() = default;
+
+ virtual std::string GetItemPath(const std::string& config) const = 0;
+
+ virtual void AddPostExcludeFiles(
+ const std::string& /*config*/, std::set<std::string>& /*files*/,
+ cmInstallRuntimeDependencySet* /*set*/) const
+ {
+ }
+ };
+
+ class TargetItem : public Item
+ {
+ public:
+ TargetItem(cmInstallTargetGenerator* target)
+ : Target(target)
+ {
+ }
+
+ std::string GetItemPath(const std::string& config) const override;
+
+ void AddPostExcludeFiles(
+ const std::string& config, std::set<std::string>& files,
+ cmInstallRuntimeDependencySet* set) const override;
+
+ private:
+ cmInstallTargetGenerator* Target;
+ };
+
+ class ImportedTargetItem : public Item
+ {
+ public:
+ ImportedTargetItem(cmInstallImportedRuntimeArtifactsGenerator* target)
+ : Target(target)
+ {
+ }
+
+ std::string GetItemPath(const std::string& config) const override;
+
+ private:
+ cmInstallImportedRuntimeArtifactsGenerator* Target;
+ };
+
+ void AddExecutable(std::unique_ptr<Item> executable);
+ void AddLibrary(std::unique_ptr<Item> library);
+ void AddModule(std::unique_ptr<Item> module);
+ bool AddBundleExecutable(std::unique_ptr<Item> bundleExecutable);
+
+ void AddExecutable(cmInstallTargetGenerator* executable)
+ {
+ this->AddExecutable(cm::make_unique<TargetItem>(executable));
+ }
+
+ void AddLibrary(cmInstallTargetGenerator* library)
+ {
+ this->AddLibrary(cm::make_unique<TargetItem>(library));
+ }
+
+ void AddModule(cmInstallTargetGenerator* module)
+ {
+ this->AddModule(cm::make_unique<TargetItem>(module));
+ }
+
+ bool AddBundleExecutable(cmInstallTargetGenerator* bundleExecutable)
+ {
+ return this->AddBundleExecutable(
+ cm::make_unique<TargetItem>(bundleExecutable));
+ }
+
+ void AddExecutable(cmInstallImportedRuntimeArtifactsGenerator* executable)
+ {
+ this->AddExecutable(cm::make_unique<ImportedTargetItem>(executable));
+ }
+
+ void AddLibrary(cmInstallImportedRuntimeArtifactsGenerator* library)
+ {
+ this->AddLibrary(cm::make_unique<ImportedTargetItem>(library));
+ }
+
+ void AddModule(cmInstallImportedRuntimeArtifactsGenerator* module)
+ {
+ this->AddModule(cm::make_unique<ImportedTargetItem>(module));
+ }
+
+ bool AddBundleExecutable(
+ cmInstallImportedRuntimeArtifactsGenerator* bundleExecutable)
+ {
+ return this->AddBundleExecutable(
+ cm::make_unique<ImportedTargetItem>(bundleExecutable));
+ }
+
+ const std::vector<std::unique_ptr<Item>>& GetExecutables() const
+ {
+ return this->Executables;
+ }
+
+ const std::vector<std::unique_ptr<Item>>& GetLibraries() const
+ {
+ return this->Libraries;
+ }
+
+ const std::vector<std::unique_ptr<Item>>& GetModules() const
+ {
+ return this->Modules;
+ }
+
+ Item* GetBundleExecutable() const { return this->BundleExecutable; }
+
+ bool Empty() const
+ {
+ return this->Executables.empty() && this->Libraries.empty() &&
+ this->Modules.empty();
+ }
+
+private:
+ std::string Name;
+ std::vector<std::unique_ptr<Item>> Executables;
+ std::vector<std::unique_ptr<Item>> Libraries;
+ std::vector<std::unique_ptr<Item>> Modules;
+ Item* BundleExecutable = nullptr;
+
+ std::map<const cmGeneratorTarget*, std::set<const cmGeneratorTarget*>>
+ TargetDepends;
+};
diff --git a/Source/cmInstallRuntimeDependencySetGenerator.cxx b/Source/cmInstallRuntimeDependencySetGenerator.cxx
new file mode 100644
index 0000000..44f03e1
--- /dev/null
+++ b/Source/cmInstallRuntimeDependencySetGenerator.cxx
@@ -0,0 +1,276 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallRuntimeDependencySetGenerator.h"
+
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorExpression.h"
+#include "cmInstallGenerator.h"
+#include "cmInstallType.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmScriptGenerator.h"
+#include "cmStringAlgorithms.h"
+#include "cmake.h"
+
+cmInstallRuntimeDependencySetGenerator::cmInstallRuntimeDependencySetGenerator(
+ DependencyType type, cmInstallRuntimeDependencySet* dependencySet,
+ std::vector<std::string> installRPaths, bool noInstallRPath,
+ std::string installNameDir, bool noInstallName, const char* depsVar,
+ const char* rpathPrefix, const char* tmpVarPrefix, std::string destination,
+ std::vector<std::string> const& configurations, std::string component,
+ std::string permissions, MessageLevel message, bool exclude_from_all,
+ cmListFileBacktrace backtrace)
+ : cmInstallGenerator(std::move(destination), configurations,
+ std::move(component), message, exclude_from_all, false,
+ std::move(backtrace))
+ , Type(type)
+ , DependencySet(dependencySet)
+ , InstallRPaths(std::move(installRPaths))
+ , NoInstallRPath(noInstallRPath)
+ , InstallNameDir(std::move(installNameDir))
+ , NoInstallName(noInstallName)
+ , Permissions(std::move(permissions))
+ , DepsVar(depsVar)
+ , RPathPrefix(rpathPrefix)
+ , TmpVarPrefix(tmpVarPrefix)
+{
+ this->ActionsPerConfig = true;
+}
+
+bool cmInstallRuntimeDependencySetGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ return true;
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ if (!this->LocalGenerator->GetMakefile()
+ ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL")
+ .empty() &&
+ !this->NoInstallName) {
+ std::string installNameDir = "@rpath/";
+ if (!this->InstallNameDir.empty()) {
+ installNameDir = this->InstallNameDir;
+ cmGeneratorExpression::ReplaceInstallPrefix(installNameDir,
+ "${CMAKE_INSTALL_PREFIX}");
+ installNameDir = cmGeneratorExpression::Evaluate(
+ installNameDir, this->LocalGenerator, config);
+ if (installNameDir.empty()) {
+ this->LocalGenerator->GetMakefile()->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "INSTALL_NAME_DIR argument must not evaluate to an "
+ "empty string",
+ this->Backtrace);
+ return;
+ }
+ if (installNameDir.back() != '/') {
+ installNameDir += '/';
+ }
+ }
+ os << indent << "set(" << this->TmpVarPrefix << "_install_name_dir \""
+ << installNameDir << "\")\n";
+ }
+
+ os << indent << "foreach(" << this->TmpVarPrefix << "_dep IN LISTS "
+ << this->DepsVar << ")\n";
+
+ if (!this->LocalGenerator->GetMakefile()
+ ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL")
+ .empty()) {
+ std::vector<std::string> evaluatedRPaths;
+ for (auto const& rpath : this->InstallRPaths) {
+ std::string result =
+ cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config);
+ if (!result.empty()) {
+ evaluatedRPaths.push_back(std::move(result));
+ }
+ }
+
+ switch (this->Type) {
+ case DependencyType::Library:
+ this->GenerateAppleLibraryScript(os, config, evaluatedRPaths,
+ indent.Next());
+ break;
+ case DependencyType::Framework:
+ this->GenerateAppleFrameworkScript(os, config, evaluatedRPaths,
+ indent.Next());
+ break;
+ }
+ } else {
+ std::string depVar = cmStrCat(this->TmpVarPrefix, "_dep");
+
+ this->AddInstallRule(
+ os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {},
+ false, this->Permissions.c_str(), nullptr, nullptr,
+ " FOLLOW_SYMLINK_CHAIN", indent.Next(), depVar.c_str());
+
+ if (this->LocalGenerator->GetMakefile()->GetSafeDefinition(
+ "CMAKE_SYSTEM_NAME") == "Linux" &&
+ !this->NoInstallRPath) {
+ std::string evaluatedRPath;
+ for (auto const& rpath : this->InstallRPaths) {
+ std::string result =
+ cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config);
+ if (!result.empty()) {
+ if (evaluatedRPath.empty()) {
+ evaluatedRPath = std::move(result);
+ } else {
+ evaluatedRPath += ':';
+ evaluatedRPath += result;
+ }
+ }
+ }
+
+ os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix
+ << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n";
+ if (evaluatedRPath.empty()) {
+ os << indent.Next() << "file(RPATH_REMOVE FILE \""
+ << GetDestDirPath(
+ ConvertToAbsoluteDestination(this->GetDestination(config)))
+ << "/${" << this->TmpVarPrefix << "_dep_name}\")\n";
+ } else {
+ os << indent.Next() << "file(RPATH_SET FILE \""
+ << GetDestDirPath(
+ ConvertToAbsoluteDestination(this->GetDestination(config)))
+ << "/${" << this->TmpVarPrefix << "_dep_name}\" NEW_RPATH "
+ << cmOutputConverter::EscapeForCMake(evaluatedRPath) << ")\n";
+ }
+ }
+ }
+
+ os << indent << "endforeach()\n";
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateAppleLibraryScript(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, Indent indent)
+{
+ os << indent << "if(NOT " << this->TmpVarPrefix
+ << "_dep MATCHES \"\\\\.framework/\")\n";
+
+ auto depName = cmStrCat(this->TmpVarPrefix, "_dep");
+ this->AddInstallRule(
+ os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, false,
+ this->Permissions.c_str(), nullptr, nullptr, " FOLLOW_SYMLINK_CHAIN",
+ indent.Next(), depName.c_str());
+
+ os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix
+ << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n";
+ auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_dep_name}");
+ this->GenerateInstallNameFixup(os, config, evaluatedRPaths,
+ cmStrCat("${", this->TmpVarPrefix, "_dep}"),
+ depNameVar, indent.Next());
+
+ os << indent << "endif()\n";
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateAppleFrameworkScript(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, Indent indent)
+{
+ os << indent << "if(" << this->TmpVarPrefix
+ << "_dep MATCHES \"^(.*/)?([^/]*\\\\.framework)/(.*)$\")\n"
+ << indent.Next() << "set(" << this->TmpVarPrefix
+ << "_dir \"${CMAKE_MATCH_1}\")\n"
+ << indent.Next() << "set(" << this->TmpVarPrefix
+ << "_name \"${CMAKE_MATCH_2}\")\n"
+ << indent.Next() << "set(" << this->TmpVarPrefix
+ << "_file \"${CMAKE_MATCH_3}\")\n"
+ << indent.Next() << "set(" << this->TmpVarPrefix << "_path \"${"
+ << this->TmpVarPrefix << "_dir}${" << this->TmpVarPrefix << "_name}\")\n";
+
+ auto depName = cmStrCat(this->TmpVarPrefix, "_path");
+ this->AddInstallRule(
+ os, this->GetDestination(config), cmInstallType_DIRECTORY, {}, false,
+ this->Permissions.c_str(), nullptr, nullptr, " USE_SOURCE_PERMISSIONS",
+ indent.Next(), depName.c_str());
+
+ auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_name}/${",
+ this->TmpVarPrefix, "_file}");
+ this->GenerateInstallNameFixup(os, config, evaluatedRPaths,
+ cmStrCat("${", this->TmpVarPrefix, "_dep}"),
+ depNameVar, indent.Next());
+
+ os << indent << "endif()\n";
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateInstallNameFixup(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, const std::string& filename,
+ const std::string& depName, Indent indent)
+{
+ if (!(this->NoInstallRPath && this->NoInstallName)) {
+ auto indent2 = indent;
+ if (evaluatedRPaths.empty() && this->NoInstallName) {
+ indent2 = indent2.Next();
+ os << indent << "if(" << this->RPathPrefix << "_" << filename << ")\n";
+ }
+ os << indent2 << "set(" << this->TmpVarPrefix << "_rpath_args)\n";
+ if (!this->NoInstallRPath) {
+ os << indent2 << "foreach(" << this->TmpVarPrefix << "_rpath IN LISTS "
+ << this->RPathPrefix << '_' << filename << ")\n"
+ << indent2.Next() << "list(APPEND " << this->TmpVarPrefix
+ << "_rpath_args -delete_rpath \"${" << this->TmpVarPrefix
+ << "_rpath}\")\n"
+ << indent2 << "endforeach()\n";
+ }
+ os << indent2 << "execute_process(COMMAND \""
+ << this->LocalGenerator->GetMakefile()->GetSafeDefinition(
+ "CMAKE_INSTALL_NAME_TOOL")
+ << "\" ${" << this->TmpVarPrefix << "_rpath_args}\n";
+ if (!this->NoInstallRPath) {
+ for (auto const& rpath : evaluatedRPaths) {
+ os << indent2 << " -add_rpath "
+ << cmOutputConverter::EscapeForCMake(rpath) << "\n";
+ }
+ }
+ if (!this->NoInstallName) {
+ os << indent2 << " -id \"${" << this->TmpVarPrefix
+ << "_install_name_dir}" << depName << "\"\n";
+ }
+ os << indent2 << " \""
+ << GetDestDirPath(
+ ConvertToAbsoluteDestination(this->GetDestination(config)))
+ << "/" << depName << "\")\n";
+ if (evaluatedRPaths.empty() && this->NoInstallName) {
+ os << indent << "endif()\n";
+ }
+ }
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateStripFixup(
+ std::ostream& os, const std::string& config, const std::string& depName,
+ Indent indent)
+{
+ std::string strip =
+ this->LocalGenerator->GetMakefile()->GetSafeDefinition("CMAKE_STRIP");
+ if (!strip.empty()) {
+ os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n"
+ << indent.Next() << "execute_process(COMMAND \"" << strip << "\" ";
+ if (this->LocalGenerator->GetMakefile()->GetSafeDefinition(
+ "CMAKE_HOST_SYSTEM_NAME") == "Darwin") {
+ os << "-x ";
+ }
+ os << "\""
+ << GetDestDirPath(
+ ConvertToAbsoluteDestination(this->GetDestination(config)))
+ << "/" << depName << "\")\n"
+ << indent << "endif()\n";
+ }
+}
+
+std::string cmInstallRuntimeDependencySetGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(this->Destination,
+ this->LocalGenerator, config);
+}
diff --git a/Source/cmInstallRuntimeDependencySetGenerator.h b/Source/cmInstallRuntimeDependencySetGenerator.h
new file mode 100644
index 0000000..8e98b57
--- /dev/null
+++ b/Source/cmInstallRuntimeDependencySetGenerator.h
@@ -0,0 +1,74 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmInstallRuntimeDependencySet;
+class cmLocalGenerator;
+
+class cmInstallRuntimeDependencySetGenerator : public cmInstallGenerator
+{
+public:
+ enum class DependencyType
+ {
+ Library,
+ Framework,
+ };
+
+ cmInstallRuntimeDependencySetGenerator(
+ DependencyType type, cmInstallRuntimeDependencySet* dependencySet,
+ std::vector<std::string> installRPaths, bool noInstallRPath,
+ std::string installNameDir, bool noInstallName, const char* depsVar,
+ const char* rpathPrefix, const char* tmpVarPrefix, std::string destination,
+ std::vector<std::string> const& configurations, std::string component,
+ std::string permissions, MessageLevel message, bool exclude_from_all,
+ cmListFileBacktrace backtrace);
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ DependencyType GetDependencyType() const { return this->Type; }
+
+ cmInstallRuntimeDependencySet* GetRuntimeDependencySet() const
+ {
+ return this->DependencySet;
+ }
+
+ std::string GetDestination(std::string const& config) const;
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+private:
+ DependencyType Type;
+ cmInstallRuntimeDependencySet* DependencySet;
+ std::vector<std::string> InstallRPaths;
+ bool NoInstallRPath;
+ std::string InstallNameDir;
+ bool NoInstallName;
+ std::string Permissions;
+ const char* DepsVar;
+ const char* RPathPrefix;
+ const char* TmpVarPrefix;
+ cmLocalGenerator* LocalGenerator = nullptr;
+
+ void GenerateAppleLibraryScript(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, Indent indent);
+ void GenerateAppleFrameworkScript(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, Indent indent);
+ void GenerateInstallNameFixup(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths,
+ const std::string& filename, const std::string& depName, Indent indent);
+ void GenerateStripFixup(std::ostream& os, const std::string& config,
+ const std::string& depName, Indent indent);
+};
diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx
index a6ed523..26f255d 100644
--- a/Source/cmRuntimeDependencyArchive.cxx
+++ b/Source/cmRuntimeDependencyArchive.cxx
@@ -198,25 +198,26 @@ void cmRuntimeDependencyArchive::SetError(const std::string& e)
this->Status.SetError(e);
}
-std::string cmRuntimeDependencyArchive::GetBundleExecutable()
+const std::string& cmRuntimeDependencyArchive::GetBundleExecutable() const
{
return this->BundleExecutable;
}
const std::vector<std::string>&
-cmRuntimeDependencyArchive::GetSearchDirectories()
+cmRuntimeDependencyArchive::GetSearchDirectories() const
{
return this->SearchDirectories;
}
-std::string cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
+const std::string& cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
+ const
{
return this->GetMakefile()->GetSafeDefinition(
"CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL");
}
bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
- const std::string& search, std::vector<std::string>& command)
+ const std::string& search, std::vector<std::string>& command) const
{
// First see if it was supplied by the user
std::string toolCommand = this->GetMakefile()->GetSafeDefinition(
@@ -309,7 +310,7 @@ bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
return false;
}
-bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
+bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name) const
{
cmsys::RegularExpressionMatch match;
auto const regexMatch =
@@ -326,7 +327,7 @@ bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
regexSearch(this->PreExcludeRegexes);
}
-bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
+bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name) const
{
cmsys::RegularExpressionMatch match;
auto const regexMatch =
@@ -353,9 +354,9 @@ bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
fileSearch(this->PostExcludeFiles)));
}
-void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
- const std::string& path,
- bool& unique)
+void cmRuntimeDependencyArchive::AddResolvedPath(
+ const std::string& name, const std::string& path, bool& unique,
+ std::vector<std::string> rpaths)
{
auto it = this->ResolvedPaths.emplace(name, std::set<std::string>{}).first;
unique = true;
@@ -366,6 +367,7 @@ void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
}
}
it->second.insert(path);
+ this->RPaths[path] = std::move(rpaths);
}
void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
@@ -373,18 +375,33 @@ void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
this->UnresolvedPaths.insert(name);
}
-cmMakefile* cmRuntimeDependencyArchive::GetMakefile()
+cmMakefile* cmRuntimeDependencyArchive::GetMakefile() const
{
return &this->Status.GetMakefile();
}
const std::map<std::string, std::set<std::string>>&
-cmRuntimeDependencyArchive::GetResolvedPaths()
+cmRuntimeDependencyArchive::GetResolvedPaths() const
{
return this->ResolvedPaths;
}
const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
+ const
{
return this->UnresolvedPaths;
}
+
+const std::map<std::string, std::vector<std::string>>&
+cmRuntimeDependencyArchive::GetRPaths() const
+{
+ return this->RPaths;
+}
+
+bool cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ const std::string& platform)
+{
+ static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
+ "Darwin" };
+ return supportedPlatforms.count(platform);
+}
diff --git a/Source/cmRuntimeDependencyArchive.h b/Source/cmRuntimeDependencyArchive.h
index 1dc3261..b170815 100644
--- a/Source/cmRuntimeDependencyArchive.h
+++ b/Source/cmRuntimeDependencyArchive.h
@@ -36,21 +36,24 @@ public:
void SetError(const std::string& e);
- std::string GetBundleExecutable();
- const std::vector<std::string>& GetSearchDirectories();
- std::string GetGetRuntimeDependenciesTool();
- bool GetGetRuntimeDependenciesCommand(const std::string& search,
- std::vector<std::string>& command);
- bool IsPreExcluded(const std::string& name);
- bool IsPostExcluded(const std::string& name);
+ const std::string& GetBundleExecutable() const;
+ const std::vector<std::string>& GetSearchDirectories() const;
+ const std::string& GetGetRuntimeDependenciesTool() const;
+ bool GetGetRuntimeDependenciesCommand(
+ const std::string& search, std::vector<std::string>& command) const;
+ bool IsPreExcluded(const std::string& name) const;
+ bool IsPostExcluded(const std::string& name) const;
void AddResolvedPath(const std::string& name, const std::string& path,
- bool& unique);
+ bool& unique, std::vector<std::string> rpaths = {});
void AddUnresolvedPath(const std::string& name);
- cmMakefile* GetMakefile();
- const std::map<std::string, std::set<std::string>>& GetResolvedPaths();
- const std::set<std::string>& GetUnresolvedPaths();
+ cmMakefile* GetMakefile() const;
+ const std::map<std::string, std::set<std::string>>& GetResolvedPaths() const;
+ const std::set<std::string>& GetUnresolvedPaths() const;
+ const std::map<std::string, std::vector<std::string>>& GetRPaths() const;
+
+ static bool PlatformSupportsRuntimeDependencies(const std::string& platform);
private:
cmExecutionStatus& Status;
@@ -70,4 +73,5 @@ private:
std::vector<std::string> PostExcludeFilesStrict;
std::map<std::string, std::set<std::string>> ResolvedPaths;
std::set<std::string> UnresolvedPaths;
+ std::map<std::string, std::vector<std::string>> RPaths;
};
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 9b81bf2..10d2e50 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -14,6 +14,7 @@
#include "cmSystemTools.h"
+#include <cm/optional>
#include <cmext/algorithm>
#include <cm3p/uv.h>
@@ -65,6 +66,7 @@
#include <cstdlib>
#include <cstring>
#include <ctime>
+#include <functional>
#include <iostream>
#include <sstream>
#include <utility>
@@ -2524,6 +2526,7 @@ std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
#endif
#if defined(CMake_USE_ELF_PARSER)
+namespace {
struct cmSystemToolsRPathInfo
{
unsigned long Position;
@@ -2531,15 +2534,15 @@ struct cmSystemToolsRPathInfo
std::string Name;
std::string Value;
};
-#endif
+
+using EmptyCallback = std::function<bool(std::string*, const cmELF&)>;
+using AdjustCallback = std::function<bool(
+ cm::optional<std::string>&, const std::string&, const char*, std::string*)>;
// FIXME: Dispatch if multiple formats are supported.
-#if defined(CMake_USE_ELF_PARSER)
-bool cmSystemTools::ChangeRPath(std::string const& file,
- std::string const& oldRPath,
- std::string const& newRPath,
- bool removeEnvironmentRPath, std::string* emsg,
- bool* changed)
+bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback,
+ const AdjustCallback& adjustCallback, std::string* emsg,
+ bool* changed)
{
if (changed) {
*changed = false;
@@ -2566,17 +2569,7 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
++se_count;
}
if (se_count == 0) {
- if (newRPath.empty()) {
- // The new rpath is empty and there is no rpath anyway so it is
- // okay.
- return true;
- }
- if (emsg) {
- *emsg =
- cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
- elf.GetErrorMessage());
- }
- return false;
+ return emptyCallback(emsg, elf);
}
for (int i = 0; i < se_count; ++i) {
@@ -2586,68 +2579,38 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
continue;
}
- // Make sure the current rpath contains the old rpath.
- std::string::size_type pos =
- cmSystemToolsFindRPath(se[i]->Value, oldRPath);
- if (pos == std::string::npos) {
- // If it contains the new rpath instead then it is okay.
- if (cmSystemToolsFindRPath(se[i]->Value, newRPath) !=
- std::string::npos) {
- remove_rpath = false;
- continue;
- }
- if (emsg) {
- std::ostringstream e;
- /* clang-format off */
- e << "The current " << se_name[i] << " is:\n"
- << " " << se[i]->Value << "\n"
- << "which does not contain:\n"
- << " " << oldRPath << "\n"
- << "as was expected.";
- /* clang-format on */
- *emsg = e.str();
- }
- return false;
- }
-
// Store information about the entry in the file.
rp[rp_count].Position = se[i]->Position;
rp[rp_count].Size = se[i]->Size;
rp[rp_count].Name = se_name[i];
- std::string::size_type prefix_len = pos;
-
- // If oldRPath was at the end of the file's RPath, and newRPath is empty,
- // we should remove the unnecessary ':' at the end.
- if (newRPath.empty() && pos > 0 && se[i]->Value[pos - 1] == ':' &&
- pos + oldRPath.length() == se[i]->Value.length()) {
- prefix_len--;
- }
-
- // Construct the new value which preserves the part of the path
- // not being changed.
- if (!removeEnvironmentRPath) {
- rp[rp_count].Value = se[i]->Value.substr(0, prefix_len);
+ // Adjust the rpath.
+ cm::optional<std::string> outRPath;
+ if (!adjustCallback(outRPath, se[i]->Value, se_name[i], emsg)) {
+ return false;
}
- rp[rp_count].Value += newRPath;
- rp[rp_count].Value += se[i]->Value.substr(pos + oldRPath.length());
- if (!rp[rp_count].Value.empty()) {
- remove_rpath = false;
- }
+ if (outRPath) {
+ if (!outRPath->empty()) {
+ remove_rpath = false;
+ }
- // Make sure there is enough room to store the new rpath and at
- // least one null terminator.
- if (rp[rp_count].Size < rp[rp_count].Value.length() + 1) {
- if (emsg) {
- *emsg = cmStrCat("The replacement path is too long for the ",
- se_name[i], " entry.");
+ // Make sure there is enough room to store the new rpath and at
+ // least one null terminator.
+ if (rp[rp_count].Size < outRPath->length() + 1) {
+ if (emsg) {
+ *emsg = cmStrCat("The replacement path is too long for the ",
+ se_name[i], " entry.");
+ }
+ return false;
}
- return false;
- }
- // This entry is ready for update.
- ++rp_count;
+ // This entry is ready for update.
+ rp[rp_count].Value = std::move(*outRPath);
+ ++rp_count;
+ } else {
+ remove_rpath = false;
+ }
}
}
@@ -2706,6 +2669,99 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
}
return true;
}
+
+std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback(
+ const std::string& newRPath)
+{
+ return [newRPath](std::string* emsg, const cmELF& elf) -> bool {
+ if (newRPath.empty()) {
+ // The new rpath is empty and there is no rpath anyway so it is
+ // okay.
+ return true;
+ }
+ if (emsg) {
+ *emsg =
+ cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
+ elf.GetErrorMessage());
+ }
+ return false;
+ };
+};
+}
+
+bool cmSystemTools::ChangeRPath(std::string const& file,
+ std::string const& oldRPath,
+ std::string const& newRPath,
+ bool removeEnvironmentRPath, std::string* emsg,
+ bool* changed)
+{
+ auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath](
+ cm::optional<std::string>& outRPath,
+ const std::string& inRPath, const char* se_name,
+ std::string* emsg2) -> bool {
+ // Make sure the current rpath contains the old rpath.
+ std::string::size_type pos = cmSystemToolsFindRPath(inRPath, oldRPath);
+ if (pos == std::string::npos) {
+ // If it contains the new rpath instead then it is okay.
+ if (cmSystemToolsFindRPath(inRPath, newRPath) != std::string::npos) {
+ return true;
+ }
+ if (emsg2) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "The current " << se_name << " is:\n"
+ << " " << inRPath << "\n"
+ << "which does not contain:\n"
+ << " " << oldRPath << "\n"
+ << "as was expected.";
+ /* clang-format on */
+ *emsg2 = e.str();
+ }
+ return false;
+ }
+
+ std::string::size_type prefix_len = pos;
+
+ // If oldRPath was at the end of the file's RPath, and newRPath is empty,
+ // we should remove the unnecessary ':' at the end.
+ if (newRPath.empty() && pos > 0 && inRPath[pos - 1] == ':' &&
+ pos + oldRPath.length() == inRPath.length()) {
+ prefix_len--;
+ }
+
+ // Construct the new value which preserves the part of the path
+ // not being changed.
+ outRPath.emplace();
+ if (!removeEnvironmentRPath) {
+ *outRPath += inRPath.substr(0, prefix_len);
+ }
+ *outRPath += newRPath;
+ *outRPath += inRPath.substr(pos + oldRPath.length());
+
+ return true;
+ };
+
+ return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
+ changed);
+}
+
+bool cmSystemTools::SetRPath(std::string const& file,
+ std::string const& newRPath, std::string* emsg,
+ bool* changed)
+{
+ auto adjustCallback = [newRPath](cm::optional<std::string>& outRPath,
+ const std::string& inRPath,
+ const char* /*se_name*/, std::string *
+ /*emsg*/) -> bool {
+ if (inRPath != newRPath) {
+ outRPath = newRPath;
+ }
+ return true;
+ };
+
+ return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
+ changed);
+}
#elif defined(CMake_USE_XCOFF_PARSER)
bool cmSystemTools::ChangeRPath(std::string const& file,
std::string const& oldRPath,
@@ -2775,6 +2831,13 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
}
return true;
}
+
+bool cmSystemTools::SetRPath(std::string const& /*file*/,
+ std::string const& /*newRPath*/,
+ std::string* /*emsg*/, bool* /*changed*/)
+{
+ return false;
+}
#else
bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
std::string const& /*oldRPath*/,
@@ -2784,6 +2847,13 @@ bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
{
return false;
}
+
+bool cmSystemTools::SetRPath(std::string const& /*file*/,
+ std::string const& /*newRPath*/,
+ std::string* /*emsg*/, bool* /*changed*/)
+{
+ return false;
+}
#endif
bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 5c3b5a9..44ccbf7 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -456,13 +456,17 @@ public:
static bool GuessLibraryInstallName(std::string const& fullPath,
std::string& soname);
- /** Try to set the RPATH in an ELF binary. */
+ /** Try to change the RPATH in an ELF binary. */
static bool ChangeRPath(std::string const& file, std::string const& oldRPath,
std::string const& newRPath,
bool removeEnvironmentRPath,
std::string* emsg = nullptr,
bool* changed = nullptr);
+ /** Try to set the RPATH in an ELF binary. */
+ static bool SetRPath(std::string const& file, std::string const& newRPath,
+ std::string* emsg = nullptr, bool* changed = nullptr);
+
/** Try to remove the RPATH from an ELF binary. */
static bool RemoveRPath(std::string const& file, std::string* emsg = nullptr,
bool* removed = nullptr);
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 331f637..fccf15b 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -478,6 +478,7 @@ if(BUILD_TESTING)
ADD_TEST_MACRO(Preprocess Preprocess)
set(ExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
-DCMake_TEST_CUDA:BOOL=${CMake_TEST_CUDA}
+ -DCMake_INSTALL_NAME_TOOL_BUG:BOOL=${CMake_INSTALL_NAME_TOOL_BUG}
)
ADD_TEST_MACRO(ExportImport ExportImport)
set_property(TEST ExportImport APPEND
diff --git a/Tests/ExportImport/CMakeLists.txt b/Tests/ExportImport/CMakeLists.txt
index 4999612..e3f32c2 100644
--- a/Tests/ExportImport/CMakeLists.txt
+++ b/Tests/ExportImport/CMakeLists.txt
@@ -77,21 +77,29 @@ set_property(
PROPERTY SYMBOLIC 1
)
-# Install the imported targets.
-add_custom_command(
- OUTPUT ${ExportImport_BINARY_DIR}/ImportInstall
- COMMAND ${CMAKE_COMMAND} -E rm -rf ${ExportImport_BINARY_DIR}/Import/install
- COMMAND ${CMAKE_COMMAND}
- --install ${ExportImport_BINARY_DIR}/Import
- --prefix ${ExportImport_BINARY_DIR}/Import/install
- ${NESTED_CONFIG_INSTALL_TYPE}
- )
-add_custom_target(ImportInstallTarget ALL DEPENDS ${ExportImport_BINARY_DIR}/ImportInstall)
+# Run the install tests.
+set(install_deps)
+set(rdep_tests)
+if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|Windows|Darwin)$" AND NOT CMake_INSTALL_NAME_TOOL_BUG)
+ set(rdep_tests RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCY_SET)
+endif()
+foreach(name IMPORTED_RUNTIME_ARTIFACTS ${rdep_tests})
+ add_custom_command(
+ OUTPUT ${ExportImport_BINARY_DIR}/ImportInstall-${name}
+ COMMAND ${CMAKE_COMMAND} -E rm -rf ${ExportImport_BINARY_DIR}/Import/install-${name}/install
+ COMMAND ${CMAKE_COMMAND}
+ --install ${ExportImport_BINARY_DIR}/Import/install-${name}
+ --prefix ${ExportImport_BINARY_DIR}/Import/install-${name}/install
+ ${NESTED_CONFIG_INSTALL_TYPE}
+ )
+ list(APPEND install_deps ${ExportImport_BINARY_DIR}/ImportInstall-${name})
+ set_property(
+ SOURCE ${ExportImport_BINARY_DIR}/ImportInstall-${name}
+ PROPERTY SYMBOLIC 1
+ )
+endforeach()
+add_custom_target(ImportInstallTarget ALL DEPENDS ${install_deps})
add_dependencies(ImportInstallTarget ImportTarget)
-set_property(
- SOURCE ${ExportImport_BINARY_DIR}/ImportInstall
- PROPERTY SYMBOLIC 1
- )
add_executable(ExportImport main.c)
add_dependencies(ExportImport ImportTarget)
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index fa0016b..a2968d4 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -690,3 +690,5 @@ if(NOT XCODE)
install(TARGETS testLibFromGeneratedSource EXPORT testLibFromGeneratedSource_Export)
install(EXPORT testLibFromGeneratedSource_Export DESTINATION lib)
endif()
+
+add_subdirectory(install-RUNTIME_DEPENDENCY_SET)
diff --git a/Tests/ExportImport/Export/install-RUNTIME_DEPENDENCY_SET/CMakeLists.txt b/Tests/ExportImport/Export/install-RUNTIME_DEPENDENCY_SET/CMakeLists.txt
new file mode 100644
index 0000000..f50cc1d
--- /dev/null
+++ b/Tests/ExportImport/Export/install-RUNTIME_DEPENDENCY_SET/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.20)
+
+set(CMAKE_SKIP_RPATH OFF)
+
+foreach(i 1 2 3 4 5 6 7 8 9 10 11 12)
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep${i}.c"
+"#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void dep${i}(void)
+{
+}
+")
+ add_library(dep${i} SHARED "${CMAKE_CURRENT_BINARY_DIR}/dep${i}.c")
+endforeach()
+
+set_target_properties(dep9 PROPERTIES
+ FRAMEWORK TRUE
+ )
+set_target_properties(dep2 PROPERTIES
+ VERSION 1.2.3
+ SOVERSION 1
+ )
+
+add_library(deplib SHARED deplib.c)
+target_link_libraries(deplib PRIVATE dep1)
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set_target_properties(deplib PROPERTIES
+ INSTALL_RPATH "@loader_path/"
+ )
+endif()
+
+install(TARGETS dep1 dep2 dep3 dep4 dep5 dep6 dep7 dep8 dep9 dep10 dep11 dep12 deplib EXPORT install-RUNTIME_DEPENDENCY_SET
+ RUNTIME DESTINATION install-RUNTIME_DEPENDENCY_SET/bin
+ LIBRARY DESTINATION install-RUNTIME_DEPENDENCY_SET/lib
+ ARCHIVE DESTINATION install-RUNTIME_DEPENDENCY_SET/lib
+ FRAMEWORK DESTINATION install-RUNTIME_DEPENDENCY_SET/frameworks
+ )
+install(EXPORT install-RUNTIME_DEPENDENCY_SET
+ FILE targets.cmake
+ DESTINATION install-RUNTIME_DEPENDENCY_SET
+ )
diff --git a/Tests/ExportImport/Export/install-RUNTIME_DEPENDENCY_SET/deplib.c b/Tests/ExportImport/Export/install-RUNTIME_DEPENDENCY_SET/deplib.c
new file mode 100644
index 0000000..e5da196
--- /dev/null
+++ b/Tests/ExportImport/Export/install-RUNTIME_DEPENDENCY_SET/deplib.c
@@ -0,0 +1,12 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void dep1(void);
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void deplib(void)
+{
+ dep1();
+}
diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt
index e64c6b4..0063130 100644
--- a/Tests/ExportImport/Import/CMakeLists.txt
+++ b/Tests/ExportImport/Import/CMakeLists.txt
@@ -29,3 +29,9 @@ add_subdirectory(version_range)
# Test install(IMPORTED_RUNTIME_ARTIFACTS)
add_subdirectory(install-IMPORTED_RUNTIME_ARTIFACTS)
+
+# Test install(RUNTIME_DEPENDENCIES) and install(RUNTIME_DEPENDENCY_SET)
+if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|Windows|Darwin)$")
+ add_subdirectory(install-RUNTIME_DEPENDENCIES)
+ add_subdirectory(install-RUNTIME_DEPENDENCY_SET)
+endif()
diff --git a/Tests/ExportImport/Import/check_installed.cmake b/Tests/ExportImport/Import/check_installed.cmake
new file mode 100644
index 0000000..6e51f92
--- /dev/null
+++ b/Tests/ExportImport/Import/check_installed.cmake
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.20)
+
+function(check_installed expect)
+ file(GLOB_RECURSE actual
+ LIST_DIRECTORIES TRUE
+ RELATIVE ${CMAKE_INSTALL_PREFIX}
+ ${CMAKE_INSTALL_PREFIX}/*
+ )
+ if(actual)
+ list(SORT actual)
+ endif()
+ if(NOT "${actual}" MATCHES "${expect}")
+ message(FATAL_ERROR "Installed files:
+ ${actual}
+do not match what we expected:
+ ${expect}
+in directory:
+ ${CMAKE_INSTALL_PREFIX}")
+ endif()
+endfunction()
diff --git a/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake
index 29b298f..054ce9c 100644
--- a/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake
+++ b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake
@@ -1,23 +1,4 @@
-cmake_minimum_required(VERSION 3.20)
-
-function(check_installed expect)
- file(GLOB_RECURSE actual
- LIST_DIRECTORIES TRUE
- RELATIVE ${CMAKE_INSTALL_PREFIX}
- ${CMAKE_INSTALL_PREFIX}/*
- )
- if(actual)
- list(SORT actual)
- endif()
- if(NOT "${actual}" MATCHES "${expect}")
- message(FATAL_ERROR "Installed files:
- ${actual}
-do not match what we expected:
- ${expect}
-in directory:
- ${CMAKE_INSTALL_PREFIX}")
- endif()
-endfunction()
+include("${CMAKE_CURRENT_LIST_DIR}/../check_installed.cmake")
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
set(_dirs [[aaa;aaa/executables;aaa/executables/testExe1-4;aaa/executables/testExe3;aaa/libraries;aaa/libraries/libtestExe2lib\.so;aaa/libraries/libtestLib3lib(-d|-r)?\.so\.1\.2;aaa/libraries/libtestLib3lib(-d|-r)?\.so\.3;aaa/libraries/libtestLib4\.so;aaa/libraries/libtestMod1\.so;aaa/libraries/libtestMod2\.so]])
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt
new file mode 100644
index 0000000..d1c4ff2
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt
@@ -0,0 +1,74 @@
+set(CMAKE_SKIP_RPATH OFF)
+
+# Import targets from the install tree.
+include(${Import_BINARY_DIR}/../Root/install-RUNTIME_DEPENDENCY_SET/targets.cmake)
+
+add_executable(exe1 main.c)
+add_executable(exe2 main.c)
+
+if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set_target_properties(exe1 exe2 PROPERTIES
+ # Multiple MACOSX_BUNDLE executables are allowed on non-macOS platforms.
+ MACOSX_BUNDLE TRUE
+ )
+endif()
+
+add_library(sublib1 SHARED sublib1.c)
+target_link_libraries(sublib1 PRIVATE dep6)
+
+add_library(sublib2 SHARED sublib2.c)
+target_link_libraries(sublib2 PRIVATE dep7)
+
+foreach(i exe1 exe2)
+ target_link_libraries(${i} PRIVATE
+ dep1
+ dep2
+ dep3
+ dep4
+ dep5
+ dep10
+ dep11
+ dep12
+ sublib1
+ sublib2
+ )
+endforeach()
+
+add_library(lib SHARED lib.c)
+target_link_libraries(lib PRIVATE dep8)
+
+add_library(mod MODULE mod.c)
+target_link_libraries(mod PRIVATE dep9)
+if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set_target_properties(mod PROPERTIES
+ SKIP_BUILD_RPATH TRUE
+ )
+endif()
+
+set(_framework_args)
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set(_framework_args FRAMEWORK DESTINATION subdir/frameworks)
+endif()
+install(TARGETS exe1 exe2 lib mod sublib1
+ RUNTIME_DEPENDENCIES
+ PRE_INCLUDE_REGEXES "$<1:dep([2-9]|1[012])>"
+ PRE_EXCLUDE_REGEXES "$<1:.*>"
+ POST_INCLUDE_REGEXES "$<1:(bin|lib)/(lib)?dep3>"
+ POST_EXCLUDE_REGEXES "$<1:(bin|lib)/(lib)?dep[34]>"
+ POST_INCLUDE_FILES "$<TARGET_FILE:dep10>" "$<TARGET_FILE:dep11>"
+ POST_EXCLUDE_FILES "$<TARGET_FILE:dep11>" "$<TARGET_FILE:dep12>"
+ DIRECTORIES "$<TARGET_FILE_DIR:dep9>"
+ RUNTIME DESTINATION "$<1:subdir/bin>"
+ LIBRARY DESTINATION "$<1:subdir/lib>"
+ ${_framework_args}
+ )
+
+install(TARGETS lib
+ RUNTIME_DEPENDENCIES
+ PRE_INCLUDE_REGEXES dep8
+ PRE_EXCLUDE_REGEXES ".*"
+ DIRECTORIES "$<TARGET_FILE_DIR:dep8>"
+ ${_framework_args}
+ )
+
+install(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/check_installed.cmake")
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/check_installed.cmake b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/check_installed.cmake
new file mode 100644
index 0000000..6a34697
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/check_installed.cmake
@@ -0,0 +1,11 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../check_installed.cmake")
+
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+ check_installed([[^lib;lib/libdep8\.so;lib/liblib\.so;subdir;subdir/bin;subdir/bin/exe1;subdir/bin/exe2;subdir/lib;subdir/lib/libdep10\.so;subdir/lib/libdep11\.so;subdir/lib/libdep2\.so\.1;subdir/lib/libdep2\.so\.1\.2\.3;subdir/lib/libdep3\.so;subdir/lib/libdep5\.so;subdir/lib/libdep6\.so;subdir/lib/libdep8\.so;subdir/lib/libdep9\.so;subdir/lib/liblib\.so;subdir/lib/libmod\.so;subdir/lib/libsublib1\.so$]])
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ set(_msvc_check [[bin;bin/dep8\.dll;bin/lib\.dll;lib;lib/lib\.lib;subdir;subdir/bin;subdir/bin/dep10\.dll;subdir/bin/dep11\.dll;subdir/bin/dep2\.dll;subdir/bin/dep3\.dll;subdir/bin/dep5\.dll;subdir/bin/dep6\.dll;subdir/bin/dep8\.dll;subdir/bin/dep9\.dll;subdir/bin/exe1\.exe;subdir/bin/exe2\.exe;subdir/bin/lib\.dll;subdir/bin/sublib1\.dll;subdir/lib;subdir/lib/mod\.dll]])
+ set(_mingw_check [[bin;bin/libdep8\.dll;bin/liblib\.dll;lib;lib/liblib\.dll\.a;lib/liblib\.lib;subdir;subdir/bin;subdir/bin/exe1\.exe;subdir/bin/exe2\.exe;subdir/bin/libdep10\.dll;subdir/bin/libdep11\.dll;subdir/bin/libdep2\.dll;subdir/bin/libdep3\.dll;subdir/bin/libdep5\.dll;subdir/bin/libdep6\.dll;subdir/bin/libdep8\.dll;subdir/bin/libdep9\.dll;subdir/bin/liblib\.dll;subdir/bin/libsublib1\.dll;subdir/lib;subdir/lib/libmod\.dll]])
+ check_installed("^(${_msvc_check}|${_mingw_check})$")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ check_installed([[^lib;lib/libdep8\.dylib;lib/liblib\.dylib;subdir;subdir/bin;subdir/bin/exe1;subdir/bin/exe2;subdir/frameworks;subdir/frameworks/dep9\.framework;subdir/frameworks/dep9\.framework/Resources;subdir/frameworks/dep9\.framework/Versions;subdir/frameworks/dep9\.framework/Versions/A;subdir/frameworks/dep9\.framework/Versions/A/Resources;subdir/frameworks/dep9\.framework/Versions/A/Resources/Info\.plist(;subdir/frameworks/dep9.framework/Versions/A/_CodeSignature;subdir/frameworks/dep9.framework/Versions/A/_CodeSignature/CodeResources)?;subdir/frameworks/dep9\.framework/Versions/A/dep9;subdir/frameworks/dep9\.framework/Versions/Current;subdir/frameworks/dep9\.framework/dep9;subdir/lib;subdir/lib/libdep10\.dylib;subdir/lib/libdep11\.dylib;subdir/lib/libdep2\.1\.2\.3\.dylib;subdir/lib/libdep2\.1\.dylib;subdir/lib/libdep3\.dylib;subdir/lib/libdep5\.dylib;subdir/lib/libdep6\.dylib;subdir/lib/libdep8\.dylib;subdir/lib/liblib\.dylib;subdir/lib/libmod\.so;subdir/lib/libsublib1\.dylib$]])
+endif()
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/lib.c b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/lib.c
new file mode 100644
index 0000000..9a64887
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/lib.c
@@ -0,0 +1,12 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void dep8(void);
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void lib(void)
+{
+ dep8();
+}
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/main.c b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/main.c
new file mode 100644
index 0000000..94a7862
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/main.c
@@ -0,0 +1,31 @@
+#ifdef _WIN32
+# define DLLIMPORT __declspec(dllimport)
+#else
+# define DLLIMPORT
+#endif
+
+DLLIMPORT extern void dep1(void);
+DLLIMPORT extern void dep2(void);
+DLLIMPORT extern void dep3(void);
+DLLIMPORT extern void dep4(void);
+DLLIMPORT extern void dep5(void);
+DLLIMPORT extern void dep10(void);
+DLLIMPORT extern void dep11(void);
+DLLIMPORT extern void dep12(void);
+DLLIMPORT extern void sublib1(void);
+DLLIMPORT extern void sublib2(void);
+
+int main(void)
+{
+ dep1();
+ dep2();
+ dep3();
+ dep4();
+ dep5();
+ dep10();
+ dep11();
+ dep12();
+ sublib1();
+ sublib2();
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/mod.c b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/mod.c
new file mode 100644
index 0000000..d001299
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/mod.c
@@ -0,0 +1,12 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void dep9(void);
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void mod(void)
+{
+ dep9();
+}
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/sublib1.c b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/sublib1.c
new file mode 100644
index 0000000..f17b902
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/sublib1.c
@@ -0,0 +1,12 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void dep6(void);
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void sublib1(void)
+{
+ dep6();
+}
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/sublib2.c b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/sublib2.c
new file mode 100644
index 0000000..61b5c83
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/sublib2.c
@@ -0,0 +1,12 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void dep7(void);
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void sublib2(void)
+{
+ dep7();
+}
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/CMakeLists.txt b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/CMakeLists.txt
new file mode 100644
index 0000000..5164506
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/CMakeLists.txt
@@ -0,0 +1,33 @@
+set(CMAKE_SKIP_RPATH OFF)
+
+# Import targets from the install tree.
+include(${Import_BINARY_DIR}/../Root/install-RUNTIME_DEPENDENCY_SET/targets.cmake)
+
+add_executable(exe main.c)
+target_link_libraries(exe PRIVATE dep3 dep4)
+
+install(TARGETS exe RUNTIME_DEPENDENCY_SET myset)
+install(IMPORTED_RUNTIME_ARTIFACTS deplib RUNTIME_DEPENDENCY_SET myset)
+
+install(RUNTIME_DEPENDENCY_SET myset
+ PRE_INCLUDE_REGEXES "dep[134]"
+ PRE_EXCLUDE_REGEXES ".*"
+ POST_INCLUDE_REGEXES "dep[13]"
+ POST_EXCLUDE_REGEXES "dep[34]"
+ DIRECTORIES "$<TARGET_FILE_DIR:dep1>"
+ )
+install(RUNTIME_DEPENDENCY_SET myset
+ PRE_INCLUDE_REGEXES "dep[134]"
+ PRE_EXCLUDE_REGEXES ".*"
+ DIRECTORIES "$<TARGET_FILE_DIR:dep1>"
+ RUNTIME DESTINATION yyy/bin
+ LIBRARY DESTINATION yyy/lib
+ )
+install(RUNTIME_DEPENDENCY_SET myset
+ PRE_INCLUDE_REGEXES "dep[134]"
+ PRE_EXCLUDE_REGEXES ".*"
+ DIRECTORIES "$<TARGET_FILE_DIR:dep1>"
+ DESTINATION zzz
+ )
+
+install(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/check_installed.cmake")
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/check_installed.cmake b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/check_installed.cmake
new file mode 100644
index 0000000..052cced
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/check_installed.cmake
@@ -0,0 +1,11 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../check_installed.cmake")
+
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+ check_installed([[^bin;bin/exe;lib;lib/libdep1\.so;lib/libdep3\.so;lib/libdeplib\.so;yyy;yyy/lib;yyy/lib/libdep1\.so;yyy/lib/libdep3\.so;yyy/lib/libdep4\.so;zzz;zzz/libdep1\.so;zzz/libdep3\.so;zzz/libdep4\.so$]])
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ set(_msvc_check [[bin;bin/dep1\.dll;bin/dep3\.dll;bin/deplib\.dll;bin/exe\.exe;yyy;yyy/bin;yyy/bin/dep1\.dll;yyy/bin/dep3\.dll;yyy/bin/dep4\.dll;zzz;zzz/dep1\.dll;zzz/dep3\.dll;zzz/dep4\.dll]])
+ set(_mingw_check [[bin;bin/exe\.exe;bin/libdep1\.dll;bin/libdep3\.dll;bin/libdeplib\.dll;yyy;yyy/bin;yyy/bin/libdep1\.dll;yyy/bin/libdep3\.dll;yyy/bin/libdep4\.dll;zzz;zzz/libdep1\.dll;zzz/libdep3\.dll;zzz/libdep4\.dll]])
+ check_installed("^(${_msvc_check}|${_mingw_check})$")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ check_installed([[^bin;bin/exe;lib;lib/libdep1\.dylib;lib/libdep3\.dylib;lib/libdeplib\.dylib;yyy;yyy/lib;yyy/lib/libdep1\.dylib;yyy/lib/libdep3\.dylib;yyy/lib/libdep4\.dylib;zzz;zzz/libdep1\.dylib;zzz/libdep3\.dylib;zzz/libdep4\.dylib$]])
+endif()
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/main.c b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/main.c
new file mode 100644
index 0000000..b359498
--- /dev/null
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCY_SET/main.c
@@ -0,0 +1,15 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void dep3(void);
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void dep4(void);
+
+int main(void)
+{
+ dep3();
+ dep4();
+ return 0;
+}
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index 9911ad5..6cf57a3 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -180,6 +180,14 @@ def check_directory(c):
expected_keys.append("scriptFile")
assert is_string(a["scriptFile"], e["scriptFile"])
+ if e.get("runtimeDependencySetName", None) is not None:
+ expected_keys.append("runtimeDependencySetName")
+ assert is_string(a["runtimeDependencySetName"], e["runtimeDependencySetName"])
+
+ if e.get("runtimeDependencySetType", None) is not None:
+ expected_keys.append("runtimeDependencySetType")
+ assert is_string(a["runtimeDependencySetType"], e["runtimeDependencySetType"])
+
if e["backtrace"] is not None:
expected_keys.append("backtrace")
check_backtrace(d, a["backtrace"], e["backtrace"])
@@ -650,6 +658,14 @@ def gen_check_directories(c, g):
if "pathsNamelink" in i:
i["paths"] = i["pathsNamelink"]
+ if sys.platform not in ("win32", "darwin") and "linux" not in sys.platform:
+ for e in expected:
+ e["installers"] = list(filter(lambda i: i["type"] != "runtimeDependencySet", e["installers"]))
+
+ if sys.platform != "darwin":
+ for e in expected:
+ e["installers"] = list(filter(lambda i: i.get("runtimeDependencySetType", None) != "framework", e["installers"]))
+
return expected
def check_directories(c, g):
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
index 7168306..8052c1a 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
@@ -17,6 +17,165 @@
],
"projectName": "Cxx",
"minimumCMakeVersion": "3.12",
- "hasInstallRule": null,
- "installers": []
+ "hasInstallRule": true,
+ "installers": [
+ {
+ "component": "Unspecified",
+ "type": "target",
+ "destination": "lib",
+ "paths": [
+ "^cxx/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?cxx_exe(\\.exe)?$"
+ ],
+ "isExcludeFromAll": null,
+ "isForAllComponents": null,
+ "isOptional": null,
+ "targetId": "^cxx_exe::@a56b12a3f5c0529fb296$",
+ "targetIndex": "cxx_exe",
+ "targetIsImportLibrary": null,
+ "targetInstallNamelink": null,
+ "exportName": null,
+ "exportTargets": null,
+ "scriptFile": null,
+ "backtrace": [
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": 38,
+ "command": "install",
+ "hasParent": true
+ },
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": null,
+ "command": null,
+ "hasParent": false
+ }
+ ]
+ },
+ {
+ "component": "Unspecified",
+ "type": "runtimeDependencySet",
+ "destination": "lib",
+ "paths": null,
+ "isExcludeFromAll": null,
+ "isForAllComponents": null,
+ "isOptional": null,
+ "targetId": null,
+ "targetIndex": null,
+ "targetIsImportLibrary": null,
+ "targetInstallNamelink": null,
+ "exportName": null,
+ "exportTargets": null,
+ "scriptFile": null,
+ "runtimeDependencySetType": "library",
+ "backtrace": [
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": 38,
+ "command": "install",
+ "hasParent": true
+ },
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": null,
+ "command": null,
+ "hasParent": false
+ }
+ ]
+ },
+ {
+ "component": "Unspecified",
+ "type": "runtimeDependencySet",
+ "destination": "fw",
+ "paths": null,
+ "isExcludeFromAll": null,
+ "isForAllComponents": null,
+ "isOptional": null,
+ "targetId": null,
+ "targetIndex": null,
+ "targetIsImportLibrary": null,
+ "targetInstallNamelink": null,
+ "exportName": null,
+ "exportTargets": null,
+ "scriptFile": null,
+ "runtimeDependencySetType": "framework",
+ "backtrace": [
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": 38,
+ "command": "install",
+ "hasParent": true
+ },
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": null,
+ "command": null,
+ "hasParent": false
+ }
+ ]
+ },
+ {
+ "component": "Unspecified",
+ "type": "runtimeDependencySet",
+ "destination": "lib",
+ "paths": null,
+ "isExcludeFromAll": null,
+ "isForAllComponents": null,
+ "isOptional": null,
+ "targetId": null,
+ "targetIndex": null,
+ "targetIsImportLibrary": null,
+ "targetInstallNamelink": null,
+ "exportName": null,
+ "exportTargets": null,
+ "scriptFile": null,
+ "runtimeDependencySetType": "library",
+ "runtimeDependencySetName": "deps",
+ "backtrace": [
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": 43,
+ "command": "install",
+ "hasParent": true
+ },
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": null,
+ "command": null,
+ "hasParent": false
+ }
+ ]
+ },
+ {
+ "component": "Unspecified",
+ "type": "runtimeDependencySet",
+ "destination": "fw",
+ "paths": null,
+ "isExcludeFromAll": null,
+ "isForAllComponents": null,
+ "isOptional": null,
+ "targetId": null,
+ "targetIndex": null,
+ "targetIsImportLibrary": null,
+ "targetInstallNamelink": null,
+ "exportName": null,
+ "exportTargets": null,
+ "scriptFile": null,
+ "runtimeDependencySetType": "framework",
+ "runtimeDependencySetName": "deps",
+ "backtrace": [
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": 43,
+ "command": "install",
+ "hasParent": true
+ },
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": null,
+ "command": null,
+ "hasParent": false
+ }
+ ]
+ }
+ ]
}
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
index c9e652b..385fa62 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
@@ -115,6 +115,23 @@
"prefix": "^(/usr/local|[A-Za-z]:.*/codemodel-v2)$",
"destinations": [
{
+ "path": "lib",
+ "backtrace": [
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": 38,
+ "command": "install",
+ "hasParent": true
+ },
+ {
+ "file": "^cxx/CMakeLists\\.txt$",
+ "line": null,
+ "command": null,
+ "hasParent": false
+ }
+ ]
+ },
+ {
"path": "bin",
"backtrace": [
{
diff --git a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
index 95c803f..3ae3b60 100644
--- a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
+++ b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
@@ -30,3 +30,18 @@ if(CMAKE_CXX_STANDARD_DEFAULT AND DEFINED CMAKE_CXX11_STANDARD_COMPILE_OPTION)
target_compile_features(cxx_standard_compile_feature_exe PRIVATE cxx_decltype)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_std_11.txt" "")
endif()
+
+set(_rdeps)
+if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|Windows|Darwin)$")
+ set(_rdeps RUNTIME_DEPENDENCIES)
+endif()
+install(TARGETS cxx_exe ${_rdeps}
+ DESTINATION lib
+ FRAMEWORK DESTINATION fw
+ )
+if(_rdeps)
+ install(RUNTIME_DEPENDENCY_SET deps
+ DESTINATION lib
+ FRAMEWORK DESTINATION fw
+ )
+endif()
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
index c71b9ba..07679b7 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
@@ -36,6 +36,7 @@ endfunction()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
if(NOT CMake_INSTALL_NAME_TOOL_BUG)
run_install_test(macos)
+ run_install_test(macos-rpath)
run_install_test(macos-unresolved)
run_install_test(macos-conflict)
run_install_test(macos-notfile)
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-rpath.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-rpath.cmake
new file mode 100644
index 0000000..798045f
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-rpath.cmake
@@ -0,0 +1,35 @@
+enable_language(C)
+
+file(WRITE "${CMAKE_BINARY_DIR}/toplib.c" "extern void sublib1(void);\nextern void sublib2(void);\nvoid toplib(void)\n{\n sublib1();\n sublib2();\n}\n")
+add_library(toplib SHARED "${CMAKE_BINARY_DIR}/toplib.c")
+file(WRITE "${CMAKE_BINARY_DIR}/sublib1.c" "extern void sublib2(void);\nvoid sublib1(void)\n{\n sublib2();\n}\n")
+add_library(sublib1 SHARED "${CMAKE_BINARY_DIR}/sublib1.c")
+file(WRITE "${CMAKE_BINARY_DIR}/sublib2.c" "void sublib2(void)\n{\n}\n")
+add_library(sublib2 SHARED "${CMAKE_BINARY_DIR}/sublib2.c")
+target_link_libraries(toplib PRIVATE sublib1 sublib2)
+target_link_libraries(sublib1 PRIVATE sublib2)
+set_property(TARGET toplib PROPERTY INSTALL_RPATH "@loader_path/d1;@loader_path/d2")
+set_property(TARGET sublib1 PROPERTY INSTALL_RPATH "@loader_path/;@loader_path/../d2")
+install(TARGETS toplib DESTINATION lib)
+install(TARGETS sublib1 DESTINATION lib/d1)
+install(TARGETS sublib2 DESTINATION lib/d2)
+
+install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:toplib>"
+ RPATH_PREFIX _rpaths
+ )
+
+ set(_expected_rpath "(^|;)@loader_path/;@loader_path/\\.\\./d2$")
+ set(_actual_rpath "${_rpaths_${CMAKE_INSTALL_PREFIX}/lib/d1/$<TARGET_FILE_NAME:sublib1>}")
+ if(NOT _actual_rpath MATCHES "${_expected_rpath}")
+ message(FATAL_ERROR "Expected rpath:\n ${_expected_rpath}\nActual rpath:\n ${_actual_rpath}")
+ endif()
+
+ # Since RPATH_PREFIX is an undocumented option for install(), we don't really need the rpath
+ # for the top files anyway.
+ if(DEFINED "_rpaths_${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:toplib>")
+ message(FATAL_ERROR "rpath for top library should not be defined")
+ endif()
+ ]])
diff --git a/Tests/RunCMake/file-RPATH/Common.cmake b/Tests/RunCMake/file-RPATH/Common.cmake
index cc1efb5..7034aad 100644
--- a/Tests/RunCMake/file-RPATH/Common.cmake
+++ b/Tests/RunCMake/file-RPATH/Common.cmake
@@ -62,3 +62,40 @@ foreach(f ${files})
message(FATAL_ERROR "RPATH_CHECK did not remove ${f}")
endif()
endforeach()
+
+# TODO Implement RPATH_SET in XCOFF.
+if(format STREQUAL "ELF")
+ foreach(f ${names})
+ file(COPY ${in}/${f} DESTINATION ${out} NO_SOURCE_PERMISSIONS)
+ endforeach()
+
+ foreach(f ${files})
+ # Set the RPATH.
+ file(RPATH_SET FILE "${f}"
+ NEW_RPATH "/new/rpath")
+ set(rpath)
+ file(STRINGS "${f}" rpath REGEX "/new/rpath" LIMIT_COUNT 1)
+ if(NOT rpath)
+ message(FATAL_ERROR "RPATH not set in ${f}")
+ endif()
+ file(STRINGS "${f}" rpath REGEX "/rpath/sample" LIMIT_COUNT 1)
+ if(rpath)
+ message(FATAL_EROR "RPATH not removed in ${f}")
+ endif()
+
+ # Remove the RPATH.
+ file(RPATH_SET FILE "${f}"
+ NEW_RPATH "")
+ set(rpath)
+ file(STRINGS "${f}" rpath REGEX "/new/rpath" LIMIT_COUNT 1)
+ if(rpath)
+ message(FATAL_ERROR "RPATH not removed from ${f}")
+ endif()
+
+ # Check again...this should remove the file.
+ file(RPATH_CHECK FILE "${f}" RPATH "/new/rpath")
+ if(EXISTS "${f}")
+ message(FATAL_ERROR "RPATH_CHECK did not remove ${f}")
+ endif()
+ endforeach()
+endif()
diff --git a/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported-result.txt b/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt b/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt
new file mode 100644
index 0000000..7ae6606
--- /dev/null
+++ b/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported\.cmake:[0-9]+ \(install\):
+ install IMPORTED_RUNTIME_ARTIFACTS RUNTIME_DEPENDENCY_SET is not supported
+ on system "[^
+]*"
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported.cmake b/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported.cmake
new file mode 100644
index 0000000..04f1995
--- /dev/null
+++ b/Tests/RunCMake/install/IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported.cmake
@@ -0,0 +1,2 @@
+add_executable(exe IMPORTED)
+install(IMPORTED_RUNTIME_ARTIFACTS exe RUNTIME_DEPENDENCY_SET deps)
diff --git a/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported-result.txt b/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt b/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt
new file mode 100644
index 0000000..cab309b
--- /dev/null
+++ b/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at RUNTIME_DEPENDENCY_SET-unsupported\.cmake:[0-9]+ \(install\):
+ install RUNTIME_DEPENDENCY_SET is not supported on system "[^
+]*"
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported.cmake b/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported.cmake
new file mode 100644
index 0000000..60772a0
--- /dev/null
+++ b/Tests/RunCMake/install/RUNTIME_DEPENDENCY_SET-unsupported.cmake
@@ -0,0 +1 @@
+install(RUNTIME_DEPENDENCY_SET deps)
diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake
index 94887a0..f79a3ea 100644
--- a/Tests/RunCMake/install/RunCMakeTest.cmake
+++ b/Tests/RunCMake/install/RunCMakeTest.cmake
@@ -44,7 +44,7 @@ function(check_installed expect)
do not match what we expected:
${expect}
in directory:
- ${CMAKE_INSTALL_PREFIX}" PARENT_SCOPE)
+ ${CMAKE_INSTALL_PREFIX}\n" PARENT_SCOPE)
endif()
endfunction()
@@ -174,6 +174,26 @@ run_install_test(FILES-PERMISSIONS)
run_install_test(TARGETS-RPATH)
run_install_test(InstallRequiredSystemLibraries)
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ run_cmake(TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle)
+ run_cmake(TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework)
+endif()
+
+if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|Darwin|Windows)$")
+ run_install_test(TARGETS-RUNTIME_DEPENDENCIES-nodep)
+ run_install_test(TARGETS-RUNTIME_DEPENDENCIES-empty)
+ set(RunCMake_TEST_OPTIONS "-DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}")
+ run_cmake(TARGETS-RUNTIME_DEPENDENCIES-cross)
+ unset(RunCMake_TEST_OPTIONS)
+ run_cmake(TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict)
+ run_cmake(RuntimeDependencies-COMPONENTS)
+else()
+ run_cmake(TARGETS-RUNTIME_DEPENDENCIES-unsupported)
+ run_cmake(TARGETS-RUNTIME_DEPENDENCY_SET-unsupported)
+ run_cmake(IMPORTED_RUNTIME_ARTIFACTS-RUNTIME_DEPENDENCY_SET-unsupported)
+ run_cmake(RUNTIME_DEPENDENCY_SET-unsupported)
+endif()
+
set(run_install_test_components 1)
run_install_test(FILES-EXCLUDE_FROM_ALL)
run_install_test(TARGETS-EXCLUDE_FROM_ALL)
diff --git a/Tests/RunCMake/install/RuntimeDependencies-COMPONENTS.cmake b/Tests/RunCMake/install/RuntimeDependencies-COMPONENTS.cmake
new file mode 100644
index 0000000..4727de3
--- /dev/null
+++ b/Tests/RunCMake/install/RuntimeDependencies-COMPONENTS.cmake
@@ -0,0 +1,39 @@
+enable_language(C)
+
+function(check_components value)
+ get_cmake_property(comp COMPONENTS)
+ if(NOT comp STREQUAL value)
+ message(FATAL_ERROR "Expected value of COMPONENTS:\n ${value}\nActual value of COMPONENTS:\n ${comp}")
+ endif()
+endfunction()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ add_library(tgt MODULE obj1.c)
+else()
+ add_executable(tgt main.c)
+endif()
+
+install(TARGETS tgt
+ RUNTIME_DEPENDENCIES
+ RUNTIME DESTINATION bin COMPONENT bin1
+ LIBRARY DESTINATION lib COMPONENT lib1
+ FRAMEWORK DESTINATION fw COMPONENT fw1
+ )
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ check_components("bin1;fw1;lib1")
+else()
+ check_components("bin1;lib1")
+endif()
+
+install(RUNTIME_DEPENDENCY_SET deps
+ RUNTIME DESTINATION bin COMPONENT bin2
+ LIBRARY DESTINATION lib COMPONENT lib2
+ FRAMEWORK DESTINATION fw COMPONENT fw2
+ )
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ check_components("bin1;fw1;fw2;lib1;lib2")
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ check_components("bin1;bin2;lib1")
+elseif()
+ check_components("bin1;lib1;lib2")
+endif()
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt
new file mode 100644
index 0000000..b7bbb55
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-cross\.cmake:[0-9]+ \(install\):
+ install TARGETS RUNTIME_DEPENDENCIES is not supported when cross-compiling\.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake
new file mode 100644
index 0000000..36b2eb7
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(exe main.c)
+install(TARGETS exe RUNTIME_DEPENDENCIES)
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake
new file mode 100644
index 0000000..dafc2a4
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake
@@ -0,0 +1 @@
+check_installed([[^static;static/(liblib\.a|lib\.lib)$]])
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake
new file mode 100644
index 0000000..e46e1d9
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+add_library(lib STATIC obj1.c)
+
+install(TARGETS lib RUNTIME_DEPENDENCIES
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION static
+ FRAMEWORK DESTINATION fw
+ )
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt
new file mode 100644
index 0000000..6ab14f6
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework\.cmake:[0-9]+ \(install\):
+ install TARGETS RUNTIME_DEPENDENCIES given no FRAMEWORK DESTINATION
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake
new file mode 100644
index 0000000..36b2eb7
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(exe main.c)
+install(TARGETS exe RUNTIME_DEPENDENCIES)
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt
new file mode 100644
index 0000000..c7b49c7
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle\.cmake:[0-9]+ \(install\):
+ install A runtime dependency set may only have one bundle executable\.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake
new file mode 100644
index 0000000..a848a24
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_executable(exe1 MACOSX_BUNDLE main.c)
+add_executable(exe2 MACOSX_BUNDLE main.c)
+
+install(TARGETS exe1 exe2
+ RUNTIME_DEPENDENCIES
+ BUNDLE DESTINATION bundles
+ FRAMEWORK DESTINATION fw
+ )
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake
new file mode 100644
index 0000000..9f455b1
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake
@@ -0,0 +1 @@
+check_installed([[^bin;bin/exe(\.exe)?$]])
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake
new file mode 100644
index 0000000..02466561
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+add_executable(exe main.c)
+
+install(TARGETS exe
+ RUNTIME_DEPENDENCIES
+ PRE_EXCLUDE_REGEXES ".*"
+ FRAMEWORK DESTINATION fw
+ )
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt
new file mode 100644
index 0000000..c098a4c
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-unsupported\.cmake:[0-9]+ \(install\):
+ install TARGETS RUNTIME_DEPENDENCIES is not supported on system "[^
+]*"
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake
new file mode 100644
index 0000000..36b2eb7
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(exe main.c)
+install(TARGETS exe RUNTIME_DEPENDENCIES)
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict-stderr.txt
new file mode 100644
index 0000000..e2484ec
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict\.cmake:[0-9]+ \(install\):
+ install TARGETS cannot have both RUNTIME_DEPENDENCIES and
+ RUNTIME_DEPENDENCY_SET\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict.cmake
new file mode 100644
index 0000000..f373b3b
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-RUNTIME_DEPENDENCIES-conflict.cmake
@@ -0,0 +1,7 @@
+enable_language(C)
+
+add_executable(exe main.c)
+install(TARGETS exe
+ RUNTIME_DEPENDENCY_SET deps
+ RUNTIME_DEPENDENCIES
+ )
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt
new file mode 100644
index 0000000..f660346
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCY_SET-unsupported\.cmake:[0-9]+ \(install\):
+ install TARGETS RUNTIME_DEPENDENCY_SET is not supported on system "[^
+]*"
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported.cmake
new file mode 100644
index 0000000..be0f507
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_SET-unsupported.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(exe main.c)
+install(TARGETS exe RUNTIME_DEPENDENCY_SET deps)
diff --git a/bootstrap b/bootstrap
index 911558d..f8d2f69 100755
--- a/bootstrap
+++ b/bootstrap
@@ -387,7 +387,10 @@ CMAKE_CXX_SOURCES="\
cmInstallFilesCommand \
cmInstallFilesGenerator \
cmInstallGenerator \
+ cmInstallGetRuntimeDependenciesGenerator \
cmInstallImportedRuntimeArtifactsGenerator \
+ cmInstallRuntimeDependencySet \
+ cmInstallRuntimeDependencySetGenerator \
cmInstallScriptGenerator \
cmInstallSubdirectoryGenerator \
cmInstallTargetGenerator \