diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e88a228..afcd6fcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,7 +129,7 @@ endif () function(configure_kernel kernel) set(XEUS_CPP_PATH "$ENV{PATH}") set(XEUS_CPP_LD_LIBRARY_PATH "$ENV{LD_LIBRARY_PATH}") - set(XEUS_CPP_RESOURCE_DIR ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/clang/${CppInterOp_CLANG_VERSION}) + set(XEUS_CPP_RESOURCE_DIR ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/clang/${CPPINTEROP_LLVM_VERSION_MAJOR}) configure_file ( "${CMAKE_CURRENT_SOURCE_DIR}/${kernel}/kernel.json.in" diff --git a/environment.yml b/environment.yml index 82d7eb2a..ca242be2 100644 --- a/environment.yml +++ b/environment.yml @@ -2,4 +2,4 @@ name: xeus-cpp channels: - conda-forge dependencies: - - xeus-cpp=0.0.1 + - xeus-cpp diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index b25606e5..fdef663f 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -59,6 +59,19 @@ using namespace std::placeholders; namespace xcpp { + struct StreamRedirectRAII { + std::string &err; + StreamRedirectRAII(std::string &e) : err(e) { + Cpp::BeginStdStreamCapture(Cpp::kStdErr); + Cpp::BeginStdStreamCapture(Cpp::kStdOut); + } + ~StreamRedirectRAII() { + std::string out = Cpp::EndStdStreamCapture(); + err = Cpp::EndStdStreamCapture(); + std::cout << out; + } + }; + void interpreter::configure_impl() { xeus::register_interpreter(this); @@ -153,28 +166,32 @@ __get_cxx_version () std::cerr.rdbuf(&null); } + std::string err; + // Attempt normal evaluation try { + StreamRedirectRAII R(err); compilation_result = Cpp::Process(code.c_str()); } catch (std::exception& e) { errorlevel = 1; - ename = "Standard Exception :"; + ename = "Standard Exception: "; evalue = e.what(); } catch (...) { errorlevel = 1; - ename = "Error :"; + ename = "Error: "; } if (compilation_result) { errorlevel = 1; - ename = "Error :"; - evalue = "Compilation error!"; + ename = "Error: "; + evalue = "Compilation error! " + err; + std::cerr << err; } // Flush streams diff --git a/test/test_xcpp_kernel.py b/test/test_xcpp_kernel.py index c1ac33a3..13cf552e 100644 --- a/test/test_xcpp_kernel.py +++ b/test/test_xcpp_kernel.py @@ -8,6 +8,7 @@ import unittest import jupyter_kernel_test +import platform class XCppTests(jupyter_kernel_test.KernelTests): @@ -24,7 +25,12 @@ class XCppTests(jupyter_kernel_test.KernelTests): code_stderr = '#include \nstd::cerr << "oops" << std::endl;' # Pager: code that should display something (anything) in the pager - #code_page_something = "?std::vector" + code_page_something = "?std::vector" + + # Exception throwing + # TODO: Remove 'if' when test work on MacOS/arm64. Throw Exceptions make + # kernel/test non-workable. + ###code_generate_error = 'throw std::runtime_error("Unknown exception");' if platform.system() != "Darwin" or platform.processor() != 'arm' else '' # Samples of code which generate a result value (ie, some text # displayed as Out[n]) @@ -41,8 +47,45 @@ class XCppTests(jupyter_kernel_test.KernelTests): { 'code': '#include \n#include "xcpp/xdisplay.hpp"\nstd::string test("foobar");\nxcpp::display(test);', 'mime': 'text/plain' + }, + { + 'code': """ +#include +#include +#include "nlohmann/json.hpp" +#include "xtl/xbase64.hpp" +namespace im { + struct image { + inline image(const std::string& filename) { + std::ifstream fin(filename, std::ios::binary); + m_buffer << fin.rdbuf(); + } + std::stringstream m_buffer; + }; + nlohmann::json mime_bundle_repr(const image& i) { + auto bundle = nlohmann::json::object(); + bundle["image/png"] = xtl::base64encode(i.m_buffer.str()); + return bundle; + } +} +#include "xcpp/xdisplay.hpp" +im::image marie("../notebooks/images/marie.png"); +xcpp::display(marie);""", + 'mime': 'image/png' } ] + +class XCppTests2(jupyter_kernel_test.KernelTests): + + kernel_name = 'xcpp' + + # language_info.name in a kernel_info_reply should match this + language_name = 'C++' + + # Code that should write the exact string `hello, world` to STDOUT + code_hello_world = '#include \nprintf("hello, world");' + + if __name__ == '__main__': unittest.main()