diff --git a/.github/workflows/deploy-github-page.yml b/.github/workflows/deploy-github-page.yml index fa0e7442..b0f7a049 100644 --- a/.github/workflows/deploy-github-page.yml +++ b/.github/workflows/deploy-github-page.yml @@ -59,6 +59,7 @@ jobs: echo "PREFIX=$PREFIX" >> $GITHUB_ENV export CMAKE_PREFIX_PATH=$PREFIX export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX + export SYSROOT_PATH=$HOME/emsdk/upstream/emscripten/cache/sysroot emcmake cmake \ -DCMAKE_BUILD_TYPE=Release \ @@ -66,6 +67,7 @@ jobs: -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DXEUS_CPP_EMSCRIPTEN_WASM_BUILD=ON \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DSYSROOT_PATH=$SYSROOT_PATH \ .. emmake make -j ${{ env.ncpus }} install @@ -76,6 +78,8 @@ jobs: micromamba activate xeus-lite-host python -m pip install jupyterlite-xeus jupyter lite build --XeusAddon.prefix=${{ env.PREFIX }} --output-dir dist + cp xcpp.data dist/extensions/@jupyterlite/xeus/static + cp $PREFIX/lib/libclangCppInterOp.so dist/extensions/@jupyterlite/xeus/static mkdir -p dist/files mv notebooks dist/files mv README.md dist/files diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1724e4e..d663307f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -257,6 +257,7 @@ jobs: echo "PREFIX=$PREFIX" >> $GITHUB_ENV export CMAKE_PREFIX_PATH=$PREFIX export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX + export SYSROOT_PATH=$HOME/emsdk/upstream/emscripten/cache/sysroot emcmake cmake \ -DCMAKE_BUILD_TYPE=Release \ @@ -264,6 +265,7 @@ jobs: -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DXEUS_CPP_EMSCRIPTEN_WASM_BUILD=ON \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DSYSROOT_PATH=$SYSROOT_PATH \ .. emmake make -j ${{ env.ncpus }} install @@ -274,6 +276,8 @@ jobs: micromamba activate xeus-lite-host python -m pip install jupyterlite-xeus jupyter lite build --XeusAddon.prefix=${{ env.PREFIX }} + cp xcpp.data _output/extensions/@jupyterlite/xeus/static + cp $PREFIX/lib/libclangCppInterOp.so _output/extensions/@jupyterlite/xeus/static - name: Setup tmate session if: ${{ failure() && runner.debug }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 31ab854a..a9a08845 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,7 @@ if(EMSCRIPTEN) set(XEUS_CPP_USE_SHARED_XEUS_CPP OFF) set(XEUS_CPP_BUILD_TESTS OFF) # ENV (https://github.com/emscripten-core/emscripten/commit/6d9681ad04f60b41ef6345ab06c29bbc9eeb84e0) - set(EMSCRIPTEN_FEATURES "${EMSCRIPTEN_FEATURES} -s \"EXTRA_EXPORTED_RUNTIME_METHODS=[ENV']\"") + set(EMSCRIPTEN_FEATURES "${EMSCRIPTEN_FEATURES} -s \"EXPORTED_RUNTIME_METHODS=[ENV']\"") endif() # Dependencies @@ -152,8 +152,22 @@ function(configure_kernel kernel) endfunction() message("Configure kernels: ...") -configure_kernel("/share/jupyter/kernels/xcpp17/") -configure_kernel("/share/jupyter/kernels/xcpp20/") +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_kernel("/share/jupyter/kernels/xcpp20/") +else() + configure_kernel("/share/jupyter/kernels/xcpp17/") + configure_kernel("/share/jupyter/kernels/xcpp20/") +endif() # Source files # ============ @@ -401,8 +415,24 @@ if(EMSCRIPTEN) xeus_cpp_set_kernel_options(xcpp) xeus_wasm_compile_options(xcpp) xeus_wasm_link_options(xcpp "web,worker") + # TODO: Remove the exported runtime methods + # after the next xeus release. + target_link_options(xcpp PUBLIC + -sEXPORTED_RUNTIME_METHODS=FS,PATH,ERRNO_CODES + # add sysroot location here + --preload-file ${SYSROOT_PATH}/include@/include + ) + # 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. endif() - # Tests # ===== @@ -492,6 +522,7 @@ if(EMSCRIPTEN) install(FILES "$/xcpp.js" "$/xcpp.wasm" + "$/xcpp.data" DESTINATION ${CMAKE_INSTALL_BINDIR}) endif () diff --git a/README.md b/README.md index a25a0cac..b997360e 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ pushd build export PREFIX=$MAMBA_ROOT_PREFIX/envs/xeus-cpp-wasm-host export CMAKE_PREFIX_PATH=$PREFIX export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX +export SYSROOT_PATH=$HOME/emsdk/upstream/emscripten/cache/sysroot emcmake cmake \ -DCMAKE_BUILD_TYPE=Release \ @@ -94,6 +95,7 @@ emcmake cmake \ -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DXEUS_CPP_EMSCRIPTEN_WASM_BUILD=ON \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DSYSROOT_PATH=$SYSROOT_PATH \ .. emmake make install ``` @@ -105,12 +107,20 @@ micromamba activate xeus-lite-host python -m pip install jupyterlite-xeus jupyter lite build --XeusAddon.prefix=$PREFIX ``` + +We now need to shift necessary files like `xcpp.data` which contains the binary representation of the file(s) +we want to include in our application. As of now this would contain all important files like Standard Headers, +Libraries etc coming out of emscripten's sysroot. Assuming we are still inside build we should do the following +```bash +cp xcpp.data _output/extensions/@jupyterlite/xeus/static +cp $PREFIX/lib/libclangCppInterOp.so _output/extensions/@jupyterlite/xeus/static +``` + Once the Jupyter Lite site has built you can test the website locally by executing ```bash jupyter lite serve --XeusAddon.prefix=$PREFIX ``` - ## Trying it online To try out xeus-cpp interactively in your web browser, just click on the binder link: diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index f099b688..cc27be25 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -28,6 +28,9 @@ using Args = std::vector; 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 if (std::find_if(ExtraArgs.begin(), ExtraArgs.end(), [](const std::string& s) { return s == "-resource-dir";}) == ExtraArgs.end()) { std::string resource_dir = Cpp::DetectResourceDir(); @@ -42,6 +45,7 @@ void* createInterpreter(const Args &ExtraArgs = {}) { 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. @@ -73,6 +77,7 @@ namespace xcpp static std::string get_stdopt() { // We need to find what's the C++ version the interpreter runs with. +#ifndef EMSCRIPTEN const char* code = R"( int __get_cxx_version () { #if __cplusplus > 202302L @@ -93,12 +98,13 @@ int __get_cxx_version () { } __get_cxx_version () )"; - auto cxx_version = Cpp::Evaluate(code); return std::to_string(cxx_version); +#else + return "20"; +#endif } - interpreter::interpreter(int argc, const char* const* argv) : xmagics() , p_cout_strbuf(nullptr) @@ -110,7 +116,6 @@ __get_cxx_version () createInterpreter(Args(argv ? argv + 1 : argv, argv + argc)); m_version = get_stdopt(); redirect_output(); - init_includes(); init_preamble(); init_magic(); } @@ -355,11 +360,6 @@ __get_cxx_version () publish_stream("stderr", s); } - void interpreter::init_includes() - { - Cpp::AddIncludePath((xeus::prefix_path() + "/include/").c_str()); - } - void interpreter::init_preamble() { //NOLINTBEGIN(cppcoreguidelines-owning-memory)