diff --git a/Help/command/POLICY_VERSION.txt b/Help/command/POLICY_VERSION.txt new file mode 100644 index 0000000000..424849d60a --- /dev/null +++ b/Help/command/POLICY_VERSION.txt @@ -0,0 +1,16 @@ +This specifies that the current CMake code is written for the given range of +CMake versions, ``[...]``. It sets the "policy version" to: + +* the range's ```` version, if specified, or to +* the ```` version, or to +* the value of the :variable:`CMAKE_POLICY_VERSION_MINIMUM` variable + if it is higher than the other two versions. + +The policy version effectively requests behavior preferred as of a given CMake +version and tells newer CMake versions to warn about their new policies. +All policies known to the running version of CMake and introduced +in that 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` 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. diff --git a/Help/command/cmake_minimum_required.rst b/Help/command/cmake_minimum_required.rst index 2833ed7a0b..47e8e6bafc 100644 --- a/Help/command/cmake_minimum_required.rst +++ b/Help/command/cmake_minimum_required.rst @@ -19,7 +19,7 @@ form ``major.minor[.patch[.tweak]]``, and the ``...`` is literal. If the running version of CMake is lower than the ```` required version it will stop processing the project and report an error. The optional ```` version, if specified, must be at least the -```` version and affects policy settings as described in `Policy Settings`_. +```` version and sets the `Policy Version`_. If the running version of CMake is older than 3.12, the extra ``...`` dots will be seen as version component separators, resulting in the ``...`` part being ignored and preserving the pre-3.12 behavior @@ -48,38 +48,18 @@ with an error instead of just a warning. calling scope, calling ``cmake_minimum_required()`` inside a function is generally discouraged. -.. _`Policy Settings`: +.. _`Policy Version`: -Policy Settings -^^^^^^^^^^^^^^^ +Policy Version +^^^^^^^^^^^^^^ -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 range of CMake versions. -All policies known to the running version of CMake and introduced -in the ```` (or ````, 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` 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. - -When a ```` version higher than 2.4 is specified the command -implicitly invokes +``cmake_minimum_required(VERSION [...])`` implicitly invokes .. code-block:: cmake cmake_policy(VERSION [...]) -which sets CMake policies based on the range of versions specified. -When a ```` version 2.4 or lower is given the command implicitly -invokes - -.. code-block:: cmake - - cmake_policy(VERSION 2.4[...]) - -which enables compatibility features for CMake 2.4 and lower. +.. include:: POLICY_VERSION.txt .. include:: DEPRECATED_POLICY_VERSIONS.txt diff --git a/Help/command/cmake_policy.rst b/Help/command/cmake_policy.rst index 4a08c01364..276e160f08 100644 --- a/Help/command/cmake_policy.rst +++ b/Help/command/cmake_policy.rst @@ -39,14 +39,7 @@ CMake is older than 3.12, the extra ``...`` dots will be seen as version component separators, resulting in the ``...`` part being ignored and preserving the pre-3.12 behavior of basing policies on ````. -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 ```` (or ````, 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` 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. +.. include:: POLICY_VERSION.txt Note that the :command:`cmake_minimum_required(VERSION)` command implicitly calls ``cmake_policy(VERSION)`` too. diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 200fc18e86..cbf8a920ce 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -254,6 +254,7 @@ Variables that Change Behavior /variable/CMAKE_MFC_FLAG /variable/CMAKE_MODULE_PATH /variable/CMAKE_POLICY_DEFAULT_CMPNNNN + /variable/CMAKE_POLICY_VERSION_MINIMUM /variable/CMAKE_POLICY_WARNING_CMPNNNN /variable/CMAKE_PREFIX_PATH /variable/CMAKE_PROGRAM_PATH diff --git a/Help/release/4.0.rst b/Help/release/4.0.rst index 80a55bf872..b1102d5b79 100644 --- a/Help/release/4.0.rst +++ b/Help/release/4.0.rst @@ -72,6 +72,10 @@ Variables to select runtime checks for compilers targeting the MSVC ABI. See policy :policy:`CMP0184`. +* The :variable:`CMAKE_POLICY_VERSION_MINIMUM` variable was added to + help pacakgers and end users try to configure existing projects that + have not been updated to work with supported CMake versions. + * The :variable:`CMAKE_XCODE_SCHEME_LLDB_INIT_FILE` variable and corresponding :prop_tgt:`XCODE_SCHEME_LLDB_INIT_FILE` target property were added to tell the :generator:`Xcode` generator what to put in the scheme's "LLDB Init File" diff --git a/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst index d643fb8df1..5f47d4e61c 100644 --- a/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst +++ b/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst @@ -22,3 +22,6 @@ not itself been updated: * Projects may set this variable before a call to :command:`add_subdirectory` that adds a third-party project in order to set its policies without modifying third-party code. + +See :variable:`CMAKE_POLICY_VERSION_MINIMUM` set policies to ``NEW`` +based on the version of CMake that introduced them. diff --git a/Help/variable/CMAKE_POLICY_VERSION_MINIMUM.rst b/Help/variable/CMAKE_POLICY_VERSION_MINIMUM.rst new file mode 100644 index 0000000000..cf48ecfe9b --- /dev/null +++ b/Help/variable/CMAKE_POLICY_VERSION_MINIMUM.rst @@ -0,0 +1,23 @@ +CMAKE_POLICY_VERSION_MINIMUM +---------------------------- + +.. versionadded:: 4.0 + +Specify a minimum :ref:`Policy Version` for a project without modifying +its calls to :command:`cmake_minimum_required(VERSION)` and +:command:`cmake_policy(VERSION)`. + +This variable should not be set by a project in CMake code as a way to +set its own policy version. Use :command:`cmake_minimum_required(VERSION)` +and/or :command:`cmake_policy(VERSION)` for that. This variable is meant +to externally set policies for which a project has not itself been updated: + +* Users running CMake may set this variable in the cache, e.g., + ``-DCMAKE_POLICY_VERSION_MINIMUM=3.5``, to try configuring a project + that has not been updated to set at least that policy version itself. + +* Projects may set this variable before a call to :command:`add_subdirectory` + that adds a third-party project in order to set its policy version without + modifying third-party code. + +See :variable:`CMAKE_POLICY_DEFAULT_CMP` to set individual policies. diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 9de978ec6d..908a7867cb 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -15,6 +15,7 @@ #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmValue.h" #include "cmVersion.h" static bool stringToId(char const* input, cmPolicies::PolicyID& pid) @@ -294,6 +295,30 @@ bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer, unsigned int patchVer, WarnCompat warnCompat) { + cmValue varVer = mf->GetDefinition("CMAKE_POLICY_VERSION_MINIMUM"); + if (!varVer.IsEmpty()) { + unsigned int varMajor = 0; + unsigned int varMinor = 0; + unsigned int varPatch = 0; + unsigned int varTweak = 0; + if (sscanf(varVer.GetCStr(), "%u.%u.%u.%u", &varMajor, &varMinor, + &varPatch, &varTweak) < 2) { + mf->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Invalid CMAKE_POLICY_VERSION_MINIMUM value \"", varVer, + "\". " + "A numeric major.minor[.patch[.tweak]] must be given.")); + return false; + } + if (varMajor > majorVer || (varMajor == majorVer && varMinor > minorVer) || + (varMajor == majorVer && varMinor == minorVer && + varPatch > patchVer)) { + majorVer = varMajor; + minorVer = varMinor; + patchVer = varPatch; + } + } + // Error on policy versions for which support has been removed. if (majorVer < 3 || (majorVer == 3 && minorVer < 5)) { if (IsFromLegacyInstallEXPORT(mf, majorVer, minorVer, patchVer)) { @@ -305,7 +330,9 @@ bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer, } else { mf->IssueMessage(MessageType::FATAL_ERROR, "Compatibility with CMake < 3.5 has been removed " - "from CMake.\n" ADVICE_UPDATE_VERSION_ARGUMENT); + "from CMake.\n" ADVICE_UPDATE_VERSION_ARGUMENT "\n" + "Or, add -DCMAKE_POLICY_VERSION_MINIMUM=3.5 to try " + "configuring anyway."); cmSystemTools::SetFatalErrorOccurred(); return false; } diff --git a/Tests/RunCMake/cmake_minimum_required/BeforeVersionRemoved-stderr.txt b/Tests/RunCMake/cmake_minimum_required/BeforeVersionRemoved-stderr.txt index 62145e638b..f2f41aff54 100644 --- a/Tests/RunCMake/cmake_minimum_required/BeforeVersionRemoved-stderr.txt +++ b/Tests/RunCMake/cmake_minimum_required/BeforeVersionRemoved-stderr.txt @@ -4,5 +4,7 @@ Update the VERSION argument value\. Or, use the \.\.\. syntax to tell CMake that the project requires at least but has been updated to work with policies introduced by or earlier\. + + Or, add -DCMAKE_POLICY_VERSION_MINIMUM=3\.5 to try configuring anyway\. Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/cmake_minimum_required/PolicyBeforeVersionRemoved-stderr.txt b/Tests/RunCMake/cmake_minimum_required/PolicyBeforeVersionRemoved-stderr.txt index c9eba0fbd5..bf4035a1a6 100644 --- a/Tests/RunCMake/cmake_minimum_required/PolicyBeforeVersionRemoved-stderr.txt +++ b/Tests/RunCMake/cmake_minimum_required/PolicyBeforeVersionRemoved-stderr.txt @@ -4,5 +4,7 @@ Update the VERSION argument value\. Or, use the \.\.\. syntax to tell CMake that the project requires at least but has been updated to work with policies introduced by or earlier\. + + Or, add -DCMAKE_POLICY_VERSION_MINIMUM=3\.5 to try configuring anyway\. Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariable-stderr.txt b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariable-stderr.txt new file mode 100644 index 0000000000..4f161bf084 --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariable-stderr.txt @@ -0,0 +1,3 @@ +^CMAKE_MINIMUM_REQUIRED_VERSION='3\.1' +CMP0071='NEW' +CMP0072=''$ diff --git a/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariable.cmake b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariable.cmake new file mode 100644 index 0000000000..553fc94d14 --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariable.cmake @@ -0,0 +1,7 @@ +set(CMAKE_POLICY_VERSION_MINIMUM 3.10) +cmake_minimum_required(VERSION 3.1...3.4) +message("CMAKE_MINIMUM_REQUIRED_VERSION='${CMAKE_MINIMUM_REQUIRED_VERSION}'") +foreach(policy CMP0071 CMP0072) + cmake_policy(GET ${policy} status) + message("${policy}='${status}'") +endforeach() diff --git a/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad-result.txt b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad-stderr.txt b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad-stderr.txt new file mode 100644 index 0000000000..3a59bb77a6 --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at PolicyVersionVariableBad\.cmake:2 \(cmake_minimum_required\): + Invalid CMAKE_POLICY_VERSION_MINIMUM value "\.\.\.3\.10"\. A numeric + major\.minor\[\.patch\[\.tweak\]\] must be given\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad.cmake b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad.cmake new file mode 100644 index 0000000000..763997b40f --- /dev/null +++ b/Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad.cmake @@ -0,0 +1,2 @@ +set(CMAKE_POLICY_VERSION_MINIMUM ...3.10) +cmake_minimum_required(VERSION 3.1...3.4) diff --git a/Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake b/Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake index cd63093c4e..d91f171546 100644 --- a/Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake @@ -7,3 +7,5 @@ run_cmake(BeforeVersionDeprecated) run_cmake(Range) run_cmake(RangeBad) run_cmake(Unknown) +run_cmake(PolicyVersionVariable) +run_cmake(PolicyVersionVariableBad)