From fc1990c93384d1d2122cd4e11398a8197b006504 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 1 Sep 2015 13:54:33 -0400 Subject: [PATCH] cmFindProgramCommand: Re-implement search using more flexible approach Avoid using KWSys SystemTools::FindProgram because it does much more than we actually need for find_program and does not allow us to control the order of preference between directories and names. Create our own cmFindProgramHelper much like cmFindLibraryHelper but without all the find_library-specific parts. --- Source/cmFindProgramCommand.cxx | 97 ++++++++++++++++++++++++++++++++- Source/cmFindProgramCommand.h | 1 + 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index ef1c16bc1..c9bc56ded 100644 --- a/Source/cmFindProgramCommand.cxx +++ b/Source/cmFindProgramCommand.cxx @@ -16,6 +16,75 @@ #include #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 Extensions; + + // Keep track of the best program file found so far. + std::string BestPath; + + // Current names under consideration. + std::vector 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::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::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 bool cmFindProgramCommand ::InitialPass(std::vector const& argsIn, cmExecutionStatus &) @@ -69,7 +138,7 @@ std::string cmFindProgramCommand::FindProgram() } if(program.empty() && !this->SearchAppBundleOnly) { - program = cmSystemTools::FindProgram(this->Names, this->SearchPaths, true); + program = this->FindNormalProgram(); } if(program.empty() && this->SearchAppBundleLast) @@ -79,6 +148,32 @@ std::string cmFindProgramCommand::FindProgram() return program; } +//---------------------------------------------------------------------------- +std::string cmFindProgramCommand::FindNormalProgram() +{ + // Search the entire path for each name. + cmFindProgramHelper helper; + for (std::vector::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::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::const_iterator name = this->Names.begin(); diff --git a/Source/cmFindProgramCommand.h b/Source/cmFindProgramCommand.h index 2881aac3e..df39b14bd 100644 --- a/Source/cmFindProgramCommand.h +++ b/Source/cmFindProgramCommand.h @@ -54,6 +54,7 @@ public: private: std::string FindProgram(); + std::string FindNormalProgram(); std::string FindAppBundle(); std::string GetBundleExecutable(std::string bundlePath);