From ed3633d88cc5faa6fd7eb68fdd774d6d1f9cfdc9 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Wed, 14 Apr 2021 10:43:30 -0400 Subject: install(TARGETS): Add RUNTIME_DEPENDENCIES option --- Source/CMakeLists.txt | 4 + Source/cmFileCommand.cxx | 5 +- Source/cmInstallCommand.cxx | 186 +++++++++++++- Source/cmInstallGenerator.cxx | 51 ++-- Source/cmInstallGenerator.h | 3 +- .../cmInstallGetRuntimeDependenciesGenerator.cxx | 206 +++++++++++++++ Source/cmInstallGetRuntimeDependenciesGenerator.h | 56 +++++ Source/cmInstallRuntimeDependencySetGenerator.cxx | 276 +++++++++++++++++++++ Source/cmInstallRuntimeDependencySetGenerator.h | 74 ++++++ Source/cmRuntimeDependencyArchive.cxx | 8 + Source/cmRuntimeDependencyArchive.h | 2 + Tests/RunCMake/install/RunCMakeTest.cmake | 17 +- .../TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt | 1 + .../TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt | 4 + .../TARGETS-RUNTIME_DEPENDENCIES-cross.cmake | 4 + ...GETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake | 1 + .../TARGETS-RUNTIME_DEPENDENCIES-empty.cmake | 9 + ...TIME_DEPENDENCIES-macos-no-framework-result.txt | 1 + ...TIME_DEPENDENCIES-macos-no-framework-stderr.txt | 4 + ...S-RUNTIME_DEPENDENCIES-macos-no-framework.cmake | 4 + ...UNTIME_DEPENDENCIES-macos-two-bundle-result.txt | 1 + ...UNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt | 4 + ...ETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake | 10 + ...GETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake | 1 + .../TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake | 9 + ...ETS-RUNTIME_DEPENDENCIES-unsupported-result.txt | 1 + ...ETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt | 5 + .../TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake | 4 + bootstrap | 2 + 29 files changed, 928 insertions(+), 25 deletions(-) create mode 100644 Source/cmInstallGetRuntimeDependenciesGenerator.cxx create mode 100644 Source/cmInstallGetRuntimeDependenciesGenerator.h create mode 100644 Source/cmInstallRuntimeDependencySetGenerator.cxx create mode 100644 Source/cmInstallRuntimeDependencySetGenerator.h create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 5bcf223..9a18184 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -345,6 +345,8 @@ set(SRCS cmGraphVizWriter.h cmInstallGenerator.h cmInstallGenerator.cxx + cmInstallGetRuntimeDependenciesGenerator.h + cmInstallGetRuntimeDependenciesGenerator.cxx cmInstallExportGenerator.cxx cmInstalledFile.h cmInstalledFile.cxx @@ -354,6 +356,8 @@ set(SRCS cmInstallImportedRuntimeArtifactsGenerator.cxx cmInstallRuntimeDependencySet.h cmInstallRuntimeDependencySet.cxx + cmInstallRuntimeDependencySetGenerator.h + cmInstallRuntimeDependencySetGenerator.cxx cmInstallScriptGenerator.h cmInstallScriptGenerator.cxx cmInstallSubdirectoryGenerator.h diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 82546b9..0ad59c7 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -3044,11 +3044,10 @@ bool HandleCreateLinkCommand(std::vector const& args, bool HandleGetRuntimeDependenciesCommand(std::vector const& args, cmExecutionStatus& status) { - static const std::set supportedPlatforms = { "Windows", "Linux", - "Darwin" }; std::string platform = status.GetMakefile().GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME"); - if (!supportedPlatforms.count(platform)) { + if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies( + platform)) { status.SetError( cmStrCat("GET_RUNTIME_DEPENDENCIES is not supported on system \"", platform, "\"")); diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index c9bb467..c36778d 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -2,8 +2,10 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallCommand.h" +#include #include #include +#include #include #include #include @@ -23,7 +25,10 @@ #include "cmInstallExportGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" +#include "cmInstallGetRuntimeDependenciesGenerator.h" #include "cmInstallImportedRuntimeArtifactsGenerator.h" +#include "cmInstallRuntimeDependencySet.h" +#include "cmInstallRuntimeDependencySetGenerator.h" #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmListFileCache.h" @@ -31,6 +36,7 @@ #include "cmMessageType.h" #include "cmPolicies.h" #include "cmProperty.h" +#include "cmRuntimeDependencyArchive.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSubcommandTable.h" @@ -40,6 +46,29 @@ namespace { +struct RuntimeDependenciesArgs +{ + std::vector Directories; + std::vector PreIncludeRegexes; + std::vector PreExcludeRegexes; + std::vector PostIncludeRegexes; + std::vector PostExcludeRegexes; + std::vector PostIncludeFiles; + std::vector PostExcludeFiles; +}; + +auto const RuntimeDependenciesArgHelper = + cmArgumentParser{} + .Bind("DIRECTORIES"_s, &RuntimeDependenciesArgs::Directories) + .Bind("PRE_INCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreIncludeRegexes) + .Bind("PRE_EXCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreExcludeRegexes) + .Bind("POST_INCLUDE_REGEXES"_s, + &RuntimeDependenciesArgs::PostIncludeRegexes) + .Bind("POST_EXCLUDE_REGEXES"_s, + &RuntimeDependenciesArgs::PostExcludeRegexes) + .Bind("POST_INCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostIncludeFiles) + .Bind("POST_EXCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostExcludeFiles); + class Helper { public: @@ -147,12 +176,106 @@ std::unique_ptr CreateInstallFilesGenerator( args.GetDestination()); } +void AddInstallRuntimeDependenciesGenerator( + Helper& helper, cmInstallRuntimeDependencySet* runtimeDependencySet, + const cmInstallCommandArguments& runtimeArgs, + const cmInstallCommandArguments& libraryArgs, + const cmInstallCommandArguments& frameworkArgs, + RuntimeDependenciesArgs runtimeDependenciesArgs, bool& installsRuntime, + bool& installsLibrary, bool& installsFramework) +{ + bool dllPlatform = + !helper.Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); + bool apple = + helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") == "Darwin"; + auto const& runtimeDependenciesArgsRef = + dllPlatform ? runtimeArgs : libraryArgs; + std::vector configurations = + runtimeDependenciesArgsRef.GetConfigurations(); + if (apple) { + std::copy(frameworkArgs.GetConfigurations().begin(), + frameworkArgs.GetConfigurations().end(), + std::back_inserter(configurations)); + } + + // Create file(GET_RUNTIME_DEPENDENCIES) generator. + auto getRuntimeDependenciesGenerator = + cm::make_unique( + runtimeDependencySet, std::move(runtimeDependenciesArgs.Directories), + std::move(runtimeDependenciesArgs.PreIncludeRegexes), + std::move(runtimeDependenciesArgs.PreExcludeRegexes), + std::move(runtimeDependenciesArgs.PostIncludeRegexes), + std::move(runtimeDependenciesArgs.PostExcludeRegexes), + std::move(runtimeDependenciesArgs.PostIncludeFiles), + std::move(runtimeDependenciesArgs.PostExcludeFiles), + runtimeDependenciesArgsRef.GetComponent(), + apple ? frameworkArgs.GetComponent() : "", true, "_CMAKE_DEPS", + "_CMAKE_RPATH", configurations, + cmInstallGenerator::SelectMessageLevel(helper.Makefile), + runtimeDependenciesArgsRef.GetExcludeFromAll() && + (apple ? frameworkArgs.GetExcludeFromAll() : true), + helper.Makefile->GetBacktrace()); + helper.Makefile->AddInstallGenerator( + std::move(getRuntimeDependenciesGenerator)); + + // Create the library dependencies generator. + auto libraryRuntimeDependenciesGenerator = + cm::make_unique( + cmInstallRuntimeDependencySetGenerator::DependencyType::Library, + runtimeDependencySet, std::vector{}, true, std::string{}, + true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP", + dllPlatform ? helper.GetRuntimeDestination(&runtimeArgs) + : helper.GetLibraryDestination(&libraryArgs), + runtimeDependenciesArgsRef.GetConfigurations(), + runtimeDependenciesArgsRef.GetComponent(), + runtimeDependenciesArgsRef.GetPermissions(), + cmInstallGenerator::SelectMessageLevel(helper.Makefile), + runtimeDependenciesArgsRef.GetExcludeFromAll(), + helper.Makefile->GetBacktrace()); + helper.Makefile->AddInstallGenerator( + std::move(libraryRuntimeDependenciesGenerator)); + if (dllPlatform) { + installsRuntime = true; + } else { + installsLibrary = true; + } + + if (apple) { + // Create the framework dependencies generator. + auto frameworkRuntimeDependenciesGenerator = + cm::make_unique( + cmInstallRuntimeDependencySetGenerator::DependencyType::Framework, + runtimeDependencySet, std::vector{}, true, std::string{}, + true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP", + frameworkArgs.GetDestination(), frameworkArgs.GetConfigurations(), + frameworkArgs.GetComponent(), frameworkArgs.GetPermissions(), + cmInstallGenerator::SelectMessageLevel(helper.Makefile), + frameworkArgs.GetExcludeFromAll(), helper.Makefile->GetBacktrace()); + helper.Makefile->AddInstallGenerator( + std::move(frameworkRuntimeDependenciesGenerator)); + installsFramework = true; + } +} + std::set const allowedTypes{ "BIN", "SBIN", "LIB", "INCLUDE", "SYSCONF", "SHAREDSTATE", "LOCALSTATE", "RUNSTATE", "DATA", "INFO", "LOCALE", "MAN", "DOC", }; +template +bool AddBundleExecutable(Helper& helper, + cmInstallRuntimeDependencySet* runtimeDependencySet, + T&& bundleExecutable) +{ + if (!runtimeDependencySet->AddBundleExecutable(bundleExecutable)) { + helper.SetError( + "A runtime dependency set may only have one bundle executable."); + return false; + } + return true; +} + bool HandleScriptMode(std::vector const& args, cmExecutionStatus& status) { @@ -289,13 +412,23 @@ bool HandleTargetsMode(std::vector const& args, // These generic args also contain the targets and the export stuff std::vector targetList; std::string exports; + std::vector runtimeDependenciesArgVector; std::vector unknownArgs; + std::vector parsedArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName); genericArgs.Bind("TARGETS"_s, targetList); genericArgs.Bind("EXPORT"_s, exports); - genericArgs.Parse(genericArgVector, &unknownArgs); + genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector); + genericArgs.Parse(genericArgVector, &unknownArgs, nullptr, &parsedArgs); bool success = genericArgs.Finalize(); + bool withRuntimeDependencies = + std::find(parsedArgs.begin(), parsedArgs.end(), "RUNTIME_DEPENDENCIES") != + parsedArgs.end(); + RuntimeDependenciesArgs runtimeDependenciesArgs = + RuntimeDependenciesArgHelper.Parse(runtimeDependenciesArgVector, + &unknownArgs); + cmInstallCommandArguments archiveArgs(helper.DefaultComponentName); cmInstallCommandArguments libraryArgs(helper.DefaultComponentName); cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName); @@ -402,6 +535,32 @@ bool HandleTargetsMode(std::vector const& args, return false; } + cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr; + if (withRuntimeDependencies) { + auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME"); + if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies( + system)) { + status.SetError( + cmStrCat("TARGETS RUNTIME_DEPENDENCIES is not supported on system \"", + system, '"')); + return false; + } + if (helper.Makefile->IsOn("CMAKE_CROSSCOMPILING")) { + status.SetError("TARGETS RUNTIME_DEPENDENCIES is not supported " + "when cross-compiling."); + return false; + } + if (helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") == + "Darwin" && + frameworkArgs.GetDestination().empty()) { + status.SetError( + "TARGETS RUNTIME_DEPENDENCIES given no FRAMEWORK DESTINATION"); + return false; + } + runtimeDependencySet = helper.Makefile->GetGlobalGenerator() + ->CreateAnonymousRuntimeDependencySet(); + } + // Select the mode for installing symlinks to versioned shared libraries. cmInstallTargetGenerator::NamelinkModeType namelinkMode = cmInstallTargetGenerator::NamelinkModeNone; @@ -546,6 +705,9 @@ bool HandleTargetsMode(std::vector const& args, target, runtimeArgs, false, helper.Makefile->GetBacktrace(), helper.GetRuntimeDestination(nullptr)); } + if (runtimeDependencySet && runtimeGenerator) { + runtimeDependencySet->AddLibrary(runtimeGenerator.get()); + } } else { // This is a non-DLL platform. // If it is marked with FRAMEWORK property use the FRAMEWORK set of @@ -591,6 +753,9 @@ bool HandleTargetsMode(std::vector const& args, namelinkOnly = (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); } + if (runtimeDependencySet && libraryGenerator) { + runtimeDependencySet->AddLibrary(libraryGenerator.get()); + } } } break; case cmStateEnums::STATIC_LIBRARY: { @@ -633,6 +798,9 @@ bool HandleTargetsMode(std::vector const& args, libraryGenerator->SetNamelinkMode(namelinkMode); namelinkOnly = (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); + if (runtimeDependencySet) { + runtimeDependencySet->AddModule(libraryGenerator.get()); + } } else { status.SetError( cmStrCat("TARGETS given no LIBRARY DESTINATION for module " @@ -685,6 +853,12 @@ bool HandleTargetsMode(std::vector const& args, target.GetName(), "\".")); return false; } + if (runtimeDependencySet) { + if (!AddBundleExecutable(helper, runtimeDependencySet, + bundleGenerator.get())) { + return false; + } + } } else { // Executables use the RUNTIME properties. if (!runtimeArgs.GetDestination().empty()) { @@ -693,6 +867,9 @@ bool HandleTargetsMode(std::vector const& args, runtimeGenerator = CreateInstallTargetGenerator( target, runtimeArgs, false, helper.Makefile->GetBacktrace(), helper.GetRuntimeDestination(&runtimeArgs)); + if (runtimeDependencySet) { + runtimeDependencySet->AddExecutable(runtimeGenerator.get()); + } } // On DLL platforms an executable may also have an import @@ -821,6 +998,13 @@ bool HandleTargetsMode(std::vector const& args, helper.Makefile->AddInstallGenerator(std::move(resourceGenerator)); } + if (withRuntimeDependencies && !runtimeDependencySet->Empty()) { + AddInstallRuntimeDependenciesGenerator( + helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs, + std::move(runtimeDependenciesArgs), installsRuntime, installsLibrary, + installsFramework); + } + // Tell the global generator about any installation component names // specified if (installsArchive) { diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx index 9f0d119..4cfeb47 100644 --- a/Source/cmInstallGenerator.cxx +++ b/Source/cmInstallGenerator.cxx @@ -43,7 +43,8 @@ void cmInstallGenerator::AddInstallRule( std::vector const& files, bool optional /* = false */, const char* permissions_file /* = 0 */, const char* permissions_dir /* = 0 */, const char* rename /* = 0 */, - const char* literal_args /* = 0 */, Indent indent) + const char* literal_args /* = 0 */, Indent indent, + const char* files_var /* = 0 */) { // Use the FILE command to install the file. std::string stype; @@ -70,37 +71,46 @@ void cmInstallGenerator::AddInstallRule( stype = "FILE"; break; } - os << indent; if (cmSystemTools::FileIsFullPath(dest)) { - os << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"; - os << indent << " \""; - bool firstIteration = true; - for (std::string const& file : files) { - if (!firstIteration) { - os << ";"; + if (!files.empty()) { + os << indent << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"; + os << indent << " \""; + bool firstIteration = true; + for (std::string const& file : files) { + if (!firstIteration) { + os << ";"; + } + os << dest << "/"; + if (rename && *rename) { + os << rename; + } else { + os << cmSystemTools::GetFilenameName(file); + } + firstIteration = false; } - os << dest << "/"; - if (rename && *rename) { - os << rename; - } else { - os << cmSystemTools::GetFilenameName(file); - } - firstIteration = false; + os << "\")\n"; + } + if (files_var) { + os << indent << "foreach(_f IN LISTS " << files_var << ")\n"; + os << indent.Next() << "get_filename_component(_fn \"${_f}\" NAME)\n"; + os << indent.Next() << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES \"" + << dest << "/${_fn}\")\n"; + os << indent << "endforeach()\n"; } - os << "\")\n"; os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"; - os << indent << indent << "message(WARNING \"ABSOLUTE path INSTALL " + os << indent.Next() << "message(WARNING \"ABSOLUTE path INSTALL " << "DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"; os << indent << "endif()\n"; os << indent << "if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"; - os << indent << indent << "message(FATAL_ERROR \"ABSOLUTE path INSTALL " + os << indent.Next() << "message(FATAL_ERROR \"ABSOLUTE path INSTALL " << "DESTINATION forbidden (by caller): " << "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"; os << indent << "endif()\n"; } std::string absDest = ConvertToAbsoluteDestination(dest); - os << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " << stype; + os << indent << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " + << stype; if (optional) { os << " OPTIONAL"; } @@ -133,6 +143,9 @@ void cmInstallGenerator::AddInstallRule( for (std::string const& f : files) { os << "\n" << indent << " \"" << f << "\""; } + if (files_var) { + os << " ${" << files_var << "}"; + } os << "\n" << indent << " "; if (!(literal_args && *literal_args)) { os << " "; diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h index 97acb88..d342c99 100644 --- a/Source/cmInstallGenerator.h +++ b/Source/cmInstallGenerator.h @@ -50,7 +50,8 @@ public: std::vector const& files, bool optional = false, const char* permissions_file = nullptr, const char* permissions_dir = nullptr, const char* rename = nullptr, - const char* literal_args = nullptr, Indent indent = Indent()); + const char* literal_args = nullptr, Indent indent = Indent(), + const char* files_var = nullptr); /** Get the install destination as it should appear in the installation script. */ diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.cxx b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx new file mode 100644 index 0000000..4d585ce --- /dev/null +++ b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx @@ -0,0 +1,206 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmInstallGetRuntimeDependenciesGenerator.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "cmGeneratorExpression.h" +#include "cmInstallRuntimeDependencySet.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmOutputConverter.h" +#include "cmStringAlgorithms.h" + +namespace { +template +void WriteMultiArgument(std::ostream& os, const cm::string_view& keyword, + const std::vector& list, + cmScriptGeneratorIndent indent, F transform) +{ + bool first = true; + for (auto const& item : list) { + cm::optional result = transform(item); + if (result) { + if (first) { + os << indent << " " << keyword << "\n"; + first = false; + } + os << indent << " " << *result << "\n"; + } + } +} + +void WriteFilesArgument( + std::ostream& os, const cm::string_view& keyword, + const std::vector>& + items, + const std::string& config, cmScriptGeneratorIndent indent) +{ + WriteMultiArgument( + os, keyword, items, indent, + [config](const std::unique_ptr& i) + -> std::string { return cmStrCat('"', i->GetItemPath(config), '"'); }); +} + +void WriteGenexEvaluatorArgument(std::ostream& os, + const cm::string_view& keyword, + const std::vector& genexes, + const std::string& config, + cmLocalGenerator* lg, + cmScriptGeneratorIndent indent) +{ + WriteMultiArgument( + os, keyword, genexes, indent, + [config, lg](const std::string& genex) -> cm::optional { + std::string result = cmGeneratorExpression::Evaluate(genex, lg, config); + if (result.empty()) { + return cm::nullopt; + } + return cmOutputConverter::EscapeForCMake(result); + }); +} +} + +cmInstallGetRuntimeDependenciesGenerator:: + cmInstallGetRuntimeDependenciesGenerator( + cmInstallRuntimeDependencySet* runtimeDependencySet, + std::vector directories, + std::vector preIncludeRegexes, + std::vector preExcludeRegexes, + std::vector postIncludeRegexes, + std::vector postExcludeRegexes, + std::vector postIncludeFiles, + std::vector postExcludeFiles, std::string libraryComponent, + std::string frameworkComponent, bool noInstallRPath, const char* depsVar, + const char* rpathPrefix, std::vector const& configurations, + MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace) + : cmInstallGenerator("", configurations, "", message, exclude_from_all, + false, std::move(backtrace)) + , RuntimeDependencySet(runtimeDependencySet) + , Directories(std::move(directories)) + , PreIncludeRegexes(std::move(preIncludeRegexes)) + , PreExcludeRegexes(std::move(preExcludeRegexes)) + , PostIncludeRegexes(std::move(postIncludeRegexes)) + , PostExcludeRegexes(std::move(postExcludeRegexes)) + , PostIncludeFiles(std::move(postIncludeFiles)) + , PostExcludeFiles(std::move(postExcludeFiles)) + , LibraryComponent(std::move(libraryComponent)) + , FrameworkComponent(std::move(frameworkComponent)) + , NoInstallRPath(noInstallRPath) + , DepsVar(depsVar) + , RPathPrefix(rpathPrefix) +{ + this->ActionsPerConfig = true; +} + +bool cmInstallGetRuntimeDependenciesGenerator::Compute(cmLocalGenerator* lg) +{ + this->LocalGenerator = lg; + return true; +} + +void cmInstallGetRuntimeDependenciesGenerator::GenerateScript(std::ostream& os) +{ + // Track indentation. + Indent indent; + + // Begin this block of installation. + os << indent << "if("; + if (this->FrameworkComponent.empty() || + this->FrameworkComponent == this->LibraryComponent) { + os << this->CreateComponentTest(this->LibraryComponent, + this->ExcludeFromAll); + } else { + os << this->CreateComponentTest(this->LibraryComponent, true) << " OR " + << this->CreateComponentTest(this->FrameworkComponent, + this->ExcludeFromAll); + } + os << ")\n"; + + // Generate the script possibly with per-configuration code. + this->GenerateScriptConfigs(os, indent.Next()); + + // End this block of installation. + os << indent << "endif()\n\n"; +} + +void cmInstallGetRuntimeDependenciesGenerator::GenerateScriptForConfig( + std::ostream& os, const std::string& config, Indent indent) +{ + std::string installNameTool = + this->LocalGenerator->GetMakefile()->GetSafeDefinition( + "CMAKE_INSTALL_NAME_TOOL"); + + os << indent << "file(GET_RUNTIME_DEPENDENCIES\n" + << indent << " RESOLVED_DEPENDENCIES_VAR " << this->DepsVar << '\n'; + WriteFilesArgument(os, "EXECUTABLES"_s, + this->RuntimeDependencySet->GetExecutables(), config, + indent); + WriteFilesArgument(os, "LIBRARIES"_s, + this->RuntimeDependencySet->GetLibraries(), config, + indent); + WriteFilesArgument(os, "MODULES"_s, this->RuntimeDependencySet->GetModules(), + config, indent); + if (this->RuntimeDependencySet->GetBundleExecutable()) { + os << indent << " BUNDLE_EXECUTABLE \"" + << this->RuntimeDependencySet->GetBundleExecutable()->GetItemPath( + config) + << "\"\n"; + } + WriteGenexEvaluatorArgument(os, "DIRECTORIES"_s, this->Directories, config, + this->LocalGenerator, indent); + WriteGenexEvaluatorArgument(os, "PRE_INCLUDE_REGEXES"_s, + this->PreIncludeRegexes, config, + this->LocalGenerator, indent); + WriteGenexEvaluatorArgument(os, "PRE_EXCLUDE_REGEXES"_s, + this->PreExcludeRegexes, config, + this->LocalGenerator, indent); + WriteGenexEvaluatorArgument(os, "POST_INCLUDE_REGEXES"_s, + this->PostIncludeRegexes, config, + this->LocalGenerator, indent); + WriteGenexEvaluatorArgument(os, "POST_EXCLUDE_REGEXES"_s, + this->PostExcludeRegexes, config, + this->LocalGenerator, indent); + WriteGenexEvaluatorArgument(os, "POST_INCLUDE_FILES"_s, + this->PostIncludeFiles, config, + this->LocalGenerator, indent); + WriteGenexEvaluatorArgument(os, "POST_EXCLUDE_FILES"_s, + this->PostExcludeFiles, config, + this->LocalGenerator, indent); + + std::set postExcludeFiles; + auto const addPostExclude = + [config, &postExcludeFiles, this]( + const std::vector>& + tgts) { + for (auto const& item : tgts) { + item->AddPostExcludeFiles(config, postExcludeFiles, + this->RuntimeDependencySet); + } + }; + addPostExclude(this->RuntimeDependencySet->GetExecutables()); + addPostExclude(this->RuntimeDependencySet->GetLibraries()); + addPostExclude(this->RuntimeDependencySet->GetModules()); + bool first = true; + for (auto const& file : postExcludeFiles) { + if (first) { + os << indent << " POST_EXCLUDE_FILES_STRICT\n"; + first = false; + } + os << indent << " \"" << file << "\"\n"; + } + + if (!installNameTool.empty() && !this->NoInstallRPath) { + os << indent << " RPATH_PREFIX " << this->RPathPrefix << '\n'; + } + os << indent << " )\n"; +} diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.h b/Source/cmInstallGetRuntimeDependenciesGenerator.h new file mode 100644 index 0000000..19f6cc6 --- /dev/null +++ b/Source/cmInstallGetRuntimeDependenciesGenerator.h @@ -0,0 +1,56 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include +#include +#include + +#include "cmInstallGenerator.h" +#include "cmListFileCache.h" +#include "cmScriptGenerator.h" + +class cmLocalGenerator; +class cmInstallRuntimeDependencySet; + +class cmInstallGetRuntimeDependenciesGenerator : public cmInstallGenerator +{ +public: + cmInstallGetRuntimeDependenciesGenerator( + cmInstallRuntimeDependencySet* runtimeDependencySet, + std::vector directories, + std::vector preIncludeRegexes, + std::vector preExcludeRegexes, + std::vector postIncludeRegexes, + std::vector postExcludeRegexes, + std::vector postIncludeFiles, + std::vector postExcludeFiles, std::string libraryComponent, + std::string frameworkComponent, bool noInstallRPath, const char* depsVar, + const char* rpathPrefix, std::vector const& configurations, + MessageLevel message, bool exclude_from_all, + cmListFileBacktrace backtrace); + + bool Compute(cmLocalGenerator* lg) override; + +protected: + void GenerateScript(std::ostream& os) override; + + void GenerateScriptForConfig(std::ostream& os, const std::string& config, + Indent indent) override; + +private: + cmInstallRuntimeDependencySet* RuntimeDependencySet; + std::vector Directories; + std::vector PreIncludeRegexes; + std::vector PreExcludeRegexes; + std::vector PostIncludeRegexes; + std::vector PostExcludeRegexes; + std::vector PostIncludeFiles; + std::vector PostExcludeFiles; + std::string LibraryComponent; + std::string FrameworkComponent; + bool NoInstallRPath; + const char* DepsVar; + const char* RPathPrefix; + cmLocalGenerator* LocalGenerator = nullptr; +}; diff --git a/Source/cmInstallRuntimeDependencySetGenerator.cxx b/Source/cmInstallRuntimeDependencySetGenerator.cxx new file mode 100644 index 0000000..44f03e1 --- /dev/null +++ b/Source/cmInstallRuntimeDependencySetGenerator.cxx @@ -0,0 +1,276 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmInstallRuntimeDependencySetGenerator.h" + +#include +#include +#include +#include + +#include "cmGeneratorExpression.h" +#include "cmInstallGenerator.h" +#include "cmInstallType.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmOutputConverter.h" +#include "cmScriptGenerator.h" +#include "cmStringAlgorithms.h" +#include "cmake.h" + +cmInstallRuntimeDependencySetGenerator::cmInstallRuntimeDependencySetGenerator( + DependencyType type, cmInstallRuntimeDependencySet* dependencySet, + std::vector installRPaths, bool noInstallRPath, + std::string installNameDir, bool noInstallName, const char* depsVar, + const char* rpathPrefix, const char* tmpVarPrefix, std::string destination, + std::vector const& configurations, std::string component, + std::string permissions, MessageLevel message, bool exclude_from_all, + cmListFileBacktrace backtrace) + : cmInstallGenerator(std::move(destination), configurations, + std::move(component), message, exclude_from_all, false, + std::move(backtrace)) + , Type(type) + , DependencySet(dependencySet) + , InstallRPaths(std::move(installRPaths)) + , NoInstallRPath(noInstallRPath) + , InstallNameDir(std::move(installNameDir)) + , NoInstallName(noInstallName) + , Permissions(std::move(permissions)) + , DepsVar(depsVar) + , RPathPrefix(rpathPrefix) + , TmpVarPrefix(tmpVarPrefix) +{ + this->ActionsPerConfig = true; +} + +bool cmInstallRuntimeDependencySetGenerator::Compute(cmLocalGenerator* lg) +{ + this->LocalGenerator = lg; + return true; +} + +void cmInstallRuntimeDependencySetGenerator::GenerateScriptForConfig( + std::ostream& os, const std::string& config, Indent indent) +{ + if (!this->LocalGenerator->GetMakefile() + ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL") + .empty() && + !this->NoInstallName) { + std::string installNameDir = "@rpath/"; + if (!this->InstallNameDir.empty()) { + installNameDir = this->InstallNameDir; + cmGeneratorExpression::ReplaceInstallPrefix(installNameDir, + "${CMAKE_INSTALL_PREFIX}"); + installNameDir = cmGeneratorExpression::Evaluate( + installNameDir, this->LocalGenerator, config); + if (installNameDir.empty()) { + this->LocalGenerator->GetMakefile()->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "INSTALL_NAME_DIR argument must not evaluate to an " + "empty string", + this->Backtrace); + return; + } + if (installNameDir.back() != '/') { + installNameDir += '/'; + } + } + os << indent << "set(" << this->TmpVarPrefix << "_install_name_dir \"" + << installNameDir << "\")\n"; + } + + os << indent << "foreach(" << this->TmpVarPrefix << "_dep IN LISTS " + << this->DepsVar << ")\n"; + + if (!this->LocalGenerator->GetMakefile() + ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL") + .empty()) { + std::vector evaluatedRPaths; + for (auto const& rpath : this->InstallRPaths) { + std::string result = + cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config); + if (!result.empty()) { + evaluatedRPaths.push_back(std::move(result)); + } + } + + switch (this->Type) { + case DependencyType::Library: + this->GenerateAppleLibraryScript(os, config, evaluatedRPaths, + indent.Next()); + break; + case DependencyType::Framework: + this->GenerateAppleFrameworkScript(os, config, evaluatedRPaths, + indent.Next()); + break; + } + } else { + std::string depVar = cmStrCat(this->TmpVarPrefix, "_dep"); + + this->AddInstallRule( + os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, + false, this->Permissions.c_str(), nullptr, nullptr, + " FOLLOW_SYMLINK_CHAIN", indent.Next(), depVar.c_str()); + + if (this->LocalGenerator->GetMakefile()->GetSafeDefinition( + "CMAKE_SYSTEM_NAME") == "Linux" && + !this->NoInstallRPath) { + std::string evaluatedRPath; + for (auto const& rpath : this->InstallRPaths) { + std::string result = + cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config); + if (!result.empty()) { + if (evaluatedRPath.empty()) { + evaluatedRPath = std::move(result); + } else { + evaluatedRPath += ':'; + evaluatedRPath += result; + } + } + } + + os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix + << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n"; + if (evaluatedRPath.empty()) { + os << indent.Next() << "file(RPATH_REMOVE FILE \"" + << GetDestDirPath( + ConvertToAbsoluteDestination(this->GetDestination(config))) + << "/${" << this->TmpVarPrefix << "_dep_name}\")\n"; + } else { + os << indent.Next() << "file(RPATH_SET FILE \"" + << GetDestDirPath( + ConvertToAbsoluteDestination(this->GetDestination(config))) + << "/${" << this->TmpVarPrefix << "_dep_name}\" NEW_RPATH " + << cmOutputConverter::EscapeForCMake(evaluatedRPath) << ")\n"; + } + } + } + + os << indent << "endforeach()\n"; +} + +void cmInstallRuntimeDependencySetGenerator::GenerateAppleLibraryScript( + std::ostream& os, const std::string& config, + const std::vector& evaluatedRPaths, Indent indent) +{ + os << indent << "if(NOT " << this->TmpVarPrefix + << "_dep MATCHES \"\\\\.framework/\")\n"; + + auto depName = cmStrCat(this->TmpVarPrefix, "_dep"); + this->AddInstallRule( + os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, false, + this->Permissions.c_str(), nullptr, nullptr, " FOLLOW_SYMLINK_CHAIN", + indent.Next(), depName.c_str()); + + os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix + << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n"; + auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_dep_name}"); + this->GenerateInstallNameFixup(os, config, evaluatedRPaths, + cmStrCat("${", this->TmpVarPrefix, "_dep}"), + depNameVar, indent.Next()); + + os << indent << "endif()\n"; +} + +void cmInstallRuntimeDependencySetGenerator::GenerateAppleFrameworkScript( + std::ostream& os, const std::string& config, + const std::vector& evaluatedRPaths, Indent indent) +{ + os << indent << "if(" << this->TmpVarPrefix + << "_dep MATCHES \"^(.*/)?([^/]*\\\\.framework)/(.*)$\")\n" + << indent.Next() << "set(" << this->TmpVarPrefix + << "_dir \"${CMAKE_MATCH_1}\")\n" + << indent.Next() << "set(" << this->TmpVarPrefix + << "_name \"${CMAKE_MATCH_2}\")\n" + << indent.Next() << "set(" << this->TmpVarPrefix + << "_file \"${CMAKE_MATCH_3}\")\n" + << indent.Next() << "set(" << this->TmpVarPrefix << "_path \"${" + << this->TmpVarPrefix << "_dir}${" << this->TmpVarPrefix << "_name}\")\n"; + + auto depName = cmStrCat(this->TmpVarPrefix, "_path"); + this->AddInstallRule( + os, this->GetDestination(config), cmInstallType_DIRECTORY, {}, false, + this->Permissions.c_str(), nullptr, nullptr, " USE_SOURCE_PERMISSIONS", + indent.Next(), depName.c_str()); + + auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_name}/${", + this->TmpVarPrefix, "_file}"); + this->GenerateInstallNameFixup(os, config, evaluatedRPaths, + cmStrCat("${", this->TmpVarPrefix, "_dep}"), + depNameVar, indent.Next()); + + os << indent << "endif()\n"; +} + +void cmInstallRuntimeDependencySetGenerator::GenerateInstallNameFixup( + std::ostream& os, const std::string& config, + const std::vector& evaluatedRPaths, const std::string& filename, + const std::string& depName, Indent indent) +{ + if (!(this->NoInstallRPath && this->NoInstallName)) { + auto indent2 = indent; + if (evaluatedRPaths.empty() && this->NoInstallName) { + indent2 = indent2.Next(); + os << indent << "if(" << this->RPathPrefix << "_" << filename << ")\n"; + } + os << indent2 << "set(" << this->TmpVarPrefix << "_rpath_args)\n"; + if (!this->NoInstallRPath) { + os << indent2 << "foreach(" << this->TmpVarPrefix << "_rpath IN LISTS " + << this->RPathPrefix << '_' << filename << ")\n" + << indent2.Next() << "list(APPEND " << this->TmpVarPrefix + << "_rpath_args -delete_rpath \"${" << this->TmpVarPrefix + << "_rpath}\")\n" + << indent2 << "endforeach()\n"; + } + os << indent2 << "execute_process(COMMAND \"" + << this->LocalGenerator->GetMakefile()->GetSafeDefinition( + "CMAKE_INSTALL_NAME_TOOL") + << "\" ${" << this->TmpVarPrefix << "_rpath_args}\n"; + if (!this->NoInstallRPath) { + for (auto const& rpath : evaluatedRPaths) { + os << indent2 << " -add_rpath " + << cmOutputConverter::EscapeForCMake(rpath) << "\n"; + } + } + if (!this->NoInstallName) { + os << indent2 << " -id \"${" << this->TmpVarPrefix + << "_install_name_dir}" << depName << "\"\n"; + } + os << indent2 << " \"" + << GetDestDirPath( + ConvertToAbsoluteDestination(this->GetDestination(config))) + << "/" << depName << "\")\n"; + if (evaluatedRPaths.empty() && this->NoInstallName) { + os << indent << "endif()\n"; + } + } +} + +void cmInstallRuntimeDependencySetGenerator::GenerateStripFixup( + std::ostream& os, const std::string& config, const std::string& depName, + Indent indent) +{ + std::string strip = + this->LocalGenerator->GetMakefile()->GetSafeDefinition("CMAKE_STRIP"); + if (!strip.empty()) { + os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n" + << indent.Next() << "execute_process(COMMAND \"" << strip << "\" "; + if (this->LocalGenerator->GetMakefile()->GetSafeDefinition( + "CMAKE_HOST_SYSTEM_NAME") == "Darwin") { + os << "-x "; + } + os << "\"" + << GetDestDirPath( + ConvertToAbsoluteDestination(this->GetDestination(config))) + << "/" << depName << "\")\n" + << indent << "endif()\n"; + } +} + +std::string cmInstallRuntimeDependencySetGenerator::GetDestination( + std::string const& config) const +{ + return cmGeneratorExpression::Evaluate(this->Destination, + this->LocalGenerator, config); +} diff --git a/Source/cmInstallRuntimeDependencySetGenerator.h b/Source/cmInstallRuntimeDependencySetGenerator.h new file mode 100644 index 0000000..8e98b57 --- /dev/null +++ b/Source/cmInstallRuntimeDependencySetGenerator.h @@ -0,0 +1,74 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include +#include +#include + +#include "cmInstallGenerator.h" +#include "cmListFileCache.h" +#include "cmScriptGenerator.h" + +class cmInstallRuntimeDependencySet; +class cmLocalGenerator; + +class cmInstallRuntimeDependencySetGenerator : public cmInstallGenerator +{ +public: + enum class DependencyType + { + Library, + Framework, + }; + + cmInstallRuntimeDependencySetGenerator( + DependencyType type, cmInstallRuntimeDependencySet* dependencySet, + std::vector installRPaths, bool noInstallRPath, + std::string installNameDir, bool noInstallName, const char* depsVar, + const char* rpathPrefix, const char* tmpVarPrefix, std::string destination, + std::vector const& configurations, std::string component, + std::string permissions, MessageLevel message, bool exclude_from_all, + cmListFileBacktrace backtrace); + + bool Compute(cmLocalGenerator* lg) override; + + DependencyType GetDependencyType() const { return this->Type; } + + cmInstallRuntimeDependencySet* GetRuntimeDependencySet() const + { + return this->DependencySet; + } + + std::string GetDestination(std::string const& config) const; + +protected: + void GenerateScriptForConfig(std::ostream& os, const std::string& config, + Indent indent) override; + +private: + DependencyType Type; + cmInstallRuntimeDependencySet* DependencySet; + std::vector InstallRPaths; + bool NoInstallRPath; + std::string InstallNameDir; + bool NoInstallName; + std::string Permissions; + const char* DepsVar; + const char* RPathPrefix; + const char* TmpVarPrefix; + cmLocalGenerator* LocalGenerator = nullptr; + + void GenerateAppleLibraryScript( + std::ostream& os, const std::string& config, + const std::vector& evaluatedRPaths, Indent indent); + void GenerateAppleFrameworkScript( + std::ostream& os, const std::string& config, + const std::vector& evaluatedRPaths, Indent indent); + void GenerateInstallNameFixup( + std::ostream& os, const std::string& config, + const std::vector& evaluatedRPaths, + const std::string& filename, const std::string& depName, Indent indent); + void GenerateStripFixup(std::ostream& os, const std::string& config, + const std::string& depName, Indent indent); +}; diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx index 06246d1..26f255d 100644 --- a/Source/cmRuntimeDependencyArchive.cxx +++ b/Source/cmRuntimeDependencyArchive.cxx @@ -397,3 +397,11 @@ cmRuntimeDependencyArchive::GetRPaths() const { return this->RPaths; } + +bool cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies( + const std::string& platform) +{ + static const std::set supportedPlatforms = { "Windows", "Linux", + "Darwin" }; + return supportedPlatforms.count(platform); +} diff --git a/Source/cmRuntimeDependencyArchive.h b/Source/cmRuntimeDependencyArchive.h index 20a38e2..b170815 100644 --- a/Source/cmRuntimeDependencyArchive.h +++ b/Source/cmRuntimeDependencyArchive.h @@ -53,6 +53,8 @@ public: const std::set& GetUnresolvedPaths() const; const std::map>& GetRPaths() const; + static bool PlatformSupportsRuntimeDependencies(const std::string& platform); + private: cmExecutionStatus& Status; std::unique_ptr Linker; diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index 94887a0..0f6ec70 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/Tests/RunCMake/install/RunCMakeTest.cmake @@ -44,7 +44,7 @@ function(check_installed expect) do not match what we expected: ${expect} in directory: - ${CMAKE_INSTALL_PREFIX}" PARENT_SCOPE) + ${CMAKE_INSTALL_PREFIX}\n" PARENT_SCOPE) endif() endfunction() @@ -174,6 +174,21 @@ run_install_test(FILES-PERMISSIONS) run_install_test(TARGETS-RPATH) run_install_test(InstallRequiredSystemLibraries) +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + run_cmake(TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle) + run_cmake(TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|Darwin|Windows)$") + run_install_test(TARGETS-RUNTIME_DEPENDENCIES-nodep) + run_install_test(TARGETS-RUNTIME_DEPENDENCIES-empty) + set(RunCMake_TEST_OPTIONS "-DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}") + run_cmake(TARGETS-RUNTIME_DEPENDENCIES-cross) + unset(RunCMake_TEST_OPTIONS) +else() + run_cmake(TARGETS-RUNTIME_DEPENDENCIES-unsupported) +endif() + set(run_install_test_components 1) run_install_test(FILES-EXCLUDE_FROM_ALL) run_install_test(TARGETS-EXCLUDE_FROM_ALL) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt new file mode 100644 index 0000000..b7bbb55 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-cross\.cmake:[0-9]+ \(install\): + install TARGETS RUNTIME_DEPENDENCIES is not supported when cross-compiling\. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake new file mode 100644 index 0000000..36b2eb7 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_executable(exe main.c) +install(TARGETS exe RUNTIME_DEPENDENCIES) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake new file mode 100644 index 0000000..dafc2a4 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake @@ -0,0 +1 @@ +check_installed([[^static;static/(liblib\.a|lib\.lib)$]]) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake new file mode 100644 index 0000000..e46e1d9 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +add_library(lib STATIC obj1.c) + +install(TARGETS lib RUNTIME_DEPENDENCIES + LIBRARY DESTINATION lib + ARCHIVE DESTINATION static + FRAMEWORK DESTINATION fw + ) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt new file mode 100644 index 0000000..6ab14f6 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework\.cmake:[0-9]+ \(install\): + install TARGETS RUNTIME_DEPENDENCIES given no FRAMEWORK DESTINATION +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake new file mode 100644 index 0000000..36b2eb7 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_executable(exe main.c) +install(TARGETS exe RUNTIME_DEPENDENCIES) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt new file mode 100644 index 0000000..c7b49c7 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle\.cmake:[0-9]+ \(install\): + install A runtime dependency set may only have one bundle executable\. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake new file mode 100644 index 0000000..a848a24 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake @@ -0,0 +1,10 @@ +enable_language(C) + +add_executable(exe1 MACOSX_BUNDLE main.c) +add_executable(exe2 MACOSX_BUNDLE main.c) + +install(TARGETS exe1 exe2 + RUNTIME_DEPENDENCIES + BUNDLE DESTINATION bundles + FRAMEWORK DESTINATION fw + ) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake new file mode 100644 index 0000000..9f455b1 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake @@ -0,0 +1 @@ +check_installed([[^bin;bin/exe(\.exe)?$]]) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake new file mode 100644 index 0000000..02466561 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +add_executable(exe main.c) + +install(TARGETS exe + RUNTIME_DEPENDENCIES + PRE_EXCLUDE_REGEXES ".*" + FRAMEWORK DESTINATION fw + ) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt new file mode 100644 index 0000000..c098a4c --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-unsupported\.cmake:[0-9]+ \(install\): + install TARGETS RUNTIME_DEPENDENCIES is not supported on system "[^ +]*" +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake new file mode 100644 index 0000000..36b2eb7 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_executable(exe main.c) +install(TARGETS exe RUNTIME_DEPENDENCIES) diff --git a/bootstrap b/bootstrap index 720fa76..f8d2f69 100755 --- a/bootstrap +++ b/bootstrap @@ -387,8 +387,10 @@ CMAKE_CXX_SOURCES="\ cmInstallFilesCommand \ cmInstallFilesGenerator \ cmInstallGenerator \ + cmInstallGetRuntimeDependenciesGenerator \ cmInstallImportedRuntimeArtifactsGenerator \ cmInstallRuntimeDependencySet \ + cmInstallRuntimeDependencySetGenerator \ cmInstallScriptGenerator \ cmInstallSubdirectoryGenerator \ cmInstallTargetGenerator \ -- cgit v0.12