From 2a78d47b16c8b7a3b599f1862cbab0de58575d84 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Fri, 18 Jun 2021 14:44:46 -0400 Subject: install(EXPORT): Install file sets --- Source/cmExportBuildFileGenerator.cxx | 19 ++++++ Source/cmExportBuildFileGenerator.h | 7 ++ Source/cmExportFileGenerator.cxx | 37 ++++++++++ Source/cmExportFileGenerator.h | 12 ++++ Source/cmExportInstallFileGenerator.cxx | 105 +++++++++++++++++++++++++++++ Source/cmExportInstallFileGenerator.h | 6 ++ Source/cmExportTryCompileFileGenerator.cxx | 19 ++++++ Source/cmExportTryCompileFileGenerator.h | 9 +++ Source/cmInstallCommand.cxx | 37 ++++++++-- Source/cmTargetExport.h | 3 + 10 files changed, 249 insertions(+), 5 deletions(-) diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index aa968dc..a47f1e5 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -11,12 +11,15 @@ #include #include "cmExportSet.h" +#include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmOutputConverter.h" #include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -135,6 +138,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateCompatibleInterfaceProperties(gte, properties); this->GenerateInterfaceProperties(gte, os, properties); + + this->GenerateTargetFileSets(gte, os); } // Generate import file content for each configuration. @@ -356,3 +361,17 @@ std::string cmExportBuildFileGenerator::InstallNameDir( return install_name_dir; } + +std::string cmExportBuildFileGenerator::GetFileSetDirectories( + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +{ + return cmOutputConverter::EscapeForCMake( + cmJoin(fileSet->GetDirectoryEntries(), ";")); +} + +std::string cmExportBuildFileGenerator::GetFileSetFiles( + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +{ + return cmOutputConverter::EscapeForCMake( + cmJoin(fileSet->GetFileEntries(), ";")); +} diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 244f526..a7985c7 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -15,9 +15,11 @@ #include "cmStateTypes.h" class cmExportSet; +class cmFileSet; class cmGeneratorTarget; class cmGlobalGenerator; class cmLocalGenerator; +class cmTargetExport; /** \class cmExportBuildFileGenerator * \brief Generate a file exporting targets from a build tree. @@ -76,6 +78,11 @@ protected: std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; + std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, + cmTargetExport* te) override; + std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, + cmTargetExport* te) override; + std::pair, std::string> FindBuildExportInfo( cmGlobalGenerator* gg, const std::string& name); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 9f38c12..896240c 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -12,6 +12,7 @@ #include "cmsys/FStream.hxx" #include "cmComputeLinkInformation.h" +#include "cmFileSet.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -1256,3 +1257,39 @@ bool cmExportFileGenerator::PopulateExportProperties( } return true; } + +void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte, + std::ostream& os, + cmTargetExport* te) +{ + auto interfaceFileSets = gte->Target->GetAllInterfaceFileSets(); + if (!interfaceFileSets.empty()) { + std::string targetName = cmStrCat(this->Namespace, gte->GetExportName()); + os << "if(NOT CMAKE_VERSION VERSION_LESS \"" << DEVEL_CMAKE_VERSION(3, 23) + << "\")\n" + " target_sources(" + << targetName << "\n"; + + for (auto const& name : interfaceFileSets) { + auto* fileSet = gte->Target->GetFileSet(name); + if (!fileSet) { + gte->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("File set \"", name, + "\" is listed in interface file sets of ", gte->GetName(), + " but has not been created")); + return; + } + + os << " INTERFACE" + << "\n FILE_SET " << cmOutputConverter::EscapeForCMake(name) + << "\n TYPE " + << cmOutputConverter::EscapeForCMake(fileSet->GetType()) + << "\n BASE_DIRS " + << this->GetFileSetDirectories(gte, fileSet, te) << "\n FILES " + << this->GetFileSetFiles(gte, fileSet, te) << "\n"; + } + + os << " )\nendif()\n\n"; + } +} diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 24e048b..5875247 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -15,7 +15,9 @@ #include "cmVersion.h" #include "cmVersionConfig.h" +class cmFileSet; class cmGeneratorTarget; +class cmTargetExport; #define STRINGIFY_HELPER(X) #X #define STRINGIFY(X) STRINGIFY_HELPER(X) @@ -184,6 +186,16 @@ protected: ImportPropertyMap& properties, std::string& errorMessage); + void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os, + cmTargetExport* te = nullptr); + + virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte, + cmFileSet* fileSet, + cmTargetExport* te) = 0; + virtual std::string GetFileSetFiles(cmGeneratorTarget* gte, + cmFileSet* fileSet, + cmTargetExport* te) = 0; + // The namespace in which the exports are placed in the generated file. std::string Namespace; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index e9ac875..2dd8b8f 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -2,19 +2,23 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportInstallFileGenerator.h" +#include #include #include #include #include "cmExportSet.h" +#include "cmFileSet.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmInstallExportGenerator.h" +#include "cmInstallFileSetGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmOutputConverter.h" #include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -147,6 +151,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateCompatibleInterfaceProperties(gt, properties); this->GenerateInterfaceProperties(gt, os, properties); + + this->GenerateTargetFileSets(gt, os, te); } if (require3_1_0) { @@ -534,3 +540,102 @@ std::string cmExportInstallFileGenerator::InstallNameDir( return install_name_dir; } + +namespace { +bool EntryIsContextSensitive( + const std::unique_ptr& cge) +{ + return cge->GetHadContextSensitiveCondition(); +} +} + +std::string cmExportInstallFileGenerator::GetFileSetDirectories( + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te) +{ + std::vector resultVector; + + auto configs = + gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + cmGeneratorExpression ge; + auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination()); + + for (auto const& config : configs) { + auto dest = cmStrCat("${_IMPORT_PREFIX}/", + cmOutputConverter::EscapeForCMake( + cge->Evaluate(gte->LocalGenerator, config, gte), + cmOutputConverter::WrapQuotes::NoWrap)); + + if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) { + resultVector.push_back( + cmStrCat("\"$<$:", dest, ">\"")); + } else { + resultVector.push_back(cmStrCat('"', dest, '"')); + break; + } + } + + return cmJoin(resultVector, " "); +} + +std::string cmExportInstallFileGenerator::GetFileSetFiles( + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te) +{ + std::vector resultVector; + + auto configs = + gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + auto fileEntries = fileSet->CompileFileEntries(); + auto directoryEntries = fileSet->CompileDirectoryEntries(); + + cmGeneratorExpression destGe; + auto destCge = + destGe.Parse(te->FileSetGenerators.at(fileSet)->GetDestination()); + + for (auto const& config : configs) { + auto directories = fileSet->EvaluateDirectoryEntries( + directoryEntries, gte->LocalGenerator, config, gte); + + std::map> files; + for (auto const& entry : fileEntries) { + fileSet->EvaluateFileEntry(directories, files, entry, + gte->LocalGenerator, config, gte); + } + auto dest = cmStrCat("${_IMPORT_PREFIX}/", + cmOutputConverter::EscapeForCMake( + destCge->Evaluate(gte->LocalGenerator, config, gte), + cmOutputConverter::WrapQuotes::NoWrap), + '/'); + + bool const contextSensitive = destCge->GetHadContextSensitiveCondition() || + std::any_of(directoryEntries.begin(), directoryEntries.end(), + EntryIsContextSensitive) || + std::any_of(fileEntries.begin(), fileEntries.end(), + EntryIsContextSensitive); + + for (auto const& it : files) { + auto prefix = it.first.empty() ? "" : cmStrCat(it.first, '/'); + for (auto const& filename : it.second) { + auto relFile = + cmStrCat(prefix, cmSystemTools::GetFilenameName(filename)); + auto escapedFile = + cmStrCat(dest, + cmOutputConverter::EscapeForCMake( + relFile, cmOutputConverter::WrapQuotes::NoWrap)); + if (contextSensitive && configs.size() != 1) { + resultVector.push_back( + cmStrCat("\"$<$:", escapedFile, ">\"")); + } else { + resultVector.push_back(cmStrCat('"', escapedFile, '"')); + } + } + } + + if (!(contextSensitive && configs.size() != 1)) { + break; + } + } + + return cmJoin(resultVector, " "); +} diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index 5cec2e0..9374c6b 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -14,6 +14,7 @@ #include "cmExportFileGenerator.h" #include "cmStateTypes.h" +class cmFileSet; class cmGeneratorTarget; class cmGlobalGenerator; class cmInstallExportGenerator; @@ -97,6 +98,11 @@ protected: std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; + std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, + cmTargetExport* te) override; + std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, + cmTargetExport* te) override; + cmInstallExportGenerator* IEGen; // The import file generated for each configuration. diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index cbe3c4d..4fe92c6 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -7,17 +7,22 @@ #include +#include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmOutputConverter.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" #include "cmValue.h" +class cmTargetExport; + cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator( cmGlobalGenerator* gg, const std::vector& targets, cmMakefile* mf, std::set const& langs) @@ -137,3 +142,17 @@ std::string cmExportTryCompileFileGenerator::InstallNameDir( return install_name_dir; } + +std::string cmExportTryCompileFileGenerator::GetFileSetDirectories( + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +{ + return cmOutputConverter::EscapeForCMake( + cmJoin(fileSet->GetDirectoryEntries(), ";")); +} + +std::string cmExportTryCompileFileGenerator::GetFileSetFiles( + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +{ + return cmOutputConverter::EscapeForCMake( + cmJoin(fileSet->GetFileEntries(), ";")); +} diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index 127b8df..8a1fd7e 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -11,9 +11,11 @@ #include "cmExportFileGenerator.h" +class cmFileSet; class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; +class cmTargetExport; class cmExportTryCompileFileGenerator : public cmExportFileGenerator { @@ -48,6 +50,13 @@ protected: std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; + std::string GetFileSetDirectories(cmGeneratorTarget* target, + cmFileSet* fileSet, + cmTargetExport* te) override; + + std::string GetFileSetFiles(cmGeneratorTarget* target, cmFileSet* fileSet, + cmTargetExport* te) override; + private: std::string FindTargets(const std::string& prop, const cmGeneratorTarget* tgt, diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 08c308d..18f2f7f 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -729,9 +729,24 @@ bool HandleTargetsMode(std::vector const& args, // Track whether this is a namelink-only rule. bool namelinkOnly = false; - auto addTargetExport = [&]() { + auto addTargetExport = [&]() -> bool { // Add this install rule to an export if one was specified. if (!exports.empty()) { + auto interfaceFileSets = target.GetAllInterfaceFileSets(); + if (std::any_of( + interfaceFileSets.begin(), interfaceFileSets.end(), + [=](const std::string& name) -> bool { + return !std::any_of( + fileSetArgs.begin(), fileSetArgs.end(), + [=](const cmInstallCommandFileSetArguments& fileSetArg) + -> bool { return fileSetArg.GetFileSet() == name; }); + })) { + status.SetError(cmStrCat( + "TARGETS target ", target.GetName(), + " is exported but not all of its file sets are installed")); + return false; + } + auto te = cm::make_unique(); te->TargetName = target.GetName(); te->ArchiveGenerator = archiveGenerator.get(); @@ -741,6 +756,9 @@ bool HandleTargetsMode(std::vector const& args, te->LibraryGenerator = libraryGenerator.get(); te->RuntimeGenerator = runtimeGenerator.get(); te->ObjectsGenerator = objectGenerator.get(); + for (auto const& gen : fileSetGenerators) { + te->FileSetGenerators[gen->GetFileSet()] = gen.get(); + } target.AddInstallIncludeDirectories( cmMakeRange(includesArgs.GetIncludeDirs())); te->NamelinkOnly = namelinkOnly; @@ -748,6 +766,7 @@ bool HandleTargetsMode(std::vector const& args, ->GetExportSets()[exports] .AddTargetExport(std::move(te)); } + return true; }; switch (target.GetType()) { @@ -759,7 +778,9 @@ bool HandleTargetsMode(std::vector const& args, // When in namelink only mode skip all libraries on Windows. if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; - addTargetExport(); + if (!addTargetExport()) { + return false; + } continue; } @@ -795,7 +816,9 @@ bool HandleTargetsMode(std::vector const& args, // When in namelink only mode skip frameworks. if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; - addTargetExport(); + if (!addTargetExport()) { + return false; + } continue; } @@ -844,7 +867,9 @@ bool HandleTargetsMode(std::vector const& args, // When in namelink only mode skip frameworks. if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; - addTargetExport(); + if (!addTargetExport()) { + return false; + } continue; } @@ -1080,7 +1105,9 @@ bool HandleTargetsMode(std::vector const& args, } // Add this install rule to an export if one was specified. - addTargetExport(); + if (!addTargetExport()) { + return false; + } // Keep track of whether we're installing anything in each category installsArchive = installsArchive || archiveGenerator; diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h index 19fc931..885ac74 100644 --- a/Source/cmTargetExport.h +++ b/Source/cmTargetExport.h @@ -6,7 +6,9 @@ #include +class cmFileSet; class cmGeneratorTarget; +class cmInstallFileSetGenerator; class cmInstallFilesGenerator; class cmInstallTargetGenerator; @@ -29,6 +31,7 @@ public: cmInstallTargetGenerator* FrameworkGenerator; cmInstallTargetGenerator* BundleGenerator; cmInstallFilesGenerator* HeaderGenerator; + std::map FileSetGenerators; ///@} bool NamelinkOnly = false; -- cgit v0.12