Skip to content
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/actions/Build_LLVM/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ runs:
git apply -v ../patches/llvm/clang${{ matrix.clang-runtime }}-*.patch
echo "Apply clang${{ matrix.clang-runtime }}-*.patch patches:"
fi
if [[ "${{ matrix.oop-jit }}" == "On" ]]; then
git apply -v ../patches/llvm/clang20-1-out-of-process-jit-execution.patch
echo "Apply out-of-process-jit-execution.patch:"
fi
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should apply this patch regardless of whether matrix.oop-jit=on. If you only apply it if CPPINTEROP_WITH_OOP_JIT=ON , this would imply if you apply the patch, DCPPINTEROP_WITH_OOP_JIT=OFF, then somehow something will go wrong.

Also, why are we not applying this patch on Windows, and testing CPPINTEROP_WITH_OOP_JIT=ON/OFF?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. The thing is, I would want CppInterOp to be compatible with upstream LLVM as well as the patched LLVM. Therefore, I was thinking about having 2 different CI workflows for version 20 with OOP-JIT and without OOP-JIT.
OOP-JIT is not supported on Windows.


Ideally, this is temporary till the patch is directly merged into LLVM and a new version is released.

Copy link
Collaborator

@mcbarton mcbarton Jun 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong, and @vgvassilev can correct me if I am wrong, but for such large patches, we have had them merged into llvm first, before applying them to previous versions in CppInterOp.

You could have a new llvm cache like you want. One where you build OOP-JIT and without OOP-JIT. This could only really be done after I find a way to make space in the cache, since we currently are unlikely to have enough space for all these new llvm cache builds. I have an idea on how to free up some space, and just need to find some time to do. I will try and do it tomorrow, as I am busy today.

cd build
cmake -DLLVM_ENABLE_PROJECTS="${{ matrix.llvm_enable_projects}}" \
-DLLVM_TARGETS_TO_BUILD="${{ matrix.llvm_targets_to_build }}" \
Expand All @@ -64,6 +68,10 @@ runs:
-DLLVM_INCLUDE_TESTS=OFF \
../llvm
ninja clang clangInterpreter clangStaticAnalyzerCore -j ${{ env.ncpus }}
if [[ "${{ matrix.oop-jit }}" == "On" ]]; then
if [ "${{ matrix.os }}}" = "macos"* ]; then SUFFIX="_osx"; fi
ninja clang_repl llvm-jitlink-executor orc_rt${SUFFIX} -j ${{ env.ncpus }}
fi
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have target name for orc_rt difference for MacOS? The target name should be independent of the system your building on.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is different in LLVM itself. I guess it might have to do with cross-compiling.

cd ./tools/
rm -rf $(find . -maxdepth 1 ! -name "clang" ! -name ".")
cd ..
Expand Down
17 changes: 9 additions & 8 deletions .github/actions/Build_and_Test_CppInterOp/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ runs:
../
else
cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DCPPINTEROP_INCLUDE_DOCS=${{ matrix.documentation }} \
-DLLVM_DIR=$LLVM_BUILD_DIR/lib/cmake/llvm \
-DClang_DIR=$LLVM_BUILD_DIR/lib/cmake/clang \
-DBUILD_SHARED_LIBS=ON \
-DCODE_COVERAGE=${{ env.CODE_COVERAGE }} \
-DCMAKE_INSTALL_PREFIX=$CPPINTEROP_DIR \
-DLLVM_ENABLE_WERROR=On \
../
-DCPPINTEROP_INCLUDE_DOCS=${{ matrix.documentation }} \
-DLLVM_DIR=$LLVM_BUILD_DIR/lib/cmake/llvm \
-DClang_DIR=$LLVM_BUILD_DIR/lib/cmake/clang \
-DBUILD_SHARED_LIBS=ON \
-DCODE_COVERAGE=${{ env.CODE_COVERAGE }} \
-DCMAKE_INSTALL_PREFIX=$CPPINTEROP_DIR \
-DLLVM_ENABLE_WERROR=On \
-DCPPINTEROP_WITH_OOP_JIT=${{ matrix.oop-jit }} \
../
fi
docs_on=$(echo "${{ matrix.documentation }}" | tr '[:lower:]' '[:upper:]')
if [[ "${docs_on}" == "ON" ]]; then
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ jobs:
llvm_enable_projects: "clang"
llvm_targets_to_build: "host;NVPTX"
coverage: true
- name: ubu24-arm-gcc12-clang-repl-20-oop
os: ubuntu-24.04-arm
compiler: gcc-12
clang-runtime: '20'
cling: Off
cppyy: Off
llvm_enable_projects: "clang;compiler-rt"
llvm_targets_to_build: "host;NVPTX"
oop-jit: On
- name: ubu24-arm-gcc12-clang-repl-20
os: ubuntu-24.04-arm
compiler: gcc-12
Expand Down Expand Up @@ -132,6 +141,15 @@ jobs:
llvm_enable_projects: "clang"
llvm_targets_to_build: "host;NVPTX"
# MacOS Arm Jobs
- name: osx15-arm-clang-clang-repl-20-oop
os: macos-15
compiler: clang
clang-runtime: '20'
cling: Off
cppyy: Off
llvm_enable_projects: "clang;compiler-rt"
llvm_targets_to_build: "host"
oop-jit: On
- name: osx15-arm-clang-clang-repl-20
os: macos-15
compiler: clang
Expand Down Expand Up @@ -182,6 +200,15 @@ jobs:
llvm_enable_projects: "clang"
llvm_targets_to_build: "host;NVPTX"
# MacOS X86 Jobs
- name: osx13-x86-clang-clang-repl-20-oop
os: macos-13
compiler: clang
clang-runtime: '20'
cling: Off
cppyy: Off
llvm_enable_projects: "clang;compiler-rt"
llvm_targets_to_build: "host"
oop-jit: On
- name: osx13-x86-clang-clang-repl-20
os: macos-13
compiler: clang
Expand Down
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@ include_directories(SYSTEM ${LLVM_INCLUDE_DIRS})
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})

