Author: Vassil Vassilev
Date: 2026-01-11T16:52:58+02:00
New Revision: f25ddef03618e263c2a545b3a870b592fa9532a7

URL: 
https://github.com/llvm/llvm-project/commit/f25ddef03618e263c2a545b3a870b592fa9532a7
DIFF: 
https://github.com/llvm/llvm-project/commit/f25ddef03618e263c2a545b3a870b592fa9532a7.diff

LOG: [clang-repl] Fix OrcRuntime lookup for Solaris and unit tests. (#175435)

The out-of-process execution in the interpreter depends on the orc
runtime. It is generally easy to discover as it is in the clang runtime
path. However, the clang runtime path is relative to clang's resource
directory which is relative to the clang binary. That does not work well
if clang is linked into a different binary which can be in a random
place in the build directory structure.

This patch performs a conservative approach to detect the common
directory structure and correctly infer the paths. That fixes the
out-of-process execution unittests. The patch also contains a small
adjustment for solaris.

Another take on trying to fix the issue uncovered by #175322.

Added: 
    

Modified: 
    clang/lib/Interpreter/Interpreter.cpp
    clang/tools/clang-repl/ClangRepl.cpp
    clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Interpreter/Interpreter.cpp 
b/clang/lib/Interpreter/Interpreter.cpp
index 763d298b052f2..f69c57fe48001 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -275,16 +275,14 @@ llvm::Error 
IncrementalExecutorBuilder::UpdateOrcRuntimePath(
   if (!IsOutOfProcess)
     return llvm::Error::success();
 
-  // Candidate runtime filenames to look for (tweak as appropriate).
   static constexpr std::array<const char *, 3> OrcRTLibNames = {
       "liborc_rt.a",
       "liborc_rt_osx.a",
       "liborc_rt-x86_64.a",
   };
 
-  // Return the first file found inside 'Base' (Base may be a directory).
   auto findInDir = [&](llvm::StringRef Base) -> std::optional<std::string> {
-    if (Base.empty())
+    if (Base.empty() || !llvm::sys::fs::exists(Base))
       return std::nullopt;
     for (const char *LibName : OrcRTLibNames) {
       llvm::SmallString<256> Candidate(Base);
@@ -296,74 +294,60 @@ llvm::Error 
IncrementalExecutorBuilder::UpdateOrcRuntimePath(
   };
 
   const clang::driver::Driver &D = C.getDriver();
-
+  const clang::driver::ToolChain &TC = C.getDefaultToolChain();
   llvm::SmallVector<std::string, 8> triedPaths;
 
-  // Prefer Driver::ResourceDir-derived locations:
-  // ResourceDir is typically: <prefix>/lib/clang/<version>
-  if (!D.ResourceDir.empty()) {
-    llvm::SmallString<256> Resource(D.ResourceDir);
-
-    // Directly searching ResourceDir is cheap and sometimes sufficient.
-    if (auto F = findInDir(Resource)) {
-      OrcRuntimePath = *F;
-      return llvm::Error::success();
-    }
-    triedPaths.emplace_back(std::string(Resource.str()));
-
-    // Build <prefix>/lib/clang/<version>/lib. Resource already contains
-    // .../clang/<version>)
-    llvm::SmallString<256> ClangLibDir(Resource);
-    // ClangLibDir currently: <prefix>/lib/clang/<version>
-    // We want: <prefix>/lib/clang/<version>/lib
-    llvm::sys::path::append(ClangLibDir, "lib");
-    if (auto F = findInDir(ClangLibDir)) {
-      OrcRuntimePath = *F;
-      return llvm::Error::success();
-    }
-    triedPaths.emplace_back(std::string(ClangLibDir.str()));
-
-    // Walk up to <prefix>/lib and search there and common variants.
-    llvm::SmallString<256> PrefixLib = Resource;
-    llvm::sys::path::remove_filename(PrefixLib); // remove <version>
-    llvm::sys::path::remove_filename(PrefixLib); // remove clang
-    if (!PrefixLib.empty()) {
-      if (auto F = findInDir(PrefixLib)) {
-        OrcRuntimePath = *F;
-        return llvm::Error::success();
+  llvm::SmallString<256> Resource(D.ResourceDir);
+  if (llvm::sys::fs::exists(Resource)) {
+    // Ask the ToolChain for its runtime paths first (most authoritative).
+    for (auto RuntimePath :
+         {TC.getRuntimePath(), std::make_optional(TC.getCompilerRTPath())}) {
+      if (RuntimePath) {
+        if (auto Found = findInDir(*RuntimePath)) {
+          OrcRuntimePath = *Found;
+          return llvm::Error::success();
+        }
+        triedPaths.emplace_back(*RuntimePath);
       }
-      triedPaths.emplace_back(std::string(PrefixLib.str()));
-
-      // Also check <prefix>/<libdir_basename>/clang/<version>/lib if present 
in
-      // this environment. We extract version from the original ResourceDir
-      // filename (the '<version>' component).
-      llvm::SmallString<64> Version =
-          llvm::sys::path::filename(llvm::StringRef(Resource));
-      llvm::SmallString<256> FormalClangLib = PrefixLib;
-      llvm::sys::path::append(FormalClangLib, "lib", "clang", Version, "lib");
-      if (auto F = findInDir(FormalClangLib)) {
+    }
+
+    // Check ResourceDir and ResourceDir/lib
+    for (auto P : {Resource.str().str(), (Resource + "/lib").str()}) {
+      if (auto F = findInDir(P)) {
         OrcRuntimePath = *F;
         return llvm::Error::success();
       }
-      triedPaths.emplace_back(std::string(FormalClangLib.str()));
+      triedPaths.emplace_back(P);
     }
-  }
-
-  // ToolChain runtime/compiler-rt locations (if available).
-  const clang::driver::ToolChain &TC = C.getDefaultToolChain();
-  for (auto RuntimePath :
-       {TC.getRuntimePath(), std::make_optional(TC.getCompilerRTPath())}) {
-    if (RuntimePath && TC.getVFS().exists(*RuntimePath)) {
-      if (auto Found = findInDir(*RuntimePath)) {
-        OrcRuntimePath = *Found;
-        return llvm::Error::success();
-      } else {
-        triedPaths.emplace_back(*RuntimePath);
+  } else {
+    // The binary was misplaced. Generic Backward Search (Climbing the tree)
+    // This allows unit tests in tools/clang/unittests to find the real lib/
+    llvm::SmallString<256> Cursor = Resource;
+    // ResourceDir-derived locations
+    llvm::StringRef Version = llvm::sys::path::filename(Resource);
+    llvm::StringRef OSName = TC.getOSLibName();
+    while (llvm::sys::path::has_parent_path(Cursor)) {
+      Cursor = llvm::sys::path::parent_path(Cursor).str();
+      // At each level, try standard relative layouts
+      for (auto Rel :
+           {(llvm::Twine("lib/clang/") + Version + "/lib/" + OSName).str(),
+            (llvm::Twine("lib/clang/") + Version + "/lib").str(),
+            (llvm::Twine("lib/") + OSName).str(), std::string("lib/clang")}) {
+        llvm::SmallString<256> Candidate = Cursor;
+        llvm::sys::path::append(Candidate, Rel);
+        if (auto F = findInDir(Candidate)) {
+          OrcRuntimePath = *F;
+          return llvm::Error::success();
+        }
+        triedPaths.emplace_back(std::string(Candidate.str()));
       }
+      // Stop if we hit the root or go too far (safety check)
+      if (triedPaths.size() > 32)
+        break;
     }
   }
 
-  // If we reached here, nothing was found. Build a helpful error string.
+  // Build a helpful error string if everything failed.
   std::string Joined;
   for (size_t i = 0; i < triedPaths.size(); ++i) {
     if (i)

diff  --git a/clang/tools/clang-repl/ClangRepl.cpp 
b/clang/tools/clang-repl/ClangRepl.cpp
index e94749555ad1a..95786d688b76e 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -288,6 +288,8 @@ int main(int argc, const char **argv) {
     return 0;
   }
 
+  ExitOnErr(sanitizeOopArguments(argv[0]));
+
   clang::IncrementalCompilerBuilder CB;
   CB.SetCompilerArgs(ClangArgv);
 
@@ -320,8 +322,6 @@ int main(int argc, const char **argv) {
     DeviceCI = ExitOnErr(CB.CreateCudaDevice());
   }
 
-  ExitOnErr(sanitizeOopArguments(argv[0]));
-
   // FIXME: Investigate if we could use runToolOnCodeWithArgs from tooling. It
   // can replace the boilerplate code for creation of the compiler instance.
   std::unique_ptr<clang::CompilerInstance> CI;

diff  --git a/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp 
b/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
index d33005244d8da..225d6c8c66cab 100644
--- a/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
+++ b/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
@@ -102,6 +102,15 @@ static std::string getExecutorPath() {
   return ExecutorPath.str().str();
 }
 
+class OutOfProcessInterpreterTest : public InterpreterTestBase {
+protected:
+  static bool HostSupportsOutOfProcessJIT() {
+    if (!InterpreterTestBase::HostSupportsJIT())
+      return false;
+    return !getExecutorPath().empty();
+  }
+};
+
 struct OutOfProcessInterpreterInfo {
   std::string OrcRuntimePath;
   std::unique_ptr<Interpreter> Interpreter;
@@ -162,8 +171,8 @@ static size_t DeclsSize(TranslationUnitDecl *PTUDecl) {
   return std::distance(PTUDecl->decls().begin(), PTUDecl->decls().end());
 }
 
-TEST_F(InterpreterTestBase, SanityWithRemoteExecution) {
-  if (!HostSupportsJIT())
+TEST_F(OutOfProcessInterpreterTest, SanityWithRemoteExecution) {
+  if (!HostSupportsOutOfProcessJIT())
     GTEST_SKIP();
 
   auto io_ctx = std::make_shared<IOContext>();
@@ -174,11 +183,6 @@ TEST_F(InterpreterTestBase, SanityWithRemoteExecution) {
   Interpreter *Interp = Info.Interpreter.get();
   ASSERT_TRUE(Interp);
 
-  std::string ExecutorPath = getExecutorPath();
-  if (!llvm::sys::fs::exists(Info.OrcRuntimePath) ||
-      !llvm::sys::fs::exists(ExecutorPath))
-    GTEST_SKIP();
-
   using PTU = PartialTranslationUnit;
   PTU &R1(cantFail(Interp->Parse("void g(); void g() {}")));
   EXPECT_EQ(2U, DeclsSize(R1.TUPart));
@@ -192,8 +196,8 @@ TEST_F(InterpreterTestBase, SanityWithRemoteExecution) {
   EXPECT_NE(std::string::npos, captured_stdout.find("CustomizeFork executed"));
 }
 
-TEST_F(InterpreterTestBase, FindRuntimeInterface) {
-  if (!HostSupportsJIT())
+TEST_F(OutOfProcessInterpreterTest, FindRuntimeInterface) {
+  if (!HostSupportsOutOfProcessJIT())
     GTEST_SKIP();
 
   // make a fresh io context for this test


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to