diff options
Diffstat (limited to 'Source/cmInstallExportGenerator.cxx')
-rw-r--r-- | Source/cmInstallExportGenerator.cxx | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx new file mode 100644 index 0000000..6e3508c --- /dev/null +++ b/Source/cmInstallExportGenerator.cxx @@ -0,0 +1,221 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmInstallExportGenerator.h" + +#include <algorithm> +#include <map> +#include <sstream> +#include <utility> + +#include <cm/memory> + +#ifndef CMAKE_BOOTSTRAP +# include "cmExportInstallAndroidMKGenerator.h" +#endif +#include "cmExportInstallFileGenerator.h" +#include "cmExportSet.h" +#include "cmInstallType.h" +#include "cmLocalGenerator.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +cmInstallExportGenerator::cmInstallExportGenerator( + cmExportSet* exportSet, std::string const& destination, + std::string file_permissions, std::vector<std::string> const& configurations, + std::string const& component, MessageLevel message, bool exclude_from_all, + std::string filename, std::string name_space, bool exportOld, bool android) + : cmInstallGenerator(destination, configurations, component, message, + exclude_from_all) + , ExportSet(exportSet) + , FilePermissions(std::move(file_permissions)) + , FileName(std::move(filename)) + , Namespace(std::move(name_space)) + , ExportOld(exportOld) + , LocalGenerator(nullptr) +{ + if (android) { +#ifndef CMAKE_BOOTSTRAP + this->EFGen = cm::make_unique<cmExportInstallAndroidMKGenerator>(this); +#endif + } else { + this->EFGen = cm::make_unique<cmExportInstallFileGenerator>(this); + } + exportSet->AddInstallation(this); +} + +cmInstallExportGenerator::~cmInstallExportGenerator() = default; + +bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg) +{ + this->LocalGenerator = lg; + this->ExportSet->Compute(lg); + return true; +} + +void cmInstallExportGenerator::ComputeTempDir() +{ + // Choose a temporary directory in which to generate the import + // files to be installed. + this->TempDir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), + "/CMakeFiles/Export"); + if (this->Destination.empty()) { + return; + } + this->TempDir += "/"; + + // Enforce a maximum length. + bool useMD5 = false; +#if defined(_WIN32) || defined(__CYGWIN__) + std::string::size_type const max_total_len = 250; +#else + std::string::size_type const max_total_len = 1000; +#endif + // Will generate files of the form "<temp-dir>/<base>-<config>.<ext>". + std::string::size_type const len = this->TempDir.size() + 1 + + this->FileName.size() + 1 + this->GetMaxConfigLength(); + if (len < max_total_len) { + // Keep the total path length below the limit. + std::string::size_type const max_len = max_total_len - len; + if (this->Destination.size() > max_len) { + useMD5 = true; + } + } else { + useMD5 = true; + } + if (useMD5) { + // Replace the destination path with a hash to keep it short. + this->TempDir += cmSystemTools::ComputeStringMD5(this->Destination); + } else { + std::string dest = this->Destination; + // Avoid unix full paths. + if (dest[0] == '/') { + dest[0] = '_'; + } + // Avoid windows full paths by removing colons. + std::replace(dest.begin(), dest.end(), ':', '_'); + // Avoid relative paths that go up the tree. + cmSystemTools::ReplaceString(dest, "../", "__/"); + // Avoid spaces. + std::replace(dest.begin(), dest.end(), ' ', '_'); + this->TempDir += dest; + } +} + +size_t cmInstallExportGenerator::GetMaxConfigLength() const +{ + // Always use at least 8 for "noconfig". + size_t len = 8; + if (this->ConfigurationTypes->empty()) { + if (this->ConfigurationName.size() > 8) { + len = this->ConfigurationName.size(); + } + } else { + for (std::string const& c : *this->ConfigurationTypes) { + if (c.size() > len) { + len = c.size(); + } + } + } + return len; +} + +void cmInstallExportGenerator::GenerateScript(std::ostream& os) +{ + // Skip empty sets. + if (ExportSet->GetTargetExports().empty()) { + std::ostringstream e; + e << "INSTALL(EXPORT) given unknown export \"" << ExportSet->GetName() + << "\""; + cmSystemTools::Error(e.str()); + return; + } + + // Create the temporary directory in which to store the files. + this->ComputeTempDir(); + cmSystemTools::MakeDirectory(this->TempDir); + + // Construct a temporary location for the file. + this->MainImportFile = cmStrCat(this->TempDir, '/', this->FileName); + + // Generate the import file for this export set. + this->EFGen->SetExportFile(this->MainImportFile.c_str()); + this->EFGen->SetNamespace(this->Namespace); + this->EFGen->SetExportOld(this->ExportOld); + if (this->ConfigurationTypes->empty()) { + if (!this->ConfigurationName.empty()) { + this->EFGen->AddConfiguration(this->ConfigurationName); + } else { + this->EFGen->AddConfiguration(""); + } + } else { + for (std::string const& c : *this->ConfigurationTypes) { + this->EFGen->AddConfiguration(c); + } + } + this->EFGen->GenerateImportFile(); + + // Perform the main install script generation. + this->cmInstallGenerator::GenerateScript(os); +} + +void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os, + Indent indent) +{ + // Create the main install rules first. + this->cmInstallGenerator::GenerateScriptConfigs(os, indent); + + // Now create a configuration-specific install rule for the import + // file of each configuration. + std::vector<std::string> files; + for (auto const& i : this->EFGen->GetConfigImportFiles()) { + files.push_back(i.second); + std::string config_test = this->CreateConfigTest(i.first); + os << indent << "if(" << config_test << ")\n"; + this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files, + false, this->FilePermissions.c_str(), nullptr, + nullptr, nullptr, indent.Next()); + os << indent << "endif()\n"; + files.clear(); + } +} + +void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os, + Indent indent) +{ + // Remove old per-configuration export files if the main changes. + std::string installedDir = + cmStrCat("$ENV{DESTDIR}", + this->ConvertToAbsoluteDestination(this->Destination), '/'); + std::string installedFile = cmStrCat(installedDir, this->FileName); + os << indent << "if(EXISTS \"" << installedFile << "\")\n"; + Indent indentN = indent.Next(); + Indent indentNN = indentN.Next(); + Indent indentNNN = indentNN.Next(); + /* clang-format off */ + os << indentN << "file(DIFFERENT EXPORT_FILE_CHANGED FILES\n" + << indentN << " \"" << installedFile << "\"\n" + << indentN << " \"" << this->MainImportFile << "\")\n"; + os << indentN << "if(EXPORT_FILE_CHANGED)\n"; + os << indentNN << "file(GLOB OLD_CONFIG_FILES \"" << installedDir + << this->EFGen->GetConfigImportFileGlob() << "\")\n"; + os << indentNN << "if(OLD_CONFIG_FILES)\n"; + os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile + << "\\\" will be replaced. Removing files [${OLD_CONFIG_FILES}].\")\n"; + os << indentNNN << "file(REMOVE ${OLD_CONFIG_FILES})\n"; + os << indentNN << "endif()\n"; + os << indentN << "endif()\n"; + os << indent << "endif()\n"; + /* clang-format on */ + + // Install the main export file. + std::vector<std::string> files; + files.push_back(this->MainImportFile); + this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files, + false, this->FilePermissions.c_str(), nullptr, nullptr, + nullptr, indent); +} + +std::string cmInstallExportGenerator::GetDestinationFile() const +{ + return this->Destination + '/' + this->FileName; +} |