if(CPPINTEROP_WITH_OOP_JIT)
if(WIN32 OR EMSCRIPTEN)
message(FATAL_ERROR "CPPINTEROP_WITH_OOP_JIT is not supported on Windows or Emscripten platforms.")
endif()
add_definitions(-DCPPINTEROP_WITH_OOP_JIT)
endif()

string(REGEX REPLACE "/build/lib/cmake/llvm$" "" LLVM_SOURCE_DIR "${LLVM_DIR}")
add_definitions(-DLLVM_SOURCE_DIR="${LLVM_SOURCE_DIR}")
Comment on lines +320 to +321
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
string(REGEX REPLACE "/build/lib/cmake/llvm$" "" LLVM_SOURCE_DIR "${LLVM_DIR}")
add_definitions(-DLLVM_SOURCE_DIR="${LLVM_SOURCE_DIR}")
string(REGEX REPLACE "/build/lib/cmake/llvm$" "" LLVM_BINARY_DIR "${LLVM_DIR}")
add_definitions(-DLLVM_SOURCE_DIR="${LLVM_BINARY_DIR}")

I guess is a better name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LLVM_BINARY_DIR is already an env variable

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reuse LLVM_BINARY_DIR?


# If the llvm sources are present add them with higher priority.
if (LLVM_BUILD_MAIN_SRC_DIR)
# LLVM_INCLUDE_DIRS contains the include paths to both LLVM's source and
Expand Down
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ git apply -v clang{version}-*.patch

on Windows.

If you want to have out-of-process JIT execution enabled in CppInterOp, then apply this patch on Linux and MacOS environment.
> Note that this patch will not work for Windows because out-of-process JIT execution is currently implemented for Linux and MacOS only.

```bash
git apply -v ../CppInterOp/patches/llvm/clang20-1-out-of-process-jit-execution.patch
```

##### Build Clang-REPL

