1515#include " clang/AST/Decl.h"
1616#include " clang/AST/DeclGroup.h"
1717#include " clang/AST/Mangle.h"
18+ #include " clang/Basic/Version.h"
19+ #include " clang/Config/config.h"
1820#include " clang/Frontend/CompilerInstance.h"
1921#include " clang/Frontend/TextDiagnosticPrinter.h"
2022#include " clang/Interpreter/Interpreter.h"
23+ #include " clang/Interpreter/RemoteJITUtils.h"
2124#include " clang/Interpreter/Value.h"
2225#include " clang/Sema/Lookup.h"
2326#include " clang/Sema/Sema.h"
27+ #include " llvm/Support/Error.h"
28+ #include " llvm/TargetParser/Host.h"
2429
2530#include " gmock/gmock.h"
2631#include " gtest/gtest.h"
2732
2833using namespace clang ;
2934
35+ llvm::ExitOnError ExitOnError;
36+
3037int Global = 42 ;
3138// JIT reports symbol not found on Windows without the visibility attribute.
3239REPL_EXTERNAL_VISIBILITY int getGlobal () { return Global; }
3340REPL_EXTERNAL_VISIBILITY void setGlobal (int val) { Global = val; }
3441
42+ #ifdef _WIN32
43+ #define STDIN_FILENO 0
44+ #define STDOUT_FILENO 1
45+ #define STDERR_FILENO 2
46+ #endif
47+
3548namespace {
3649
3750class InterpreterTest : public InterpreterTestBase {
@@ -52,6 +65,93 @@ createInterpreter(const Args &ExtraArgs = {},
5265 return cantFail (clang::Interpreter::create (std::move (CI)));
5366}
5467
68+ static std::string getExecutorPath () {
69+ llvm::SmallString<256 > ExecutorPath (llvm::sys::fs::getMainExecutable (
70+ nullptr , reinterpret_cast <void *>(&getExecutorPath)));
71+ llvm::sys::path::remove_filename (ExecutorPath);
72+
73+ llvm::sys::path::remove_filename (ExecutorPath); // Remove "Interpreter"
74+ llvm::sys::path::remove_filename (ExecutorPath); // Remove "unittests"
75+ llvm::sys::path::remove_filename (ExecutorPath); // Remove "clang"
76+ llvm::sys::path::remove_filename (ExecutorPath); // Remove "tools"
77+
78+ llvm::sys::path::append (ExecutorPath, " bin" , " llvm-jitlink-executor" );
79+ return ExecutorPath.str ().str ();
80+ }
81+
82+ static std::string getOrcRuntimePath () {
83+ llvm::SmallString<256 > RuntimePath (llvm::sys::fs::getMainExecutable (
84+ nullptr , reinterpret_cast <void *>(&getOrcRuntimePath)));
85+
86+ llvm::sys::path::remove_filename (RuntimePath);
87+
88+ llvm::sys::path::remove_filename (RuntimePath); // Remove "Interpreter"
89+ llvm::sys::path::remove_filename (RuntimePath); // Remove "unittests"
90+ llvm::sys::path::remove_filename (RuntimePath); // Remove "clang"
91+ llvm::sys::path::remove_filename (RuntimePath); // Remove "tools"
92+
93+ llvm::sys::path::append (RuntimePath, CLANG_INSTALL_LIBDIR_BASENAME, " clang" ,
94+ CLANG_VERSION_MAJOR_STRING, " lib" );
95+
96+ llvm::Triple SystemTriple (llvm::sys::getProcessTriple ());
97+ if (SystemTriple.isOSBinFormatMachO ()) {
98+ llvm::sys::path::append (RuntimePath, " darwin" , " liborc_rt_osx.a" );
99+ } else if (SystemTriple.isOSBinFormatELF ()) {
100+ llvm::sys::path::append (RuntimePath, " x86_64-unknown-linux-gnu" ,
101+ " liborc_rt.a" );
102+ }
103+
104+ return RuntimePath.str ().str ();
105+ }
106+
107+ static std::unique_ptr<Interpreter>
108+ createInterpreterWithRemoteExecution (const Args &ExtraArgs = {},
109+ DiagnosticConsumer *Client = nullptr ) {
110+ Args ClangArgs = {" -Xclang" , " -emit-llvm-only" };
111+ llvm::append_range (ClangArgs, ExtraArgs);
112+ auto CB = clang::IncrementalCompilerBuilder ();
113+ CB.SetCompilerArgs (ClangArgs);
114+ auto CI = cantFail (CB.CreateCpp ());
115+ if (Client)
116+ CI->getDiagnostics ().setClient (Client, /* ShouldOwnClient=*/ false );
117+
118+ std::unique_ptr<llvm::orc::LLJITBuilder> JB;
119+
120+ llvm::Triple SystemTriple (llvm::sys::getProcessTriple ());
121+
122+ if ((SystemTriple.isOSBinFormatELF () || SystemTriple.isOSBinFormatMachO ())) {
123+ std::string OOPExecutor = getExecutorPath ();
124+ std::string OrcRuntimePath = getOrcRuntimePath ();
125+ bool UseSharedMemory = false ;
126+ std::string SlabAllocateSizeString = " " ;
127+ std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
128+ EPC = ExitOnError (launchExecutor (OOPExecutor, UseSharedMemory,
129+ SlabAllocateSizeString,
130+ [=] { // Lambda defined inline
131+ auto redirect = [](int from, int to) {
132+ if (from != to) {
133+ dup2 (from, to);
134+ close (from);
135+ }
136+ };
137+
138+ redirect (0 , STDIN_FILENO);
139+ redirect (1 , STDOUT_FILENO);
140+ redirect (2 , STDERR_FILENO);
141+
142+ setvbuf (stdout, nullptr , _IONBF, 0 );
143+ setvbuf (stderr, nullptr , _IONBF, 0 );
144+ }));
145+ if (EPC) {
146+ CB.SetTargetTriple (EPC->getTargetTriple ().getTriple ());
147+ JB = ExitOnError (clang::Interpreter::createLLJITBuilder (std::move (EPC),
148+ OrcRuntimePath));
149+ }
150+ }
151+
152+ return cantFail (clang::Interpreter::create (std::move (CI), std::move (JB)));
153+ }
154+
55155static size_t DeclsSize (TranslationUnitDecl *PTUDecl) {
56156 return std::distance (PTUDecl->decls ().begin (), PTUDecl->decls ().end ());
57157}
@@ -68,6 +168,23 @@ TEST_F(InterpreterTest, Sanity) {
68168 EXPECT_EQ (1U , DeclsSize (R2.TUPart ));
69169}
70170
171+ TEST_F (InterpreterTest, SanityWithRemoteExecution) {
172+ if (!HostSupportsJIT ())
173+ GTEST_SKIP ();
174+
175+ std::string OrcRuntimePath = getOrcRuntimePath ();
176+
177+ std::unique_ptr<Interpreter> Interp = createInterpreterWithRemoteExecution ();
178+
179+ using PTU = PartialTranslationUnit;
180+
181+ PTU &R1 (cantFail (Interp->Parse (" void g(); void g() {}" )));
182+ EXPECT_EQ (2U , DeclsSize (R1.TUPart ));
183+
184+ PTU &R2 (cantFail (Interp->Parse (" int i;" )));
185+ EXPECT_EQ (1U , DeclsSize (R2.TUPart ));
186+ }
187+
71188static std::string DeclToString (Decl *D) {
72189 return llvm::cast<NamedDecl>(D)->getQualifiedNameAsString ();
73190}
0 commit comments