diff options
-rw-r--r-- | Help/command/cmake_minimum_required.rst | 34 | ||||
-rw-r--r-- | Help/command/cmake_policy.rst | 21 | ||||
-rw-r--r-- | Help/release/dev/policy-version-range.rst | 8 | ||||
-rw-r--r-- | Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst | 6 | ||||
-rw-r--r-- | Source/CPack/cmCPackGenerator.cxx | 3 | ||||
-rw-r--r-- | Source/cmCMakeMinimumRequired.cxx | 27 | ||||
-rw-r--r-- | Source/cmCMakePolicyCommand.cxx | 19 | ||||
-rw-r--r-- | Source/cmMakefile.cxx | 7 | ||||
-rw-r--r-- | Source/cmMakefile.h | 3 | ||||
-rw-r--r-- | Source/cmPolicies.cxx | 39 | ||||
-rw-r--r-- | Source/cmPolicies.h | 3 | ||||
-rw-r--r-- | Source/cmQtAutoGenerator.cxx | 2 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_minimum_required/Range-stderr.txt | 4 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_minimum_required/Range.cmake | 6 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_minimum_required/RangeBad-result.txt | 1 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt | 56 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_minimum_required/RangeBad.cmake | 10 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake | 2 |
18 files changed, 210 insertions, 41 deletions
diff --git a/Help/command/cmake_minimum_required.rst b/Help/command/cmake_minimum_required.rst index 9535bf34f0..7c021901f3 100644 --- a/Help/command/cmake_minimum_required.rst +++ b/Help/command/cmake_minimum_required.rst @@ -4,11 +4,15 @@ cmake_minimum_required Set the minimum required version of cmake for a project and update `Policy Settings`_ to match the version given:: - cmake_minimum_required(VERSION major.minor[.patch[.tweak]] - [FATAL_ERROR]) + cmake_minimum_required(VERSION <min>[...<max>] [FATAL_ERROR]) -If the current version of CMake is lower than that required it will -stop processing the project and report an error. +``<min>`` and the optional ``<max>`` are each CMake versions of the form +``major.minor[.patch[.tweak]]``, and the ``...`` is literal. + +If the running version of CMake is lower than the ``<min>`` required +version it will stop processing the project and report an error. +The optional ``<max>`` version, if specified, must be at least the +``<min>`` version and affects policy settings as described below. The ``FATAL_ERROR`` option is accepted but ignored by CMake 2.6 and higher. It should be specified so CMake versions 2.4 and lower fail @@ -30,21 +34,23 @@ Policy Settings The ``cmake_minimum_required(VERSION)`` command implicitly invokes the :command:`cmake_policy(VERSION)` command to specify that the current -project code is written for the given version of CMake. -All policies introduced in the specified version or earlier will be -set to use NEW behavior. All policies introduced after the specified -version will be unset. This effectively requests behavior preferred +project code is written for the given range of CMake versions. +All policies known to the running version of CMake and introduced +in the ``<min>`` (or ``<max>``, if specified) version or earlier will +be set to use ``NEW`` behavior. All policies introduced in later +versions will be unset. This effectively requests behavior preferred as of a given CMake version and tells newer CMake versions to warn about their new policies. -When a version higher than 2.4 is specified the command implicitly -invokes:: +When a ``<min>`` version higher than 2.4 is specified the command +implicitly invokes:: - cmake_policy(VERSION major[.minor[.patch[.tweak]]]) + cmake_policy(VERSION <min>[...<max>]) -which sets the cmake policy version level to the version specified. -When version 2.4 or lower is given the command implicitly invokes:: +which sets CMake policies based on the range of versions specified. +When a ``<min>`` version 2.4 or lower is given the command implicitly +invokes:: - cmake_policy(VERSION 2.4) + cmake_policy(VERSION 2.4[...<max>]) which enables compatibility features for CMake 2.4 and lower. diff --git a/Help/command/cmake_policy.rst b/Help/command/cmake_policy.rst index b51b9512cf..6a8dd620e7 100644 --- a/Help/command/cmake_policy.rst +++ b/Help/command/cmake_policy.rst @@ -24,17 +24,22 @@ The ``cmake_policy`` command is used to set policies to ``OLD`` or ``NEW`` behavior. While setting policies individually is supported, we encourage projects to set policies based on CMake versions:: - cmake_policy(VERSION major.minor[.patch[.tweak]]) - -Specify that the current CMake code is written for the given -version of CMake. All policies introduced in the specified version or -earlier will be set to use ``NEW`` behavior. All policies introduced -after the specified version will be unset (unless the + cmake_policy(VERSION <min>[...<max>]) + +``<min>`` and the optional ``<max>`` are each CMake versions of the form +``major.minor[.patch[.tweak]]``, and the ``...`` is literal. The ``<min>`` +version must be at least ``2.4`` and at most the running version of CMake. +The ``<max>`` version, if specified, must be at least the ``<min>`` version +but may exceed the running version of CMake. + +This specifies that the current CMake code is written for the given +range of CMake versions. All policies known to the running version of CMake +and introduced in the ``<min>`` (or ``<max>``, if specified) version +or earlier will be set to use ``NEW`` behavior. All policies +introduced in later versions will be unset (unless the :variable:`CMAKE_POLICY_DEFAULT_CMP<NNNN>` variable sets a default). This effectively requests behavior preferred as of a given CMake version and tells newer CMake versions to warn about their new policies. -The policy version specified must be at least 2.4 or the command will -report an error. Note that the :command:`cmake_minimum_required(VERSION)` command implicitly calls ``cmake_policy(VERSION)`` too. diff --git a/Help/release/dev/policy-version-range.rst b/Help/release/dev/policy-version-range.rst new file mode 100644 index 0000000000..b2d1f17b06 --- /dev/null +++ b/Help/release/dev/policy-version-range.rst @@ -0,0 +1,8 @@ +policy-version-range +-------------------- + +* The :command:`cmake_minimum_required` and :command:`cmake_policy(VERSION)` + commands now accept a version range using the form ``<min>[...<max>]``. + The ``<min>`` version is required but policies are set based on the + ``<max>`` version. This allows projects to specify a range of versions + for which they have been updated and avoid explicit policy settings. diff --git a/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst b/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst index 5a51634dbe..f466468d81 100644 --- a/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst +++ b/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst @@ -1,7 +1,5 @@ CMAKE_MINIMUM_REQUIRED_VERSION ------------------------------ -Version specified to :command:`cmake_minimum_required` command - -Variable containing the ``VERSION`` component specified in the -:command:`cmake_minimum_required` command. +The ``<min>`` version of CMake given to the most recent call to the +:command:`cmake_minimum_required(VERSION)` command. diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index d41a9e5c3c..64aba10e25 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -1002,7 +1002,8 @@ int cmCPackGenerator::DoPackage() { // scope that enables package generators to run internal scripts with // latest CMake policies enabled cmMakefile::ScopePushPop pp{ this->MakefileMap }; - this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion()); + this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion(), + std::string()); if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory" diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx index bcc41fca91..c4834a875b 100644 --- a/Source/cmCMakeMinimumRequired.cxx +++ b/Source/cmCMakeMinimumRequired.cxx @@ -45,9 +45,24 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, return this->EnforceUnknownArguments(); } + // Separate the <min> version and any trailing ...<max> component. + std::string::size_type const dd = version_string.find("..."); + std::string const version_min = version_string.substr(0, dd); + std::string const version_max = dd != std::string::npos + ? version_string.substr(dd + 3, std::string::npos) + : std::string(); + if (dd != std::string::npos && + (version_min.empty() || version_max.empty())) { + std::ostringstream e; + e << "VERSION \"" << version_string + << "\" does not have a version on both sides of \"...\"."; + this->SetError(e.str()); + return false; + } + // Save the required version string. this->Makefile->AddDefinition("CMAKE_MINIMUM_REQUIRED_VERSION", - version_string.c_str()); + version_min.c_str()); // Get the current version number. unsigned int current_major = cmVersion::GetMajorVersion(); @@ -61,10 +76,10 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, unsigned int required_minor = 0; unsigned int required_patch = 0; unsigned int required_tweak = 0; - if (sscanf(version_string.c_str(), "%u.%u.%u.%u", &required_major, + if (sscanf(version_min.c_str(), "%u.%u.%u.%u", &required_major, &required_minor, &required_patch, &required_tweak) < 2) { std::ostringstream e; - e << "could not parse VERSION \"" << version_string << "\"."; + e << "could not parse VERSION \"" << version_min << "\"."; this->SetError(e.str()); return false; } @@ -78,7 +93,7 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, current_patch == required_patch && current_tweak < required_tweak)) { // The current version is too low. std::ostringstream e; - e << "CMake " << version_string + e << "CMake " << version_min << " or higher is required. You are running version " << cmVersion::GetCMakeVersion(); this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); @@ -95,9 +110,9 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args, this->Makefile->IssueMessage( cmake::AUTHOR_WARNING, "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0."); - this->Makefile->SetPolicyVersion("2.4"); + this->Makefile->SetPolicyVersion("2.4", version_max); } else { - this->Makefile->SetPolicyVersion(version_string.c_str()); + this->Makefile->SetPolicyVersion(version_min, version_max); } return true; diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx index 3ccc815e68..7ca1cbcb43 100644 --- a/Source/cmCMakePolicyCommand.cxx +++ b/Source/cmCMakePolicyCommand.cxx @@ -156,6 +156,23 @@ bool cmCMakePolicyCommand::HandleVersionMode( this->SetError("VERSION given too many arguments"); return false; } - this->Makefile->SetPolicyVersion(args[1].c_str()); + std::string const& version_string = args[1]; + + // Separate the <min> version and any trailing ...<max> component. + std::string::size_type const dd = version_string.find("..."); + std::string const version_min = version_string.substr(0, dd); + std::string const version_max = dd != std::string::npos + ? version_string.substr(dd + 3, std::string::npos) + : std::string(); + if (dd != std::string::npos && + (version_min.empty() || version_max.empty())) { + std::ostringstream e; + e << "VERSION \"" << version_string + << "\" does not have a version on both sides of \"...\"."; + this->SetError(e.str()); + return false; + } + + this->Makefile->SetPolicyVersion(version_min, version_max); return true; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 23883f7175..92d7681e94 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1464,7 +1464,7 @@ void cmMakefile::Configure() this->SetCheckCMP0000(true); // Implicitly set the version for the user. - this->SetPolicyVersion("2.4"); + this->SetPolicyVersion("2.4", std::string()); } } bool hasProject = false; @@ -4149,9 +4149,10 @@ void cmMakefile::PopSnapshot(bool reportError) assert(this->StateSnapshot.IsValid()); } -bool cmMakefile::SetPolicyVersion(std::string const& version_min) +bool cmMakefile::SetPolicyVersion(std::string const& version_min, + std::string const& version_max) { - return cmPolicies::ApplyPolicyVersion(this, version_min); + return cmPolicies::ApplyPolicyVersion(this, version_min, version_max); } bool cmMakefile::HasCMP0054AlreadyBeenReported( diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index e90cf2f190..414c08c743 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -285,7 +285,8 @@ public: bool SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status); bool SetPolicy(const char* id, cmPolicies::PolicyStatus status); cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id) const; - bool SetPolicyVersion(std::string const& version_min); + bool SetPolicyVersion(std::string const& version_min, + std::string const& version_max); void RecordPolicies(cmPolicies::PolicyMap& pm); //@} diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index cf61edd3ae..dba22b38d6 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -154,7 +154,8 @@ static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy, } bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, - std::string const& version_min) + std::string const& version_min, + std::string const& version_max) { // Parse components of the minimum version. unsigned int minMajor = 2; @@ -205,6 +206,42 @@ bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, unsigned int polMajor = minMajor; unsigned int polMinor = minMinor; unsigned int polPatch = minPatch; + + if (!version_max.empty()) { + // Parse components of the maximum version. + unsigned int maxMajor = 0; + unsigned int maxMinor = 0; + unsigned int maxPatch = 0; + unsigned int maxTweak = 0; + if (sscanf(version_max.c_str(), "%u.%u.%u.%u", &maxMajor, &maxMinor, + &maxPatch, &maxTweak) < 2) { + std::ostringstream e; + e << "Invalid policy max version value \"" << version_max << "\". " + << "A numeric major.minor[.patch[.tweak]] must be given."; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + + // It is an error if the min version is greater than the max version. + if (minMajor > maxMajor || (minMajor == maxMajor && minMinor > maxMinor) || + (minMajor == maxMajor && minMinor == maxMinor && + minPatch > maxPatch) || + (minMajor == maxMajor && minMinor == maxMinor && + minPatch == maxPatch && minTweak > maxTweak)) { + std::ostringstream e; + e << "Policy VERSION range \"" << version_min << "..." << version_max + << "\"" + << " specifies a larger minimum than maximum."; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + + // Use the max version as the policy version. + polMajor = maxMajor; + polMinor = maxMinor; + polPatch = maxPatch; + } + return cmPolicies::ApplyPolicyVersion(mf, polMajor, polMinor, polPatch); } diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 00f3fd006e..33896feb9a 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -289,7 +289,8 @@ public: ///! Set a policy level for this listfile static bool ApplyPolicyVersion(cmMakefile* mf, - std::string const& version_min); + std::string const& version_min, + std::string const& version_max); static bool ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer, unsigned int minorVer, unsigned int patchVer); diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index 1939bd4e66..5c35d76421 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -612,7 +612,7 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile, auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot); // The OLD/WARN behavior for policy CMP0053 caused a speed regression. // https://gitlab.kitware.com/cmake/cmake/issues/17570 - makefile->SetPolicyVersion("3.9"); + makefile->SetPolicyVersion("3.9", std::string()); gg.SetCurrentMakefile(makefile.get()); success = this->Init(makefile.get()); } diff --git a/Tests/RunCMake/cmake_minimum_required/Range-stderr.txt b/Tests/RunCMake/cmake_minimum_required/Range-stderr.txt new file mode 100644 index 0000000000..7d2bdae3b8 --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/Range-stderr.txt @@ -0,0 +1,4 @@ +^CMAKE_MINIMUM_REQUIRED_VERSION='3\.10' +CMP0071='NEW' +CMP0072='NEW' +CMP0073=''$ diff --git a/Tests/RunCMake/cmake_minimum_required/Range.cmake b/Tests/RunCMake/cmake_minimum_required/Range.cmake new file mode 100644 index 0000000000..0080092693 --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/Range.cmake @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.10...3.11) +message("CMAKE_MINIMUM_REQUIRED_VERSION='${CMAKE_MINIMUM_REQUIRED_VERSION}'") +foreach(policy CMP0071 CMP0072 CMP0073) + cmake_policy(GET ${policy} status) + message("${policy}='${status}'") +endforeach() diff --git a/Tests/RunCMake/cmake_minimum_required/RangeBad-result.txt b/Tests/RunCMake/cmake_minimum_required/RangeBad-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/RangeBad-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt b/Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt new file mode 100644 index 0000000000..b2c62fbfc7 --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt @@ -0,0 +1,56 @@ +^CMake Error at RangeBad.cmake:1 \(cmake_minimum_required\): + cmake_minimum_required VERSION "3.11..." does not have a version on both + sides of "...". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:2 \(cmake_minimum_required\): + cmake_minimum_required VERSION "...3.11" does not have a version on both + sides of "...". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:3 \(cmake_minimum_required\): + cmake_minimum_required VERSION "..." does not have a version on both sides + of "...". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:4 \(cmake_minimum_required\): + Invalid policy max version value "4". A numeric + major.minor\[.patch\[.tweak\]\] must be given. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:5 \(cmake_minimum_required\): + Policy VERSION range "3.11...3.10" specifies a larger minimum than maximum. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:6 \(cmake_policy\): + cmake_policy VERSION "3.11..." does not have a version on both sides of + "...". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:7 \(cmake_policy\): + cmake_policy VERSION "...3.11" does not have a version on both sides of + "...". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:8 \(cmake_policy\): + cmake_policy VERSION "..." does not have a version on both sides of "...". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:9 \(cmake_policy\): + Invalid policy max version value "4". A numeric + major.minor\[.patch\[.tweak\]\] must be given. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at RangeBad.cmake:10 \(cmake_policy\): + Policy VERSION range "3.11...3.10" specifies a larger minimum than maximum. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_minimum_required/RangeBad.cmake b/Tests/RunCMake/cmake_minimum_required/RangeBad.cmake new file mode 100644 index 0000000000..2a2dade2cb --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/RangeBad.cmake @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.11...) +cmake_minimum_required(VERSION ...3.11) +cmake_minimum_required(VERSION ...) +cmake_minimum_required(VERSION 3.11...4) +cmake_minimum_required(VERSION 3.11...3.10) +cmake_policy(VERSION 3.11...) +cmake_policy(VERSION ...3.11) +cmake_policy(VERSION ...) +cmake_policy(VERSION 3.11...4) +cmake_policy(VERSION 3.11...3.10) diff --git a/Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake b/Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake index e4c65e3b6b..22aa5b76b3 100644 --- a/Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake @@ -3,3 +3,5 @@ include(RunCMake) run_cmake(Before24) run_cmake(CompatBefore24) run_cmake(PolicyBefore24) +run_cmake(Range) +run_cmake(RangeBad) |