/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallGenerator.h" #include #include #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" cmInstallGenerator::cmInstallGenerator( std::string destination, std::vector const& configurations, std::string component, MessageLevel message, bool exclude_from_all, bool all_components, cmListFileBacktrace backtrace) : cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations) , Destination(std::move(destination)) , Component(std::move(component)) , Message(message) , ExcludeFromAll(exclude_from_all) , AllComponents(all_components) , Backtrace(std::move(backtrace)) { } cmInstallGenerator::~cmInstallGenerator() = default; bool cmInstallGenerator::HaveInstall() { return true; } void cmInstallGenerator::CheckCMP0082(bool& haveSubdirectoryInstall, bool& haveInstallAfterSubdirectory) { if (haveSubdirectoryInstall) { haveInstallAfterSubdirectory = true; } } void cmInstallGenerator::AddInstallRule( std::ostream& os, std::string const& dest, cmInstallType type, 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) { // Use the FILE command to install the file. std::string stype; switch (type) { case cmInstallType_DIRECTORY: stype = "DIRECTORY"; break; case cmInstallType_PROGRAMS: stype = "PROGRAM"; break; case cmInstallType_EXECUTABLE: stype = "EXECUTABLE"; break; case cmInstallType_STATIC_LIBRARY: stype = "STATIC_LIBRARY"; break; case cmInstallType_SHARED_LIBRARY: stype = "SHARED_LIBRARY"; break; case cmInstallType_MODULE_LIBRARY: stype = "MODULE"; break; case cmInstallType_FILES: 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 << ";"; } os << dest << "/"; if (rename && *rename) { os << rename; } else { os << cmSystemTools::GetFilenameName(file); } firstIteration = false; } os << "\")\n"; os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"; os << indent << indent << "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 " << "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; if (optional) { os << " OPTIONAL"; } switch (this->Message) { case MessageDefault: break; case MessageAlways: os << " MESSAGE_ALWAYS"; break; case MessageLazy: os << " MESSAGE_LAZY"; break; case MessageNever: os << " MESSAGE_NEVER"; break; } if (permissions_file && *permissions_file) { os << " PERMISSIONS" << permissions_file; } if (permissions_dir && *permissions_dir) { os << " DIR_PERMISSIONS" << permissions_dir; } if (rename && *rename) { os << " RENAME \"" << rename << "\""; } os << " FILES"; if (files.size() == 1) { os << " \"" << files[0] << "\""; } else { for (std::string const& f : files) { os << "\n" << indent << " \"" << f << "\""; } os << "\n" << indent << " "; if (!(literal_args && *literal_args)) { os << " "; } } if (literal_args && *literal_args) { os << literal_args; } os << ")\n"; } std::string cmInstallGenerator::CreateComponentTest( const std::string& component, bool exclude_from_all) { std::string result = R"("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "x)"; result += component; result += "x\""; if (!exclude_from_all) { result += " OR NOT CMAKE_INSTALL_COMPONENT"; } return result; } void cmInstallGenerator::GenerateScript(std::ostream& os) { // Track indentation. Indent indent; // Begin this block of installation. if (!this->AllComponents) { std::string component_test = this->CreateComponentTest(this->Component, this->ExcludeFromAll); os << indent << "if(" << component_test << ")\n"; } // Generate the script possibly with per-configuration code. this->GenerateScriptConfigs(os, this->AllComponents ? indent : indent.Next()); // End this block of installation. if (!this->AllComponents) { os << indent << "endif()\n\n"; } } bool cmInstallGenerator::InstallsForConfig(const std::string& config) { return this->GeneratesForConfig(config); } std::string cmInstallGenerator::ConvertToAbsoluteDestination( std::string const& dest) { std::string result; if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest)) { result = "${CMAKE_INSTALL_PREFIX}/"; } result += dest; return result; } cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel( cmMakefile* mf, bool never) { if (never) { return MessageNever; } std::string m = mf->GetSafeDefinition("CMAKE_INSTALL_MESSAGE"); if (m == "ALWAYS") { return MessageAlways; } if (m == "LAZY") { return MessageLazy; } if (m == "NEVER") { return MessageNever; } 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 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"; } } }