]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
fix: Use OS-specific methods to reliably find the ccache executable path
authorJoel Rosdahl <joel@rosdahl.net>
Sun, 8 Mar 2026 12:19:11 +0000 (13:19 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Sun, 8 Mar 2026 12:19:11 +0000 (13:19 +0100)
argv[0] is not guaranteed to reflect the actual location of the
executable (e.g. when invoked via a symlink). Use platform-specific APIs
instead. Fall back to the argv[0]-based approach if the OS method fails.

src/ccache/ccache.cpp
src/ccache/util/process.cpp
src/ccache/util/process.hpp

index 138f3e0f709b901108f2e310bb426d322cc2d115..2cf4a3cf8159aad47d06b67d3aae15545fcbe56b 100644 (file)
@@ -2805,14 +2805,20 @@ cache_compilation(int argc, const char* const* argv)
   }
 
   {
-    fs::path argv0 =
+    const auto exe_path = util::get_executable_path();
+    fs::path ccache_exe_dir;
+    if (!exe_path.empty()) {
+      ccache_exe_dir = exe_path.parent_path();
+    } else {
+      fs::path argv0 =
 #ifdef _WIN32
-      util::add_exe_suffix(argv[0]);
+        util::add_exe_suffix(argv[0]);
 #else
-      argv[0];
+        argv[0];
 #endif
-    const auto ccache_exe_dir =
-      fs::canonical(argv0).value_or(argv0).parent_path();
+      ccache_exe_dir = fs::canonical(argv0).value_or(argv0).parent_path();
+    }
+
     Context ctx(ccache_exe_dir);
     ctx.initialize(std::move(argv_parts.compiler_and_args),
                    argv_parts.config_settings);
index 065cce6259a6bbe0e2c78129eb9ddd95128d8acf..1ffcdb669035c9ee19ac80ac0ef8842e42e6a2b2 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2023-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2023-2026 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
 
 #include "process.hpp"
 
+#include <ccache/util/filesystem.hpp>
 #include <ccache/util/wincompat.hpp>
 
-#include <cstring>
-
-#ifdef HAVE_UNISTD_H
+#ifdef _WIN32
+#  include <windows.h>
+#else
 #  include <unistd.h>
+#  ifdef __APPLE__
+#    include <mach-o/dyld.h>
+#  endif
 #endif
 
+#include <climits>
+#include <cstring>
+#include <vector>
+
+namespace fs = util::filesystem;
+
 namespace {
 
 // Process umask, read and written by get_umask and set_umask.
@@ -39,6 +49,43 @@ mode_t g_umask = [] {
 
 namespace util {
 
+fs::path
+get_executable_path()
+{
+#ifdef _WIN32
+  std::vector<wchar_t> buf(MAX_PATH);
+  while (true) {
+    DWORD len =
+      GetModuleFileNameW(nullptr, buf.data(), static_cast<DWORD>(buf.size()));
+    if (len == 0) {
+      return {};
+    }
+    if (len < static_cast<DWORD>(buf.size())) {
+      return fs::path(std::wstring(buf.data(), len));
+    }
+    buf.resize(buf.size() * 2);
+  }
+#elif defined(__APPLE__)
+  uint32_t size = PATH_MAX;
+  std::vector<char> buf(size);
+  if (_NSGetExecutablePath(buf.data(), &size) != 0) {
+    buf.resize(size);
+    if (_NSGetExecutablePath(buf.data(), &size) != 0) {
+      return {};
+    }
+  }
+  return fs::path(buf.data());
+#else
+  char buf[PATH_MAX];
+  ssize_t len = readlink("/proc/self/exe", buf, PATH_MAX - 1);
+  if (len < 0) {
+    return {};
+  }
+  buf[len] = '\0';
+  return fs::path(buf);
+#endif
+}
+
 const char*
 get_hostname()
 {
index 2d0acba126cf92eab63a285575e63dfc7723e71d..cc169ac33bf2be0aaf9f4d0d1c6e361770a1352b 100644 (file)
 
 #include <sys/stat.h>
 
+#include <filesystem>
+
 namespace util {
 
+// Return the absolute path to the current executable using OS-specific methods.
+// Returns an empty path on failure.
+std::filesystem::path get_executable_path();
+
 // Return a static string with the current hostname.
 const char* get_hostname();