[llvm] r184914 - Port GetMainExecutable over to PathV2.

Rafael Espindola rafael.espindola at gmail.com
Tue Jun 25 22:01:35 PDT 2013


Author: rafael
Date: Wed Jun 26 00:01:35 2013
New Revision: 184914

URL: http://llvm.org/viewvc/llvm-project?rev=184914&view=rev
Log:
Port GetMainExecutable over to PathV2.

I will remove the V1 version as soon as I change clang in the next commit.

Modified:
    llvm/trunk/include/llvm/Support/FileSystem.h
    llvm/trunk/lib/Support/Unix/PathV2.inc
    llvm/trunk/lib/Support/Windows/PathV2.inc
    llvm/trunk/tools/bugpoint/ToolRunner.cpp
    llvm/trunk/tools/llvm-config/llvm-config.cpp
    llvm/trunk/unittests/Support/ProgramTest.cpp

Modified: llvm/trunk/include/llvm/Support/FileSystem.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileSystem.h?rev=184914&r1=184913&r2=184914&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileSystem.h (original)
+++ llvm/trunk/include/llvm/Support/FileSystem.h Wed Jun 26 00:01:35 2013
@@ -696,7 +696,10 @@ error_code map_file_pages(const Twine &p
 ///          platform specific error_code.
 error_code unmap_file_pages(void *base, size_t size);
 
-
+/// Return the path to the main executable, given the value of argv[0] from
+/// program startup and the address of main itself. In extremis, this function
+/// may fail and return an empty path.
+std::string getMainExecutable(const char *argv0, void *MainExecAddr);
 
 /// @}
 /// @name Iterators

Modified: llvm/trunk/lib/Support/Unix/PathV2.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/PathV2.inc?rev=184914&r1=184913&r2=184914&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Unix/PathV2.inc (original)
+++ llvm/trunk/lib/Support/Unix/PathV2.inc Wed Jun 26 00:01:35 2013
@@ -109,6 +109,112 @@ namespace {
 namespace llvm {
 namespace sys  {
 namespace fs {
+#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
+    defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \
+    defined(__linux__) || defined(__CYGWIN__)
+static int
+test_dir(char buf[PATH_MAX], char ret[PATH_MAX],
+    const char *dir, const char *bin)
+{
+  struct stat sb;
+
+  snprintf(buf, PATH_MAX, "%s/%s", dir, bin);
+  if (realpath(buf, ret) == NULL)
+    return (1);
+  if (stat(buf, &sb) != 0)
+    return (1);
+
+  return (0);
+}
+
+static char *
+getprogpath(char ret[PATH_MAX], const char *bin)
+{
+  char *pv, *s, *t, buf[PATH_MAX];
+
+  /* First approach: absolute path. */
+  if (bin[0] == '/') {
+    if (test_dir(buf, ret, "/", bin) == 0)
+      return (ret);
+    return (NULL);
+  }
+
+  /* Second approach: relative path. */
+  if (strchr(bin, '/') != NULL) {
+    if (getcwd(buf, PATH_MAX) == NULL)
+      return (NULL);
+    if (test_dir(buf, ret, buf, bin) == 0)
+      return (ret);
+    return (NULL);
+  }
+
+  /* Third approach: $PATH */
+  if ((pv = getenv("PATH")) == NULL)
+    return (NULL);
+  s = pv = strdup(pv);
+  if (pv == NULL)
+    return (NULL);
+  while ((t = strsep(&s, ":")) != NULL) {
+    if (test_dir(buf, ret, t, bin) == 0) {
+      free(pv);
+      return (ret);
+    }
+  }
+  free(pv);
+  return (NULL);
+}
+#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__
+
+/// GetMainExecutable - Return the path to the main executable, given the
+/// value of argv[0] from program startup.
+std::string getMainExecutable(const char *argv0, void *MainAddr) {
+#if defined(__APPLE__)
+  // On OS X the executable path is saved to the stack by dyld. Reading it
+  // from there is much faster than calling dladdr, especially for large
+  // binaries with symbols.
+  char exe_path[MAXPATHLEN];
+  uint32_t size = sizeof(exe_path);
+  if (_NSGetExecutablePath(exe_path, &size) == 0) {
+    char link_path[MAXPATHLEN];
+    if (realpath(exe_path, link_path))
+      return Path(link_path);
+  }
+#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
+      defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__)
+  char exe_path[PATH_MAX];
+
+  if (getprogpath(exe_path, argv0) != NULL)
+    return Path(exe_path);
+#elif defined(__linux__) || defined(__CYGWIN__)
+  char exe_path[MAXPATHLEN];
+  StringRef aPath("/proc/self/exe");
+  if (sys::fs::exists(aPath)) {
+      // /proc is not always mounted under Linux (chroot for example).
+      ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path));
+      if (len >= 0)
+          return StringRef(exe_path, len);
+  } else {
+      // Fall back to the classical detection.
+      if (getprogpath(exe_path, argv0) != NULL)
+          return exe_path;
+  }
+#elif defined(HAVE_DLFCN_H)
+  // Use dladdr to get executable path if available.
+  Dl_info DLInfo;
+  int err = dladdr(MainAddr, &DLInfo);
+  if (err == 0)
+    return Path();
+
+  // If the filename is a symlink, we need to resolve and return the location of
+  // the actual executable.
+  char link_path[MAXPATHLEN];
+  if (realpath(DLInfo.dli_fname, link_path))
+    return Path(link_path);
+#else
+#error GetMainExecutable is not implemented on this host yet.
+#endif
+  return "";
+}
 
 TimeValue file_status::getLastModificationTime() const {
   TimeValue Ret;

Modified: llvm/trunk/lib/Support/Windows/PathV2.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/PathV2.inc?rev=184914&r1=184913&r2=184914&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/PathV2.inc (original)
+++ llvm/trunk/lib/Support/Windows/PathV2.inc Wed Jun 26 00:01:35 2013
@@ -128,6 +128,13 @@ namespace llvm {
 namespace sys  {
 namespace fs {
 
+std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
+  char pathname[MAX_PATH];
+  DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH);
+  return ret != MAX_PATH ? pathname : "";
+}
+
+
 TimeValue file_status::getLastModificationTime() const {
   ULARGE_INTEGER UI;
   UI.LowPart = LastWriteTimeLow;

Modified: llvm/trunk/tools/bugpoint/ToolRunner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/bugpoint/ToolRunner.cpp?rev=184914&r1=184913&r2=184914&view=diff
==============================================================================
--- llvm/trunk/tools/bugpoint/ToolRunner.cpp (original)
+++ llvm/trunk/tools/bugpoint/ToolRunner.cpp Wed Jun 26 00:01:35 2013
@@ -252,8 +252,8 @@ static std::string PrependMainExecutable
   // Check the directory that the calling program is in.  We can do
   // this if ProgramPath contains at least one / character, indicating that it
   // is a relative path to the executable itself.
-  sys::Path Main = sys::Path::GetMainExecutable(Argv0, MainAddr);
-  StringRef Result = sys::path::parent_path(Main.str());
+  std::string Main = sys::fs::getMainExecutable(Argv0, MainAddr);
+  StringRef Result = sys::path::parent_path(Main);
 
   if (!Result.empty()) {
     SmallString<128> Storage = Result;

Modified: llvm/trunk/tools/llvm-config/llvm-config.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-config/llvm-config.cpp?rev=184914&r1=184913&r2=184914&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-config/llvm-config.cpp (original)
+++ llvm/trunk/tools/llvm-config/llvm-config.cpp Wed Jun 26 00:01:35 2013
@@ -162,11 +162,11 @@ Typical components:\n\
 }
 
 /// \brief Compute the path to the main executable.
-llvm::sys::Path GetExecutablePath(const char *Argv0) {
+std::string GetExecutablePath(const char *Argv0) {
   // This just needs to be some symbol in the binary; C++ doesn't
   // allow taking the address of ::main however.
   void *P = (void*) (intptr_t) GetExecutablePath;
-  return llvm::sys::Path::GetMainExecutable(Argv0, P);
+  return llvm::sys::fs::getMainExecutable(Argv0, P);
 }
 
 int main(int argc, char **argv) {
@@ -180,7 +180,7 @@ int main(int argc, char **argv) {
   // tree.
   bool IsInDevelopmentTree;
   enum { MakefileStyle, CMakeStyle, CMakeBuildModeStyle } DevelopmentTreeLayout;
-  llvm::SmallString<256> CurrentPath(GetExecutablePath(argv[0]).str());
+  llvm::SmallString<256> CurrentPath(GetExecutablePath(argv[0]));
   std::string CurrentExecPrefix;
   std::string ActiveObjRoot;
 

Modified: llvm/trunk/unittests/Support/ProgramTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ProgramTest.cpp?rev=184914&r1=184913&r2=184914&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/ProgramTest.cpp (original)
+++ llvm/trunk/unittests/Support/ProgramTest.cpp Wed Jun 26 00:01:35 2013
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/PathV1.h"
 #include "llvm/Support/Program.h"
@@ -56,7 +57,8 @@ TEST(ProgramTest, CreateProcessTrailingS
     exit(1);
   }
 
-  Path my_exe = Path::GetMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+  std::string my_exe =
+      sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
   const char *argv[] = {
     my_exe.c_str(),
     "--gtest_filter=ProgramTest.CreateProcessTrailingSlashChild",
@@ -80,7 +82,7 @@ TEST(ProgramTest, CreateProcessTrailingS
   StringRef nul("/dev/null");
 #endif
   const StringRef *redirects[] = { &nul, &nul, 0 };
-  int rc = ExecuteAndWait(my_exe.str(), argv, &envp[0], redirects,
+  int rc = ExecuteAndWait(my_exe, argv, &envp[0], redirects,
                           /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error,
                           &ExecutionFailed);
   EXPECT_FALSE(ExecutionFailed) << error;





More information about the llvm-commits mailing list