diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index c04458de..d9d11055 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -21,7 +21,7 @@ jobs: fetch-depth: 0 - name: Setup Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: "3.11" diff --git a/.github/workflows/clang-tidy-review-post.yml b/.github/workflows/clang-tidy-review-post.yml index 4dbd3368..7a982e1d 100644 --- a/.github/workflows/clang-tidy-review-post.yml +++ b/.github/workflows/clang-tidy-review-post.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Post review comments id: post-review - uses: ZedThree/clang-tidy-review/post@v0.21.0 + uses: ZedThree/clang-tidy-review/post@v0.23.1 with: max_comments: 10 diff --git a/.github/workflows/clang-tidy-review.yml b/.github/workflows/clang-tidy-review.yml index 25de5f02..5cac4d4e 100644 --- a/.github/workflows/clang-tidy-review.yml +++ b/.github/workflows/clang-tidy-review.yml @@ -17,40 +17,23 @@ jobs: steps: - name: Checkout PR branch - uses: actions/checkout@v6 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - - name: Install LLVM and Clang - uses: KyleMayes/install-llvm-action@v2 - with: - version: "20" + uses: actions/checkout@v7 - name: Run clang-tidy - uses: ZedThree/clang-tidy-review@v0.21.0 + uses: ZedThree/clang-tidy-review@v0.23.1 id: review with: build_dir: build - apt_packages: wget,libxml2,libxml2-dev,libtinfo-dev,zlib1g-dev,libzstd-dev,curl exclude: "test/*,unittests/*,benchmark/*,demos/*" split_workflow: true config_file: .clang-tidy cmake_command: > - cmake . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=On || true && - rm -rf build && - set -x && - wget https://github.com/mamba-org/micromamba-releases/releases/download/1.5.10-0/micromamba-linux-64 && - mv ./micromamba-linux-64 ./micromamba && - chmod a+x ./micromamba && - export PATH="$PWD:$PATH" && - eval "$(micromamba shell hook -s posix)" && - micromamba create -n xeus-cpp -y --log-level warning -f $GITHUB_WORKSPACE/environment-dev.yml && - micromamba activate xeus-cpp && - git config --global --add safe.directory /github/workspace && - cmake . -B build -DCMAKE_C_COMPILER="$GITHUB_WORKSPACE/llvm/bin/clang" -DCMAKE_CXX_COMPILER="$GITHUB_WORKSPACE/llvm/bin/clang++" -DCMAKE_EXPORT_COMPILE_COMMANDS=On + set -eu && + python3 -c "import hashlib, pathlib, urllib.request; p = pathlib.Path('micromamba'); urllib.request.urlretrieve('https://github.com/mamba-org/micromamba-releases/releases/download/2.8.1-0/micromamba-linux-64', p); assert hashlib.sha256(p.read_bytes()).hexdigest() == '9689782d863c05a1bf5d2d371ba527104e7a4eb4310c1637d8653b751aed9c82'" && + chmod +x ./micromamba && + git config --global --add safe.directory /github/workspace && + MAMBA_ROOT_PREFIX="$PWD/.micromamba" ./micromamba create -n xeus-cpp -y --log-level warning -f environment-dev.yml && + MAMBA_ROOT_PREFIX="$PWD/.micromamba" ./micromamba run -n xeus-cpp cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: Upload artifacts - uses: ZedThree/clang-tidy-review/upload@v0.21.0 + uses: ZedThree/clang-tidy-review/upload@v0.23.1 diff --git a/.github/workflows/deploy-github-page.yml b/.github/workflows/deploy-github-page.yml index 68ce65a6..d79b2adb 100644 --- a/.github/workflows/deploy-github-page.yml +++ b/.github/workflows/deploy-github-page.yml @@ -26,10 +26,10 @@ jobs: os: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: install mamba - uses: mamba-org/setup-micromamba@v2 + uses: mamba-org/setup-micromamba@v3 with: environment-file: environment-wasm-build.yml init-shell: bash @@ -154,7 +154,7 @@ jobs: --output-dir dist - name: Upload artifact - uses: actions/upload-pages-artifact@v4 + uses: actions/upload-pages-artifact@v5 with: path: ./dist @@ -173,4 +173,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4270a427..5af9e5bd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,47 +17,12 @@ concurrency: jobs: prepare-dell: - name: Activate self-host infrastructure runs-on: [self-hosted, spotter] steps: - - name: Send Magic Packet - env: - TARGET_IP: 192.168.100.30 - MAC_ADDR: a4:bb:6d:51:d5:d2 - # The container has no ping, emulate it. - run: | - # Mask the IP and potential broadcast to keep logs clean - echo "::add-mask::$MAC_ADDR" - echo "::add-mask::$BROADCAST" - echo "::add-mask::$TARGET_IP" - BROADCAST=$(echo $TARGET_IP | sed 's/\.[0-9]*$/ .255/' | tr -d ' ') - PING="timeout 1 bash -c 'cat < /dev/null > /dev/tcp/$TARGET_IP/22' 2>/dev/null" - - # Install tool silently - sudo apt-get update -qq && sudo apt-get install -y -qq wakeonlan > /dev/null - - # Check if already awake (using the Bash TCP PING variable) - if eval "$PING"; then - echo "Target machine is already awake. Exiting." - exit 0 - fi - - # If offline, send WoL - echo "Machine is offline. Sending WoL..." - wakeonlan -i $BROADCAST $MAC_ADDR > /dev/null - - # Wait & Verify Loop (checks every 10s for 4 minutes) - echo "Waiting for response (checking Port 22)..." - for i in {1..24}; do - if eval "$PING"; then - echo "Machine is online and SSH is ready." - exit 0 - fi - sleep 10 - done - - echo "Error: Target hardware did not respond within the timeout period." - exit 1 + - uses: compiler-research/ci-workflows/actions/wake-on-lan@main + with: + mac: a4:bb:6d:51:d5:d2 + target-host: 192.168.100.30 build: needs: prepare-dell @@ -108,7 +73,7 @@ jobs: micromamba_shell_init: cmd.exe steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Backup in case setup-micromamba fails to cleanup when ci job fails on self hosted runner if: ${{ runner.environment == 'self-hosted' }} @@ -117,7 +82,7 @@ jobs: rm -rf /root/micromamba-bin/micromamba || true - name: install mamba - uses: mamba-org/setup-micromamba@v2 + uses: mamba-org/setup-micromamba@v3 with: environment-file: environment-dev.yml init-shell: >- @@ -236,7 +201,7 @@ jobs: - name: Upload to codecov.io if: ${{ success() && (matrix.coverage == true) }} - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@v7 with: files: ./coverage.info fail_ci_if_error: true @@ -263,10 +228,10 @@ jobs: os: macos-15 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: install mamba - uses: mamba-org/setup-micromamba@v2 + uses: mamba-org/setup-micromamba@v3 with: environment-file: environment-wasm-build.yml init-shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index 3316a7d0..612c907e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,10 +100,34 @@ if (NOT TARGET xeus AND NOT TARGET xeus-static) endif() endif () -find_package(CppInterOp ${CppInterOp_REQUIRED_VERSION} REQUIRED) -if(CppInterOp_FOUND) - message(STATUS "Found CppInterOp: config=${CPPINTEROP_CMAKE_DIR} dir=${CPPINTEROP_INSTALL_PREFIX} (found version=${CPPINTEROP_VERSION} compatible with Clang ${CPPINTEROP_LLVM_VERSION_MAJOR}.x)") -endif() +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + find_package(CppInterOp ${CppInterOp_REQUIRED_VERSION} REQUIRED) + if(CppInterOp_FOUND) + message(STATUS "Found CppInterOp: config=${CPPINTEROP_CMAKE_DIR} dir=${CPPINTEROP_INSTALL_PREFIX} (found version=${CPPINTEROP_VERSION} compatible with Clang ${CPPINTEROP_LLVM_VERSION_MAJOR}.x)") + endif() + if(EMSCRIPTEN) + set(XEUS_CPP_CPPINTEROP_SHARED_JSON "") + if (CPPINTEROP_SHARED_LIB) + set(XEUS_CPP_CPPINTEROP_SHARED_JSON + ",\n \"libclangCppInterOp.so\": \"lib/libclangCppInterOp.so\"") + endif () + endif () + set(XEUS_CPP_TEST_BINARY_DIRECTORY "${CMAKE_BINARY_DIR}/test/") +else () + set(XEUS_CPP_TEST_BINARY_DIRECTORY "${CMAKE_BINARY_DIR}/bin/") + get_target_property( + CPPINTEROP_LIBRARY_TYPE + clangCppInterOp + TYPE + ) + + if(CPPINTEROP_LIBRARY_TYPE STREQUAL "SHARED_LIBRARY") + set(CPPINTEROP_SHARED_LIB TRUE) + set(CPPINTEROP_LIBRARIES "${CMAKE_BINARY_DIR}/lib/libclangCppInterOp.so.${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}") + set(XEUS_CPP_CPPINTEROP_SHARED_JSON + ",\n \"libclangCppInterOp.so\": \"lib/libclangCppInterOp.so\"") + endif () +endif () find_package(argparse REQUIRED) find_package(pugixml REQUIRED) diff --git a/etc/xeus-cpp/tags.d/stl.json b/etc/xeus-cpp/tags.d/stl.json index 6eedd965..9bb2b315 100644 --- a/etc/xeus-cpp/tags.d/stl.json +++ b/etc/xeus-cpp/tags.d/stl.json @@ -1,4 +1,4 @@ { - "url": "https://en.cppreference.com/w/", + "url": "https://en.cppreference.com/", "tagfile": "cppreference-doxygen-web.tag" -} \ No newline at end of file +} diff --git a/share/jupyter/kernels/xc11/wasm_kernel.json.in b/share/jupyter/kernels/xc11/wasm_kernel.json.in index a74ad4ba..db662fac 100644 --- a/share/jupyter/kernels/xc11/wasm_kernel.json.in +++ b/share/jupyter/kernels/xc11/wasm_kernel.json.in @@ -13,8 +13,8 @@ "metadata": { "debugger": false, "shared": { - "libxeus.so": "lib/libxeus.so", - "libclangCppInterOp.so": "lib/libclangCppInterOp.so" + "libxeus.so": "lib/libxeus.so" + @XEUS_CPP_CPPINTEROP_SHARED_JSON@ } } } diff --git a/share/jupyter/kernels/xc17/wasm_kernel.json.in b/share/jupyter/kernels/xc17/wasm_kernel.json.in index a820d69b..4315a427 100644 --- a/share/jupyter/kernels/xc17/wasm_kernel.json.in +++ b/share/jupyter/kernels/xc17/wasm_kernel.json.in @@ -13,8 +13,8 @@ "metadata": { "debugger": false, "shared": { - "libxeus.so": "lib/libxeus.so", - "libclangCppInterOp.so": "lib/libclangCppInterOp.so" + "libxeus.so": "lib/libxeus.so" + @XEUS_CPP_CPPINTEROP_SHARED_JSON@ } } } diff --git a/share/jupyter/kernels/xc23/wasm_kernel.json.in b/share/jupyter/kernels/xc23/wasm_kernel.json.in index 7dd2bd3c..8d00e7b0 100644 --- a/share/jupyter/kernels/xc23/wasm_kernel.json.in +++ b/share/jupyter/kernels/xc23/wasm_kernel.json.in @@ -13,8 +13,8 @@ "metadata": { "debugger": false, "shared": { - "libxeus.so": "lib/libxeus.so", - "libclangCppInterOp.so": "lib/libclangCppInterOp.so" + "libxeus.so": "lib/libxeus.so" + @XEUS_CPP_CPPINTEROP_SHARED_JSON@ } } } diff --git a/share/jupyter/kernels/xcpp17/wasm_kernel.json.in b/share/jupyter/kernels/xcpp17/wasm_kernel.json.in index 02ec0595..88aacb22 100644 --- a/share/jupyter/kernels/xcpp17/wasm_kernel.json.in +++ b/share/jupyter/kernels/xcpp17/wasm_kernel.json.in @@ -12,8 +12,8 @@ "metadata": { "debugger": false, "shared": { - "libxeus.so": "lib/libxeus.so", - "libclangCppInterOp.so": "lib/libclangCppInterOp.so" + "libxeus.so": "lib/libxeus.so" + @XEUS_CPP_CPPINTEROP_SHARED_JSON@ } } } diff --git a/share/jupyter/kernels/xcpp20/wasm_kernel.json.in b/share/jupyter/kernels/xcpp20/wasm_kernel.json.in index 015bd5a3..148fd971 100644 --- a/share/jupyter/kernels/xcpp20/wasm_kernel.json.in +++ b/share/jupyter/kernels/xcpp20/wasm_kernel.json.in @@ -12,8 +12,8 @@ "metadata": { "debugger": false, "shared": { - "libxeus.so": "lib/libxeus.so", - "libclangCppInterOp.so": "lib/libclangCppInterOp.so" + "libxeus.so": "lib/libxeus.so" + @XEUS_CPP_CPPINTEROP_SHARED_JSON@ } } } diff --git a/share/jupyter/kernels/xcpp23/wasm_kernel.json.in b/share/jupyter/kernels/xcpp23/wasm_kernel.json.in index 2de544f6..c1291759 100644 --- a/share/jupyter/kernels/xcpp23/wasm_kernel.json.in +++ b/share/jupyter/kernels/xcpp23/wasm_kernel.json.in @@ -12,8 +12,8 @@ "metadata": { "debugger": false, "shared": { - "libxeus.so": "lib/libxeus.so", - "libclangCppInterOp.so": "lib/libclangCppInterOp.so" + "libxeus.so": "lib/libxeus.so" + @XEUS_CPP_CPPINTEROP_SHARED_JSON@ } } } diff --git a/src/xinspect.cpp b/src/xinspect.cpp index 1ec45717..79ed24a8 100644 --- a/src/xinspect.cpp +++ b/src/xinspect.cpp @@ -214,7 +214,7 @@ namespace xcpp } )"; + + inspect_result + R"(">)"; auto data = nl::json::object({{"text/plain", inspect_result}, {"text/html", html_content}}); return data; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 10fb803d..aaeac88f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -78,22 +78,22 @@ if(EMSCRIPTEN) ) target_include_directories(test_xeus_cpp PRIVATE ${XEUS_CPP_INCLUDE_DIR}) - - add_custom_command(TARGET test_xeus_cpp POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_INSTALL_PREFIX}/lib/libclangCppInterOp.so - ${CMAKE_CURRENT_BINARY_DIR}/libclangCppInterOp.so - COMMENT "Copying libclangCppInterOp.so to the test directory" - ) - + if (CPPINTEROP_SHARED_LIB) + add_custom_command(TARGET test_xeus_cpp POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CPPINTEROP_LIBRARIES} + ${XEUS_CPP_TEST_BINARY_DIRECTORY}/libclangCppInterOp.so + COMMENT "Copying libclangCppInterOp.so to the test directory" + ) + endif () add_custom_command(TARGET test_xeus_cpp POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_INSTALL_PREFIX}/lib/libxeus.so - ${CMAKE_CURRENT_BINARY_DIR}/libxeus.so + ${XEUS_CPP_TEST_BINARY_DIRECTORY}/libxeus.so COMMENT "Copying libxeus.so to the test directory" ) add_custom_target(check-xeus-cpp - COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_BINARY_DIR} node test_xeus_cpp.js + COMMAND ${CMAKE_COMMAND} -E chdir ${XEUS_CPP_TEST_BINARY_DIRECTORY} node test_xeus_cpp.js DEPENDS test_xeus_cpp ) else() diff --git a/test/test_interpreter.cpp b/test/test_interpreter.cpp index a1a11f57..23de2c3b 100644 --- a/test/test_interpreter.cpp +++ b/test/test_interpreter.cpp @@ -68,6 +68,44 @@ class StreamRedirectRAII { TEST_SUITE("execute_request") { + TEST_CASE("Silent mode restores std::cout and std::cerr buffers") + { + std::vector Args = {}; +#if defined(__EMSCRIPTEN__) + Args = {"-Xclang", "-iwithsysroot/include/compat"}; +#endif + xcpp::interpreter interpreter((int)Args.size(), Args.data()); + + auto* cout_before = std::cout.rdbuf(); + auto* cerr_before = std::cerr.rdbuf(); + + xeus::execute_request_config config; + config.silent = true; + config.store_history = false; + config.allow_stdin = false; + + nl::json header = nl::json::object(); + xeus::xrequest_context::guid_list id = {}; + xeus::xrequest_context context(header, id); + + std::promise promise; + auto callback = [&promise](nl::json result) { promise.set_value(result); }; + + std::string code = R"( + #include + std::cout << "hidden stdout\n"; + std::cerr << "hidden stderr\n"; + )"; + + interpreter.execute_request(context, callback, code, config, nl::json::object()); + + auto reply = promise.get_future().get(); + REQUIRE(reply["status"] == "ok"); + + REQUIRE(std::cout.rdbuf() == cout_before); + REQUIRE(std::cerr.rdbuf() == cerr_before); + } + TEST_CASE("stl") { std::vector Args = { @@ -184,7 +222,7 @@ TEST_SUITE("execute_request") xcpp::interpreter interpreter((int)Args.size(), Args.data()); std::string code = "?std::vector"; - std::string inspect_result = "https://en.cppreference.com/w/cpp/container/vector"; + std::string inspect_result = "https://en.cppreference.com/cpp/container/vector"; nl::json user_expressions = nl::json::object(); xeus::execute_request_config config; config.silent = false; @@ -209,6 +247,9 @@ TEST_SUITE("execute_request") ); nl::json result = future.get(); REQUIRE(result["payload"][0]["data"]["text/plain"] == inspect_result); + std::string inspect_html = result["payload"][0]["data"]["text/html"]; + REQUIRE(inspect_html.find("src=\"" + inspect_result + "\"") != std::string::npos); + REQUIRE(inspect_html.find("action=purge") == std::string::npos); REQUIRE(result["user_expressions"] == nl::json::object()); REQUIRE(result["status"] == "ok"); } @@ -219,7 +260,7 @@ TEST_SUITE("execute_request") xcpp::interpreter interpreter((int)Args.size(), Args.data()); std::string code = "?move (utility)"; - std::string inspect_result = "https://en.cppreference.com/w/cpp/utility/move"; + std::string inspect_result = "https://en.cppreference.com/cpp/utility/move"; nl::json user_expressions = nl::json::object(); xeus::execute_request_config config; config.silent = false; @@ -254,7 +295,7 @@ TEST_SUITE("execute_request") xcpp::interpreter interpreter((int)Args.size(), Args.data()); std::string code = "?move (algorithm)"; - std::string inspect_result = "https://en.cppreference.com/w/cpp/algorithm/move"; + std::string inspect_result = "https://en.cppreference.com/cpp/algorithm/move"; nl::json user_expressions = nl::json::object(); xeus::execute_request_config config; config.silent = false; @@ -289,7 +330,7 @@ TEST_SUITE("execute_request") xcpp::interpreter interpreter((int)Args.size(), Args.data()); std::string code = "?std::vector.push_back"; - std::string inspect_result = "https://en.cppreference.com/w/cpp/container/vector/push_back"; + std::string inspect_result = "https://en.cppreference.com/cpp/container/vector/push_back"; nl::json user_expressions = nl::json::object(); xeus::execute_request_config config; config.silent = false; @@ -900,10 +941,12 @@ TEST_SUITE("xutils_handler"){ exit(0); } else { - - int status; + + int status = 0; + REQUIRE(waitpid(pid, &status, 0) == pid); + REQUIRE(WIFEXITED(status)); REQUIRE(WEXITSTATUS(status) == 0); - + } } } @@ -1229,41 +1272,3 @@ TEST_SUITE("mime_bundle_repr") REQUIRE(res == expected); } } - -#if !defined(__EMSCRIPTEN__) -// TODO: Currently any test added to this file will fail for the wasm build saying memory access out of bounds. -TEST_CASE("Silent mode restores std::cout and std::cerr buffers") -{ - std::vector Args = {}; - xcpp::interpreter interpreter((int)Args.size(), Args.data()); - - auto* cout_before = std::cout.rdbuf(); - auto* cerr_before = std::cerr.rdbuf(); - - xeus::execute_request_config config; - config.silent = true; - config.store_history = false; - config.allow_stdin = false; - - nl::json header = nl::json::object(); - xeus::xrequest_context::guid_list id = {}; - xeus::xrequest_context context(header, id); - - std::promise promise; - auto callback = [&promise](nl::json result) { promise.set_value(result); }; - - std::string code = R"( - #include - std::cout << "hidden stdout\n"; - std::cerr << "hidden stderr\n"; - )"; - - interpreter.execute_request(context, callback, code, config, nl::json::object()); - - auto reply = promise.get_future().get(); - REQUIRE(reply["status"] == "ok"); - - REQUIRE(std::cout.rdbuf() == cout_before); - REQUIRE(std::cerr.rdbuf() == cerr_before); -} -#endif \ No newline at end of file