From 3fee5398bd381e3721972220a8415b62bc96b172 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Tue, 28 Jun 2022 14:15:19 -0400 Subject: install(EXPORT): Check for missing file sets at generate time Missing file sets were originally checked at configure time in install(TARGETS ... EXPORT), but were not checked at generate time. If a file set was added after install(TARGETS ... EXPORT) was called, an abortion error was thrown. Check again at generate time to gracefully display an error message instead of crashing. Fixes: #23680 --- Source/cmExportSet.cxx | 31 +++++++++++++++++++++- Source/cmExportSet.h | 2 +- Source/cmInstallExportGenerator.cxx | 3 +-- ...ExportMissingSetsInterfacePostExport-result.txt | 1 + ...ExportMissingSetsInterfacePostExport-stderr.txt | 6 +++++ ...leSetExportMissingSetsInterfacePostExport.cmake | 6 +++++ ...stallMissingSetsInterfacePostInstall-result.txt | 1 + ...stallMissingSetsInterfacePostInstall-stderr.txt | 6 +++++ ...SetInstallMissingSetsInterfacePostInstall.cmake | 6 +++++ Tests/RunCMake/target_sources/RunCMakeTest.cmake | 2 ++ 10 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport-result.txt create mode 100644 Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport-stderr.txt create mode 100644 Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport.cmake create mode 100644 Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall-result.txt create mode 100644 Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall-stderr.txt create mode 100644 Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall.cmake diff --git a/Source/cmExportSet.cxx b/Source/cmExportSet.cxx index a20aa9a..3d4ef0a 100644 --- a/Source/cmExportSet.cxx +++ b/Source/cmExportSet.cxx @@ -2,10 +2,15 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportSet.h" +#include #include #include +#include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" +#include "cmMessageType.h" +#include "cmStringAlgorithms.h" +#include "cmTarget.h" #include "cmTargetExport.h" cmExportSet::cmExportSet(std::string name) @@ -15,11 +20,35 @@ cmExportSet::cmExportSet(std::string name) cmExportSet::~cmExportSet() = default; -void cmExportSet::Compute(cmLocalGenerator* lg) +bool cmExportSet::Compute(cmLocalGenerator* lg) { for (std::unique_ptr& tgtExport : this->TargetExports) { tgtExport->Target = lg->FindGeneratorTargetToUse(tgtExport->TargetName); + + auto const interfaceFileSets = + tgtExport->Target->Target->GetAllInterfaceFileSets(); + auto const fileSetInTargetExport = + [&tgtExport, lg](const std::string& fileSetName) -> bool { + auto* fileSet = tgtExport->Target->Target->GetFileSet(fileSetName); + + if (!tgtExport->FileSetGenerators.count(fileSet)) { + lg->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is listed in interface file sets of ", + tgtExport->Target->GetName(), + " but has not been exported")); + return false; + } + return true; + }; + + if (!std::all_of(interfaceFileSets.begin(), interfaceFileSets.end(), + fileSetInTargetExport)) { + return false; + } } + + return true; } void cmExportSet::AddTargetExport(std::unique_ptr te) diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h index 07deb11..b75a26d 100644 --- a/Source/cmExportSet.h +++ b/Source/cmExportSet.h @@ -25,7 +25,7 @@ public: cmExportSet(const cmExportSet&) = delete; cmExportSet& operator=(const cmExportSet&) = delete; - void Compute(cmLocalGenerator* lg); + bool Compute(cmLocalGenerator* lg); void AddTargetExport(std::unique_ptr tgt); diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 820f24a..9cb376d 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -49,8 +49,7 @@ cmInstallExportGenerator::~cmInstallExportGenerator() = default; bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg) { this->LocalGenerator = lg; - this->ExportSet->Compute(lg); - return true; + return this->ExportSet->Compute(lg); } void cmInstallExportGenerator::ComputeTempDir() diff --git a/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport-result.txt b/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport-stderr.txt b/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport-stderr.txt new file mode 100644 index 0000000..b8d35af --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error in CMakeLists\.txt: + File set "a" is listed in interface file sets of lib1 but has not been + exported + + +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport.cmake b/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport.cmake new file mode 100644 index 0000000..72fab47 --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetExportMissingSetsInterfacePostExport.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +add_library(lib1 STATIC empty.c) +install(TARGETS lib1 EXPORT a) +target_sources(lib1 INTERFACE FILE_SET a TYPE HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES h1.h) +export(EXPORT a) diff --git a/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall-result.txt b/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall-stderr.txt b/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall-stderr.txt new file mode 100644 index 0000000..b8d35af --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error in CMakeLists\.txt: + File set "a" is listed in interface file sets of lib1 but has not been + exported + + +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall.cmake b/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall.cmake new file mode 100644 index 0000000..4e1edff --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterfacePostInstall.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +add_library(lib1 STATIC empty.c) +install(TARGETS lib1 EXPORT a) +target_sources(lib1 INTERFACE FILE_SET a TYPE HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES h1.h) +install(EXPORT a DESTINATION lib/cmake/test) diff --git a/Tests/RunCMake/target_sources/RunCMakeTest.cmake b/Tests/RunCMake/target_sources/RunCMakeTest.cmake index e78ee9d..6a3c7b9 100644 --- a/Tests/RunCMake/target_sources/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_sources/RunCMakeTest.cmake @@ -33,6 +33,8 @@ run_cmake(FileSetWrongBaseDirsRelative) run_cmake(FileSetOverlappingBaseDirs) run_cmake(FileSetInstallMissingSetsPrivate) run_cmake(FileSetInstallMissingSetsInterface) +run_cmake(FileSetInstallMissingSetsInterfacePostInstall) +run_cmake(FileSetExportMissingSetsInterfacePostExport) run_cmake(FileSetReadOnlyPrivate) run_cmake(FileSetReadOnlyInterface) run_cmake(FileSetNoExistInstall) -- cgit v0.12