summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/install.rst33
-rw-r--r--Help/release/dev/install-imported-runtime-artifacts.rst5
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/cmInstallCommand.cxx224
-rw-r--r--Source/cmInstallImportedRuntimeArtifactsGenerator.cxx146
-rw-r--r--Source/cmInstallImportedRuntimeArtifactsGenerator.h44
-rw-r--r--Tests/ExportImport/CMakeLists.txt28
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt6
-rw-r--r--Tests/ExportImport/Import/CMakeLists.txt3
-rw-r--r--Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt30
-rw-r--r--Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake57
-rwxr-xr-xbootstrap1
12 files changed, 572 insertions, 7 deletions
diff --git a/Help/command/install.rst b/Help/command/install.rst
index 2259176..2865e1d 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -9,6 +9,7 @@ Synopsis
.. parsed-literal::
install(`TARGETS`_ <target>... [...])
+ install(`IMPORTED_RUNTIME_ARTIFACTS`_ <target>... [...])
install({`FILES`_ | `PROGRAMS`_} <file>... [...])
install(`DIRECTORY`_ <dir>... [...])
install(`SCRIPT`_ <file> [...])
@@ -382,6 +383,38 @@ set to ``TRUE`` has undefined behavior.
to ensure that such out-of-directory targets are built before the
subdirectory-specific install rules are run.
+Installing Imported Runtime Artifacts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. _`install(IMPORTED_RUNTIME_ARTIFACTS)`:
+.. _IMPORTED_RUNTIME_ARTIFACTS:
+
+.. versionadded:: 3.21
+
+.. code-block:: cmake
+
+ install(IMPORTED_RUNTIME_ARTIFACTS targets...
+ [[LIBRARY|RUNTIME|FRAMEWORK|BUNDLE]
+ [DESTINATION <dir>]
+ [PERMISSIONS permissions...]
+ [CONFIGURATIONS [Debug|Release|...]]
+ [COMPONENT <component>]
+ [OPTIONAL] [EXCLUDE_FROM_ALL]
+ ] [...]
+ )
+
+The ``IMPORTED_RUNTIME_ARTIFACTS`` form specifies rules for installing the
+runtime artifacts of imported targets. Projects may do this if they want to
+bundle outside executables or modules inside their installation. The
+``LIBRARY``, ``RUNTIME``, ``FRAMEWORK``, and ``BUNDLE`` arguments have the
+same semantics that they do in the `TARGETS`_ mode. Only the runtime artifacts
+of imported targets are installed (except in the case of :prop_tgt:`FRAMEWORK`
+libraries, :prop_tgt:`MACOSX_BUNDLE` executables, and :prop_tgt:`BUNDLE`
+CFBundles.) For example, headers and import libraries associated with DLLs are
+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.
+
Installing Files
^^^^^^^^^^^^^^^^
diff --git a/Help/release/dev/install-imported-runtime-artifacts.rst b/Help/release/dev/install-imported-runtime-artifacts.rst
new file mode 100644
index 0000000..e2821c1
--- /dev/null
+++ b/Help/release/dev/install-imported-runtime-artifacts.rst
@@ -0,0 +1,5 @@
+install-imported-runtime-artifacts
+----------------------------------
+
+* The :command:`install` command gained a new ``IMPORTED_RUNTIME_ARTIFACTS``
+ mode, which can be used to install the runtime artifacts of imported targets.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index bd9e4c2..844a2ee 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -350,6 +350,8 @@ set(SRCS
cmInstalledFile.cxx
cmInstallFilesGenerator.h
cmInstallFilesGenerator.cxx
+ cmInstallImportedRuntimeArtifactsGenerator.h
+ cmInstallImportedRuntimeArtifactsGenerator.cxx
cmInstallScriptGenerator.h
cmInstallScriptGenerator.cxx
cmInstallSubdirectoryGenerator.h
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index e973764..c9bb467 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallCommand.h"
+#include <cassert>
#include <cstddef>
#include <set>
#include <sstream>
@@ -22,6 +23,7 @@
#include "cmInstallExportGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
+#include "cmInstallImportedRuntimeArtifactsGenerator.h"
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmListFileCache.h"
@@ -865,6 +867,227 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
return true;
}
+bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ // This is the IMPORTED_RUNTIME_ARTIFACTS mode.
+ std::vector<cmTarget*> targets;
+
+ struct ArgVectors
+ {
+ std::vector<std::string> Library;
+ std::vector<std::string> Runtime;
+ std::vector<std::string> Framework;
+ std::vector<std::string> Bundle;
+ };
+
+ static auto const argHelper = cmArgumentParser<ArgVectors>{}
+ .Bind("LIBRARY"_s, &ArgVectors::Library)
+ .Bind("RUNTIME"_s, &ArgVectors::Runtime)
+ .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
+ .Bind("BUNDLE"_s, &ArgVectors::Bundle);
+
+ 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 etc. (see above)
+ std::vector<std::string> targetList;
+ std::vector<std::string> unknownArgs;
+ cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
+ genericArgs.Bind("IMPORTED_RUNTIME_ARTIFACTS"_s, targetList);
+ genericArgs.Parse(genericArgVector, &unknownArgs);
+ bool success = genericArgs.Finalize();
+
+ cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments bundleArgs(helper.DefaultComponentName);
+
+ // now parse the args for specific parts of the target (e.g. LIBRARY,
+ // RUNTIME etc.
+ libraryArgs.Parse(argVectors.Library, &unknownArgs);
+ runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
+ frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
+ bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ status.SetError(
+ cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given unknown argument \"",
+ unknownArgs[0], "\"."));
+ return false;
+ }
+
+ // apply generic args
+ libraryArgs.SetGenericArguments(&genericArgs);
+ runtimeArgs.SetGenericArguments(&genericArgs);
+ frameworkArgs.SetGenericArguments(&genericArgs);
+ bundleArgs.SetGenericArguments(&genericArgs);
+
+ success = success && libraryArgs.Finalize();
+ success = success && runtimeArgs.Finalize();
+ success = success && frameworkArgs.Finalize();
+ success = success && bundleArgs.Finalize();
+
+ if (!success) {
+ return false;
+ }
+
+ // Check if there is something to do.
+ if (targetList.empty()) {
+ return true;
+ }
+
+ for (std::string const& tgt : targetList) {
+ if (helper.Makefile->IsAlias(tgt)) {
+ status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"",
+ tgt, "\" which is an alias."));
+ return false;
+ }
+ // Lookup this target in the current directory.
+ cmTarget* target = helper.Makefile->FindTargetToUse(tgt);
+ if (!target || !target->IsImported()) {
+ // If no local target has been found, find it in the global scope.
+ cmTarget* const global_target =
+ helper.Makefile->GetGlobalGenerator()->FindTarget(tgt, true);
+ if (global_target && global_target->IsImported()) {
+ target = global_target;
+ }
+ }
+ if (target) {
+ // Found the target. Check its type.
+ if (target->GetType() != cmStateEnums::EXECUTABLE &&
+ target->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ target->GetType() != cmStateEnums::MODULE_LIBRARY) {
+ status.SetError(
+ cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"", tgt,
+ "\" which is not an executable, library, or module."));
+ return false;
+ }
+ // Store the target in the list to be installed.
+ targets.push_back(target);
+ } else {
+ // Did not find the target.
+ status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"",
+ tgt, "\" which does not exist."));
+ return false;
+ }
+ }
+
+ // Keep track of whether we will be performing an installation of
+ // any files of the given type.
+ bool installsLibrary = false;
+ bool installsRuntime = false;
+ bool installsFramework = false;
+ bool installsBundle = false;
+
+ auto const createInstallGenerator =
+ [helper](cmTarget& target, const cmInstallCommandArguments& typeArgs,
+ const std::string& destination)
+ -> std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator> {
+ return cm::make_unique<cmInstallImportedRuntimeArtifactsGenerator>(
+ target.GetName(), destination, typeArgs.GetPermissions(),
+ typeArgs.GetConfigurations(), typeArgs.GetComponent(),
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile),
+ typeArgs.GetExcludeFromAll(), typeArgs.GetOptional(),
+ helper.Makefile->GetBacktrace());
+ };
+
+ // Generate install script code to install the given targets.
+ for (cmTarget* ti : targets) {
+ // Handle each target type.
+ cmTarget& target = *ti;
+ std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
+ libraryGenerator;
+ std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
+ runtimeGenerator;
+ std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
+ frameworkGenerator;
+ std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
+ bundleGenerator;
+
+ switch (target.GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ if (target.IsDLLPlatform()) {
+ runtimeGenerator = createInstallGenerator(
+ target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
+ } else if (target.IsFrameworkOnApple()) {
+ if (frameworkArgs.GetDestination().empty()) {
+ status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given no "
+ "FRAMEWORK DESTINATION for shared "
+ "library FRAMEWORK target \"",
+ target.GetName(), "\"."));
+ return false;
+ }
+ frameworkGenerator = createInstallGenerator(
+ target, frameworkArgs, frameworkArgs.GetDestination());
+ } else {
+ libraryGenerator = createInstallGenerator(
+ target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
+ }
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ libraryGenerator = createInstallGenerator(
+ target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
+ break;
+ case cmStateEnums::EXECUTABLE:
+ if (target.IsAppBundleOnApple()) {
+ if (bundleArgs.GetDestination().empty()) {
+ status.SetError(
+ cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given no BUNDLE "
+ "DESTINATION for MACOSX_BUNDLE executable target \"",
+ target.GetName(), "\"."));
+ return false;
+ }
+ bundleGenerator = createInstallGenerator(
+ target, bundleArgs, bundleArgs.GetDestination());
+ } else {
+ runtimeGenerator = createInstallGenerator(
+ target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
+ }
+ break;
+ default:
+ assert(false && "This should never happen");
+ break;
+ }
+
+ // Keep track of whether we're installing anything in each category
+ installsLibrary = installsLibrary || libraryGenerator;
+ installsRuntime = installsRuntime || runtimeGenerator;
+ installsFramework = installsFramework || frameworkGenerator;
+ installsBundle = installsBundle || bundleGenerator;
+
+ helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(bundleGenerator));
+ }
+
+ // 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());
+ }
+ if (installsBundle) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ bundleArgs.GetComponent());
+ }
+
+ return true;
+}
+
bool HandleFilesMode(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -1705,6 +1928,7 @@ bool cmInstallCommand(std::vector<std::string> const& args,
{ "SCRIPT"_s, HandleScriptMode },
{ "CODE"_s, HandleScriptMode },
{ "TARGETS"_s, HandleTargetsMode },
+ { "IMPORTED_RUNTIME_ARTIFACTS"_s, HandleImportedRuntimeArtifactsMode },
{ "FILES"_s, HandleFilesMode },
{ "PROGRAMS"_s, HandleFilesMode },
{ "DIRECTORY"_s, HandleDirectoryMode },
diff --git a/Source/cmInstallImportedRuntimeArtifactsGenerator.cxx b/Source/cmInstallImportedRuntimeArtifactsGenerator.cxx
new file mode 100644
index 0000000..01980ac
--- /dev/null
+++ b/Source/cmInstallImportedRuntimeArtifactsGenerator.cxx
@@ -0,0 +1,146 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallImportedRuntimeArtifactsGenerator.h"
+
+#include <cassert>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallType.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+
+namespace {
+const cmsys::RegularExpression FrameworkRegularExpression(
+ "^(.*/)?([^/]*)\\.framework/(.*)$");
+
+const cmsys::RegularExpression BundleRegularExpression(
+ "^(.*/)?([^/]*)\\.app/(.*)$");
+
+const cmsys::RegularExpression CFBundleRegularExpression(
+ "^(.*/)?([^/]*)\\.bundle/(.*)$");
+}
+
+cmInstallImportedRuntimeArtifactsGenerator::
+ cmInstallImportedRuntimeArtifactsGenerator(
+ std::string targetName, std::string const& dest,
+ std::string file_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ bool optional, cmListFileBacktrace backtrace)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all, false, std::move(backtrace))
+ , TargetName(std::move(targetName))
+ , FilePermissions(std::move(file_permissions))
+ , Optional(optional)
+{
+ this->ActionsPerConfig = true;
+}
+
+bool cmInstallImportedRuntimeArtifactsGenerator::Compute(cmLocalGenerator* lg)
+{
+ // Lookup this target in the current directory.
+ this->Target = lg->FindGeneratorTargetToUse(this->TargetName);
+ if (!this->Target || !this->Target->IsImported()) {
+ // If no local target has been found, find it in the global scope.
+ this->Target =
+ lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
+ }
+
+ return true;
+}
+
+std::string cmInstallImportedRuntimeArtifactsGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(
+ this->Destination, this->Target->GetLocalGenerator(), config);
+}
+
+void cmInstallImportedRuntimeArtifactsGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ auto location = this->Target->GetFullPath(config);
+
+ switch (this->Target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ if (this->Target->IsBundleOnApple()) {
+ cmsys::RegularExpressionMatch match;
+ if (BundleRegularExpression.find(location.c_str(), match)) {
+ auto bundleDir = match.match(1);
+ auto bundleName = match.match(2);
+ auto bundlePath = cmStrCat(bundleDir, bundleName, ".app");
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_DIRECTORY, { bundlePath },
+ this->Optional, nullptr,
+ this->FilePermissions.c_str(), nullptr,
+ " USE_SOURCE_PERMISSIONS", indent);
+ }
+ } else {
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_EXECUTABLE, { location },
+ this->Optional, this->FilePermissions.c_str(),
+ nullptr, nullptr, nullptr, indent);
+ }
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ if (this->Target->IsFrameworkOnApple()) {
+ cmsys::RegularExpressionMatch match;
+ if (FrameworkRegularExpression.find(location.c_str(), match)) {
+ auto frameworkDir = match.match(1);
+ auto frameworkName = match.match(2);
+ auto frameworkPath =
+ cmStrCat(frameworkDir, frameworkName, ".framework");
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_DIRECTORY, { frameworkPath },
+ this->Optional, nullptr,
+ this->FilePermissions.c_str(), nullptr,
+ " USE_SOURCE_PERMISSIONS", indent);
+ }
+ } else {
+ std::vector<std::string> files{ location };
+ auto soName = this->Target->GetSOName(config);
+ auto soNameFile =
+ cmStrCat(this->Target->GetDirectory(config), '/', soName);
+ if (!soName.empty() && soNameFile != location) {
+ files.push_back(soNameFile);
+ }
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_SHARED_LIBRARY, files,
+ this->Optional, this->FilePermissions.c_str(),
+ nullptr, nullptr, nullptr, indent);
+ }
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ if (this->Target->IsCFBundleOnApple()) {
+ cmsys::RegularExpressionMatch match;
+ if (CFBundleRegularExpression.find(location.c_str(), match)) {
+ auto bundleDir = match.match(1);
+ auto bundleName = match.match(2);
+ auto bundlePath = cmStrCat(bundleDir, bundleName, ".bundle");
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_DIRECTORY, { bundlePath },
+ this->Optional, nullptr,
+ this->FilePermissions.c_str(), nullptr,
+ " USE_SOURCE_PERMISSIONS", indent);
+ }
+ } else {
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_MODULE_LIBRARY, { location },
+ this->Optional, this->FilePermissions.c_str(),
+ nullptr, nullptr, nullptr, indent);
+ }
+ break;
+ default:
+ assert(false && "This should never happen");
+ break;
+ }
+}
diff --git a/Source/cmInstallImportedRuntimeArtifactsGenerator.h b/Source/cmInstallImportedRuntimeArtifactsGenerator.h
new file mode 100644
index 0000000..9e045ee
--- /dev/null
+++ b/Source/cmInstallImportedRuntimeArtifactsGenerator.h
@@ -0,0 +1,44 @@
+/* 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 cmGeneratorTarget;
+class cmLocalGenerator;
+
+class cmInstallImportedRuntimeArtifactsGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallImportedRuntimeArtifactsGenerator(
+ std::string targetName, std::string const& dest,
+ std::string file_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ bool optional, cmListFileBacktrace backtrace = cmListFileBacktrace());
+ ~cmInstallImportedRuntimeArtifactsGenerator() override = default;
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ cmGeneratorTarget* GetTarget() const { return this->Target; }
+
+ bool GetOptional() const { return this->Optional; }
+
+ std::string GetDestination(std::string const& config) const;
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+private:
+ std::string const TargetName;
+ cmGeneratorTarget* Target;
+ std::string const FilePermissions;
+ bool const Optional;
+};
diff --git a/Tests/ExportImport/CMakeLists.txt b/Tests/ExportImport/CMakeLists.txt
index d88eb11..4999612 100644
--- a/Tests/ExportImport/CMakeLists.txt
+++ b/Tests/ExportImport/CMakeLists.txt
@@ -16,14 +16,12 @@ set_property(
)
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-if(_isMultiConfig)
- set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+if(_isMultiConfig OR CMAKE_BUILD_TYPE)
+ set(NESTED_CONFIG_TYPE -C "$<CONFIG>")
+ set(NESTED_CONFIG_INSTALL_TYPE --config "$<CONFIG>")
else()
- if(CMAKE_BUILD_TYPE)
- set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
- else()
- set(NESTED_CONFIG_TYPE)
- endif()
+ set(NESTED_CONFIG_TYPE)
+ set(NESTED_CONFIG_INSTALL_TYPE)
endif()
if(MINGW OR MSYS)
@@ -79,5 +77,21 @@ 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)
+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 6d9b4ab..fa0016b 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -395,6 +395,10 @@ target_include_directories(systemlib
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
+add_library(testMod1 MODULE empty.cpp)
+add_library(testMod2 MODULE empty.cpp)
+set_property(TARGET testMod2 PROPERTY BUNDLE 1)
+
install(TARGETS testLibRequired
EXPORT RequiredExp DESTINATION lib
INCLUDES DESTINATION
@@ -523,6 +527,7 @@ install(
testLibDeprecation
testLibCycleA testLibCycleB
testLibNoSONAME
+ testMod1 testMod2
cmp0022NEW cmp0022OLD
TopDirLib SubDirLinkA
systemlib
@@ -595,6 +600,7 @@ export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 te
testLib4lib testLib4libdbg testLib4libopt
testLibCycleA testLibCycleB
testLibNoSONAME
+ testMod1 testMod2
testLibPerConfigDest
NAMESPACE bld_
APPEND FILE ExportBuildTree.cmake
diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt
index a8a98fc..e64c6b4 100644
--- a/Tests/ExportImport/Import/CMakeLists.txt
+++ b/Tests/ExportImport/Import/CMakeLists.txt
@@ -26,3 +26,6 @@ add_subdirectory(Interface)
# Test package version range
add_subdirectory(version_range)
+
+# Test install(IMPORTED_RUNTIME_ARTIFACTS)
+add_subdirectory(install-IMPORTED_RUNTIME_ARTIFACTS)
diff --git a/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt
new file mode 100644
index 0000000..76efe2f
--- /dev/null
+++ b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Import targets from the exported build tree.
+include(${Import_BINARY_DIR}/../Export/ExportBuildTree.cmake)
+
+set(_tgts
+ bld_testExe1 # Ordinary executable
+ bld_testExe2lib # Ordinary shared library
+ bld_testLib3 # Shared library with version and soversion
+ bld_testLib4 # Framework library
+ bld_testExe3 # Bundle executable
+ bld_testMod1 # Module library
+ bld_testMod2 # CFBundle
+ )
+
+install(IMPORTED_RUNTIME_ARTIFACTS ${_tgts}
+ RUNTIME DESTINATION aaa/executables
+ LIBRARY DESTINATION aaa/libraries
+ BUNDLE DESTINATION aaa/bundles
+ FRAMEWORK DESTINATION aaa/frameworks
+ )
+
+install(IMPORTED_RUNTIME_ARTIFACTS ${_tgts}
+ DESTINATION bbb
+ )
+
+install(IMPORTED_RUNTIME_ARTIFACTS ${_tgts}
+ BUNDLE DESTINATION zzz/bundles
+ FRAMEWORK DESTINATION zzz/frameworks
+ )
+
+install(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/check_installed.cmake")
diff --git a/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake
new file mode 100644
index 0000000..29b298f
--- /dev/null
+++ b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake
@@ -0,0 +1,57 @@
+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()
+
+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]])
+ set(_alldest [[bbb;bbb/libtestExe2lib\.so;bbb/libtestLib3lib(-d|-r)?\.so\.1\.2;bbb/libtestLib3lib(-d|-r)?\.so\.3;bbb/libtestLib4\.so;bbb/libtestMod1\.so;bbb/libtestMod2\.so;bbb/testExe1-4;bbb/testExe3]])
+ set(_default [[bin;bin/testExe1-4;bin/testExe3;lib;lib/libtestExe2lib\.so;lib/libtestLib3lib(-d|-r)?\.so\.1\.2;lib/libtestLib3lib(-d|-r)?\.so\.3;lib/libtestLib4\.so;lib/libtestMod1\.so;lib/libtestMod2\.so]])
+ check_installed("^${_dirs};${_alldest};${_default}$")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ set(_dirs_msvc [[aaa;aaa/executables;aaa/executables/testExe1\.exe;aaa/executables/testExe2lib\.dll;aaa/executables/testExe3\.exe;aaa/executables/testLib3dll(-d|-r)?\.dll;aaa/executables/testLib4\.dll;aaa/libraries;aaa/libraries/testMod1\.dll;aaa/libraries/testMod2\.dll]])
+ set(_dirs_mingw [[aaa;aaa/executables;aaa/executables/libtestExe2lib\.dll;aaa/executables/libtestLib3dll(-d|-r)?\.dll;aaa/executables/libtestLib4\.dll;aaa/executables/testExe1\.exe;aaa/executables/testExe3\.exe;aaa/libraries;aaa/libraries/libtestMod1\.dll;aaa/libraries/libtestMod2\.dll]])
+
+ set(_alldest_msvc [[bbb;bbb/testExe1\.exe;bbb/testExe2lib\.dll;bbb/testExe3\.exe;bbb/testLib3dll(-d|-r)?\.dll;bbb/testLib4\.dll;bbb/testMod1\.dll;bbb/testMod2\.dll]])
+ set(_alldest_mingw [[bbb;bbb/libtestExe2lib\.dll;bbb/libtestLib3dll(-d|-r)?\.dll;bbb/libtestLib4\.dll;bbb/libtestMod1\.dll;bbb/libtestMod2\.dll;bbb/testExe1\.exe;bbb/testExe3\.exe]])
+
+ set(_default_msvc [[bin;bin/testExe1\.exe;bin/testExe2lib\.dll;bin/testExe3\.exe;bin/testLib3dll(-d|-r)?\.dll;bin/testLib4\.dll;lib;lib/testMod1\.dll;lib/testMod2\.dll]])
+ set(_default_mingw [[bin;bin/libtestExe2lib\.dll;bin/libtestLib3dll(-d|-r)?\.dll;bin/libtestLib4\.dll;bin/testExe1\.exe;bin/testExe3\.exe;lib;lib/libtestMod1\.dll;lib/libtestMod2\.dll]])
+
+ check_installed("^(${_dirs_msvc};${_alldest_msvc};${_default_msvc}|${_dirs_mingw};${_alldest_mingw};${_default_mingw})$")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ set(_bundles [[aaa/bundles;aaa/bundles/testExe3\.app;aaa/bundles/testExe3\.app/Contents;aaa/bundles/testExe3\.app/Contents/Info\.plist;aaa/bundles/testExe3\.app/Contents/MacOS;aaa/bundles/testExe3\.app/Contents/MacOS/testExe3(;aaa/bundles/testExe3\.app/Contents/PkgInfo)?(;aaa/bundles/testExe3\.app/Contents/_CodeSignature;aaa/bundles/testExe3\.app/Contents/_CodeSignature/CodeResources)?]])
+ set(_executables [[aaa/executables;aaa/executables/testExe1(-4)?]])
+ set(_frameworks [[aaa/frameworks;aaa/frameworks/testLib4\.framework;aaa/frameworks/testLib4\.framework/Headers;aaa/frameworks/testLib4\.framework/Headers/testLib4\.h;aaa/frameworks/testLib4\.framework/Resources;aaa/frameworks/testLib4\.framework/Versions;aaa/frameworks/testLib4\.framework/Versions/A;aaa/frameworks/testLib4\.framework/Versions/A/Resources;aaa/frameworks/testLib4\.framework/Versions/A/Resources/Info\.plist(;aaa/frameworks/testLib4\.framework/Versions/A/_CodeSignature;aaa/frameworks/testLib4\.framework/Versions/A/_CodeSignature/CodeResources)?;aaa/frameworks/testLib4\.framework/Versions/A/testLib4;aaa/frameworks/testLib4\.framework/Versions/Current;aaa/frameworks/testLib4\.framework/testLib4]])
+ set(_libraries [[aaa/libraries;aaa/libraries/libtestExe2lib\.dylib;aaa/libraries/libtestLib3lib(-d|-r)?\.1\.2\.dylib;aaa/libraries/libtestLib3lib(-d|-r)?\.3\.dylib;aaa/libraries/libtestMod1\.so;aaa/libraries/testMod2\.bundle;aaa/libraries/testMod2\.bundle/Contents;aaa/libraries/testMod2\.bundle/Contents/Info\.plist;aaa/libraries/testMod2\.bundle/Contents/MacOS;aaa/libraries/testMod2\.bundle/Contents/MacOS/testMod2(;aaa/libraries/testMod2\.bundle/Contents/_CodeSignature;aaa/libraries/testMod2\.bundle/Contents/_CodeSignature/CodeResources)?]])
+ set(_dirs "aaa;${_bundles};${_executables};${_frameworks};${_libraries}")
+
+ set(_alldest [[bbb;bbb/libtestExe2lib\.dylib;bbb/libtestLib3lib(-d|-r)?\.1\.2\.dylib;bbb/libtestLib3lib(-d|-r)?\.3\.dylib;bbb/libtestMod1\.so;bbb/testExe1(-4)?;bbb/testExe3\.app;bbb/testExe3\.app/Contents;bbb/testExe3\.app/Contents/Info\.plist;bbb/testExe3\.app/Contents/MacOS;bbb/testExe3\.app/Contents/MacOS/testExe3(;bbb/testExe3\.app/Contents/PkgInfo)?(;bbb/testExe3\.app/Contents/_CodeSignature;bbb/testExe3\.app/Contents/_CodeSignature/CodeResources)?;bbb/testLib4\.framework;bbb/testLib4\.framework/Headers;bbb/testLib4\.framework/Headers/testLib4\.h;bbb/testLib4\.framework/Resources;bbb/testLib4\.framework/Versions;bbb/testLib4\.framework/Versions/A;bbb/testLib4\.framework/Versions/A/Resources;bbb/testLib4\.framework/Versions/A/Resources/Info\.plist(;bbb/testLib4\.framework/Versions/A/_CodeSignature;bbb/testLib4\.framework/Versions/A/_CodeSignature/CodeResources)?;bbb/testLib4\.framework/Versions/A/testLib4;bbb/testLib4\.framework/Versions/Current;bbb/testLib4\.framework/testLib4;bbb/testMod2\.bundle;bbb/testMod2\.bundle/Contents;bbb/testMod2\.bundle/Contents/Info\.plist;bbb/testMod2\.bundle/Contents/MacOS;bbb/testMod2\.bundle/Contents/MacOS/testMod2(;bbb/testMod2\.bundle/Contents/_CodeSignature;bbb/testMod2\.bundle/Contents/_CodeSignature/CodeResources)?]])
+
+ set(_default_bin [[bin;bin/testExe1(-4)?]])
+ set(_default_lib [[lib;lib/libtestExe2lib\.dylib;lib/libtestLib3lib(-d|-r)?\.1\.2\.dylib;lib/libtestLib3lib(-d|-r)?\.3\.dylib;lib/libtestMod1\.so;lib/testMod2\.bundle;lib/testMod2\.bundle/Contents;lib/testMod2\.bundle/Contents/Info\.plist;lib/testMod2\.bundle/Contents/MacOS;lib/testMod2\.bundle/Contents/MacOS/testMod2(;lib/testMod2\.bundle/Contents/_CodeSignature;lib/testMod2\.bundle/Contents/_CodeSignature/CodeResources)?]])
+ set(_default_bundles [[zzz/bundles;zzz/bundles/testExe3\.app;zzz/bundles/testExe3\.app/Contents;zzz/bundles/testExe3\.app/Contents/Info\.plist;zzz/bundles/testExe3\.app/Contents/MacOS;zzz/bundles/testExe3\.app/Contents/MacOS/testExe3(;zzz/bundles/testExe3\.app/Contents/PkgInfo)?(;zzz/bundles/testExe3\.app/Contents/_CodeSignature;zzz/bundles/testExe3\.app/Contents/_CodeSignature/CodeResources)?]])
+ set(_default_frameworks [[zzz/frameworks;zzz/frameworks/testLib4\.framework;zzz/frameworks/testLib4\.framework/Headers;zzz/frameworks/testLib4\.framework/Headers/testLib4\.h;zzz/frameworks/testLib4\.framework/Resources;zzz/frameworks/testLib4\.framework/Versions;zzz/frameworks/testLib4\.framework/Versions/A;zzz/frameworks/testLib4\.framework/Versions/A/Resources;zzz/frameworks/testLib4\.framework/Versions/A/Resources/Info\.plist(;zzz/frameworks/testLib4\.framework/Versions/A/_CodeSignature;zzz/frameworks/testLib4\.framework/Versions/A/_CodeSignature/CodeResources)?;zzz/frameworks/testLib4\.framework/Versions/A/testLib4;zzz/frameworks/testLib4\.framework/Versions/Current;zzz/frameworks/testLib4\.framework/testLib4]])
+ set(_default "${_default_bin};${_default_lib};zzz;${_default_bundles};${_default_frameworks}")
+
+ # Need to break this up due to too many pairs of parentheses
+ check_installed("^${_dirs};bbb;")
+ check_installed(";${_alldest};bin;")
+ check_installed(";${_default}$")
+endif()
diff --git a/bootstrap b/bootstrap
index aefd210..911558d 100755
--- a/bootstrap
+++ b/bootstrap
@@ -387,6 +387,7 @@ CMAKE_CXX_SOURCES="\
cmInstallFilesCommand \
cmInstallFilesGenerator \
cmInstallGenerator \
+ cmInstallImportedRuntimeArtifactsGenerator \
cmInstallScriptGenerator \
cmInstallSubdirectoryGenerator \
cmInstallTargetGenerator \