diff options
author | Brad King <brad.king@kitware.com> | 2021-06-01 12:42:08 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2021-06-01 12:42:16 (GMT) |
commit | 02957bb58906bcb769410b6d4938dbdbfcacb78f (patch) | |
tree | 4d82f0744daedfb77cc13952663bc3aefed907da | |
parent | 5eb2aa1f57e99f30be5ea145ce9af5fd9652392f (diff) | |
parent | f7ba3a05893279f6704db15358b08fd4ecb28814 (diff) | |
download | CMake-02957bb58906bcb769410b6d4938dbdbfcacb78f.zip CMake-02957bb58906bcb769410b6d4938dbdbfcacb78f.tar.gz CMake-02957bb58906bcb769410b6d4938dbdbfcacb78f.tar.bz2 |
Merge topic 'install-imported-runtime-artifacts'
f7ba3a0589 FileAPI: Populate information for IMPORTED_RUNTIME_ARTIFACTS
df7040a271 install(): Add IMPORTED_RUNTIME_ARTIFACTS mode
60e752ced8 Refactor: Move common methods into cmInstallGenerator
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !6162
22 files changed, 746 insertions, 88 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/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst index 0e530bc..e7d78c3 100644 --- a/Help/manual/cmake-file-api.7.rst +++ b/Help/manual/cmake-file-api.7.rst @@ -747,6 +747,11 @@ with members: An :command:`install(CODE)` call. This type has no additional members. + ``importedRuntimeArtifacts`` + An :command:`install(IMPORTED_RUNTIME_ARTIFACTS)` call. + The ``destination`` member is populated. The ``isOptional`` member may + exist. This type has no additional members. + ``isExcludeFromAll`` Optional member that is present with boolean value ``true`` when :command:`install` is called with the ``EXCLUDE_FROM_ALL`` option. 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/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index 945b547..ff11f4a 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -29,6 +29,7 @@ #include "cmInstallExportGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" +#include "cmInstallImportedRuntimeArtifactsGenerator.h" #include "cmInstallScriptGenerator.h" #include "cmInstallSubdirectoryGenerator.h" #include "cmInstallTargetGenerator.h" @@ -1009,6 +1010,15 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen) installer["scriptFile"] = RelativeIfUnder( this->TopSource, installScript->GetScript(this->Config)); } + } else if (auto* installImportedRuntimeArtifacts = + dynamic_cast<cmInstallImportedRuntimeArtifactsGenerator*>( + gen)) { + installer["type"] = "importedRuntimeArtifacts"; + installer["destination"] = + installImportedRuntimeArtifacts->GetDestination(this->Config); + if (installImportedRuntimeArtifacts->GetOptional()) { + installer["isOptional"] = true; + } } // Add fields common to all install generators. 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/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index ccefd92..d932fd9 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -184,9 +184,8 @@ void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os, Indent indent) { // Remove old per-configuration export files if the main changes. - std::string installedDir = - cmStrCat("$ENV{DESTDIR}", - this->ConvertToAbsoluteDestination(this->Destination), '/'); + std::string installedDir = cmStrCat( + "$ENV{DESTDIR}", ConvertToAbsoluteDestination(this->Destination), '/'); std::string installedFile = cmStrCat(installedDir, this->FileName); os << indent << "if(EXISTS \"" << installedFile << "\")\n"; Indent indentN = indent.Next(); diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx index cf5f45e..9f0d119 100644 --- a/Source/cmInstallGenerator.cxx +++ b/Source/cmInstallGenerator.cxx @@ -2,10 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallGenerator.h" -#include <ostream> +#include <sstream> #include <utility> #include "cmMakefile.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" cmInstallGenerator::cmInstallGenerator( @@ -98,7 +99,7 @@ void cmInstallGenerator::AddInstallRule( << "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"; os << indent << "endif()\n"; } - std::string absDest = this->ConvertToAbsoluteDestination(dest); + std::string absDest = ConvertToAbsoluteDestination(dest); os << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " << stype; if (optional) { os << " OPTIONAL"; @@ -183,7 +184,7 @@ bool cmInstallGenerator::InstallsForConfig(const std::string& config) } std::string cmInstallGenerator::ConvertToAbsoluteDestination( - std::string const& dest) const + std::string const& dest) { std::string result; if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest)) { @@ -211,3 +212,59 @@ cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel( } return MessageDefault; } + +std::string cmInstallGenerator::GetDestDirPath(std::string const& file) +{ + // Construct the path of the file on disk after installation on + // which tweaks may be performed. + std::string toDestDirPath = "$ENV{DESTDIR}"; + if (file[0] != '/' && file[0] != '$') { + toDestDirPath += "/"; + } + toDestDirPath += file; + return toDestDirPath; +} + +void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent, + const std::string& config, + std::string const& file, + const TweakMethod& tweak) +{ + std::ostringstream tw; + tweak(tw, indent.Next(), config, file); + std::string tws = tw.str(); + if (!tws.empty()) { + os << indent << "if(EXISTS \"" << file << "\" AND\n" + << indent << " NOT IS_SYMLINK \"" << file << "\")\n"; + os << tws; + os << indent << "endif()\n"; + } +} + +void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent, + const std::string& config, + std::string const& dir, + std::vector<std::string> const& files, + const TweakMethod& tweak) +{ + if (files.size() == 1) { + // Tweak a single file. + AddTweak(os, indent, config, GetDestDirPath(cmStrCat(dir, files[0])), + tweak); + } else { + // Generate a foreach loop to tweak multiple files. + std::ostringstream tw; + AddTweak(tw, indent.Next(), config, "${file}", tweak); + std::string tws = tw.str(); + if (!tws.empty()) { + Indent indent2 = indent.Next().Next(); + os << indent << "foreach(file\n"; + for (std::string const& f : files) { + os << indent2 << "\"" << GetDestDirPath(cmStrCat(dir, f)) << "\"\n"; + } + os << indent2 << ")\n"; + os << tws; + os << indent << "endforeach()\n"; + } + } +} diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h index 0117617..97acb88 100644 --- a/Source/cmInstallGenerator.h +++ b/Source/cmInstallGenerator.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <functional> #include <iosfwd> #include <string> #include <vector> @@ -53,7 +54,7 @@ public: /** Get the install destination as it should appear in the installation script. */ - std::string ConvertToAbsoluteDestination(std::string const& dest) const; + static std::string ConvertToAbsoluteDestination(std::string const& dest); /** Test if this generator installs something for a given configuration. */ bool InstallsForConfig(const std::string& config); @@ -70,12 +71,25 @@ public: cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; } + static std::string GetDestDirPath(std::string const& file); + protected: void GenerateScript(std::ostream& os) override; std::string CreateComponentTest(const std::string& component, bool exclude_from_all); + using TweakMethod = + std::function<void(std::ostream& os, Indent indent, + const std::string& config, const std::string& file)>; + static void AddTweak(std::ostream& os, Indent indent, + const std::string& config, std::string const& file, + const TweakMethod& tweak); + static void AddTweak(std::ostream& os, Indent indent, + const std::string& config, std::string const& dir, + std::vector<std::string> const& files, + const TweakMethod& tweak); + // Information shared by most generator types. std::string const Destination; std::string const Component; 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/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 3e79ad8..35165cf 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -77,12 +77,15 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( } // Tweak files located in the destination directory. - std::string toDir = cmStrCat(this->ConvertToAbsoluteDestination(dest), '/'); + std::string toDir = cmStrCat(ConvertToAbsoluteDestination(dest), '/'); // Add pre-installation tweaks. if (!files.NoTweak) { - this->AddTweak(os, indent, config, toDir, files.To, - &cmInstallTargetGenerator::PreReplacementTweaks); + AddTweak(os, indent, config, toDir, files.To, + [this](std::ostream& o, Indent i, const std::string& c, + const std::string& f) { + this->PreReplacementTweaks(o, i, c, f); + }); } // Write code to install the target file. @@ -102,8 +105,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( // Add post-installation tweaks. if (!files.NoTweak) { - this->AddTweak(os, indent, config, toDir, files.To, - &cmInstallTargetGenerator::PostReplacementTweaks); + AddTweak(os, indent, config, toDir, files.To, + [this](std::ostream& o, Indent i, const std::string& c, + const std::string& f) { + this->PostReplacementTweaks(o, i, c, f); + }); } } @@ -461,63 +467,6 @@ bool cmInstallTargetGenerator::Compute(cmLocalGenerator* lg) return true; } -void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent, - const std::string& config, - std::string const& file, - TweakMethod tweak) -{ - std::ostringstream tw; - (this->*tweak)(tw, indent.Next(), config, file); - std::string tws = tw.str(); - if (!tws.empty()) { - os << indent << "if(EXISTS \"" << file << "\" AND\n" - << indent << " NOT IS_SYMLINK \"" << file << "\")\n"; - os << tws; - os << indent << "endif()\n"; - } -} - -void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent, - const std::string& config, - std::string const& dir, - std::vector<std::string> const& files, - TweakMethod tweak) -{ - if (files.size() == 1) { - // Tweak a single file. - this->AddTweak(os, indent, config, - this->GetDestDirPath(cmStrCat(dir, files[0])), tweak); - } else { - // Generate a foreach loop to tweak multiple files. - std::ostringstream tw; - this->AddTweak(tw, indent.Next(), config, "${file}", tweak); - std::string tws = tw.str(); - if (!tws.empty()) { - Indent indent2 = indent.Next().Next(); - os << indent << "foreach(file\n"; - for (std::string const& f : files) { - os << indent2 << "\"" << this->GetDestDirPath(cmStrCat(dir, f)) - << "\"\n"; - } - os << indent2 << ")\n"; - os << tws; - os << indent << "endforeach()\n"; - } - } -} - -std::string cmInstallTargetGenerator::GetDestDirPath(std::string const& file) -{ - // Construct the path of the file on disk after installation on - // which tweaks may be performed. - std::string toDestDirPath = "$ENV{DESTDIR}"; - if (file[0] != '/' && file[0] != '$') { - toDestDirPath += "/"; - } - toDestDirPath += file; - return toDestDirPath; -} - void cmInstallTargetGenerator::PreReplacementTweaks(std::ostream& os, Indent indent, const std::string& config, diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index 84fce42..6173f2c 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -93,15 +93,6 @@ public: protected: void GenerateScriptForConfig(std::ostream& os, const std::string& config, Indent indent) override; - using TweakMethod = void (cmInstallTargetGenerator::*)(std::ostream&, Indent, - const std::string&, - const std::string&); - void AddTweak(std::ostream& os, Indent indent, const std::string& config, - std::string const& file, TweakMethod tweak); - void AddTweak(std::ostream& os, Indent indent, const std::string& config, - std::string const& dir, std::vector<std::string> const& files, - TweakMethod tweak); - std::string GetDestDirPath(std::string const& file); void PreReplacementTweaks(std::ostream& os, Indent indent, const std::string& config, std::string const& file); 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/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py index b9a1fbf..9911ad5 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py +++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py @@ -644,7 +644,7 @@ def gen_check_directories(c, g): if sys.platform not in ("win32", "cygwin", "msys"): for e in expected: - e["installers"] = list(filter(lambda i: "_dllExtra" not in i or not i["_dllExtra"], e["installers"])) + e["installers"] = list(filter(lambda i: not i.get("_dllExtra", False), e["installers"])) if "aix" not in sys.platform: for i in e["installers"]: if "pathsNamelink" in i: diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json index d127274..92b9526 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json +++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json @@ -14,6 +14,67 @@ ], "projectName": "Imported", "minimumCMakeVersion": "3.12", - "hasInstallRule": null, - "installers": [] + "hasInstallRule": true, + "installers": [ + { + "component": "Unspecified", + "type": "importedRuntimeArtifacts", + "destination": "lib", + "paths": null, + "isExcludeFromAll": null, + "isForAllComponents": null, + "isOptional": null, + "targetId": null, + "targetIndex": null, + "targetIsImportLibrary": null, + "targetInstallNamelink": null, + "exportName": null, + "exportTargets": null, + "scriptFile": null, + "backtrace": [ + { + "file": "^imported/CMakeLists\\.txt$", + "line": 32, + "command": "install", + "hasParent": true + }, + { + "file": "^imported/CMakeLists\\.txt$", + "line": null, + "command": null, + "hasParent": false + } + ] + }, + { + "component": "Unspecified", + "type": "importedRuntimeArtifacts", + "destination": "lib2", + "paths": null, + "isExcludeFromAll": null, + "isForAllComponents": null, + "isOptional": true, + "targetId": null, + "targetIndex": null, + "targetIsImportLibrary": null, + "targetInstallNamelink": null, + "exportName": null, + "exportTargets": null, + "scriptFile": null, + "backtrace": [ + { + "file": "^imported/CMakeLists\\.txt$", + "line": 35, + "command": "install", + "hasParent": true + }, + { + "file": "^imported/CMakeLists\\.txt$", + "line": null, + "command": null, + "hasParent": false + } + ] + } + ] } diff --git a/Tests/RunCMake/FileAPI/imported/CMakeLists.txt b/Tests/RunCMake/FileAPI/imported/CMakeLists.txt index f79d87c..770838b 100644 --- a/Tests/RunCMake/FileAPI/imported/CMakeLists.txt +++ b/Tests/RunCMake/FileAPI/imported/CMakeLists.txt @@ -28,3 +28,10 @@ endif() add_library(imported_interface_lib INTERFACE IMPORTED) add_executable(link_imported_interface_exe ../empty.c) target_link_libraries(link_imported_interface_exe PRIVATE imported_interface_lib) + +install(IMPORTED_RUNTIME_ARTIFACTS imported_shared_lib + DESTINATION lib +) +install(IMPORTED_RUNTIME_ARTIFACTS imported_shared_lib + DESTINATION lib2 OPTIONAL +) @@ -387,6 +387,7 @@ CMAKE_CXX_SOURCES="\ cmInstallFilesCommand \ cmInstallFilesGenerator \ cmInstallGenerator \ + cmInstallImportedRuntimeArtifactsGenerator \ cmInstallScriptGenerator \ cmInstallSubdirectoryGenerator \ cmInstallTargetGenerator \ |