]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
fix: Detect compiler from unresolved symlink with fallback
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 23 Nov 2023 20:46:20 +0000 (21:46 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 23 Nov 2023 21:48:51 +0000 (22:48 +0100)
This is a generalization of the fix in PR #1348 for issue #1347.

src/ccache.cpp
src/ccache.hpp
unittest/test_ccache.cpp

index cc4449239bd707d53c63ed58e37204801203f5be..833c667d30b561bc028ff4996d890dd9546b6f3d 100644 (file)
@@ -243,35 +243,35 @@ init_hash_debug(Context& ctx,
   }
 }
 
-CompilerType
-guess_compiler(std::string_view path)
-{
-  std::string compiler_path(path);
-  const auto name_original =
-    util::to_lowercase(Util::remove_extension(Util::base_name(compiler_path)));
-
 #ifndef _WIN32
+std::string
+follow_symlinks(const fs::path& path)
+{
   // Follow symlinks to the real compiler to learn its name. We're not using
   // util::real_path in order to save some unnecessary stat calls.
+  fs::path p = path;
   while (true) {
-    auto symlink_target = fs::read_symlink(compiler_path);
+    auto symlink_target = fs::read_symlink(p);
     if (!symlink_target) {
       // Not a symlink.
       break;
     }
     if (symlink_target->is_absolute()) {
-      compiler_path = *symlink_target;
+      p = *symlink_target;
     } else {
-      compiler_path =
-        FMT("{}/{}", Util::dir_name(compiler_path), symlink_target->string());
+      p = p.parent_path() / *symlink_target;
     }
   }
+  return p;
+}
 #endif
 
+static CompilerType
+do_guess_compiler(const fs::path& path)
+{
   const auto name =
-    util::to_lowercase(Util::remove_extension(Util::base_name(compiler_path)));
-  if (name.find("clang-cl") != std::string_view::npos
-      || name_original.find("clang-cl") != std::string_view::npos) {
+    util::to_lowercase(path.filename().replace_extension("").string());
+  if (name.find("clang-cl") != std::string_view::npos) {
     return CompilerType::clang_cl;
   } else if (name.find("clang") != std::string_view::npos) {
     return CompilerType::clang;
@@ -289,6 +289,21 @@ guess_compiler(std::string_view path)
   }
 }
 
+CompilerType
+guess_compiler(const fs::path& path)
+{
+  CompilerType type = do_guess_compiler(path);
+#ifdef _WIN32
+  return type;
+#else
+  if (type == CompilerType::other) {
+    return do_guess_compiler(follow_symlinks(path));
+  } else {
+    return type;
+  }
+#endif
+}
+
 static bool
 include_file_too_new(const Context& ctx,
                      const std::string& path,
index c085c02db218cf4e658f4ef36ba8d934b1fea7e8..771031a0ffd1aa13fdd39db1fd4153712e8e4acc 100644 (file)
@@ -53,7 +53,7 @@ void find_compiler(Context& ctx,
                    const FindExecutableFunction& find_executable_function,
                    bool masquerading_as_compiler);
 
-CompilerType guess_compiler(std::string_view path);
+CompilerType guess_compiler(const std::filesystem::path& path);
 
 bool is_ccache_executable(const std::filesystem::path& path);
 
index d2fd04be5b879e2309604a90cdbed60b08527a5a..02c6161cb87955dae30d1baca899e3026c62b0b9 100644 (file)
@@ -21,6 +21,7 @@
 #include "TestUtil.hpp"
 
 #include <util/file.hpp>
+#include <util/filesystem.hpp>
 #include <util/fmtmacros.hpp>
 #include <util/path.hpp>
 #include <util/wincompat.hpp>
@@ -35,6 +36,7 @@
 #  include <unistd.h>
 #endif
 
+namespace fs = util::filesystem;
 using TestUtil::TestContext;
 
 TEST_SUITE_BEGIN("ccache");
@@ -193,14 +195,24 @@ TEST_CASE("guess_compiler")
 #ifndef _WIN32
   SUBCASE("Follow symlink to actual compiler")
   {
-    const auto cwd = util::actual_cwd();
-    util::write_file(FMT("{}/gcc", cwd), "");
-    CHECK(symlink("gcc", FMT("{}/intermediate", cwd).c_str()) == 0);
-    const auto cc = FMT("{}/cc", cwd);
-    CHECK(symlink("intermediate", cc.c_str()) == 0);
+    const auto cwd = fs::path(util::actual_cwd());
+    util::write_file(cwd / "gcc", "");
+    CHECK(fs::create_symlink("gcc", cwd / "intermediate"));
+    const auto cc = cwd / "cc";
+    CHECK(fs::create_symlink("intermediate", cc));
 
     CHECK(guess_compiler(cc) == CompilerType::gcc);
   }
+
+  SUBCASE("Classify clang-cl symlink to clang")
+  {
+    const auto cwd = fs::path(util::actual_cwd());
+    util::write_file(cwd / "clang", "");
+    const auto clang_cl = cwd / "clang-cl";
+    CHECK(fs::create_symlink("clang", clang_cl));
+
+    CHECK(guess_compiler(clang_cl) == CompilerType::clang_cl);
+  }
 #endif
 }