/* 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()->IsOn("APPLE")) { 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); }