Author: Vassil Vassilev Date: 2026-01-18T18:27:48+01:00 New Revision: f006cd76790e0d7cf34b8c1dbd6be7baf4842158
URL: https://github.com/llvm/llvm-project/commit/f006cd76790e0d7cf34b8c1dbd6be7baf4842158 DIFF: https://github.com/llvm/llvm-project/commit/f006cd76790e0d7cf34b8c1dbd6be7baf4842158.diff LOG: [clang-repl] Skip out-of-process execution due to compiler-rt path mismatch (#176198) 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 Added: Modified: clang/lib/Interpreter/IncrementalExecutor.cpp clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp Removed: ################################################################################ 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..3684e7e8148fa 100644 --- a/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp +++ b/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp @@ -104,84 +104,117 @@ 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(); + + 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 +232,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. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
