diff options
Diffstat (limited to 'Source/cmInstallExportGenerator.cxx')
-rw-r--r-- | Source/cmInstallExportGenerator.cxx | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx new file mode 100644 index 0000000..f5bedab --- /dev/null +++ b/Source/cmInstallExportGenerator.cxx @@ -0,0 +1,220 @@ +/* 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> + +#ifdef CMAKE_BUILD_WITH_CMAKE +# include "cmExportInstallAndroidMKGenerator.h" +#endif +#include "cmExportInstallFileGenerator.h" +#include "cmExportSet.h" +#include "cmInstallType.h" +#include "cmLocalGenerator.h" +#include "cmSystemTools.h" + +cmInstallExportGenerator::cmInstallExportGenerator( + cmExportSet* exportSet, const char* destination, + const char* file_permissions, std::vector<std::string> const& configurations, + const char* component, MessageLevel message, bool exclude_from_all, + const char* filename, const char* name_space, bool exportOld, bool android) + : cmInstallGenerator(destination, configurations, component, message, + exclude_from_all) + , ExportSet(exportSet) + , FilePermissions(file_permissions) + , FileName(filename) + , Namespace(name_space) + , ExportOld(exportOld) + , LocalGenerator(nullptr) +{ + if (android) { +#ifdef CMAKE_BUILD_WITH_CMAKE + this->EFGen = new cmExportInstallAndroidMKGenerator(this); +#endif + } else { + this->EFGen = new cmExportInstallFileGenerator(this); + } + exportSet->AddInstallation(this); +} + +cmInstallExportGenerator::~cmInstallExportGenerator() +{ + delete this->EFGen; +} + +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 = this->LocalGenerator->GetCurrentBinaryDirectory(); + this->TempDir += "/CMakeFiles"; + this->TempDir += "/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 = this->TempDir; + this->MainImportFile += "/"; + this->MainImportFile += 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 = "$ENV{DESTDIR}"; + installedDir += this->ConvertToAbsoluteDestination(this->Destination); + installedDir += "/"; + std::string installedFile = installedDir; + installedFile += 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); +} |