From 1a353511250a7191086bf15645fe7c8f79caac1a Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 13 Feb 2025 12:37:32 -0500 Subject: Add CMAKE_POLICY_VERSION_MINIMUM to help configure outdated projects Provide packagers and end users with a way to try configuring projects that have not been updated to set their policy version to a supported level. Closes: #26698 --- Help/command/POLICY_VERSION.txt | 4 ++- Help/manual/cmake-variables.7.rst | 1 + Help/release/4.0.rst | 4 +++ Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst | 3 +++ Help/variable/CMAKE_POLICY_VERSION_MINIMUM.rst | 23 +++++++++++++++++ Source/cmPolicies.cxx | 29 +++++++++++++++++++++- .../BeforeVersionRemoved-stderr.txt | 2 ++ .../PolicyBeforeVersionRemoved-stderr.txt | 2 ++ .../PolicyVersionVariable-stderr.txt | 3 +++ .../PolicyVersionVariable.cmake | 7 ++++++ .../PolicyVersionVariableBad-result.txt | 1 + .../PolicyVersionVariableBad-stderr.txt | 5 ++++ .../PolicyVersionVariableBad.cmake | 2 ++ .../cmake_minimum_required/RunCMakeTest.cmake | 2 ++ 14 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 Help/variable/CMAKE_POLICY_VERSION_MINIMUM.rst create mode 100644 Tests/RunCMake/cmake_minimum_required/PolicyVersionVariable-stderr.txt create mode 100644 Tests/RunCMake/cmake_minimum_required/PolicyVersionVariable.cmake create mode 100644 Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad-result.txt create mode 100644 Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad-stderr.txt create mode 100644 Tests/RunCMake/cmake_minimum_required/PolicyVersionVariableBad.cmake diff --git a/Help/command/POLICY_VERSION.txt b/Help/command/POLICY_VERSION.txt index 9ac998c..424849d 100644 --- a/Help/command/POLICY_VERSION.txt +++ b/Help/command/POLICY_VERSION.txt @@ -2,7 +2,9 @@ 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. +* 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. diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 200fc18..cbf8a92 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 80a55bf..b1102d5 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 d643fb8..5f47d4e 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 0000000..cf48ecf --- /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 9de978e..908a786 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 62145e6..f2f41af 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 c9eba0f..bf4035a 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 0000000..4f161bf --- /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 0000000..553fc94 --- /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 0000000..d00491f --- /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 0000000..3a59bb7 --- /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 0000000..763997b --- /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 cd63093..d91f171 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) -- cgit v0.12