<div dir="ltr">I tweaked this in r221932 to go back to wchar_t / wstring because of some STL difficulties with MSVC "14".</div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 3, 2014 at 5:29 PM, Michael J. Spencer <span dir="ltr"><<a href="mailto:bigcheesegs@gmail.com" target="_blank">bigcheesegs@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: mspencer<br>
Date: Mon Nov  3 19:29:29 2014<br>
New Revision: 221220<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=221220&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=221220&view=rev</a><br>
Log:<br>
[Support][Program] Add findProgramByName(Name, OptionalPaths)<br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/Support/Program.h<br>
    llvm/trunk/lib/Support/Unix/Program.inc<br>
    llvm/trunk/lib/Support/Windows/Program.inc<br>
<br>
Modified: llvm/trunk/include/llvm/Support/Program.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Program.h?rev=221220&r1=221219&r2=221220&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Program.h?rev=221220&r1=221219&r2=221220&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/Program.h (original)<br>
+++ llvm/trunk/include/llvm/Support/Program.h Mon Nov  3 19:29:29 2014<br>
@@ -15,6 +15,7 @@<br>
 #define LLVM_SUPPORT_PROGRAM_H<br>
<br>
 #include "llvm/ADT/ArrayRef.h"<br>
+#include "llvm/Support/ErrorOr.h"<br>
 #include "llvm/Support/Path.h"<br>
 #include <system_error><br>
