From df7040a2718a0de2b074a6e55c5ce960d85d8d6f Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Wed, 26 May 2021 13:30:32 -0400 Subject: install(): Add IMPORTED_RUNTIME_ARTIFACTS mode --- Help/command/install.rst | 33 +++ .../dev/install-imported-runtime-artifacts.rst | 5 + Source/CMakeLists.txt | 2 + Source/cmInstallCommand.cxx | 224 +++++++++++++++++++++ .../cmInstallImportedRuntimeArtifactsGenerator.cxx | 146 ++++++++++++++ .../cmInstallImportedRuntimeArtifactsGenerator.h | 44 ++++ Tests/ExportImport/CMakeLists.txt | 28 ++- Tests/ExportImport/Export/CMakeLists.txt | 6 + Tests/ExportImport/Import/CMakeLists.txt | 3 + .../CMakeLists.txt | 30 +++ .../check_installed.cmake | 57 ++++++ bootstrap | 1 + 12 files changed, 572 insertions(+), 7 deletions(-) create mode 100644 Help/release/dev/install-imported-runtime-artifacts.rst create mode 100644 Source/cmInstallImportedRuntimeArtifactsGenerator.cxx create mode 100644 Source/cmInstallImportedRuntimeArtifactsGenerator.h create mode 100644 Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt create mode 100644 Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake 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`_ ... [...]) + install(`IMPORTED_RUNTIME_ARTIFACTS`_ ... [...]) install({`FILES`_ | `PROGRAMS`_} ... [...]) install(`DIRECTORY`_ ... [...]) install(`SCRIPT`_ [...]) @@ -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 ] + [PERMISSIONS permissions...] + [CONFIGURATIONS [Debug|Release|...]] + [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 #include #include #include @@ -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 const& args, return true; } +bool HandleImportedRuntimeArtifactsMode(std::vector const& args, + cmExecutionStatus& status) +{ + Helper helper(status); + + // This is the IMPORTED_RUNTIME_ARTIFACTS mode. + std::vector targets; + + struct ArgVectors + { + std::vector Library; + std::vector Runtime; + std::vector Framework; + std::vector Bundle; + }; + + static auto const argHelper = cmArgumentParser{} + .Bind("LIBRARY"_s, &ArgVectors::Library) + .Bind("RUNTIME"_s, &ArgVectors::Runtime) + .Bind("FRAMEWORK"_s, &ArgVectors::Framework) + .Bind("BUNDLE"_s, &ArgVectors::Bundle); + + std::vector 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 targetList; + std::vector 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 { + return cm::make_unique( + 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 + libraryGenerator; + std::unique_ptr + runtimeGenerator; + std::unique_ptr + frameworkGenerator; + std::unique_ptr + 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 const& args, cmExecutionStatus& status) { @@ -1705,6 +1928,7 @@ bool cmInstallCommand(std::vector 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 +#include +#include +#include + +#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 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 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 +#include +#include + +#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 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 "$") + set(NESTED_CONFIG_INSTALL_TYPE --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 $ ) +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 \ -- cgit v0.12