| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmInstallRuntimeDependencySetGenerator.h" | |
| #include <ostream> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include "cmDiagnosticContext.h" | |
| #include "cmGeneratorExpression.h" | |
| #include "cmInstallGenerator.h" | |
| #include "cmInstallType.h" | |
| #include "cmLocalGenerator.h" | |
| #include "cmMakefile.h" | |
| #include "cmMessageType.h" | |
| #include "cmScriptGenerator.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmake.h" | |
| cmInstallRuntimeDependencySetGenerator::cmInstallRuntimeDependencySetGenerator( | |
| DependencyType type, cmInstallRuntimeDependencySet* dependencySet, | |
| std::vector<std::string> installRPaths, bool noInstallRPath, | |
| std::string installNameDir, bool noInstallName, char const* depsVar, | |
| char const* rpathPrefix, char const* tmpVarPrefix, std::string destination, | |
| std::vector<std::string> const& configurations, std::string component, | |
| std::string permissions, MessageLevel message, bool excludeFromAll, | |
| cmDiagnosticContext context) | |
| : cmInstallGenerator(std::move(destination), configurations, | |
| std::move(component), message, excludeFromAll, false, | |
| std::move(context)) | |
| , 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, std::string const& 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->Context.GetBacktrace()); | |
| return; | |
| } | |
| if (installNameDir.back() != '/') { | |
| installNameDir += '/'; | |
| } | |
| } | |
| os << indent << "set(" << this->TmpVarPrefix << "_install_name_dir \"" | |
| << installNameDir << "\")\n"; | |
| } | |
| os << indent << "foreach(" << this->TmpVarPrefix << "_dep IN LISTS " | |
| << this->DepsVar << ")\n"; | |
| if (!this->LocalGenerator->GetMakefile() | |
| ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL") | |
| .empty()) { | |
| std::vector<std::string> evaluatedRPaths; | |
| for (auto const& rpath : this->InstallRPaths) { | |
| std::string result = | |
| cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config); | |
| if (!result.empty()) { | |
| evaluatedRPaths.push_back(std::move(result)); | |
| } | |
| } | |
| switch (this->Type) { | |
| case DependencyType::Library: | |
| this->GenerateAppleLibraryScript(os, config, evaluatedRPaths, | |
| indent.Next()); | |
| break; | |
| case DependencyType::Framework: | |
| this->GenerateAppleFrameworkScript(os, config, evaluatedRPaths, | |
| indent.Next()); | |
| break; | |
| } | |
| } else { | |
| std::string depVar = cmStrCat(this->TmpVarPrefix, "_dep"); | |
| this->AddInstallRule( | |
| os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, | |
| false, this->Permissions.c_str(), nullptr, nullptr, | |
| " FOLLOW_SYMLINK_CHAIN", indent.Next(), depVar.c_str()); | |
| if (this->LocalGenerator->GetMakefile()->GetSafeDefinition( | |
| "CMAKE_SYSTEM_NAME") == "Linux" && | |
| !this->NoInstallRPath) { | |
| std::string evaluatedRPath; | |
| for (auto const& rpath : this->InstallRPaths) { | |
| std::string result = | |
| cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config); | |
| if (!result.empty()) { | |
| if (evaluatedRPath.empty()) { | |
| evaluatedRPath = std::move(result); | |
| } else { | |
| evaluatedRPath += ':'; | |
| evaluatedRPath += result; | |
| } | |
| } | |
| } | |
| os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix | |
| << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n"; | |
| if (evaluatedRPath.empty()) { | |
| os << indent.Next() << "file(RPATH_REMOVE FILE \"" | |
| << GetDestDirPath( | |
| ConvertToAbsoluteDestination(this->GetDestination(config))) | |
| << "/${" << this->TmpVarPrefix << "_dep_name}\")\n"; | |
| } else { | |
| os << indent.Next() << "file(RPATH_SET FILE \"" | |
| << GetDestDirPath( | |
| ConvertToAbsoluteDestination(this->GetDestination(config))) | |
| << "/${" << this->TmpVarPrefix << "_dep_name}\" NEW_RPATH " | |
| << cmScriptGenerator::Quote(evaluatedRPath) << ")\n"; | |
| } | |
| } | |
| } | |
| os << indent << "endforeach()\n"; | |
| } | |
| void cmInstallRuntimeDependencySetGenerator::GenerateAppleLibraryScript( | |
| std::ostream& os, std::string const& config, | |
| std::vector<std::string> const& 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, std::string const& config, | |
| std::vector<std::string> const& 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, std::string const& config, | |
| std::vector<std::string> const& evaluatedRPaths, std::string const& filename, | |
| std::string const& 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 " << cmScriptGenerator::Quote(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, std::string const& config, std::string const& 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()->IsOn("APPLE")) { | |
| os << "-x "; | |
| } | |
| os << "\"" | |
| << GetDestDirPath( | |
| ConvertToAbsoluteDestination(this->GetDestination(config))) | |
| << "/" << depName << "\")\n" | |
| << indent << "endif()\n"; | |
| } | |
| } | |
| std::string cmInstallRuntimeDependencySetGenerator::GetDestination( | |
| std::string const& config) const | |
| { | |
| std::string dest = cmGeneratorExpression::Evaluate( | |
| this->Destination, this->LocalGenerator, config); | |
| this->CheckAbsoluteDestination(dest, this->LocalGenerator); | |
| return dest; | |
| } |