summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/find_program.rst7
-rw-r--r--Help/release/dev/find_program-NAMES_PER_DIR.rst6
-rw-r--r--Source/cmFindLibraryCommand.cxx11
-rw-r--r--Source/cmFindProgramCommand.cxx153
-rw-r--r--Source/cmFindProgramCommand.h10
-rw-r--r--Source/cmSystemTools.cxx9
-rw-r--r--Source/cmSystemTools.h2
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rwxr-xr-xTests/RunCMake/find_program/A/testA1
-rwxr-xr-xTests/RunCMake/find_program/B/testB1
-rw-r--r--Tests/RunCMake/find_program/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/find_program/DirsPerName-stdout.txt1
-rw-r--r--Tests/RunCMake/find_program/DirsPerName.cmake6
-rw-r--r--Tests/RunCMake/find_program/NamesPerDir-stdout.txt1
-rw-r--r--Tests/RunCMake/find_program/NamesPerDir.cmake6
-rw-r--r--Tests/RunCMake/find_program/RunCMakeTest.cmake9
-rwxr-xr-xTests/RunCMake/find_program/Win/testCom.com0
-rwxr-xr-xTests/RunCMake/find_program/Win/testCom.exe0
-rwxr-xr-xTests/RunCMake/find_program/Win/testExe.exe0
-rw-r--r--Tests/RunCMake/find_program/WindowsCom-stdout.txt1
-rw-r--r--Tests/RunCMake/find_program/WindowsCom.cmake6
-rw-r--r--Tests/RunCMake/find_program/WindowsExe-stdout.txt1
-rw-r--r--Tests/RunCMake/find_program/WindowsExe.cmake6
23 files changed, 214 insertions, 27 deletions
diff --git a/Help/command/find_program.rst b/Help/command/find_program.rst
index 2a5ce9a..d3430c0 100644
--- a/Help/command/find_program.rst
+++ b/Help/command/find_program.rst
@@ -2,7 +2,7 @@ find_program
------------
.. |FIND_XXX| replace:: find_program
-.. |NAMES| replace:: NAMES name1 [name2 ...]
+.. |NAMES| replace:: NAMES name1 [name2 ...] [NAMES_PER_DIR]
.. |SEARCH_XXX| replace:: program
.. |SEARCH_XXX_DESC| replace:: program
.. |prefix_XXX_SUBDIR| replace:: ``<prefix>/[s]bin``
@@ -26,3 +26,8 @@ find_program
:variable:`CMAKE_FIND_ROOT_PATH_MODE_PROGRAM`
.. include:: FIND_XXX.txt
+
+When more than one value is given to the ``NAMES`` option this command by
+default will consider one name at a time and search every directory
+for it. The ``NAMES_PER_DIR`` option tells this command to consider one
+directory at a time and search for all names in it.
diff --git a/Help/release/dev/find_program-NAMES_PER_DIR.rst b/Help/release/dev/find_program-NAMES_PER_DIR.rst
new file mode 100644
index 0000000..04cd170
--- /dev/null
+++ b/Help/release/dev/find_program-NAMES_PER_DIR.rst
@@ -0,0 +1,6 @@
+find_program-NAMES_PER_DIR
+--------------------------
+
+* The :command:`find_program` command learned a ``NAMES_PER_DIR``
+ option to consdier all given ``NAMES`` in each directory before
+ moving on to the next directory.
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
index e8d158e..e7696af 100644
--- a/Source/cmFindLibraryCommand.cxx
+++ b/Source/cmFindLibraryCommand.cxx
@@ -203,6 +203,7 @@ struct cmFindLibraryHelper
}
bool HasValidSuffix(std::string const& name);
void AddName(std::string const& name);
+ void SetName(std::string const& name);
bool CheckDirectory(std::string const& path);
bool CheckDirectoryForName(std::string const& path, Name& name);
};
@@ -322,6 +323,13 @@ void cmFindLibraryHelper::AddName(std::string const& name)
}
//----------------------------------------------------------------------------
+void cmFindLibraryHelper::SetName(std::string const& name)
+{
+ this->Names.clear();
+ this->AddName(name);
+}
+
+//----------------------------------------------------------------------------
bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
{
for(std::vector<Name>::iterator i = this->Names.begin();
@@ -459,8 +467,7 @@ std::string cmFindLibraryCommand::FindNormalLibraryDirsPerName()
ni != this->Names.end() ; ++ni)
{
// Switch to searching for this name.
- std::string const& name = *ni;
- helper.AddName(name);
+ helper.SetName(*ni);
// Search every directory.
for(std::vector<std::string>::const_iterator
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index fbd9fd3..e64ed87 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -16,6 +16,80 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
+//----------------------------------------------------------------------------
+struct cmFindProgramHelper
+{
+ cmFindProgramHelper()
+ {
+#if defined (_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+ // Consider platform-specific extensions.
+ this->Extensions.push_back(".com");
+ this->Extensions.push_back(".exe");
+#endif
+ // Consider original name with no extensions.
+ this->Extensions.push_back("");
+ }
+
+ // List of valid extensions.
+ std::vector<std::string> Extensions;
+
+ // Keep track of the best program file found so far.
+ std::string BestPath;
+
+ // Current names under consideration.
+ std::vector<std::string> Names;
+
+ // Current full path under consideration.
+ std::string TestPath;
+
+ void AddName(std::string const& name)
+ {
+ this->Names.push_back(name);
+ }
+ void SetName(std::string const& name)
+ {
+ this->Names.clear();
+ this->AddName(name);
+ }
+ bool CheckDirectory(std::string const& path)
+ {
+ for (std::vector<std::string>::iterator i = this->Names.begin();
+ i != this->Names.end(); ++i)
+ {
+ if (this->CheckDirectoryForName(path, *i))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ bool CheckDirectoryForName(std::string const& path, std::string const& name)
+ {
+ for (std::vector<std::string>::iterator ext = this->Extensions.begin();
+ ext != this->Extensions.end(); ++ext)
+ {
+ this->TestPath = path;
+ this->TestPath += name;
+ if (!ext->empty() && cmSystemTools::StringEndsWith(name, ext->c_str()))
+ {
+ continue;
+ }
+ this->TestPath += *ext;
+ if (cmSystemTools::FileExists(this->TestPath, true))
+ {
+ this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+cmFindProgramCommand::cmFindProgramCommand()
+{
+ this->NamesPerDirAllowed = true;
+}
+
// cmFindProgramCommand
bool cmFindProgramCommand
::InitialPass(std::vector<std::string> const& argsIn, cmExecutionStatus &)
@@ -41,7 +115,7 @@ bool cmFindProgramCommand
return true;
}
- std::string result = FindProgram(this->Names);
+ std::string result = FindProgram();
if(result != "")
{
// Save the value in the cache
@@ -59,31 +133,92 @@ bool cmFindProgramCommand
return true;
}
-std::string cmFindProgramCommand::FindProgram(std::vector<std::string> names)
+std::string cmFindProgramCommand::FindProgram()
{
std::string program = "";
if(this->SearchAppBundleFirst || this->SearchAppBundleOnly)
{
- program = FindAppBundle(names);
+ program = FindAppBundle();
}
if(program.empty() && !this->SearchAppBundleOnly)
{
- program = cmSystemTools::FindProgram(names, this->SearchPaths, true);
+ program = this->FindNormalProgram();
}
if(program.empty() && this->SearchAppBundleLast)
{
- program = this->FindAppBundle(names);
+ program = this->FindAppBundle();
}
return program;
}
-std::string cmFindProgramCommand
-::FindAppBundle(std::vector<std::string> names)
+//----------------------------------------------------------------------------
+std::string cmFindProgramCommand::FindNormalProgram()
+{
+ if(this->NamesPerDir)
+ {
+ return this->FindNormalProgramNamesPerDir();
+ }
+ else
+ {
+ return this->FindNormalProgramDirsPerName();
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string cmFindProgramCommand::FindNormalProgramNamesPerDir()
+{
+ // Search for all names in each directory.
+ cmFindProgramHelper helper;
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end() ; ++ni)
+ {
+ helper.AddName(*ni);
+ }
+ // Search every directory.
+ for (std::vector<std::string>::const_iterator
+ p = this->SearchPaths.begin(); p != this->SearchPaths.end(); ++p)
+ {
+ if(helper.CheckDirectory(*p))
+ {
+ return helper.BestPath;
+ }
+ }
+ // Couldn't find the program.
+ return "";
+}
+
+//----------------------------------------------------------------------------
+std::string cmFindProgramCommand::FindNormalProgramDirsPerName()
+{
+ // Search the entire path for each name.
+ cmFindProgramHelper helper;
+ for (std::vector<std::string>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end() ; ++ni)
+ {
+ // Switch to searching for this name.
+ helper.SetName(*ni);
+
+ // Search every directory.
+ for (std::vector<std::string>::const_iterator
+ p = this->SearchPaths.begin();
+ p != this->SearchPaths.end(); ++p)
+ {
+ if (helper.CheckDirectory(*p))
+ {
+ return helper.BestPath;
+ }
+ }
+ }
+ // Couldn't find the program.
+ return "";
+}
+
+std::string cmFindProgramCommand::FindAppBundle()
{
- for(std::vector<std::string>::const_iterator name = names.begin();
- name != names.end() ; ++name)
+ for(std::vector<std::string>::const_iterator name = this->Names.begin();
+ name != this->Names.end() ; ++name)
{
std::string appName = *name + std::string(".app");
diff --git a/Source/cmFindProgramCommand.h b/Source/cmFindProgramCommand.h
index 70f758f..f88186b 100644
--- a/Source/cmFindProgramCommand.h
+++ b/Source/cmFindProgramCommand.h
@@ -25,6 +25,7 @@
class cmFindProgramCommand : public cmFindBase
{
public:
+ cmFindProgramCommand();
/**
* This is a virtual constructor for the command.
*/
@@ -52,11 +53,12 @@ public:
cmTypeMacro(cmFindProgramCommand, cmFindBase);
-protected:
- std::string FindProgram(std::vector<std::string> names);
-
private:
- std::string FindAppBundle(std::vector<std::string> names);
+ std::string FindProgram();
+ std::string FindNormalProgram();
+ std::string FindNormalProgramDirsPerName();
+ std::string FindNormalProgramNamesPerDir();
+ std::string FindAppBundle();
std::string GetBundleExecutable(std::string bundlePath);
};
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 64eeed6..b1b7f47 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1409,15 +1409,6 @@ std::string cmSystemTools::ConvertToRunCommandPath(const char* path)
#endif
}
-bool cmSystemTools::StringEndsWith(const char* str1, const char* str2)
-{
- if ( !str1 || !str2 || strlen(str1) < strlen(str2) )
- {
- return 0;
- }
- return !strncmp(str1 + (strlen(str1)-strlen(str2)), str2, strlen(str2));
-}
-
// compute the relative path from here to there
std::string cmSystemTools::RelativePath(const char* local, const char* remote)
{
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index c12a1db..d14897f 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -336,8 +336,6 @@ public:
// be used when RunCommand is called from cmake, because the
// running cmake needs paths to be in its format
static std::string ConvertToRunCommandPath(const char* path);
- //! Check if the first string ends with the second one.
- static bool StringEndsWith(const char* str1, const char* str2);
/** compute the relative path from local to remote. local must
be a directory. remote can be a file or a directory.
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 4d96866..241cf90 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -184,6 +184,7 @@ add_RunCMake_test(find_file)
add_RunCMake_test(find_library)
add_RunCMake_test(find_package)
add_RunCMake_test(find_path)
+add_RunCMake_test(find_program -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
add_RunCMake_test(get_filename_component)
add_RunCMake_test(get_property)
add_RunCMake_test(if)
diff --git a/Tests/RunCMake/find_program/A/testA b/Tests/RunCMake/find_program/A/testA
new file mode 100755
index 0000000..1a24852
--- /dev/null
+++ b/Tests/RunCMake/find_program/A/testA
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/Tests/RunCMake/find_program/B/testB b/Tests/RunCMake/find_program/B/testB
new file mode 100755
index 0000000..1a24852
--- /dev/null
+++ b/Tests/RunCMake/find_program/B/testB
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/Tests/RunCMake/find_program/CMakeLists.txt b/Tests/RunCMake/find_program/CMakeLists.txt
new file mode 100644
index 0000000..74b3ff8
--- /dev/null
+++ b/Tests/RunCMake/find_program/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/find_program/DirsPerName-stdout.txt b/Tests/RunCMake/find_program/DirsPerName-stdout.txt
new file mode 100644
index 0000000..f763bb0
--- /dev/null
+++ b/Tests/RunCMake/find_program/DirsPerName-stdout.txt
@@ -0,0 +1 @@
+-- PROG='[^']*/Tests/RunCMake/find_program/B/testB'
diff --git a/Tests/RunCMake/find_program/DirsPerName.cmake b/Tests/RunCMake/find_program/DirsPerName.cmake
new file mode 100644
index 0000000..54db6dd
--- /dev/null
+++ b/Tests/RunCMake/find_program/DirsPerName.cmake
@@ -0,0 +1,6 @@
+find_program(PROG
+ NAMES testB testA
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/A ${CMAKE_CURRENT_SOURCE_DIR}/B
+ NO_DEFAULT_PATH
+ )
+message(STATUS "PROG='${PROG}'")
diff --git a/Tests/RunCMake/find_program/NamesPerDir-stdout.txt b/Tests/RunCMake/find_program/NamesPerDir-stdout.txt
new file mode 100644
index 0000000..964e259
--- /dev/null
+++ b/Tests/RunCMake/find_program/NamesPerDir-stdout.txt
@@ -0,0 +1 @@
+-- PROG='[^']*/Tests/RunCMake/find_program/A/testA'
diff --git a/Tests/RunCMake/find_program/NamesPerDir.cmake b/Tests/RunCMake/find_program/NamesPerDir.cmake
new file mode 100644
index 0000000..49ce49d
--- /dev/null
+++ b/Tests/RunCMake/find_program/NamesPerDir.cmake
@@ -0,0 +1,6 @@
+find_program(PROG
+ NAMES testB testA NAMES_PER_DIR
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/A ${CMAKE_CURRENT_SOURCE_DIR}/B
+ NO_DEFAULT_PATH
+ )
+message(STATUS "PROG='${PROG}'")
diff --git a/Tests/RunCMake/find_program/RunCMakeTest.cmake b/Tests/RunCMake/find_program/RunCMakeTest.cmake
new file mode 100644
index 0000000..2adec11
--- /dev/null
+++ b/Tests/RunCMake/find_program/RunCMakeTest.cmake
@@ -0,0 +1,9 @@
+include(RunCMake)
+
+run_cmake(DirsPerName)
+run_cmake(NamesPerDir)
+
+if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN)$")
+ run_cmake(WindowsCom)
+ run_cmake(WindowsExe)
+endif()
diff --git a/Tests/RunCMake/find_program/Win/testCom.com b/Tests/RunCMake/find_program/Win/testCom.com
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/find_program/Win/testCom.com
diff --git a/Tests/RunCMake/find_program/Win/testCom.exe b/Tests/RunCMake/find_program/Win/testCom.exe
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/find_program/Win/testCom.exe
diff --git a/Tests/RunCMake/find_program/Win/testExe.exe b/Tests/RunCMake/find_program/Win/testExe.exe
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/find_program/Win/testExe.exe
diff --git a/Tests/RunCMake/find_program/WindowsCom-stdout.txt b/Tests/RunCMake/find_program/WindowsCom-stdout.txt
new file mode 100644
index 0000000..e386fce
--- /dev/null
+++ b/Tests/RunCMake/find_program/WindowsCom-stdout.txt
@@ -0,0 +1 @@
+-- PROG='[^']*/Tests/RunCMake/find_program/Win/testCom.com'
diff --git a/Tests/RunCMake/find_program/WindowsCom.cmake b/Tests/RunCMake/find_program/WindowsCom.cmake
new file mode 100644
index 0000000..b32d9e8
--- /dev/null
+++ b/Tests/RunCMake/find_program/WindowsCom.cmake
@@ -0,0 +1,6 @@
+find_program(PROG
+ NAMES testCom
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/Win
+ NO_DEFAULT_PATH
+ )
+message(STATUS "PROG='${PROG}'")
diff --git a/Tests/RunCMake/find_program/WindowsExe-stdout.txt b/Tests/RunCMake/find_program/WindowsExe-stdout.txt
new file mode 100644
index 0000000..bdf48aa
--- /dev/null
+++ b/Tests/RunCMake/find_program/WindowsExe-stdout.txt
@@ -0,0 +1 @@
+-- PROG='[^']*/Tests/RunCMake/find_program/Win/testExe.exe'
diff --git a/Tests/RunCMake/find_program/WindowsExe.cmake b/Tests/RunCMake/find_program/WindowsExe.cmake
new file mode 100644
index 0000000..3a336ec
--- /dev/null
+++ b/Tests/RunCMake/find_program/WindowsExe.cmake
@@ -0,0 +1,6 @@
+find_program(PROG
+ NAMES testExe
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/Win
+ NO_DEFAULT_PATH
+ )
+message(STATUS "PROG='${PROG}'")