[clang] [clang-repl][Solaris] Disable out-of-process execution due to compiler-rt path mismatch (PR #176198)
Vassil Vassilev via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 16 09:21:03 PST 2026
https://github.com/vgvassilev updated https://github.com/llvm/llvm-project/pull/176198
>From 3a674020bb177516f03f50deb625ebf5053de17e Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Thu, 15 Jan 2026 16:30:40 +0000
Subject: [PATCH] [clang-repl] Skip out-of-process execution due to compiler-rt
path mismatch
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On some setups (Solaris), clang-repl attempts to enable out-of-process execution,
but fails to locate the ORC runtime due to a mismatch between the toolchain’s
expected compiler-rt path and the actual on-disk layout.
Specifically, ToolChain::getCompilerRT() relies on getArchNameForCompilerRTLib(),
which returns an architecture name that does not match the Solaris compiler-rt
directory naming. As a result, the ORC runtime (orc_rt) is not detected at the
correct path, even though it exists under lib/clang/<version>/lib/sunos/.
As an initial workaround, special-case Solaris in
getArchNameForCompilerRTLib() to return "sunos", aligning the expected path with
the system layout and preventing clang-repl from attempting out-of-process
execution on Solaris.
Note that compiler-rt libraries on Solaris are suffixed with -<arch> (e.g.
liborc_rt-x86_64.a) to support multilib configurations, which is not yet fully
handled by the current lookup logic. A more complete solution will require
revisiting compiler-rt path resolution for Solaris.
The discussion is available here: https://github.com/llvm/llvm-project/pull/175322
---
clang/lib/Interpreter/IncrementalExecutor.cpp | 6 +-
.../OutOfProcessInterpreterTests.cpp | 144 +++++++++++-------
2 files changed, 91 insertions(+), 59 deletions(-)
diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 71a54dc7d3809..246b844183411 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -501,15 +501,15 @@ llvm::Error IncrementalExecutorBuilder::UpdateOrcRuntimePath(
std::string Joined;
for (size_t i = 0; i < triedPaths.size(); ++i) {
if (i > 0)
- Joined += "\n "; // Use newlines for better readability
+ Joined += "\n ";
Joined += triedPaths[i];
}
return llvm::make_error<llvm::StringError>(
- llvm::formatv("OrcRuntime library not found. Checked:\n {0}",
+ llvm::formatv("OrcRuntime library not found. Checked: {0}",
Joined.empty() ? "<none>" : Joined)
.str(),
- llvm::inconvertibleErrorCode());
+ std::make_error_code(std::errc::no_such_file_or_directory));
}
} // end namespace clang
diff --git a/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp b/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
index 36dd678d4647c..9df089d811265 100644
--- a/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
+++ b/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
@@ -104,84 +104,118 @@ 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> Interp;
};
-static OutOfProcessInterpreterInfo
+static llvm::Expected<OutOfProcessInterpreterInfo>
createInterpreterWithRemoteExecution(std::shared_ptr<IOContext> io_ctx,
const Args &ExtraArgs = {}) {
Args ClangArgs = {"-Xclang", "-emit-llvm-only"};
llvm::append_range(ClangArgs, ExtraArgs);
auto Config = std::make_unique<IncrementalExecutorBuilder>();
- llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
-
- if (SystemTriple.isOSBinFormatELF() || SystemTriple.isOSBinFormatMachO()) {
- Config->IsOutOfProcess = true;
- Config->OOPExecutor = getExecutorPath();
- Config->UseSharedMemory = false;
- Config->SlabAllocateSize = 0;
-
- // Capture the raw file descriptors by value explicitly. This lambda will
- // be invoked in the child process after fork(), so capturing the fd ints is
- // safe and avoids capturing FILE* pointers or outer 'this'.
- int stdin_fd = fileno(io_ctx->stdin_file.get());
- int stdout_fd = fileno(io_ctx->stdout_file.get());
- int stderr_fd = fileno(io_ctx->stderr_file.get());
-
- Config->CustomizeFork = [stdin_fd, stdout_fd, stderr_fd]() {
- auto redirect = [](int from, int to) {
- if (from != to) {
- dup2(from, to);
- close(from);
- }
- };
-
- redirect(stdin_fd, STDIN_FILENO);
- redirect(stdout_fd, STDOUT_FILENO);
- redirect(stderr_fd, STDERR_FILENO);
-
- // Unbuffer the stdio in the child; useful for deterministic tests.
- setvbuf(stdout, nullptr, _IONBF, 0);
- setvbuf(stderr, nullptr, _IONBF, 0);
-
- // Helpful marker for the unit-test to assert that fork customization ran.
- printf("CustomizeFork executed\n");
- fflush(stdout);
+
+ Config->IsOutOfProcess = true;
+ Config->OOPExecutor = getExecutorPath();
+ Config->UseSharedMemory = false;
+ Config->SlabAllocateSize = 0;
+
+ // Capture the raw file descriptors by value explicitly. This lambda will
+ // be invoked in the child process after fork(), so capturing the fd ints is
+ // safe and avoids capturing FILE* pointers or outer 'this'.
+ int stdin_fd = fileno(io_ctx->stdin_file.get());
+ int stdout_fd = fileno(io_ctx->stdout_file.get());
+ int stderr_fd = fileno(io_ctx->stderr_file.get());
+
+ Config->CustomizeFork = [stdin_fd, stdout_fd, stderr_fd]() {
+ auto redirect = [](int from, int to) {
+ if (from != to) {
+ dup2(from, to);
+ close(from);
+ }
};
- }
+
+ redirect(stdin_fd, STDIN_FILENO);
+ redirect(stdout_fd, STDOUT_FILENO);
+ redirect(stderr_fd, STDERR_FILENO);
+
+ // Unbuffer the stdio in the child; useful for deterministic tests.
+ setvbuf(stdout, nullptr, _IONBF, 0);
+ setvbuf(stderr, nullptr, _IONBF, 0);
+
+ // Helpful marker for the unit-test to assert that fork customization ran.
+ printf("CustomizeFork executed\n");
+ fflush(stdout);
+ };
auto CB = IncrementalCompilerBuilder();
CB.SetCompilerArgs(ClangArgs);
CB.SetDriverCompilationCallback(Config->UpdateOrcRuntimePathCB);
- auto CI = cantFail(CB.CreateCpp());
- return {Config->OrcRuntimePath,
- cantFail(Interpreter::create(std::move(CI), std::move(Config)))};
+
+ auto CIOrErr = CB.CreateCpp();
+ if (!CIOrErr)
+ return CIOrErr.takeError();
+
+ OutOfProcessInterpreterInfo Info;
+ Info.OrcRuntimePath = Config->OrcRuntimePath;
+
+ auto InterpOrErr =
+ Interpreter::create(std::move(*CIOrErr), std::move(Config));
+ if (!InterpOrErr)
+ return InterpOrErr.takeError();
+
+ printf("orc: %s\n", Info.OrcRuntimePath.c_str());
+ Info.Interp = std::move(*InterpOrErr);
+ return Info;
}
+class OutOfProcessInterpreterTest : public InterpreterTestBase {
+protected:
+ static bool HostSupportsOutOfProcessJIT() {
+ if (!InterpreterTestBase::HostSupportsJIT())
+ return false;
+
+ llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
+ if (!SystemTriple.isOSBinFormatELF() && !SystemTriple.isOSBinFormatMachO())
+ return false;
+
+ return !getExecutorPath().empty();
+ }
+
+ static void SetUpTestSuite() {
+ if (!HostSupportsOutOfProcessJIT())
+ GTEST_SKIP() << "Host does not support out-of-process JIT";
+
+ auto io_ctx = std::make_shared<IOContext>();
+ if (!io_ctx->initializeTempFiles())
+ GTEST_SKIP() << "Cannot initialize temporary files";
+
+ auto ErrOrI = createInterpreterWithRemoteExecution(io_ctx);
+ if (!ErrOrI) {
+ consumeError(llvm::handleErrors(
+ ErrOrI.takeError(), [](const llvm::StringError &SE) {
+ // check for your specific error code
+ if (SE.convertToErrorCode() ==
+ std::errc::no_such_file_or_directory) {
+ // skip the test
+ GTEST_SKIP() << "File not found: " << SE.getMessage();
+ }
+ }));
+ }
+ }
+};
+
static size_t DeclsSize(TranslationUnitDecl *PTUDecl) {
return std::distance(PTUDecl->decls().begin(), PTUDecl->decls().end());
}
TEST_F(OutOfProcessInterpreterTest, SanityWithRemoteExecution) {
- if (!HostSupportsOutOfProcessJIT())
- GTEST_SKIP();
-
auto io_ctx = std::make_shared<IOContext>();
ASSERT_TRUE(io_ctx->initializeTempFiles());
OutOfProcessInterpreterInfo Info =
- createInterpreterWithRemoteExecution(io_ctx);
+ cantFail(createInterpreterWithRemoteExecution(io_ctx));
Interpreter *Interp = Info.Interp.get();
ASSERT_TRUE(Interp);
@@ -199,14 +233,12 @@ TEST_F(OutOfProcessInterpreterTest, SanityWithRemoteExecution) {
}
TEST_F(OutOfProcessInterpreterTest, FindRuntimeInterface) {
- if (!HostSupportsOutOfProcessJIT())
- GTEST_SKIP();
-
// make a fresh io context for this test
auto io_ctx = std::make_shared<IOContext>();
ASSERT_TRUE(io_ctx->initializeTempFiles());
- OutOfProcessInterpreterInfo I = createInterpreterWithRemoteExecution(io_ctx);
+ OutOfProcessInterpreterInfo I =
+ cantFail(createInterpreterWithRemoteExecution(io_ctx));
ASSERT_TRUE(I.Interp);
// FIXME: Not yet supported.
More information about the cfe-commits
mailing list