diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index acd2a18aca..76449a89ae 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -151,6 +151,8 @@ add_library( cmComputeTargetDepends.cxx cmConfigureLog.h cmConfigureLog.cxx + cmConstStack.h + cmConstStack.tcc cmCPackPropertiesGenerator.h cmCPackPropertiesGenerator.cxx cmCryptoHash.cxx @@ -486,8 +488,6 @@ add_library( cmSourceFileLocationKind.h cmSourceGroup.cxx cmSourceGroup.h - cmStack.h - cmStack.tcc cmStandardLevel.h cmStandardLevelResolver.cxx cmStandardLevelResolver.h diff --git a/Source/cmStack.h b/Source/cmConstStack.h similarity index 50% rename from Source/cmStack.h rename to Source/cmConstStack.h index 1c11090a98..d6059e7022 100644 --- a/Source/cmStack.h +++ b/Source/cmConstStack.h @@ -5,31 +5,19 @@ #include "cmConfigure.h" // IWYU pragma: keep #include -#include -enum class cmStackType +/** Base class template for CRTP to represent a stack of constant values. + Provide value semantics, but use efficient reference-counting underneath + to avoid copies. */ +template +class cmConstStack { - Const, - Mutable, -}; - -template -struct cmStackEntry; - -/** Base class template for CRTP to represent a stack of values. - Copies of the stack share data; mutating data on one copy will - change the data on all copies. */ -template -class cmStack -{ - using Entry = cmStackEntry; - + struct Entry; std::shared_ptr TopEntry; public: /** Default-construct an empty stack. */ - cmStack(); + cmConstStack(); /** Get a stack with the given call context added to the top. */ Stack Push(T value) const; @@ -41,21 +29,11 @@ public: /** Get the value at the top of the stack. This may be called only if Empty() would return false. */ T const& Top() const; - template - typename std::enable_if::type& Top(); /** Return true if this stack is empty. */ bool Empty() const; protected: - using Base = cmStack; - - cmStack(std::shared_ptr parent, T value); - cmStack(std::shared_ptr top); + cmConstStack(std::shared_ptr parent, T value); + cmConstStack(std::shared_ptr top); }; - -/** Specialization of cmStack for CRTP to represent a stack of constant values. - Provide value semantics, but use efficient reference-counting underneath - to avoid copies. */ -template -using cmConstStack = cmStack; diff --git a/Source/cmConstStack.tcc b/Source/cmConstStack.tcc new file mode 100644 index 0000000000..ee69c9c478 --- /dev/null +++ b/Source/cmConstStack.tcc @@ -0,0 +1,62 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file LICENSE.rst or https://cmake.org/licensing for details. */ + +#include +#include +#include + +template +struct cmConstStack::Entry +{ + Entry(std::shared_ptr parent, T value) + : Value(std::move(value)) + , Parent(std::move(parent)) + { + } + + T Value; + std::shared_ptr Parent; +}; + +template +cmConstStack::cmConstStack() = default; + +template +Stack cmConstStack::Push(T value) const +{ + return Stack(this->TopEntry, std::move(value)); +} + +template +Stack cmConstStack::Pop() const +{ + assert(this->TopEntry); + return Stack(this->TopEntry->Parent); +} + +template +T const& cmConstStack::Top() const +{ + assert(this->TopEntry); + return this->TopEntry->Value; +} + +template +bool cmConstStack::Empty() const +{ + return !this->TopEntry; +} + +template +cmConstStack::cmConstStack(std::shared_ptr parent, + T value) + : TopEntry( + std::make_shared(std::move(parent), std::move(value))) +{ +} + +template +cmConstStack::cmConstStack(std::shared_ptr top) + : TopEntry(std::move(top)) +{ +} diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx index 23f2b7284d..62a01e5eed 100644 --- a/Source/cmExportPackageInfoGenerator.cxx +++ b/Source/cmExportPackageInfoGenerator.cxx @@ -311,7 +311,8 @@ bool cmExportPackageInfoGenerator::NoteLinkedTarget( auto pkgInfo = [](cmTarget* t) -> Package { cmFindPackageStack pkgStack = t->GetFindPackageStack(); if (!pkgStack.Empty()) { - return std::make_pair(pkgStack.Top().Name, pkgStack.Top().PackageInfo); + return std::make_pair(pkgStack.Top().Name, + *pkgStack.Top().PackageInfo); } cmPackageInformation package; diff --git a/Source/cmExportSbomGenerator.cxx b/Source/cmExportSbomGenerator.cxx index 26bee6eae9..c99141f3fb 100644 --- a/Source/cmExportSbomGenerator.cxx +++ b/Source/cmExportSbomGenerator.cxx @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -320,7 +321,8 @@ bool cmExportSbomGenerator::NoteLinkedTarget( auto pkgInfo = [](cmTarget* t) -> Package { cmFindPackageStack pkgStack = t->GetFindPackageStack(); if (!pkgStack.Empty()) { - return std::make_pair(pkgStack.Top().Name, pkgStack.Top().PackageInfo); + return std::make_pair(pkgStack.Top().Name, + *pkgStack.Top().PackageInfo); } std::string const pkgName = t->GetSafeProperty("EXPORT_FIND_PACKAGE_NAME"); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index f109995659..e3e1ba793c 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -1213,13 +1213,15 @@ bool cmFindPackageCommand::FindPackage( } } + // Record package information discovered while it is loaded. + this->PackageInfo = std::make_shared(); + // RAII objects to ensure we leave this function with consistent state. FlushDebugBufferOnExit flushDebugBufferOnExit(*this); PushPopRootPathStack pushPopRootPathStack(*this); SetRestoreFindDefinitions setRestoreFindDefinitions(*this); - cmFindPackageStackRAII findPackageStackRAII(this->Makefile, this->Name); - - findPackageStackRAII.BindTop(this->CurrentPackageInfo); + cmMakefile::FindPackageStackRAII findPackageStackRAII( + this->Makefile, this->Name, this->PackageInfo); // See if we have been told to delegate to FetchContent or some other // redirected config package first. We have to check all names that @@ -1267,8 +1269,8 @@ bool cmFindPackageCommand::FindPackage( this->Names.clear(); this->Names.emplace_back(overrideName); // Force finding this one this->Variable = cmStrCat(this->Name, "_DIR"); - this->CurrentPackageInfo->Directory = redirectsDir; - this->CurrentPackageInfo->Version = this->VersionFound; + this->PackageInfo->Directory = redirectsDir; + this->PackageInfo->Version = this->VersionFound; this->SetConfigDirCacheVariable(redirectsDir); break; } @@ -1666,12 +1668,6 @@ bool cmFindPackageCommand::HandlePackageMode( "fileFound is true but FileFound is empty!"); fileFound = false; } - - if (fileFound) { - this->CurrentPackageInfo->Directory = - cmSystemTools::GetFilenamePath(this->FileFound); - this->CurrentPackageInfo->Version = this->VersionFound; - } } std::string const foundVar = cmStrCat(this->Name, "_FOUND"); @@ -1733,6 +1729,12 @@ bool cmFindPackageCommand::HandlePackageMode( // The configuration file is invalid. result = false; } + + if (this->UseConfigFiles && found) { + this->PackageInfo->Directory = + cmSystemTools::GetFilenamePath(this->FileFound); + this->PackageInfo->Version = this->VersionFound; + } } if (this->UseFindModules && !found && diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index 5a73938bfa..7c7166648d 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -284,7 +284,7 @@ private: std::set OptionalComponents; std::set RequiredTargets; std::string DebugBuffer; - cmPackageInformation* CurrentPackageInfo; + std::shared_ptr PackageInfo; enum class SearchResult { diff --git a/Source/cmFindPackageStack.cxx b/Source/cmFindPackageStack.cxx index 6f5045ae74..0803049a06 100644 --- a/Source/cmFindPackageStack.cxx +++ b/Source/cmFindPackageStack.cxx @@ -3,13 +3,5 @@ #define cmFindPackageStack_cxx #include "cmFindPackageStack.h" -#include "cmStack.tcc" // IWYU pragma: keep -template class cmStack; - -template cmFindPackageCall& -cmStack::Top(); - -cmFindPackageCall const& cmFindPackageStack::Top() const -{ - return this->cmStack::Top(); -} +#include "cmConstStack.tcc" // IWYU pragma: keep +template class cmConstStack; diff --git a/Source/cmFindPackageStack.h b/Source/cmFindPackageStack.h index e7fb9a6ee4..e3ac8ca78e 100644 --- a/Source/cmFindPackageStack.h +++ b/Source/cmFindPackageStack.h @@ -10,9 +10,7 @@ #include -#include "cmStack.h" - -class cmMakefile; +#include "cmConstStack.h" /** * This data represents the actual contents of find_package @@ -39,52 +37,19 @@ class cmFindPackageCall { public: std::string const Name; - cmPackageInformation PackageInfo; + std::shared_ptr PackageInfo; unsigned int Index; }; -/** - * RAII type to manage the find_package call stack. - */ -// Note: implemented in cmMakefile.cxx -class cmFindPackageStackRAII -{ - cmMakefile* Makefile; - cmPackageInformation** Value = nullptr; - -public: - cmFindPackageStackRAII(cmMakefile* mf, std::string const& pkg); - ~cmFindPackageStackRAII(); - - cmFindPackageStackRAII(cmFindPackageStackRAII const&) = delete; - cmFindPackageStackRAII& operator=(cmFindPackageStackRAII const&) = delete; - - /** Get a mutable pointer to the top of the stack. - The pointer is invalidated if BindTop is called again or when the - cmFindPackageStackRAII goes out of scope. */ - void BindTop(cmPackageInformation*& value); -}; - /** * Represents a stack of find_package calls with efficient value semantics. */ class cmFindPackageStack - : protected cmStack + : public cmConstStack { - using cmStack::cmStack; - friend cmFindPackageStack::Base; - friend class cmFindPackageStackRAII; - -public: - using cmStack::Push; - using cmStack::Pop; - using cmStack::Empty; - - cmFindPackageCall const& Top() const; + using cmConstStack::cmConstStack; + friend class cmConstStack; }; #ifndef cmFindPackageStack_cxx -extern template class cmStack; - -extern template cmFindPackageCall& -cmStack::Top(); +extern template class cmConstStack; #endif diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 92a3a976d1..34ac595a5a 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -458,9 +458,8 @@ bool cmListFile::ParseString(cm::string_view str, return parser.ParseString(str); } -#include "cmStack.tcc" -template class cmStack; +#include "cmConstStack.tcc" +template class cmConstStack; std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc) { diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index eac77d7e03..337fc2613f 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -14,8 +14,8 @@ #include #include +#include "cmConstStack.h" #include "cmList.h" -#include "cmStack.h" #include "cmSystemTools.h" /** \class cmListFileCache @@ -171,12 +171,11 @@ bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs); class cmListFileBacktrace : public cmConstStack { - using cmStack::cmStack; - friend cmListFileBacktrace::Base; + using cmConstStack::cmConstStack; + friend class cmConstStack; }; #ifndef cmListFileCache_cxx -extern template class cmStack; +extern template class cmConstStack; #endif // Wrap type T as a value with a backtrace. For purposes of diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 7d928ecf63..c9c68c1055 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -51,7 +51,6 @@ #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmSourceGroup.h" -#include "cmStack.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateTypes.h" @@ -4338,47 +4337,45 @@ cmMakefile::MacroPushPop::~MacroPushPop() this->Makefile->PopMacroScope(this->ReportError); } -cmFindPackageStackRAII::cmFindPackageStackRAII(cmMakefile* mf, - std::string const& name) +cmMakefile::FindPackageStackRAII::FindPackageStackRAII( + cmMakefile* mf, std::string const& name, + std::shared_ptr pkgInfo) : Makefile(mf) { this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Push(cmFindPackageCall{ name, - cmPackageInformation(), + std::move(pkgInfo), this->Makefile->FindPackageStackNextIndex, }); this->Makefile->FindPackageStackNextIndex++; } -void cmFindPackageStackRAII::BindTop(cmPackageInformation*& value) +cmMakefile::FindPackageStackRAII::~FindPackageStackRAII() { - if (this->Value) { - *this->Value = nullptr; - } - this->Value = &value; - value = &this->Makefile->FindPackageStack.cmStack::Top().PackageInfo; -} - -cmFindPackageStackRAII::~cmFindPackageStackRAII() -{ - if (this->Value) { - *this->Value = nullptr; - } - this->Makefile->FindPackageStackNextIndex = this->Makefile->FindPackageStack.Top().Index + 1; this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Pop(); if (!this->Makefile->FindPackageStack.Empty()) { - auto top = this->Makefile->FindPackageStack.Top(); + // We have just finished an inner package found as a dependency of an + // outer package. Targets created in the outer package after this + // point may depend on the inner package, so if they are exported, + // their find_dependency call for the outer package should be + // ordered after the find_dependency call for the inner package. + // + // Any targets created by the outer package before the inner package + // was loaded will have already saved a copy of the outer package + // stack with its original index. Replace the top entry with a new + // one representing the same outer package with a new index. + cmFindPackageCall outer = this->Makefile->FindPackageStack.Top(); this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Pop(); - top.Index = this->Makefile->FindPackageStackNextIndex; + outer.Index = this->Makefile->FindPackageStackNextIndex; this->Makefile->FindPackageStackNextIndex++; this->Makefile->FindPackageStack = - this->Makefile->FindPackageStack.Push(top); + this->Makefile->FindPackageStack.Push(outer); } } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 09843c97d5..41fff122c8 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -1100,7 +1100,21 @@ public: // searches std::deque> FindPackageRootPathStack; - friend class cmFindPackageStackRAII; + /** + * RAII type to manage the find_package call stack. + */ + class FindPackageStackRAII + { + cmMakefile* Makefile; + + public: + FindPackageStackRAII(cmMakefile* mf, std::string const& pkg, + std::shared_ptr pkgInfo); + ~FindPackageStackRAII(); + + FindPackageStackRAII(FindPackageStackRAII const&) = delete; + FindPackageStackRAII& operator=(FindPackageStackRAII const&) = delete; + }; class DebugFindPkgRAII { diff --git a/Source/cmStack.tcc b/Source/cmStack.tcc deleted file mode 100644 index 210833b453..0000000000 --- a/Source/cmStack.tcc +++ /dev/null @@ -1,85 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file LICENSE.rst or https://cmake.org/licensing for details. */ - -#include -#include -#include - -template -struct cmStackEntry -{ - cmStackEntry(std::shared_ptr parent, T value) - : Value(std::move(value)) - , Parent(std::move(parent)) - { - } - - T mutable Value; - std::shared_ptr Parent; -}; - -template -struct cmStackEntry -{ - cmStackEntry(std::shared_ptr parent, T value) - : Value(std::move(value)) - , Parent(std::move(parent)) - { - } - - T Value; - std::shared_ptr Parent; -}; - -template -cmStack::cmStack() = default; - -template -Stack cmStack::Push(T value) const -{ - return Stack(this->TopEntry, std::move(value)); -} - -template -Stack cmStack::Pop() const -{ - assert(this->TopEntry); - return Stack(this->TopEntry->Parent); -} - -template -T const& cmStack::Top() const -{ - assert(this->TopEntry); - return this->TopEntry->Value; -} - -template -template -typename std::enable_if::type& cmStack::Top() -{ - static_assert(Mutable == cmStackType::Mutable, - "T& cmStack::Top should only exist for mutable cmStack"); - assert(this->TopEntry); - return this->TopEntry->Value; -} - -template -bool cmStack::Empty() const -{ - return !this->TopEntry; -} - -template -cmStack::cmStack(std::shared_ptr parent, - T value) - : TopEntry( - std::make_shared(std::move(parent), std::move(value))) -{ -} - -template -cmStack::cmStack(std::shared_ptr top) - : TopEntry(std::move(top)) -{ -} diff --git a/Tests/RunCMake/find_package/NestedConfig.cmake b/Tests/RunCMake/find_package/NestedConfig.cmake new file mode 100644 index 0000000000..9bd376a20c --- /dev/null +++ b/Tests/RunCMake/find_package/NestedConfig.cmake @@ -0,0 +1,3 @@ +cmake_policy(SET CMP0074 NEW) +set(Outer_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/NestedConfig) +find_package(Outer CONFIG) diff --git a/Tests/RunCMake/find_package/NestedConfig/OuterConfig.cmake b/Tests/RunCMake/find_package/NestedConfig/OuterConfig.cmake new file mode 100644 index 0000000000..2a1332b87b --- /dev/null +++ b/Tests/RunCMake/find_package/NestedConfig/OuterConfig.cmake @@ -0,0 +1 @@ +find_package(Inner CONFIG NO_DEFAULT_PATH) diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake index f0fc80b3a7..1d96eeb745 100644 --- a/Tests/RunCMake/find_package/RunCMakeTest.cmake +++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake @@ -36,6 +36,7 @@ run_cmake(MissingConfigRequired) run_cmake(MissingConfigVersion) run_cmake(MixedModeOptions) run_cmake_with_options(ModuleModeDebugPkg --debug-find-pkg=Foo,Zot) +run_cmake(NestedConfig) run_cmake(PackageRoot) run_cmake(PackageRootNestedConfig) run_cmake(PackageRootNestedModule) diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp index 7ccc932773..91f3014d0f 100644 --- a/Utilities/IWYU/mapping.imp +++ b/Utilities/IWYU/mapping.imp @@ -70,12 +70,8 @@ { include: [ "", private, "\"cmCursesStandardIncludes.h\"", public ] }, { include: [ "\"form.h\"", private, "\"cmCursesStandardIncludes.h\"", public ] }, - # Help IWYU understand our explicit instantiation for cmStack. - { symbol: [ "cmStack::cmStack", private, "\"cmStack.h\"", public ] }, - { symbol: [ "cmStack::Empty", private, "\"cmStack.h\"", public ] }, - { symbol: [ "cmStack::Top", private, "\"cmStack.h\"", public ] }, - { symbol: [ "cmStack::Pop", private, "\"cmStack.h\"", public ] }, - { symbol: [ "cmStack::Push", private, "\"cmStack.h\"", public ] }, + # Help IWYU understand our explicit instantiation for cmConstStack. + { symbol: [ "cmConstStack::cmConstStack", private, "\"cmConstStack.h\"", public ] }, ] # vim: set ft=toml: