Browse Source

Merge topic 'if-command-PATH_EQUAL'

be4b9e10af if command: Add PATH_EQUAL operator

Acked-by: Kitware Robot <[email protected]>
Tested-by: buildbot <[email protected]>
Merge-request: !7321
Brad King 3 years ago
parent
commit
ab1edff492

+ 29 - 1
Help/command/if.rst

@@ -47,7 +47,7 @@ Compound conditions are evaluated in the following order of precedence:
    `GREATER_EQUAL`_, `STREQUAL`_, `STRLESS`_, `STRLESS_EQUAL`_,
    `STRGREATER`_, `STRGREATER_EQUAL`_, `VERSION_EQUAL`_, `VERSION_LESS`_,
    `VERSION_LESS_EQUAL`_, `VERSION_GREATER`_, `VERSION_GREATER_EQUAL`_,
-   and `MATCHES`_.
+   `PATH_EQUAL`_, and `MATCHES`_.
 
 4. Unary logical operator `NOT`_.
 
@@ -314,6 +314,34 @@ Version Comparisons
   Any non-integer version component or non-integer trailing part of a version
   component effectively truncates the string at that point.
 
+Path Comparisons
+""""""""""""""""
+
+.. _PATH_EQUAL:
+
+``if(<variable|string> PATH_EQUAL <variable|string>)``
+ .. versionadded:: 3.24
+  Compares the lexical representations of two paths provided as string
+  literals or variables. No normalization is performed on either path.
+
+  Lexical comparison has the advantage over string comparison to have a
+  knowledge of the structure of the path. So, the following comparison is
+  ``TRUE`` using ``PATH_EQUAL`` operator, but ``FALSE`` with ``STREQUAL``:
+
+  .. code-block:: cmake
+
+    # comparison is TRUE
+    if ("/a//b/c" PATH_EQUAL "/a/b/c")
+       ...
+    endif()
+
+    # comparison is FALSE
+    if ("/a//b/c" STREQUAL "/a/b/c")
+       ...
+    endif()
+
+  See :ref:`cmake_path(COMPARE) <Path COMPARE>` for more details.
+
 Variable Expansion
 ^^^^^^^^^^^^^^^^^^
 

+ 1 - 0
Help/manual/cmake-policies.7.rst

@@ -58,6 +58,7 @@ Policies Introduced by CMake 3.24
 .. toctree::
    :maxdepth: 1
 
+   CMP0139: The if() command supports path comparisons using PATH_EQUAL operator. </policy/CMP0139>
    CMP0138: MSVC compilers use -ZI instead of /Zi for x86 and x64 by default. </policy/CMP0138>
    CMP0137: try_compile() passes platform variables in project mode. </policy/CMP0137>
    CMP0136: Watcom runtime library flags are selected by an abstraction. </policy/CMP0136>

+ 17 - 0
Help/policy/CMP0139.rst

@@ -0,0 +1,17 @@
+CMP0139
+-------
+
+.. versionadded:: 3.24
+
+The :command:`if` command supports path comparisons using ``PATH_EQUAL``
+operator.
+
+The ``OLD`` behavior for this policy is to ignore the ``PATH_EQUAL`` operator.
+The ``NEW`` behavior is to interpret the ``PATH_EQUAL`` operator.
+
+This policy was introduced in CMake version 3.24.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior.  Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt

+ 5 - 0
Help/release/dev/if-PATH_EQUAL.rst

@@ -0,0 +1,5 @@
+if-PATH_EQUAL
+-------------
+
+* The :command:`if` command gains the capability to compare paths by using the
+  ``PATH_EQUAL`` operator. See policy :policy:`CMP0139`.

+ 26 - 0
Source/cmConditionEvaluator.cxx

@@ -16,6 +16,7 @@
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmCMakePath.h"
 #include "cmExpandedCommandArgument.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -58,6 +59,7 @@ auto const keyVERSION_GREATER = "VERSION_GREATER"_s;
 auto const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL"_s;
 auto const keyVERSION_LESS = "VERSION_LESS"_s;
 auto const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"_s;
+auto const keyPATH_EQUAL = "PATH_EQUAL"_s;
 
 cmSystemTools::CompareOp const MATCH2CMPOP[5] = {
   cmSystemTools::OP_LESS, cmSystemTools::OP_LESS_EQUAL,
@@ -217,6 +219,7 @@ cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
   , Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054))
   , Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057))
   , Policy64Status(makefile.GetPolicyStatus(cmPolicies::CMP0064))
+  , Policy139Status(makefile.GetPolicyStatus(cmPolicies::CMP0139))
 {
 }
 
@@ -775,6 +778,29 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
         this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
       }
     }
+
+    else if (this->IsKeyword(keyPATH_EQUAL, *args.next)) {
+
+      if (this->Policy139Status != cmPolicies::OLD &&
+          this->Policy139Status != cmPolicies::WARN) {
+
+        cmValue lhs = this->GetVariableOrString(*args.current);
+        cmValue rhs = this->GetVariableOrString(*args.nextnext);
+        const auto result = cmCMakePath{ *lhs } == cmCMakePath{ *rhs };
+        newArgs.ReduceTwoArgs(result, args);
+      }
+
+      else if (this->Policy139Status == cmPolicies::WARN) {
+        std::ostringstream e;
+        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0139)
+          << "\n"
+             "PATH_EQUAL will be interpreted as an operator "
+             "when the policy is set to NEW.  "
+             "Since the policy is not set the OLD behavior will be used.";
+
+        this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+      }
+    }
   }
   return true;
 }

+ 1 - 0
Source/cmConditionEvaluator.h

@@ -79,4 +79,5 @@ private:
   cmPolicies::PolicyStatus Policy54Status;
   cmPolicies::PolicyStatus Policy57Status;
   cmPolicies::PolicyStatus Policy64Status;
+  cmPolicies::PolicyStatus Policy139Status;
 };

+ 5 - 1
Source/cmPolicies.h

@@ -417,7 +417,11 @@ class cmMakefile;
          cmPolicies::WARN)                                                    \
   SELECT(POLICY, CMP0138,                                                     \
          "MSVC compilers use -ZI instead of /Zi for x86 and x64 by default.", \
-         3, 24, 0, cmPolicies::WARN)
+         3, 24, 0, cmPolicies::WARN)                                          \
+  SELECT(                                                                     \
+    POLICY, CMP0139,                                                          \
+    "The if() command supports path comparisons using PATH_EQUAL operator.",  \
+    3, 24, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \

+ 25 - 0
Tests/RunCMake/CMP0139/CMP0139-NEW.cmake

@@ -0,0 +1,25 @@
+cmake_policy(SET CMP0139 NEW)
+
+
+set(path "a///b/c")
+if (NOT path PATH_EQUAL "a/b/c")
+  message(SEND_ERROR "if(PATH_EQUAL): '${path}' not equal to 'a/b/c'")
+endif()
+set(path2 "a/b/c")
+if (NOT path PATH_EQUAL path2)
+  message(SEND_ERROR "if(PATH_EQUAL): '${path}' not equal to '${path2}'")
+endif()
+
+set (path "a/b/d/../c")
+if (path PATH_EQUAL "a/b/c")
+  message(SEND_ERROR "if(PATH_EQUAL): '${path}' equal to 'a/b/c'")
+endif()
+set(path2 "a/b/c")
+if ("a/b/d/../c" PATH_EQUAL path2)
+  message(SEND_ERROR "if(PATH_EQUAL): 'a/b/d/../c' equal to '${path2}'")
+endif()
+
+cmake_path(NORMAL_PATH path)
+if (NOT path PATH_EQUAL "a/b/c")
+  message(SEND_ERROR "if(PATH_EQUAL): '${path}' not equal to 'a/b/c'")
+endif()

+ 1 - 0
Tests/RunCMake/CMP0139/CMP0139-OLD-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/CMP0139/CMP0139-OLD-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at CMP0139-OLD.cmake:[0-9]+ \(if\):
+  if given arguments:
+
+    "/path1" "PATH_EQUAL" "/path2"
+
+  Unknown arguments specified
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 5 - 0
Tests/RunCMake/CMP0139/CMP0139-OLD.cmake

@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0139 OLD)
+
+if("/path1" PATH_EQUAL "/path2")
+  message("PATH_EQUAL recognized")
+endif()

+ 1 - 0
Tests/RunCMake/CMP0139/CMP0139-WARN-result.txt

@@ -0,0 +1 @@
+1

+ 19 - 0
Tests/RunCMake/CMP0139/CMP0139-WARN-stderr.txt

@@ -0,0 +1,19 @@
+CMake Warning \(dev\) at CMP0139-WARN.cmake:[0-9]+ \(if\):
+  Policy CMP0139 is not set: The if\(\) command supports path comparisons using
+  PATH_EQUAL operator.  Run "cmake --help-policy CMP0139" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+
+  PATH_EQUAL will be interpreted as an operator when the policy is set to
+  NEW.  Since the policy is not set the OLD behavior will be used.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error at CMP0139-WARN.cmake:[0-9]+ \(if\):
+  if given arguments:
+
+    "/path1" "PATH_EQUAL" "/path2"
+
+  Unknown arguments specified
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/CMP0139/CMP0139-WARN.cmake

@@ -0,0 +1,4 @@
+
+if("/path1" PATH_EQUAL "/path2")
+  message("PATH_EQUAL recognized")
+endif()

+ 3 - 0
Tests/RunCMake/CMP0139/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.2)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 5 - 0
Tests/RunCMake/CMP0139/RunCMakeTest.cmake

@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0139-OLD)
+run_cmake(CMP0139-WARN)
+run_cmake(CMP0139-NEW)

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -150,6 +150,7 @@ endif()
 
 add_RunCMake_test(CMP0132)
 add_RunCMake_test(CMP0135)
+add_RunCMake_test(CMP0139)
 
 # The test for Policy 65 requires the use of the
 # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode