Merge topic 'find_program-conditional-cwd'

c76c1ea208 find_program: Consider CWD only for paths with separator

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2120
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index 13a18e2..db34077 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -34,6 +34,9 @@
   // Current names under consideration.
   std::vector<std::string> Names;
 
+  // Current name with extension under consideration.
+  std::string TestNameExt;
+
   // Current full path under consideration.
   std::string TestPath;
 
@@ -43,6 +46,19 @@
     this->Names.clear();
     this->AddName(name);
   }
+  bool CheckCompoundNames()
+  {
+    for (std::string const& n : this->Names) {
+      // Only perform search relative to current directory if the file name
+      // contains a directory separator.
+      if (n.find('/') != std::string::npos) {
+        if (this->CheckDirectoryForName("", n)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
   bool CheckDirectory(std::string const& path)
   {
     for (std::string const& n : this->Names) {
@@ -55,14 +71,16 @@
   bool CheckDirectoryForName(std::string const& path, std::string const& name)
   {
     for (std::string const& ext : this->Extensions) {
-      this->TestPath = path;
-      this->TestPath += name;
       if (!ext.empty() && cmSystemTools::StringEndsWith(name, ext.c_str())) {
         continue;
       }
-      this->TestPath += ext;
+      this->TestNameExt = name;
+      this->TestNameExt += ext;
+      this->TestPath =
+        cmSystemTools::CollapseCombinedPath(path, this->TestNameExt);
+
       if (cmSystemTools::FileExists(this->TestPath, true)) {
-        this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
+        this->BestPath = this->TestPath;
         return true;
       }
     }
@@ -145,8 +163,8 @@
     helper.AddName(n);
   }
 
-  // Check for the names themselves (e.g. absolute paths).
-  if (helper.CheckDirectory(std::string())) {
+  // Check for the names themselves if they contain a directory separator.
+  if (helper.CheckCompoundNames()) {
     return helper.BestPath;
   }
 
@@ -168,8 +186,8 @@
     // Switch to searching for this name.
     helper.SetName(n);
 
-    // Check for the name by itself (e.g. an absolute path).
-    if (helper.CheckDirectory(std::string())) {
+    // Check for the names themselves if they contain a directory separator.
+    if (helper.CheckCompoundNames()) {
       return helper.BestPath;
     }
 
diff --git a/Tests/RunCMake/find_program/RelAndAbsPath-stdout.txt b/Tests/RunCMake/find_program/RelAndAbsPath-stdout.txt
new file mode 100644
index 0000000..cb3c99f
--- /dev/null
+++ b/Tests/RunCMake/find_program/RelAndAbsPath-stdout.txt
@@ -0,0 +1,6 @@
+-- PROG_ABS='PROG_ABS-NOTFOUND'
+-- PROG_ABS_NPD='PROG_ABS_NPD-NOTFOUND'
+-- PROG_CWD='PROG_CWD-NOTFOUND'
+-- PROG_CWD_NPD='PROG_CWD_NPD-NOTFOUND'
+-- PROG_CWD_DOT='[^']*/Tests/RunCMake/find_program/testCWD'
+-- PROG_CWD_DOT_NPD='[^']*/Tests/RunCMake/find_program/testCWD'
diff --git a/Tests/RunCMake/find_program/RelAndAbsPath.cmake b/Tests/RunCMake/find_program/RelAndAbsPath.cmake
new file mode 100644
index 0000000..9a42c5e
--- /dev/null
+++ b/Tests/RunCMake/find_program/RelAndAbsPath.cmake
@@ -0,0 +1,63 @@
+# testNoSuchFile should only be found if the file absolute path is
+# incorrectly prepended with the search path.
+
+function(strip_windows_path_prefix p outvar)
+    if(CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
+        string(REGEX REPLACE "^.:" "" p "${p}")
+    endif()
+    set(${outvar} "${p}" PARENT_SCOPE)
+endfunction()
+
+strip_windows_path_prefix("${CMAKE_CURRENT_SOURCE_DIR}" srcdir)
+
+file(MAKE_DIRECTORY "tmp${srcdir}")
+configure_file(testCWD "tmp${srcdir}/testNoSuchFile" COPYONLY)
+
+find_program(PROG_ABS
+  NAMES "${srcdir}/testNoSuchFile"
+  PATHS "${CMAKE_CURRENT_BINARY_DIR}/tmp"
+  NO_DEFAULT_PATH
+  )
+message(STATUS "PROG_ABS='${PROG_ABS}'")
+
+find_program(PROG_ABS_NPD
+  NAMES "${srcdir}/testNoSuchFile"
+  PATHS "${CMAKE_CURRENT_BINARY_DIR}/tmp"
+  NAMES_PER_DIR
+  NO_DEFAULT_PATH
+  )
+message(STATUS "PROG_ABS_NPD='${PROG_ABS_NPD}'")
+
+# ./testCWD should not be found without '.' being in the path list.
+
+configure_file(testCWD testCWD COPYONLY)
+
+find_program(PROG_CWD
+  NAMES testCWD
+  NO_DEFAULT_PATH
+  )
+message(STATUS "PROG_CWD='${PROG_CWD}'")
+
+find_program(PROG_CWD_NPD
+  NAMES testCWD
+  NAMES_PER_DIR
+  NO_DEFAULT_PATH
+  )
+message(STATUS "PROG_CWD_NPD='${PROG_CWD_NPD}'")
+
+# Confirm that adding '.' to path does locate ./testCWD.
+
+find_program(PROG_CWD_DOT
+  NAMES testCWD
+  PATHS .
+  NO_DEFAULT_PATH
+  )
+message(STATUS "PROG_CWD_DOT='${PROG_CWD_DOT}'")
+
+find_program(PROG_CWD_DOT_NPD
+  NAMES testCWD
+  PATHS .
+  NAMES_PER_DIR
+  NO_DEFAULT_PATH
+  )
+message(STATUS "PROG_CWD_DOT_NPD='${PROG_CWD_DOT_NPD}'")
diff --git a/Tests/RunCMake/find_program/RunCMakeTest.cmake b/Tests/RunCMake/find_program/RunCMakeTest.cmake
index 89307c1..6903f05 100644
--- a/Tests/RunCMake/find_program/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_program/RunCMakeTest.cmake
@@ -3,6 +3,7 @@
 run_cmake(EnvAndHints)
 run_cmake(DirsPerName)
 run_cmake(NamesPerDir)
+run_cmake(RelAndAbsPath)
 
 if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN)$")
   run_cmake(WindowsCom)
diff --git a/Tests/RunCMake/find_program/testCWD b/Tests/RunCMake/find_program/testCWD
new file mode 100755
index 0000000..1a24852
--- /dev/null
+++ b/Tests/RunCMake/find_program/testCWD
@@ -0,0 +1 @@
+#!/bin/sh