Skip to content

Enable support for multiple kernels for xeus-cpp-lite #290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 6, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
26 changes: 6 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ function(configure_native_kernel kernel)
endfunction()

function(configure_wasm_kernel kernel)
set(XEUS_CPP_RESOURCE_DIR "/lib/clang/${CPPINTEROP_LLVM_VERSION_MAJOR}" PARENT_SCOPE)

configure_file (
"${CMAKE_CURRENT_SOURCE_DIR}${kernel}wasm_kernel.json.in"
Expand All @@ -169,17 +170,9 @@ endfunction()

message("Configure kernels: ...")
if(EMSCRIPTEN)
# TODO: Currently jupyterlite-xeus and xeus-lite do not provide
# methods to fetch information from the arguments present in the
# generated emscripten kernel.
# The following needs to be done here :
# 1) We need to configure the kernel properly
# Check issue https://github.com/compiler-research/xeus-cpp/issues/185.
# 2) Once the above is done we need to add support in jupyterlite-xeus & xeus-lite
# to be able to deal with arguments present in kernel.json
# 3) Finally we should fetch the C++ version from the kernel.json file and
# be able to pass it to our wasm interpreter rather than forcing a version.
configure_wasm_kernel("/share/jupyter/kernels/xcpp17/")
configure_wasm_kernel("/share/jupyter/kernels/xcpp20/")
configure_wasm_kernel("/share/jupyter/kernels/xcpp23/")
else()
configure_native_kernel("/share/jupyter/kernels/xcpp17/")
configure_native_kernel("/share/jupyter/kernels/xcpp20/")
Expand Down Expand Up @@ -444,20 +437,13 @@ if(EMSCRIPTEN)
xeus_wasm_link_options(xcpp "web,worker")
target_link_options(xcpp
PUBLIC "SHELL: --preload-file ${SYSROOT_PATH}/include@/include"
#PUBLIC "SHELL: --preload-file ${CMAKE_INSTALL_PREFIX}${XEUS_CPP_RESOURCE_DIR}@${XEUS_CPP_RESOURCE_DIR}"
PUBLIC "SHELL: --preload-file ${XEUS_CPP_DATA_DIR}@/share/xeus-cpp"
PUBLIC "SHELL: --preload-file ${XEUS_CPP_CONF_DIR}@/etc/xeus-cpp"
PUBLIC "SHELL: --post-js ${CMAKE_CURRENT_SOURCE_DIR}/wasm_patches/post.js"
)
# TODO: Emscripten supports preloading files just once before it generates
# the xcpp.data file (containing the binary representation of the file(s) we
# want to include in our application).
# Hence although we are adding support for Standard Headers, Libraries etc
# through emscripten's sysroot for now, we need to do the following:
# 1) Enable CppInterOp to provide us with a resource dir.
# 2) If the above cannot be done, we can use the resource dir provided
# by llvm on emscripten-forge but would involve adding a dependency.
# 3) Shift the resource dir and the sysroot to a common location.
# 4) Preload everything required together.
# TODO: Uncomment the above line regarding preloading clang's resource dir
# once has been supported through cppinterop.
endif()
# Tests
# =====
Expand Down
2 changes: 1 addition & 1 deletion include/xeus-cpp/xinterpreter_wasm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace xcpp
{
public:

wasm_interpreter();
wasm_interpreter(int argc = 0, char** argv = nullptr);
virtual ~wasm_interpreter() = default;

};
Expand Down
15 changes: 15 additions & 0 deletions share/jupyter/kernels/xcpp17/wasm_kernel.json.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"display_name": "C++17",
"argv": [
"@XEUS_CPP_KERNELSPEC_PATH@xcpp",
"-resource-dir", "@XEUS_CPP_RESOURCE_DIR@",
"-std=c++17"
],
"language": "cpp",
"metadata": {
"debugger": false,
"shared": {
"libclangCppInterOp.so": "lib/libclangCppInterOp.so"
}
}
}
3 changes: 1 addition & 2 deletions share/jupyter/kernels/xcpp20/wasm_kernel.json.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
"display_name": "C++20",
"argv": [
"@XEUS_CPP_KERNELSPEC_PATH@xcpp",
"-f",
"{connection_file}",
"-resource-dir", "@XEUS_CPP_RESOURCE_DIR@",
"-std=c++20"
],
"language": "cpp",
Expand Down
15 changes: 15 additions & 0 deletions share/jupyter/kernels/xcpp23/wasm_kernel.json.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"display_name": "C++23",
"argv": [
"@XEUS_CPP_KERNELSPEC_PATH@xcpp",
"-resource-dir", "@XEUS_CPP_RESOURCE_DIR@",
"-std=c++23"
],
"language": "cpp",
"metadata": {
"debugger": false,
"shared": {
"libclangCppInterOp.so": "lib/libclangCppInterOp.so"
}
}
}
23 changes: 22 additions & 1 deletion src/main_emscripten_kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,30 @@

