| /* 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 <sstream> |
| #include <utility> |
| |
| #include "cmMakefile.h" |
| #include "cmStringAlgorithms.h" |
| #include "cmSystemTools.h" |
| |
| cmInstallGenerator::cmInstallGenerator( |
| std::string destination, std::vector<std::string> 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<std::string> 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, const char* files_var /* = nullptr */) |
| { |
| // 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; |
| } |
| if (cmSystemTools::FileIsFullPath(dest)) { |
| 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 << "\")\n"; |
| } |
| if (files_var) { |
| os << indent << "foreach(_cmake_abs_file IN LISTS " << files_var |
| << ")\n"; |
| os << indent.Next() |
| << "get_filename_component(_cmake_abs_file_name " |
| "\"${_cmake_abs_file}\" NAME)\n"; |
| os << indent.Next() << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES \"" |
| << dest << "/${_cmake_abs_file_name}\")\n"; |
| os << indent << "endforeach()\n"; |
| os << indent << "unset(_cmake_abs_file_name)\n"; |
| os << indent << "unset(_cmake_abs_file)\n"; |
| } |
| os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"; |
| 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.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 << indent << "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 << "\""; |
| } |
| if (files_var) { |
| os << " ${" << files_var << "}"; |
| } |
| 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, bool all_components) |
| { |
| if (all_components) { |
| if (exclude_from_all) { |
| return "CMAKE_INSTALL_COMPONENT"; |
| } |
| return {}; |
| } |
| |
| std::string result = "CMAKE_INSTALL_COMPONENT STREQUAL \""; |
| result += component; |
| result += "\""; |
| if (!exclude_from_all) { |
| result += " OR NOT CMAKE_INSTALL_COMPONENT"; |
| } |
| |
| return result; |
| } |
| |
| void cmInstallGenerator::GenerateScript(std::ostream& os) |
| { |
| // Track indentation. |
| Indent indent; |
| |
| std::string component_test = this->CreateComponentTest( |
| this->Component, this->ExcludeFromAll, this->AllComponents); |
| |
| // Begin this block of installation. |
| if (!component_test.empty()) { |
| 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 (!component_test.empty()) { |
| 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<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"; |
| } |
| } |
| } |