summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Support/FileSystem.h5
-rw-r--r--lib/Support/Unix/PathV2.inc106
-rw-r--r--lib/Support/Windows/PathV2.inc7
-rw-r--r--tools/bugpoint/ToolRunner.cpp4
-rw-r--r--tools/llvm-config/llvm-config.cpp6
-rw-r--r--unittests/Support/ProgramTest.cpp6
6 files changed, 126 insertions, 8 deletions
diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h
index 5c514dc95c..699bf4b391 100644
--- a/include/llvm/Support/FileSystem.h
+++ b/include/llvm/Support/FileSystem.h
@@ -696,7 +696,10 @@ error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
/// 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
diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc
index f5903f1530..c7a1c92d46 100644
--- a/lib/Support/Unix/PathV2.inc
+++ b/lib/Support/Unix/PathV2.inc
@@ -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;
diff --git a/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc
index 0c12bb440e..6987e5fc9d 100644
--- a/lib/Support/Windows/PathV2.inc
+++ b/lib/Support/Windows/PathV2.inc
@@ -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;
diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp
index 4e6f6e27cc..9cc5f9a7e6 100644
--- a/tools/bugpoint/ToolRunner.cpp
+++ b/tools/bugpoint/ToolRunner.cpp
@@ -252,8 +252,8 @@ static std::string PrependMainExecutablePath(const std::string &ExeName,
// 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;
diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp
index 5151d1a091..fc3ab68f7d 100644
--- a/tools/llvm-config/llvm-config.cpp
+++ b/tools/llvm-config/llvm-config.cpp
@@ -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;
diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp
index 1cf53d50b0..7886761c9a 100644
--- a/unittests/Support/ProgramTest.cpp
+++ b/unittests/Support/ProgramTest.cpp
@@ -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, CreateProcessTrailingSlash) {
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, CreateProcessTrailingSlash) {
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;