#include "xeus-cpp/xinterpreter_wasm.hpp"

template <class interpreter_type>
static interpreter_type* builder_with_args(emscripten::val js_args)
{
// TODO: Refactor interpreter constructor to avoid static args-to-argv conversion.
static std::vector<std::string> args = emscripten::vecFromJSArray<std::string>(js_args);
static std::vector<const char*> argv_vec;

for (const auto& s : args)
{
argv_vec.push_back(s.c_str());
}

int argc = static_cast<int>(argv_vec.size());
char** argv = const_cast<char**>(argv_vec.data());

auto* res = new interpreter_type(argc, argv);
argv_vec.clear();
args.clear();
return res;
}

EMSCRIPTEN_BINDINGS(my_module)
{
xeus::export_core();
using interpreter_type = xcpp::wasm_interpreter;
xeus::export_kernel<interpreter_type>("xkernel");
xeus::export_kernel<interpreter_type, &builder_with_args<interpreter_type>>("xkernel");
}
17 changes: 8 additions & 9 deletions src/xinterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "xinput.hpp"
#include "xinspect.hpp"
#include "xmagics/os.hpp"
#include <iostream>
#ifndef EMSCRIPTEN
#include "xmagics/xassist.hpp"
#endif
Expand All @@ -27,25 +28,23 @@
using Args = std::vector<const char*>;

void* createInterpreter(const Args &ExtraArgs = {}) {
Args ClangArgs = {/*"-xc++"*/"-v"}; // ? {"-Xclang", "-emit-llvm-only", "-Xclang", "-diagnostic-log-file", "-Xclang", "-", "-xc++"};
#ifdef EMSCRIPTEN
ClangArgs.push_back("-std=c++20");
#else
Args ClangArgs = {/*"-xc++"*/"-v"};
if (std::find_if(ExtraArgs.begin(), ExtraArgs.end(), [](const std::string& s) {
return s == "-resource-dir";}) == ExtraArgs.end()) {
std::string resource_dir = Cpp::DetectResourceDir();
if (resource_dir.empty())
std::cerr << "Failed to detect the resource-dir\n";
ClangArgs.push_back("-resource-dir");
ClangArgs.push_back(resource_dir.c_str());
if (!resource_dir.empty()) {
ClangArgs.push_back("-resource-dir");
ClangArgs.push_back(resource_dir.c_str());
} else {
std::cerr << "Failed to detect the resource-dir\n";
}
}
std::vector<std::string> CxxSystemIncludes;
Cpp::DetectSystemCompilerIncludePaths(CxxSystemIncludes);
for (const std::string& CxxInclude : CxxSystemIncludes) {
ClangArgs.push_back("-isystem");
ClangArgs.push_back(CxxInclude.c_str());
}
#endif
ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end());
// FIXME: We should process the kernel input options and conditionally pass
// the gpu args here.
Expand Down
5 changes: 2 additions & 3 deletions src/xinterpreter_wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@

namespace xcpp
{

wasm_interpreter::wasm_interpreter()
: interpreter(0, nullptr)
wasm_interpreter::wasm_interpreter(int argc, char** argv)
: interpreter(argc, argv)
{
}
}
Loading