Hi rnk,

This solves the problem of fallback onto the same binary if clang-cl has been 
renamed to cl.exe and put on the path, as happens with the VS integration.

http://llvm-reviews.chandlerc.com/D1731

Files:
  lib/Driver/Tools.cpp

Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -31,6 +31,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/raw_ostream.h"
@@ -6655,6 +6656,39 @@
   C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput));
 }
 
+// Try to find FallbackName on PATH that is not identical to ClangProgramPath.
+// If one cannot be found, return FallbackName.
+// We do this special search to prevent clang-cl from falling back onto itself
+// if it's available as cl.exe on the path.
+static std::string FindFallback(const char *FallbackName,
+                                const char *ClangProgramPath) {
+  llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
+  if (!OptPath.hasValue())
+    return FallbackName;
+  const char *Path = OptPath->c_str();
+  const char *PathEnd = Path + OptPath->length();
+
+#ifdef LLVM_ON_WIN32
+  const char SepChar = ';';
+#else
+  const char SepChar = ':';
+#endif
+
+  while (Path != PathEnd) {
+    const char *Sep = std::find(Path, PathEnd, SepChar);
+    SmallString<128> FilePath(Path, Sep);
+    llvm::sys::path::append(FilePath, FallbackName);
+    if (llvm::sys::fs::can_execute(Twine(FilePath)) &&
+        !llvm::sys::fs::equivalent(Twine(FilePath), ClangProgramPath))
+      return FilePath.str();
+
+    Path = Sep;
+    while (*Path == SepChar)
+      ++Path;
+  }
+  return FallbackName;
+}
+
 Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
                                            const InputInfo &Output,
                                            const InputInfoList &Inputs,
@@ -6707,9 +6741,8 @@
                                       Output.getFilename());
   CmdArgs.push_back(Fo);
 
-  // FIXME: If we've put clang-cl as cl.exe on the path, we have a problem.
-  const char *Exec =
-    Args.MakeArgString(getToolChain().GetProgramPath("cl.exe"));
+  const Driver &D = getToolChain().getDriver();
+  std::string Exec = FindFallback("cl.exe", D.getClangProgramPath());
 
-  return new Command(JA, *this, Exec, CmdArgs);
+  return new Command(JA, *this, Args.MakeArgString(Exec), CmdArgs);
 }
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -31,6 +31,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/raw_ostream.h"
@@ -6655,6 +6656,39 @@
   C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput));
 }
 
+// Try to find FallbackName on PATH that is not identical to ClangProgramPath.
+// If one cannot be found, return FallbackName.
+// We do this special search to prevent clang-cl from falling back onto itself
+// if it's available as cl.exe on the path.
+static std::string FindFallback(const char *FallbackName,
+                                const char *ClangProgramPath) {
+  llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
+  if (!OptPath.hasValue())
+    return FallbackName;
+  const char *Path = OptPath->c_str();
+  const char *PathEnd = Path + OptPath->length();
+
+#ifdef LLVM_ON_WIN32
+  const char SepChar = ';';
+#else
+  const char SepChar = ':';
+#endif
+
+  while (Path != PathEnd) {
+    const char *Sep = std::find(Path, PathEnd, SepChar);
+    SmallString<128> FilePath(Path, Sep);
+    llvm::sys::path::append(FilePath, FallbackName);
+    if (llvm::sys::fs::can_execute(Twine(FilePath)) &&
+        !llvm::sys::fs::equivalent(Twine(FilePath), ClangProgramPath))
+      return FilePath.str();
+
+    Path = Sep;
+    while (*Path == SepChar)
+      ++Path;
+  }
+  return FallbackName;
+}
+
 Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
                                            const InputInfo &Output,
                                            const InputInfoList &Inputs,
@@ -6707,9 +6741,8 @@
                                       Output.getFilename());
   CmdArgs.push_back(Fo);
 
-  // FIXME: If we've put clang-cl as cl.exe on the path, we have a problem.
-  const char *Exec =
-    Args.MakeArgString(getToolChain().GetProgramPath("cl.exe"));
+  const Driver &D = getToolChain().getDriver();
+  std::string Exec = FindFallback("cl.exe", D.getClangProgramPath());
 
-  return new Command(JA, *this, Exec, CmdArgs);
+  return new Command(JA, *this, Args.MakeArgString(Exec), CmdArgs);
 }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to