<br>
@@ -63,6 +64,23 @@ struct ProcessInfo {<br>
   /// the program could not be found.<br>
   std::string FindProgramByName(const std::string& name);<br>
<br>
+  /// \brief Find the first executable file \p Name in \p Paths.<br>
+  ///<br>
+  /// This does not perform hashing as a shell would but instead stats each PATH<br>
+  /// entry individually so should generally be avoided. Core LLVM library<br>
+  /// functions and options should instead require fully specified paths.<br>
+  ///<br>
+  /// \param Name name of the executable to find. If it contains any system<br>
+  ///   slashes, it will be returned as is.<br>
+  /// \param Paths optional list of paths to search for \p Name. If empty it<br>
+  ///   will use the system PATH environment instead.<br>
+  ///<br>
+  /// \returns The fully qualified path to the first \p Name in \p Paths if it<br>
+  ///   exists. \p Name if \p Name has slashes in it. Otherwise an error.<br>
+  ErrorOr<std::string><br>
+  findProgramByName(StringRef Name,<br>
+                    ArrayRef<StringRef> Paths = ArrayRef<StringRef>());<br>
+<br>
   // These functions change the specified standard stream (stdin or stdout) to<br>
   // binary mode. They return errc::success if the specified stream<br>
   // was changed. Otherwise a platform dependent error is returned.<br>
<br>
Modified: llvm/trunk/lib/Support/Unix/Program.inc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Program.inc?rev=221220&r1=221219&r2=221220&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Program.inc?rev=221220&r1=221219&r2=221220&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Support/Unix/Program.inc (original)<br>
+++ llvm/trunk/lib/Support/Unix/Program.inc Mon Nov  3 19:29:29 2014<br>
@@ -17,6 +17,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "Unix.h"<br>
+#include "llvm/ADT/StringExtras.h"<br>
 #include "llvm/Support/Compiler.h"<br>
 #include "llvm/Support/FileSystem.h"<br>
 #include "llvm/Support/raw_ostream.h"<br>
@@ -100,6 +101,33 @@ sys::FindProgramByName(const std::string<br>
   return "";<br>
 }<br>
<br>
+ErrorOr<std::string> sys::findProgramByName(StringRef Name,<br>
+                                            ArrayRef<StringRef> Paths) {<br>
+  assert(!Name.empty() && "Must have a name!");<br>
+  // Use the given path verbatim if it contains any slashes; this matches<br>
+  // the behavior of sh(1) and friends.<br>
+  if (Name.find('/') != StringRef::npos)<br>
+    return std::string(Name);<br>
+<br>
+  if (Paths.empty()) {<br>
+    SmallVector<StringRef, 16> SearchPaths;<br>
+    SplitString(std::getenv("PATH"), SearchPaths, ":");<br>
+    return findProgramByName(Name, SearchPaths);<br>
+  }<br>
+<br>
+  for (auto Path : Paths) {<br>
+    if (Path.empty())<br>
+      continue;<br>
+<br>
+    // Check to see if this first directory contains the executable...<br>
+    SmallString<128> FilePath(Path);<br>
+    sys::path::append(FilePath, Name);<br>
+    if (sys::fs::can_execute(FilePath.c_str()))<br>
+      return std::string(FilePath.str()); // Found the executable!<br>
+  }<br>
+  return std::errc::no_such_file_or_directory;<br>
+}<br>
+<br>
 static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) {<br>
   if (!Path) // Noop<br>
     return false;<br>
<br>
Modified: llvm/trunk/lib/Support/Windows/Program.inc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Program.inc?rev=221220&r1=221219&r2=221220&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Program.inc?rev=221220&r1=221219&r2=221220&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Support/Windows/Program.inc (original)<br>
+++ llvm/trunk/lib/Support/Windows/Program.inc Mon Nov  3 19:29:29 2014<br>
@@ -12,9 +12,11 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "WindowsSupport.h"<br>
+#include "llvm/ADT/StringExtras.h"<br>
 #include "llvm/Support/ConvertUTF.h"<br>
 #include "llvm/Support/FileSystem.h"<br>
 #include "llvm/Support/raw_ostream.h"<br>
+#include "llvm/Support/WindowsError.h"<br>
 #include <cstdio><br>
 #include <fcntl.h><br>
 #include <io.h><br>
@@ -69,6 +71,68 @@ std::string sys::FindProgramByName(const<br>
   return std::string(result.data(), result.size());<br>
 }<br>
<br>
+ErrorOr<std::string> sys::findProgramByName(StringRef Name,<br>
+                                            ArrayRef<StringRef> Paths) {<br>
+  assert(!Name.empty() && "Must have a name!");<br>
+<br>
+  if (Name.find_first_of("/\\") != StringRef::npos)<br>
+    return std::string(Name);<br>
+<br>
+  const char16_t *Path = nullptr;<br>
+  std::u16string PathStorage;<br>
+  if (!Paths.empty()) {<br>
+    PathStorage.reserve(Paths.size() * MAX_PATH);<br>
+    for (int i = 0; i < Paths.size(); ++i) {<br>
+      if (i)<br>
+        PathStorage.push_back(';');<br>
+      StringRef P = Paths[i];<br>
+      SmallVector<wchar_t, MAX_PATH> TmpPath;<br>
+      if (std::error_code EC = windows::UTF8ToUTF16(P, TmpPath))<br>
+        return EC;<br>
+      PathStorage.append(TmpPath.begin(), TmpPath.end());<br>
+    }<br>
+    Path = PathStorage.c_str();<br>
+  }<br>
+<br>
+  SmallVector<wchar_t, MAX_PATH> U16Name;<br>
+  if (std::error_code EC = windows::UTF8ToUTF16(Name, U16Name))<br>
+    return EC;<br>
+<br>
+  SmallVector<StringRef, 12> PathExts;<br>
+  PathExts.push_back("");<br>
+  SplitString(std::getenv("PATHEXT"), PathExts, ";");<br>
+<br>
+  SmallVector<wchar_t, MAX_PATH> U16Result;<br>
+  DWORD Len = MAX_PATH;<br>
+  for (StringRef Ext : PathExts) {<br>
+    SmallVector<wchar_t, MAX_PATH> U16Ext;<br>
+    if (std::error_code EC = windows::UTF8ToUTF16(Ext, U16Ext))<br>
+      return EC;<br>
+<br>
+    do {<br>
+      U16Result.reserve(Len);<br>
+      Len = ::SearchPathW((const wchar_t *)Path, c_str(U16Name),<br>
+                          U16Ext.empty() ? nullptr : c_str(U16Ext),<br>
+                          U16Result.capacity(), U16Result.data(), nullptr);<br>
+    } while (Len > U16Result.capacity());<br>
+<br>
+    if (Len != 0)<br>
+      break; // Found it.<br>
+  }<br>
+<br>
+  if (Len == 0)<br>
+    return mapWindowsError(::GetLastError());<br>
+<br>
+  U16Result.set_size(Len);<br>
+<br>
+  SmallVector<char, MAX_PATH> U8Result;<br>
+  if (std::error_code EC =<br>
+          windows::UTF16ToUTF8(U16Result.data(), U16Result.size(), U8Result))<br>
+    return EC;<br>
+<br>
+  return std::string(U8Result.begin(), U8Result.end());<br>
+}<br>
+<br>
 static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) {<br>
   HANDLE h;<br>
   if (path == 0) {<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>