mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00
find_package: Improve support for CPS multiple inclusion
Keep track of CPS files we have imported in CMake's state, and use this (instead of the prior, temporary work-around that used `<name>_CONFIG`) as a guard for trying to import more than once from the same file. This has two advantages; first, it is robust against finding the same package name in different locations in alternating searches, and second, it allows us to load additional appendices associated with a root package that has already been loaded. Fixes: #26731
This commit is contained in:
@@ -415,6 +415,7 @@ add_library(
|
|||||||
cmOrderDirectories.h
|
cmOrderDirectories.h
|
||||||
cmPackageInfoReader.cxx
|
cmPackageInfoReader.cxx
|
||||||
cmPackageInfoReader.h
|
cmPackageInfoReader.h
|
||||||
|
cmPackageState.h
|
||||||
cmPathResolver.cxx
|
cmPathResolver.cxx
|
||||||
cmPathResolver.h
|
cmPathResolver.h
|
||||||
cmPlistParser.cxx
|
cmPlistParser.cxx
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <cm/optional>
|
#include <cm/optional>
|
||||||
@@ -29,10 +30,12 @@
|
|||||||
#include "cmListFileCache.h"
|
#include "cmListFileCache.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmMessageType.h"
|
#include "cmMessageType.h"
|
||||||
|
#include "cmPackageState.h"
|
||||||
#include "cmPolicies.h"
|
#include "cmPolicies.h"
|
||||||
#include "cmRange.h"
|
#include "cmRange.h"
|
||||||
#include "cmSearchPath.h"
|
#include "cmSearchPath.h"
|
||||||
#include "cmState.h"
|
#include "cmState.h"
|
||||||
|
#include "cmStateSnapshot.h"
|
||||||
#include "cmStateTypes.h"
|
#include "cmStateTypes.h"
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
#include "cmSystemTools.h"
|
#include "cmSystemTools.h"
|
||||||
@@ -1543,7 +1546,6 @@ bool cmFindPackageCommand::HandlePackageMode(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const fileVar = cmStrCat(this->Name, "_CONFIG");
|
|
||||||
std::string const foundVar = cmStrCat(this->Name, "_FOUND");
|
std::string const foundVar = cmStrCat(this->Name, "_FOUND");
|
||||||
std::string const notFoundMessageVar =
|
std::string const notFoundMessageVar =
|
||||||
cmStrCat(this->Name, "_NOT_FOUND_MESSAGE");
|
cmStrCat(this->Name, "_NOT_FOUND_MESSAGE");
|
||||||
@@ -1574,15 +1576,7 @@ bool cmFindPackageCommand::HandlePackageMode(
|
|||||||
if (this->CpsReader) {
|
if (this->CpsReader) {
|
||||||
// The package has been found.
|
// The package has been found.
|
||||||
found = true;
|
found = true;
|
||||||
|
result = this->ReadPackage();
|
||||||
// Don't read a CPS file if we've already read it.
|
|
||||||
cmValue const& previousFileFound =
|
|
||||||
this->Makefile->GetDefinition(fileVar);
|
|
||||||
if (previousFileFound.Compare(this->FileFound) == 0) {
|
|
||||||
result = true;
|
|
||||||
} else {
|
|
||||||
result = this->ReadPackage();
|
|
||||||
}
|
|
||||||
} else if (this->ReadListFile(this->FileFound, DoPolicyScope)) {
|
} else if (this->ReadListFile(this->FileFound, DoPolicyScope)) {
|
||||||
// The package has been found.
|
// The package has been found.
|
||||||
found = true;
|
found = true;
|
||||||
@@ -1765,6 +1759,7 @@ bool cmFindPackageCommand::HandlePackageMode(
|
|||||||
this->Makefile->AddDefinition(foundVar, found ? "1" : "0");
|
this->Makefile->AddDefinition(foundVar, found ? "1" : "0");
|
||||||
|
|
||||||
// Set a variable naming the configuration file that was found.
|
// Set a variable naming the configuration file that was found.
|
||||||
|
std::string const fileVar = cmStrCat(this->Name, "_CONFIG");
|
||||||
if (found) {
|
if (found) {
|
||||||
this->Makefile->AddDefinition(fileVar, this->FileFound);
|
this->Makefile->AddDefinition(fileVar, this->FileFound);
|
||||||
} else {
|
} else {
|
||||||
@@ -2016,8 +2011,15 @@ bool cmFindPackageCommand::ReadPackage()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we made it here, we want to actually import something, but we also
|
||||||
|
// need to ensure we don't try to import the same file more than once (which
|
||||||
|
// will fail due to the targets already existing). Retrieve the package state
|
||||||
|
// so we can record what we're doing.
|
||||||
|
cmPackageState& state =
|
||||||
|
this->Makefile->GetStateSnapshot().GetPackageState(this->FileFound);
|
||||||
|
|
||||||
// Import targets from root file.
|
// Import targets from root file.
|
||||||
if (!this->ImportPackageTargets(this->FileFound, *this->CpsReader)) {
|
if (!this->ImportPackageTargets(state, this->FileFound, *this->CpsReader)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2026,7 +2028,7 @@ bool cmFindPackageCommand::ReadPackage()
|
|||||||
for (auto const& appendix : this->CpsAppendices) {
|
for (auto const& appendix : this->CpsAppendices) {
|
||||||
cmMakefile::CallRAII appendixScope{ this->Makefile, appendix.first,
|
cmMakefile::CallRAII appendixScope{ this->Makefile, appendix.first,
|
||||||
this->Status };
|
this->Status };
|
||||||
if (!this->ImportPackageTargets(appendix.first, appendix.second)) {
|
if (!this->ImportPackageTargets(state, appendix.first, appendix.second)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2035,13 +2037,13 @@ bool cmFindPackageCommand::ReadPackage()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool cmFindPackageCommand::FindPackageDependencies(
|
bool cmFindPackageCommand::FindPackageDependencies(
|
||||||
std::string const& fileName, cmPackageInfoReader const& reader,
|
std::string const& filePath, cmPackageInfoReader const& reader,
|
||||||
RequiredStatus required)
|
RequiredStatus required)
|
||||||
{
|
{
|
||||||
// Get package requirements.
|
// Get package requirements.
|
||||||
for (cmPackageRequirement const& dep : reader.GetRequirements()) {
|
for (cmPackageRequirement const& dep : reader.GetRequirements()) {
|
||||||
cmExecutionStatus status{ *this->Makefile };
|
cmExecutionStatus status{ *this->Makefile };
|
||||||
cmMakefile::CallRAII scope{ this->Makefile, fileName, status };
|
cmMakefile::CallRAII scope{ this->Makefile, filePath, status };
|
||||||
|
|
||||||
// For each requirement, set up a nested instance to find it.
|
// For each requirement, set up a nested instance to find it.
|
||||||
cmFindPackageCommand fp{ status };
|
cmFindPackageCommand fp{ status };
|
||||||
@@ -2077,9 +2079,16 @@ bool cmFindPackageCommand::FindPackageDependencies(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cmFindPackageCommand::ImportPackageTargets(std::string const& fileName,
|
bool cmFindPackageCommand::ImportPackageTargets(cmPackageState& packageState,
|
||||||
|
std::string const& filePath,
|
||||||
cmPackageInfoReader& reader)
|
cmPackageInfoReader& reader)
|
||||||
{
|
{
|
||||||
|
// Check if we've already imported this file.
|
||||||
|
std::string fileName = cmSystemTools::GetFilenameName(filePath);
|
||||||
|
if (cm::contains(packageState.ImportedFiles, fileName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Import base file.
|
// Import base file.
|
||||||
if (!reader.ImportTargets(this->Makefile, this->Status)) {
|
if (!reader.ImportTargets(this->Makefile, this->Status)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -2089,8 +2098,8 @@ bool cmFindPackageCommand::ImportPackageTargets(std::string const& fileName,
|
|||||||
cmsys::Glob glob;
|
cmsys::Glob glob;
|
||||||
glob.RecurseOff();
|
glob.RecurseOff();
|
||||||
if (glob.FindFiles(
|
if (glob.FindFiles(
|
||||||
cmStrCat(cmSystemTools::GetFilenamePath(fileName), '/',
|
cmStrCat(cmSystemTools::GetFilenamePath(filePath), '/',
|
||||||
cmSystemTools::GetFilenameWithoutExtension(fileName),
|
cmSystemTools::GetFilenameWithoutExtension(filePath),
|
||||||
"@*.[Cc][Pp][Ss]"_s))) {
|
"@*.[Cc][Pp][Ss]"_s))) {
|
||||||
|
|
||||||
// Try to read supplemental data from each file found.
|
// Try to read supplemental data from each file found.
|
||||||
@@ -2106,6 +2115,7 @@ bool cmFindPackageCommand::ImportPackageTargets(std::string const& fileName,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packageState.ImportedFiles.emplace(std::move(fileName));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,7 @@ namespace std {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
class cmExecutionStatus;
|
class cmExecutionStatus;
|
||||||
|
class cmPackageState;
|
||||||
class cmSearchPath;
|
class cmSearchPath;
|
||||||
|
|
||||||
/** \class cmFindPackageCommand
|
/** \class cmFindPackageCommand
|
||||||
@@ -159,11 +160,12 @@ private:
|
|||||||
RequiredFromPackageVar,
|
RequiredFromPackageVar,
|
||||||
RequiredFromFindVar
|
RequiredFromFindVar
|
||||||
};
|
};
|
||||||
bool FindPackageDependencies(std::string const& fileName,
|
bool FindPackageDependencies(std::string const& filePath,
|
||||||
cmPackageInfoReader const& reader,
|
cmPackageInfoReader const& reader,
|
||||||
RequiredStatus required);
|
RequiredStatus required);
|
||||||
|
|
||||||
bool ImportPackageTargets(std::string const& fileName,
|
bool ImportPackageTargets(cmPackageState& packageState,
|
||||||
|
std::string const& filePath,
|
||||||
cmPackageInfoReader& reader);
|
cmPackageInfoReader& reader);
|
||||||
void StoreVersionFound();
|
void StoreVersionFound();
|
||||||
void SetConfigDirCacheVariable(std::string const& value);
|
void SetConfigDirCacheVariable(std::string const& value);
|
||||||
|
17
Source/cmPackageState.h
Normal file
17
Source/cmPackageState.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cmConfigure.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
/** \class cmPackageState
|
||||||
|
* \brief Information about the state of an imported package.
|
||||||
|
*/
|
||||||
|
class cmPackageState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::unordered_set<std::string> ImportedFiles;
|
||||||
|
};
|
@@ -6,11 +6,13 @@
|
|||||||
#include "cmConfigure.h" // IWYU pragma: keep
|
#include "cmConfigure.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "cmDefinitions.h"
|
#include "cmDefinitions.h"
|
||||||
#include "cmLinkedTree.h"
|
#include "cmLinkedTree.h"
|
||||||
#include "cmListFileCache.h"
|
#include "cmListFileCache.h"
|
||||||
|
#include "cmPackageState.h"
|
||||||
#include "cmPolicies.h"
|
#include "cmPolicies.h"
|
||||||
#include "cmPropertyMap.h"
|
#include "cmPropertyMap.h"
|
||||||
#include "cmStateSnapshot.h"
|
#include "cmStateSnapshot.h"
|
||||||
@@ -84,5 +86,7 @@ struct cmStateDetail::BuildsystemDirectoryStateType
|
|||||||
|
|
||||||
cmPropertyMap Properties;
|
cmPropertyMap Properties;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, cmPackageState> Packages;
|
||||||
|
|
||||||
std::vector<cmStateSnapshot> Children;
|
std::vector<cmStateSnapshot> Children;
|
||||||
};
|
};
|
||||||
|
@@ -6,12 +6,14 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <cm/iterator>
|
#include <cm/iterator>
|
||||||
|
|
||||||
#include "cmDefinitions.h"
|
#include "cmDefinitions.h"
|
||||||
#include "cmLinkedTree.h"
|
#include "cmLinkedTree.h"
|
||||||
#include "cmListFileCache.h"
|
#include "cmListFileCache.h"
|
||||||
|
#include "cmPackageState.h"
|
||||||
#include "cmPropertyMap.h"
|
#include "cmPropertyMap.h"
|
||||||
#include "cmState.h"
|
#include "cmState.h"
|
||||||
#include "cmStateDirectory.h"
|
#include "cmStateDirectory.h"
|
||||||
@@ -418,6 +420,12 @@ std::string cmStateSnapshot::GetProjectName() const
|
|||||||
return this->Position->BuildSystemDirectory->ProjectName;
|
return this->Position->BuildSystemDirectory->ProjectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmPackageState& cmStateSnapshot::GetPackageState(
|
||||||
|
std::string const& packagePath)
|
||||||
|
{
|
||||||
|
return this->Position->BuildSystemDirectory->Packages[packagePath];
|
||||||
|
}
|
||||||
|
|
||||||
void cmStateSnapshot::InitializeFromParent_ForSubdirsCommand()
|
void cmStateSnapshot::InitializeFromParent_ForSubdirsCommand()
|
||||||
{
|
{
|
||||||
std::string currentSrcDir = *this->GetDefinition("CMAKE_CURRENT_SOURCE_DIR");
|
std::string currentSrcDir = *this->GetDefinition("CMAKE_CURRENT_SOURCE_DIR");
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include "cmStateTypes.h"
|
#include "cmStateTypes.h"
|
||||||
#include "cmValue.h"
|
#include "cmValue.h"
|
||||||
|
|
||||||
|
class cmPackageState;
|
||||||
class cmState;
|
class cmState;
|
||||||
class cmStateDirectory;
|
class cmStateDirectory;
|
||||||
|
|
||||||
@@ -57,6 +58,8 @@ public:
|
|||||||
void SetProjectName(std::string const& name);
|
void SetProjectName(std::string const& name);
|
||||||
std::string GetProjectName() const;
|
std::string GetProjectName() const;
|
||||||
|
|
||||||
|
cmPackageState& GetPackageState(std::string const& packagePath);
|
||||||
|
|
||||||
void InitializeFromParent_ForSubdirsCommand();
|
void InitializeFromParent_ForSubdirsCommand();
|
||||||
|
|
||||||
struct StrictWeakOrder
|
struct StrictWeakOrder
|
||||||
|
@@ -54,12 +54,6 @@ endfunction()
|
|||||||
find_package(Sample CONFIG)
|
find_package(Sample CONFIG)
|
||||||
test_version(Sample "2.10.11" 3 2 10 11 0)
|
test_version(Sample "2.10.11" 3 2 10 11 0)
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Test finding a package more than once.
|
|
||||||
|
|
||||||
find_package(Repeat REQUIRED)
|
|
||||||
find_package(Repeat REQUIRED)
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Test some more complicated version parsing.
|
# Test some more complicated version parsing.
|
||||||
|
|
||||||
@@ -275,6 +269,21 @@ elseif(TARGET TransitiveDep::Target5)
|
|||||||
message(SEND_ERROR "TransitiveDep::Target5 exists ?!")
|
message(SEND_ERROR "TransitiveDep::Target5 exists ?!")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Test finding a package more than once.
|
||||||
|
|
||||||
|
find_package(Repeat REQUIRED OPTIONAL_COMPONENTS DoesNotExist)
|
||||||
|
if(NOT TARGET Repeat::Base)
|
||||||
|
message(SEND_ERROR "Repeat::Base missing !")
|
||||||
|
elseif(TARGET Repeat::Extra)
|
||||||
|
message(SEND_ERROR "Repeat::Extra exists ?!")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Repeat REQUIRED COMPONENTS Extra)
|
||||||
|
if(NOT TARGET Repeat::Extra)
|
||||||
|
message(SEND_ERROR "Repeat::Extra missing !")
|
||||||
|
endif()
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Test default configurations.
|
# Test default configurations.
|
||||||
|
|
||||||
|
9
Tests/FindPackageCpsTest/cps/Repeat-extra.cps
Normal file
9
Tests/FindPackageCpsTest/cps/Repeat-extra.cps
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"cps_version": "0.13",
|
||||||
|
"name": "Repeat",
|
||||||
|
"components": {
|
||||||
|
"Extra": {
|
||||||
|
"type": "interface"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -3,7 +3,7 @@
|
|||||||
"name": "Repeat",
|
"name": "Repeat",
|
||||||
"cps_path": "@prefix@/cps",
|
"cps_path": "@prefix@/cps",
|
||||||
"components": {
|
"components": {
|
||||||
"Repeat": {
|
"Base": {
|
||||||
"type": "interface"
|
"type": "interface"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user