From 1a353511250a7191086bf15645fe7c8f79caac1a Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 13 Feb 2025 12:37:32 -0500 Subject: [PATCH] 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 +++ .../variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst | 3 ++ .../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 9ac998c134..424849d60a 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 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)