summaryrefslogtreecommitdiffstats
path: root/Source/cmFindPackageCommand.cxx
diff options
context:
space:
mode:
authorMarc Chevier <marc.chevrier@gmail.com>2020-09-22 13:14:13 (GMT)
committerMarc Chevrier <marc.chevrier@gmail.com>2020-09-23 10:52:25 (GMT)
commitd7df81067b3d0dfc476fd3603e7b948a1637edb3 (patch)
treee565c3e5f4bcc1a3f4f25267d82da9530b2c666e /Source/cmFindPackageCommand.cxx
parent09095dbcd2dd43763e37142b65bdaaeb34deb45d (diff)
downloadCMake-d7df81067b3d0dfc476fd3603e7b948a1637edb3.zip
CMake-d7df81067b3d0dfc476fd3603e7b948a1637edb3.tar.gz
CMake-d7df81067b3d0dfc476fd3603e7b948a1637edb3.tar.bz2
find_package: Add support of version range
This enhancement is the first step for solving issue #21107
Diffstat (limited to 'Source/cmFindPackageCommand.cxx')
-rw-r--r--Source/cmFindPackageCommand.cxx161
1 files changed, 116 insertions, 45 deletions
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 0bcdfec..1ff093f 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -49,6 +49,11 @@ cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::Builds(
cmFindPackageCommand::PathLabel
cmFindPackageCommand::PathLabel::SystemRegistry("SYSTEM_PACKAGE_REGISTRY");
+const cm::string_view cmFindPackageCommand::VERSION_ENDPOINT_INCLUDED(
+ "INCLUDE");
+const cm::string_view cmFindPackageCommand::VERSION_ENDPOINT_EXCLUDED(
+ "EXCLUDE");
+
struct StrverscmpGreater
{
bool operator()(const std::string& lhs, const std::string& rhs) const
@@ -90,6 +95,8 @@ void cmFindPackageCommand::Sort(std::vector<std::string>::iterator begin,
cmFindPackageCommand::cmFindPackageCommand(cmExecutionStatus& status)
: cmFindCommon(status)
+ , VersionRangeMin(VERSION_ENDPOINT_INCLUDED)
+ , VersionRangeMax(VERSION_ENDPOINT_INCLUDED)
{
this->CMakePathName = "PACKAGE";
this->DebugMode = false;
@@ -242,7 +249,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
DoingHints
};
Doing doing = DoingNone;
- cmsys::RegularExpression version("^[0-9.]+$");
+ cmsys::RegularExpression versionRegex(
+ R"V(^([0-9]+(\.[0-9]+)*)(\.\.\.(<?)([0-9]+(\.[0-9]+)*))?$)V");
bool haveVersion = false;
std::set<unsigned int> configArgs;
std::set<unsigned int> moduleArgs;
@@ -345,9 +353,9 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
return false;
}
this->Configs.push_back(args[i]);
- } else if (!haveVersion && version.find(args[i])) {
+ } else if (!haveVersion && versionRegex.find(args[i])) {
haveVersion = true;
- this->Version = args[i];
+ this->VersionComplete = args[i];
} else {
this->SetError(
cmStrCat("called with invalid argument \"", args[i], "\""));
@@ -386,23 +394,23 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
// Ignore EXACT with no version.
- if (this->Version.empty() && this->VersionExact) {
+ if (this->VersionComplete.empty() && this->VersionExact) {
this->VersionExact = false;
this->Makefile->IssueMessage(
MessageType::AUTHOR_WARNING,
"Ignoring EXACT since no version is requested.");
}
- if (this->Version.empty() || components.empty()) {
+ if (this->VersionComplete.empty() || components.empty()) {
// Check whether we are recursing inside "Find<name>.cmake" within
// another find_package(<name>) call.
std::string mod = cmStrCat(this->Name, "_FIND_MODULE");
if (this->Makefile->IsOn(mod)) {
- if (this->Version.empty()) {
+ if (this->VersionComplete.empty()) {
// Get version information from the outer call if necessary.
// Requested version string.
- std::string ver = cmStrCat(this->Name, "_FIND_VERSION");
- this->Version = this->Makefile->GetSafeDefinition(ver);
+ std::string ver = cmStrCat(this->Name, "_FIND_VERSION_COMPLETE");
+ this->VersionComplete = this->Makefile->GetSafeDefinition(ver);
// Whether an exact version is required.
std::string exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
@@ -415,32 +423,46 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
}
+ // fill various parts of version specification
+ if (!this->VersionComplete.empty()) {
+ if (!versionRegex.find(this->VersionComplete)) {
+ this->SetError("called with invalid version specification");
+ return false;
+ }
+
+ this->Version = versionRegex.match(1);
+ this->VersionMax = versionRegex.match(5);
+ if (versionRegex.match(4) == "<"_s) {
+ this->VersionRangeMax = VERSION_ENDPOINT_EXCLUDED;
+ }
+ if (!this->VersionMax.empty()) {
+ this->VersionRange = this->VersionComplete;
+ }
+ }
+
+ if (this->VersionExact && !this->VersionRange.empty()) {
+ this->SetError("EXACT cannot be specified with a version range.");
+ return false;
+ }
+
+ // Parse the version number and store the results that were
+ // successfully parsed.
+ auto parseVersion = [](const std::string& version, unsigned int& major,
+ unsigned int& minor, unsigned int& patch,
+ unsigned int& tweak) -> unsigned int {
+ return sscanf(version.c_str(), "%u.%u.%u.%u", &major, &minor, &patch,
+ &tweak);
+ };
+
if (!this->Version.empty()) {
- // Try to parse the version number and store the results that were
- // successfully parsed.
- unsigned int parsed_major;
- unsigned int parsed_minor;
- unsigned int parsed_patch;
- unsigned int parsed_tweak;
this->VersionCount =
- sscanf(this->Version.c_str(), "%u.%u.%u.%u", &parsed_major,
- &parsed_minor, &parsed_patch, &parsed_tweak);
- switch (this->VersionCount) {
- case 4:
- this->VersionTweak = parsed_tweak;
- CM_FALLTHROUGH;
- case 3:
- this->VersionPatch = parsed_patch;
- CM_FALLTHROUGH;
- case 2:
- this->VersionMinor = parsed_minor;
- CM_FALLTHROUGH;
- case 1:
- this->VersionMajor = parsed_major;
- CM_FALLTHROUGH;
- default:
- break;
- }
+ parseVersion(this->Version, this->VersionMajor, this->VersionMinor,
+ this->VersionPatch, this->VersionTweak);
+ }
+ if (!this->VersionMax.empty()) {
+ this->VersionMaxCount = parseVersion(
+ this->VersionMax, this->VersionMaxMajor, this->VersionMaxMinor,
+ this->VersionMaxPatch, this->VersionMaxTweak);
}
std::string disableFindPackageVar =
@@ -647,23 +669,49 @@ void cmFindPackageCommand::SetModuleVariables(const std::string& components)
this->AddFindDefinition(req, "1"_s);
}
+ if (!this->VersionComplete.empty()) {
+ std::string req = cmStrCat(this->Name, "_FIND_VERSION_COMPLETE");
+ this->AddFindDefinition(req, this->VersionComplete);
+ }
+
+ // Tell the module that is about to be read what version of the
+ // package has been requested.
+ auto addDefinition = [this](const std::string& variable,
+ cm::string_view value) {
+ this->AddFindDefinition(variable, value);
+ };
+
if (!this->Version.empty()) {
- // Tell the module that is about to be read what version of the
- // package has been requested.
- auto addDefinition = [this](const std::string& variable,
- cm::string_view value) {
- this->AddFindDefinition(variable, value);
- };
- std::string ver = cmStrCat(this->Name, "_FIND_VERSION");
- this->SetVersionVariables(addDefinition, ver, this->Version,
+ auto prefix = cmStrCat(this->Name, "_FIND_VERSION"_s);
+ this->SetVersionVariables(addDefinition, prefix, this->Version,
this->VersionCount, this->VersionMajor,
this->VersionMinor, this->VersionPatch,
this->VersionTweak);
// Tell the module whether an exact version has been requested.
- std::string exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
+ auto exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
this->AddFindDefinition(exact, this->VersionExact ? "1"_s : "0"_s);
}
+ if (!this->VersionRange.empty()) {
+ auto prefix = cmStrCat(this->Name, "_FIND_VERSION_MIN"_s);
+ this->SetVersionVariables(addDefinition, prefix, this->Version,
+ this->VersionCount, this->VersionMajor,
+ this->VersionMinor, this->VersionPatch,
+ this->VersionTweak);
+
+ prefix = cmStrCat(this->Name, "_FIND_VERSION_MAX"_s);
+ this->SetVersionVariables(addDefinition, prefix, this->VersionMax,
+ this->VersionMaxCount, this->VersionMaxMajor,
+ this->VersionMaxMinor, this->VersionMaxPatch,
+ this->VersionMaxTweak);
+
+ auto id = cmStrCat(this->Name, "_FIND_VERSION_RANGE");
+ this->AddFindDefinition(id, this->VersionRange);
+ id = cmStrCat(this->Name, "_FIND_VERSION_RANGE_MIN");
+ this->AddFindDefinition(id, this->VersionRangeMin);
+ id = cmStrCat(this->Name, "_FIND_VERSION_RANGE_MAX");
+ this->AddFindDefinition(id, this->VersionRangeMax);
+ }
}
void cmFindPackageCommand::AddFindDefinition(const std::string& var,
@@ -873,7 +921,9 @@ bool cmFindPackageCommand::HandlePackageMode(
e << "Could not find a configuration file for package \"" << this->Name
<< "\" that "
<< (this->VersionExact ? "exactly matches" : "is compatible with")
- << " requested version \"" << this->Version << "\".\n"
+ << " requested version "
+ << (this->VersionRange.empty() ? "" : "range ") << "\""
+ << this->VersionComplete << "\".\n"
<< "The following configuration files were considered but not "
"accepted:\n";
@@ -883,9 +933,9 @@ bool cmFindPackageCommand::HandlePackageMode(
}
} else {
std::string requestedVersionString;
- if (!this->Version.empty()) {
+ if (!this->VersionComplete.empty()) {
requestedVersionString =
- cmStrCat(" (requested version ", this->Version, ')');
+ cmStrCat(" (requested version ", this->VersionComplete, ')');
}
if (this->UseConfigFiles) {
@@ -1174,7 +1224,9 @@ void cmFindPackageCommand::AppendSuccessInformation()
std::string versionInfoPropName =
cmStrCat("_CMAKE_", this->Name, "_REQUIRED_VERSION");
std::string versionInfo;
- if (!this->Version.empty()) {
+ if (!this->VersionRange.empty()) {
+ versionInfo = this->VersionRange;
+ } else if (!this->Version.empty()) {
versionInfo =
cmStrCat(this->VersionExact ? "==" : ">=", ' ', this->Version);
}
@@ -1717,6 +1769,8 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
// Set the input variables.
this->Makefile->AddDefinition("PACKAGE_FIND_NAME", this->Name);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_COMPLETE",
+ this->VersionComplete);
auto addDefinition = [this](const std::string& variable,
cm::string_view value) {
@@ -1726,6 +1780,23 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
this->Version, this->VersionCount,
this->VersionMajor, this->VersionMinor,
this->VersionPatch, this->VersionTweak);
+ if (!this->VersionRange.empty()) {
+ this->SetVersionVariables(addDefinition, "PACKAGE_FIND_VERSION_MIN",
+ this->Version, this->VersionCount,
+ this->VersionMajor, this->VersionMinor,
+ this->VersionPatch, this->VersionTweak);
+ this->SetVersionVariables(addDefinition, "PACKAGE_FIND_VERSION_MAX",
+ this->VersionMax, this->VersionMaxCount,
+ this->VersionMaxMajor, this->VersionMaxMinor,
+ this->VersionMaxPatch, this->VersionMaxTweak);
+
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_RANGE",
+ this->VersionComplete);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_RANGE_MIN",
+ this->VersionRangeMin);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_RANGE_MAX",
+ this->VersionRangeMax);
+ }
// Load the version check file. Pass NoPolicyScope because we do
// our own policy push/pop independent of CMP0011.