Clang-REPL is an interpreter that CppInterOp works alongside. Build Clang (and
Expand Down Expand Up @@ -175,6 +182,30 @@ $env:LLVM_DIR= $PWD.Path
cd ..\
```

##### Build Clang-REPL with Out-of-Process JIT Execution

To have ``Out-of-Process JIT Execution`` enabled, run following commands to build clang and clang-repl to support this feature:
> Only for Linux and Macos
```bash
mkdir build
cd build
cmake -DLLVM_ENABLE_PROJECTS="clang;compiler-rt \
-DLLVM_TARGETS_TO_BUILD="host;NVPTX" \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DCLANG_ENABLE_STATIC_ANALYZER=OFF \
-DCLANG_ENABLE_ARCMT=OFF \
-DCLANG_ENABLE_FORMAT=OFF \
-DCLANG_ENABLE_BOOTSTRAP=OFF \
../llvm

## For Linux
cmake --build . --target clang clang-repl llvm-jitlink-executor orc_rt --parallel $(nproc --all)

## For MacOS
cmake --build . --target clang clang-repl llvm-jitlink-executor orc_rt_osx --parallel $(sysctl -n hw.ncpu)
```

#### Build Cling and related dependencies

Besides the Clang-REPL interpreter, CppInterOp also works alongside the Cling
Expand Down Expand Up @@ -324,6 +355,8 @@ cmake -DBUILD_SHARED_LIBS=ON -DLLVM_DIR=$LLVM_DIR/build/lib/cmake/llvm -DClang_D
cmake --build . --target install --parallel $(nproc --all)
```

> Do make sure to add ``-DCPPINTEROP_WITH_OOP_JIT=ON``, if you want to have out-of-process JIT execution feature enabled.

and

```powershell
Expand Down
43 changes: 43 additions & 0 deletions docs/InstallationAndUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ and

on Windows.

If you want to have out-of-process JIT execution enabled in CppInterOp, then apply this patch on Linux and MacOS environment.
.. note::

This patch will not work for Windows because out-of-process JIT execution is currently implemented for Linux and MacOS only.

.. code:: bash

git apply -v ../CppInterOp/patches/llvm/clang20-1-out-of-process-jit-execution.patch

******************
Build Clang-REPL
******************
Expand Down Expand Up @@ -116,6 +125,36 @@ On Windows you execute the following
$env:LLVM_DIR= $PWD.Path
cd ..\

***************************************************
Build Clang-REPL with Out-of-Process JIT Execution
***************************************************

To have `Out-of-Process JIT Execution` enabled, run following commands to build clang and clang-repl to support this feature:

.. note::

Only for Linux and Macos

.. code:: bash

mkdir build
cd build
cmake -DLLVM_ENABLE_PROJECTS="clang;compiler-rt \
-DLLVM_TARGETS_TO_BUILD="host;NVPTX" \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DCLANG_ENABLE_STATIC_ANALYZER=OFF \
-DCLANG_ENABLE_ARCMT=OFF \
-DCLANG_ENABLE_FORMAT=OFF \
-DCLANG_ENABLE_BOOTSTRAP=OFF \
../llvm

# For Linux
cmake --build . --target clang clang-repl llvm-jitlink-executor orc_rt --parallel $(nproc --all)

# For MacOS
cmake --build . --target clang clang-repl llvm-jitlink-executor orc_rt_osx --parallel $(sysctl -n hw.ncpu)

**************************************
Build Cling and related dependencies
**************************************
Expand Down Expand Up @@ -280,6 +319,10 @@ commands on Linux and MacOS
cmake -DBUILD_SHARED_LIBS=ON -DLLVM_DIR=$LLVM_DIR/build/lib/cmake/llvm -DClang_DIR=$LLVM_DIR/build/lib/cmake/clang -DCMAKE_INSTALL_PREFIX=$CPPINTEROP_DIR ..
cmake --build . --target install --parallel $(nproc --all)

.. note::

Do make sure to add `-DCPPINTEROP_WITH_OOP_JIT=ON`, if you want to have out-of-process JIT execution feature enabled.

and

.. code:: powershell
Expand Down
4 changes: 3 additions & 1 deletion include/CppInterOp/CppInterOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ CPPINTEROP_API void GetOperator(TCppScope_t scope, Operator op,
///\returns nullptr on failure.
CPPINTEROP_API TInterp_t
CreateInterpreter(const std::vector<const char*>& Args = {},
const std::vector<const char*>& GpuArgs = {});
const std::vector<const char*>& GpuArgs = {}, bool outOfProcess = false);

/// Deletes an instance of an interpreter.
///\param[in] I - the interpreter to be deleted, if nullptr, deletes the last.
Expand Down Expand Up @@ -901,6 +901,8 @@ CPPINTEROP_API void CodeComplete(std::vector<std::string>& Results,
///\returns 0 on success, non-zero on failure.
CPPINTEROP_API int Undo(unsigned N = 1);

CPPINTEROP_API pid_t GetExecutorPID();

} // end namespace Cpp

#endif // CPPINTEROP_CPPINTEROP_H
66 changes: 64 additions & 2 deletions lib/CppInterOp/Compatibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,22 @@ inline void codeComplete(std::vector<std::string>& Results,

#include "llvm/Support/Error.h"

#include <vector>

#ifdef CPPINTEROP_WITH_OOP_JIT
#include "clang/Basic/Version.h"
#include "clang/Interpreter/RemoteJITUtils.h"
#include "llvm/TargetParser/Host.h"

#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
#endif

static const llvm::ExitOnError ExitOnError;

namespace compat {

inline std::unique_ptr<clang::Interpreter>
createClangInterpreter(std::vector<const char*>& args) {
createClangInterpreter(std::vector<const char*>& args, bool outOfProcess) {
auto has_arg = [](const char* x, llvm::StringRef match = "cuda") {
llvm::StringRef Arg = x;
Arg = Arg.trim().ltrim('-');
Expand Down Expand Up @@ -246,16 +258,62 @@ createClangInterpreter(std::vector<const char*>& args) {
(*ciOrErr)->LoadRequestedPlugins();
if (CudaEnabled)
DeviceCI->LoadRequestedPlugins();

#ifdef CPPINTEROP_WITH_OOP_JIT
std::unique_ptr<llvm::orc::LLJITBuilder> JB;

if (outOfProcess) {
std::string OOPExecutor =
std::string(LLVM_SOURCE_DIR) + "/build/bin/llvm-jitlink-executor";
bool UseSharedMemory = false;
std::string SlabAllocateSizeString = "";
std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
EPC = ExitOnError(
launchExecutor(OOPExecutor, UseSharedMemory, SlabAllocateSizeString));

#ifdef __APPLE__
std::string OrcRuntimePath =
std::string(LLVM_SOURCE_DIR) +
"/build/lib/clang/20/lib/darwin/liborc_rt_osx.a";
#else
std::string OrcRuntimePath =
std::string(LLVM_SOURCE_DIR) +
"/build/lib/x86_64-unknown-linux-gnu/liborc_rt.a";
#endif
if (EPC) {

CB.SetTargetTriple(EPC->getTargetTriple().getTriple());
JB = ExitOnError(clang::Interpreter::createLLJITBuilder(std::move(EPC),
OrcRuntimePath));
}
}

auto innerOrErr =
CudaEnabled
? clang::Interpreter::createWithCUDA(std::move(*ciOrErr),
std::move(DeviceCI))
: clang::Interpreter::create(std::move(*ciOrErr), std::move(JB));
#else
if (outOfProcess) {
llvm::errs()
<< "[CreateClangInterpreter]: No compatibility with out-of-process JIT"
<< "(To enable recompile CppInterOp with "
"`-DCPPINTEROP_WITH_OOP_JIT=ON`)"
<< "\n";
return nullptr;
}
auto innerOrErr =
CudaEnabled ? clang::Interpreter::createWithCUDA(std::move(*ciOrErr),
std::move(DeviceCI))
: clang::Interpreter::create(std::move(*ciOrErr));
#endif

if (!innerOrErr) {
llvm::logAllUnhandledErrors(innerOrErr.takeError(), llvm::errs(),
"Failed to build Interpreter:");
return nullptr;
}

if (CudaEnabled) {
if (auto Err = (*innerOrErr)->LoadDynamicLibrary("libcudart.so")) {
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
Expand Down Expand Up @@ -371,6 +429,10 @@ inline void codeComplete(std::vector<std::string>& Results,
#endif
}

inline pid_t getExecutorPID() {
return getLastLaunchedExecutorPID();
}

} // namespace compat

#include "CppInterOpInterpreter.h"
Expand All @@ -395,7 +457,7 @@ class SynthesizingCodeRAII {
"Failed to generate PTU:");
}
};
}
} // namespace compat

#endif // CPPINTEROP_USE_REPL

Expand Down
8 changes: 6 additions & 2 deletions lib/CppInterOp/CppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3031,7 +3031,7 @@ static std::string MakeResourcesPath() {
} // namespace

TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
const std::vector<const char*>& GpuArgs /*={}*/) {
const std::vector<const char*>& GpuArgs /*={}*/, bool outOfProcess) {
std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr);
std::string ResourceDir = MakeResourcesPath();
std::vector<const char*> ClingArgv = {"-resource-dir", ResourceDir.c_str(),
Expand Down Expand Up @@ -3075,7 +3075,7 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
auto I = new compat::Interpreter(ClingArgv.size(), &ClingArgv[0]);
#else
auto Interp = compat::Interpreter::create(static_cast<int>(ClingArgv.size()),
ClingArgv.data());
ClingArgv.data(), nullptr, {}, nullptr, true, outOfProcess);
if (!Interp)
return nullptr;
auto* I = Interp.release();
Expand Down Expand Up @@ -3909,4 +3909,8 @@ int Undo(unsigned N) {
#endif
}

pid_t GetExecutorPID() {
return compat::getExecutorPID();
}

} // end namespace Cpp
4 changes: 2 additions & 2 deletions lib/CppInterOp/CppInterOpInterpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,15 @@ class Interpreter {
create(int argc, const char* const* argv, const char* llvmdir = nullptr,
const std::vector<std::shared_ptr<clang::ModuleFileExtension>>&
moduleExtensions = {},
void* extraLibHandle = nullptr, bool noRuntime = true) {
void* extraLibHandle = nullptr, bool noRuntime = true, bool outOfProcess = false) {
// Initialize all targets (required for device offloading)
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();

std::vector<const char*> vargs(argv + 1, argv + argc);
auto CI = compat::createClangInterpreter(vargs);
auto CI = compat::createClangInterpreter(vargs, outOfProcess);
if (!CI) {
llvm::errs() << "Interpreter creation failed\n";
return nullptr;
Expand Down
Loading
Loading