From f1d994e2b55ec6e01134858daf3958764b121486 Mon Sep 17 00:00:00 2001 From: mcbarton Date: Fri, 24 Jan 2025 12:03:46 +0000 Subject: [PATCH] Add automated tests for Emscripten builds --- .github/workflows/deploy-pages.yml | 13 ++-- .github/workflows/emscripten.yml | 15 +++-- CMakeLists.txt | 14 ++-- Emscripten-build-instructions.md | 13 +++- cmake/CppInterOp/CppInterOpConfig.cmake.in | 6 +- cmake/modules/GoogleTest.cmake | 16 ++++- docs/Emscripten-build-instructions.rst | 13 +++- lib/Interpreter/CMakeLists.txt | 62 ++++++++++-------- lib/Interpreter/exports.ld | 62 ++++++++++++++++++ unittests/CMakeLists.txt | 16 +++-- unittests/CppInterOp/CMakeLists.txt | 65 ++++++++++++++++--- .../CppInterOp/DynamicLibraryManagerTest.cpp | 3 + .../CppInterOp/FunctionReflectionTest.cpp | 18 +++++ unittests/CppInterOp/InterpreterTest.cpp | 9 +++ unittests/CppInterOp/JitTest.cpp | 3 + unittests/CppInterOp/ScopeReflectionTest.cpp | 12 ++++ .../CppInterOp/TestSharedLib/CMakeLists.txt | 11 ++++ unittests/CppInterOp/TypeReflectionTest.cpp | 3 + .../CppInterOp/VariableReflectionTest.cpp | 6 ++ unittests/CppInterOp/main.cpp | 6 ++ 20 files changed, 294 insertions(+), 72 deletions(-) create mode 100644 lib/Interpreter/exports.ld create mode 100644 unittests/CppInterOp/main.cpp diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index da9c2dc25..4ef1199d7 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -93,10 +93,11 @@ jobs: if: ${{ runner.os != 'windows' }} shell: bash -l {0} run: | + set -e ./emsdk/emsdk activate ${{matrix.emsdk_ver}} source ./emsdk/emsdk_env.sh micromamba create -f environment-wasm.yml --platform=emscripten-wasm32 - + export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot export PREFIX=$MAMBA_ROOT_PREFIX/envs/CppInterOp-wasm export CMAKE_PREFIX_PATH=$PREFIX export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX @@ -130,6 +131,7 @@ jobs: -DCODE_COVERAGE=${{ env.CODE_COVERAGE }} \ -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DSYSROOT_PATH=$SYSROOT_PATH \ ../ else emcmake cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ @@ -141,13 +143,15 @@ jobs: -DCODE_COVERAGE=${{ env.CODE_COVERAGE }} \ -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DSYSROOT_PATH=$SYSROOT_PATH \ ../ fi - + emmake make -j ${{ env.ncpus }} check-cppinterop emmake make -j ${{ env.ncpus }} install cd .. - + + echo "SYSROOT_PATH=$SYSROOT_PATH" >> $GITHUB_ENV echo "CB_PYTHON_DIR=$CB_PYTHON_DIR" >> $GITHUB_ENV echo "CPPINTEROP_BUILD_DIR=$CPPINTEROP_BUILD_DIR" >> $GITHUB_ENV echo "CPPINTEROP_DIR=$CPPINTEROP_DIR" >> $GITHUB_ENV @@ -160,7 +164,6 @@ jobs: run: | ./emsdk/emsdk activate ${{matrix.emsdk_ver}} source ./emsdk/emsdk_env.sh - export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot micromamba activate CppInterOp-wasm git clone --depth=1 https://github.com/compiler-research/xeus-cpp.git cd ./xeus-cpp @@ -175,7 +178,7 @@ jobs: -DXEUS_CPP_EMSCRIPTEN_WASM_BUILD=ON \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ -DCppInterOp_DIR="${{ env.CPPINTEROP_BUILD_DIR }}/lib/cmake/CppInterOp" \ - -DSYSROOT_PATH=$SYSROOT_PATH \ + -DSYSROOT_PATH=${{ env.SYSROOT_PATH }} \ .. emmake make -j ${{ env.ncpus }} install diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 10563d300..704cc59bd 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -550,10 +550,11 @@ jobs: if: ${{ runner.os != 'windows' }} shell: bash -l {0} run: | + set -e ./emsdk/emsdk activate ${{matrix.emsdk_ver}} source ./emsdk/emsdk_env.sh micromamba create -f environment-wasm.yml --platform=emscripten-wasm32 - + export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot export PREFIX=$MAMBA_ROOT_PREFIX/envs/CppInterOp-wasm export CMAKE_PREFIX_PATH=$PREFIX export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX @@ -587,6 +588,7 @@ jobs: -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ -DLLVM_ENABLE_WERROR=On \ + -DSYSROOT_PATH=$SYSROOT_PATH \ ../ else emcmake cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ @@ -599,13 +601,15 @@ jobs: -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ -DLLVM_ENABLE_WERROR=On \ + -DSYSROOT_PATH=$SYSROOT_PATH \ ../ fi - - emmake make -j ${{ env.ncpus }} install + emmake make -j ${{ env.ncpus }} check-cppinterop + emmake make -j ${{ env.ncpus }} install cd .. - + + echo "SYSROOT_PATH=$SYSROOT_PATH" >> $GITHUB_ENV echo "CB_PYTHON_DIR=$CB_PYTHON_DIR" >> $GITHUB_ENV echo "CPPINTEROP_BUILD_DIR=$CPPINTEROP_BUILD_DIR" >> $GITHUB_ENV echo "CPPINTEROP_DIR=$CPPINTEROP_DIR" >> $GITHUB_ENV @@ -618,7 +622,6 @@ jobs: run: | ./emsdk/emsdk activate ${{matrix.emsdk_ver}} source ./emsdk/emsdk_env.sh - export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot micromamba activate CppInterOp-wasm git clone --depth=1 https://github.com/compiler-research/xeus-cpp.git cd ./xeus-cpp @@ -633,6 +636,6 @@ jobs: -DXEUS_CPP_EMSCRIPTEN_WASM_BUILD=ON \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ -DCppInterOp_DIR="${{ env.CPPINTEROP_BUILD_DIR }}/lib/cmake/CppInterOp" \ - -DSYSROOT_PATH=$SYSROOT_PATH \ + -DSYSROOT_PATH=${{ env.SYSROOT_PATH }} \ .. emmake make -j ${{ env.ncpus }} install diff --git a/CMakeLists.txt b/CMakeLists.txt index b27d0a762..bb919284c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -361,11 +361,15 @@ endif() # Add appropriate flags for GCC if (LLVM_COMPILER_IS_GCC_COMPATIBLE) - if (APPLE) + if (APPLE OR EMSCRIPTEN) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings") endif () + # Needed due to an error which occurs when you compile gtest on emscripten + if (EMSCRIPTEN) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare") + endif() endif () # Fixes "C++ exception handler used, but unwind semantics are not enabled" warning Windows @@ -451,13 +455,7 @@ option(CPPINTEROP_ENABLE_DOXYGEN "Use doxygen to generate CppInterOp interal API option(CPPINTEROP_ENABLE_SPHINX "Use sphinx to generage CppInterOp user documentation") -if(EMSCRIPTEN) - message("Build with emscripten") - option(CPPINTEROP_ENABLE_TESTING "Enables the testing infrastructure." OFF) -else() - message("Build with cmake") - option(CPPINTEROP_ENABLE_TESTING "Enables the testing infrastructure." ON) -endif() +option(CPPINTEROP_ENABLE_TESTING "Enables the testing infrastructure." ON) if(MSVC) diff --git a/Emscripten-build-instructions.md b/Emscripten-build-instructions.md index 662643db3..943062f07 100644 --- a/Emscripten-build-instructions.md +++ b/Emscripten-build-instructions.md @@ -25,11 +25,12 @@ git clone https://github.com/emscripten-core/emsdk.git ./emsdk/emsdk install 3.1.73 ``` -and activate the emsdk environment +and activate the emsdk environment (we are defining SYSROOT_PATH for use later) ```bash ./emsdk/emsdk activate 3.1.73 source ./emsdk/emsdk_env.sh +export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot ``` Now clone the 19.x release of the LLVM project repository and CppInterOp (the building of the emscripten version of llvm can be @@ -97,7 +98,7 @@ export CMAKE_PREFIX_PATH=$PREFIX export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX ``` -Now to build CppInterOp execute the following +Now to build and test your Emscripten build of CppInterOp by executing the following ```bash mkdir build @@ -109,7 +110,14 @@ emcmake cmake -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=ON \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ -DCMAKE_INSTALL_PREFIX=$PREFIX \ + -DSYSROOT_PATH=$SYSROOT_PATH \ ../ +emmake make -j $(nproc --all) check-cppinterop +``` + +Assuming it passes all test you can install by executing the following + +```bash emmake make -j $(nproc --all) install ``` @@ -126,7 +134,6 @@ the CppInterOp build folder, you can build the wasm version of xeus-cpp by execu ```bash cd ../.. -export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot git clone --depth=1 https://github.com/compiler-research/xeus-cpp.git cd ./xeus-cpp mkdir build diff --git a/cmake/CppInterOp/CppInterOpConfig.cmake.in b/cmake/CppInterOp/CppInterOpConfig.cmake.in index 47707d920..ce2f2449e 100644 --- a/cmake/CppInterOp/CppInterOpConfig.cmake.in +++ b/cmake/CppInterOp/CppInterOpConfig.cmake.in @@ -17,7 +17,11 @@ endif() ### build/install workaround if (@BUILD_SHARED_LIBS@) - set(_lib_suffix ${CMAKE_SHARED_LIBRARY_SUFFIX}) + if(EMSCRIPTEN) + set(_lib_suffix ".wasm") + else() + set(_lib_suffix ${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif() set(_lib_prefix ${CMAKE_SHARED_LIBRARY_PREFIX}) else() set(_lib_suffix ${CMAKE_STATIC_LIBRARY_SUFFIX}) diff --git a/cmake/modules/GoogleTest.cmake b/cmake/modules/GoogleTest.cmake index a753c1c94..18a1bc81c 100644 --- a/cmake/modules/GoogleTest.cmake +++ b/cmake/modules/GoogleTest.cmake @@ -13,13 +13,20 @@ if(WIN32) -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL:PATH=${_gtest_byproduct_binary_dir}/lib/ -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=${_gtest_byproduct_binary_dir}/lib/ -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO:PATH=${_gtest_byproduct_binary_dir}/lib/ - -Dgtest_force_shared_crt=ON - BUILD_COMMAND ${CMAKE_COMMAND} --build --config $) + -Dgtest_force_shared_crt=ON) elseif(APPLE) set(EXTRA_GTEST_OPTS -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT}) endif() include(ExternalProject) +if (EMSCRIPTEN) + set(config_cmd emcmake cmake) + set(build_cmd emmake make) +else() + set(config_cmd ${CMAKE_COMMAND}) + set(build_cmd ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/unittests/googletest-prefix/src/googletest-build/ --config $) +endif() + ExternalProject_Add( googletest GIT_REPOSITORY https://github.com/google/googletest.git @@ -31,7 +38,9 @@ ExternalProject_Add( # CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=DebugLibs # -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=ReleaseLibs # -Dgtest_force_shared_crt=ON - CMAKE_ARGS -G ${CMAKE_GENERATOR} + CONFIGURE_COMMAND ${config_cmd} -G ${CMAKE_GENERATOR} + -S ${CMAKE_BINARY_DIR}/unittests/googletest-prefix/src/googletest/ + -B ${CMAKE_BINARY_DIR}/unittests/googletest-prefix/src/googletest-build/ -DCMAKE_BUILD_TYPE=$ -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} @@ -40,6 +49,7 @@ ExternalProject_Add( -DCMAKE_AR=${CMAKE_AR} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} ${EXTRA_GTEST_OPTS} + BUILD_COMMAND ${build_cmd} # Disable install step INSTALL_COMMAND "" BUILD_BYPRODUCTS ${_gtest_byproducts} diff --git a/docs/Emscripten-build-instructions.rst b/docs/Emscripten-build-instructions.rst index aa0254c3f..f849f64bf 100644 --- a/docs/Emscripten-build-instructions.rst +++ b/docs/Emscripten-build-instructions.rst @@ -35,12 +35,13 @@ This can be installed by executing (we only currently support version git clone https://github.com/emscripten-core/emsdk.git ./emsdk/emsdk install 3.1.73 -and activate the emsdk environment +and activate the emsdk environment (we are defining SYSROOT_PATH for use later) .. code:: bash ./emsdk/emsdk activate 3.1.73 source ./emsdk/emsdk_env.sh + export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot Now clone the 19.x release of the LLVM project repository and CppInterOp (the building of the emscripten version of llvm can be avoided by @@ -115,7 +116,7 @@ You will also want to set a few environment variables export CMAKE_PREFIX_PATH=$PREFIX export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX -Now to build CppInterOp execute the following +Now to build and test your Emscripten build of CppInterOp by executing the following .. code:: bash @@ -128,7 +129,14 @@ Now to build CppInterOp execute the following -DBUILD_SHARED_LIBS=ON \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ -DCMAKE_INSTALL_PREFIX=$PREFIX \ + -DSYSROOT_PATH=$SYSROOT_PATH \ ../ + emmake make -j $(nproc --all) check-cppinterop + +Assuming it passes all test you can install by executing the following. + +.. code:: bash + emmake make -j $(nproc --all) install Once this finishes building we need to take note of where we built @@ -147,7 +155,6 @@ build folder, you can build the wasm version of xeus-cpp by executing .. code:: bash cd ../.. - export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot git clone --depth=1 https://github.com/compiler-research/xeus-cpp.git cd ./xeus-cpp mkdir build diff --git a/lib/Interpreter/CMakeLists.txt b/lib/Interpreter/CMakeLists.txt index 933505691..510521c55 100644 --- a/lib/Interpreter/CMakeLists.txt +++ b/lib/Interpreter/CMakeLists.txt @@ -1,33 +1,7 @@ if(EMSCRIPTEN) set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) - set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-s SIDE_MODULE=1") - set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-s SIDE_MODULE=1") set(CMAKE_STRIP FALSE) - - add_llvm_library(clangCppInterOp - SHARED - - CppInterOp.cpp - CXCppInterOp.cpp - DynamicLibraryManager.cpp - DynamicLibraryManagerSymbol.cpp - Paths.cpp - - # Additional libraries from Clang and LLD - LINK_LIBS - clangInterpreter - ) - #FIXME: Setting no_soname=1 is needed until https://github.com/emscripten-core/emscripten/blob/ac676d5e437525d15df5fd46bc2c208ec6d376a3/cmake/Modules/Platform/Emscripten.cmake#L36 - # is patched out of emsdk, as --soname is not recognised by emscripten. A PR to do this has been done here https://github.com/emscripten-core/emscripten/pull/23453 - #FIXME: A patch is needed to llvm to remove -Wl,-z,defs since it is now recognised on emscripten. What needs to be removed is here - # https://github.com/llvm/llvm-project/blob/128e2e446e90c3b1827cfc7d4d19e3c0976beff3/llvm/cmake/modules/HandleLLVMOptions.cmake#L318 . The PR to do try to do this is here - # https://github.com/llvm/llvm-project/pull/123396 - set_target_properties(clangCppInterOp - PROPERTIES NO_SONAME 1 -) - target_link_options(clangCppInterOp PRIVATE - PUBLIC "SHELL: -s WASM_BIGINT" - ) + set(LLVM_LINK_COMPONENTS "") else() set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} @@ -41,6 +15,7 @@ else() if ("LLVMFrontendDriver" IN_LIST LLVM_AVAILABLE_LIBS) list(APPEND LLVM_LINK_COMPONENTS FrontendDriver) endif() +endif() if ("LLVMOrcDebugging" IN_LIST LLVM_AVAILABLE_LIBS) list(APPEND LLVM_LINK_COMPONENTS OrcDebugging) endif() @@ -65,6 +40,11 @@ else() set(cling_clang_interp clangInterpreter) endif() +if(EMSCRIPTEN) + set(link_libs + ${cling_clang_interp} + ) +else() set(link_libs ${cling_clang_interp} clangAST @@ -73,6 +53,7 @@ else() clangLex clangSema ) +endif() if(NOT WIN32) list(APPEND link_libs dl) @@ -124,7 +105,6 @@ else() clangStaticAnalyzerCore ) endif(LLVM_LINK_LLVM_DYLIB) - add_llvm_library(clangCppInterOp DISABLE_LLVM_LINK_LLVM_DYLIB CppInterOp.cpp @@ -133,6 +113,32 @@ else() LINK_LIBS ${link_libs} ) + +if(EMSCRIPTEN) + # FIXME: When dynamically linking the Emscripten shared library to the + # unit tests main_module you get errors due to undefined symbols. The reading of the file + # below into a SYMBOLS_LIST variable is a temporary workaround that exports the undefined + # symbols from the shared library, until it can be determined why they are not being exported already. + file(READ "${CMAKE_SOURCE_DIR}/lib/Interpreter/exports.ld" SYMBOLS_LIST) + + # Replace newlines with spaces + string(REPLACE "\n" " " SYMBOLS_LIST "${SYMBOLS_LIST}") + + #FIXME: Setting no_soname=1 is needed until https://github.com/emscripten-core/emscripten/blob/ac676d5e437525d15df5fd46bc2c208ec6d376a3/cmake/Modules/Platform/Emscripten.cmake#L36 + # is patched out of emsdk, as --soname is not recognised by emscripten. A PR to do this has been done here https://github.com/emscripten-core/emscripten/pull/23453 + #FIXME: A patch is needed to llvm to remove -Wl,-z,defs since it is now recognised on emscripten. What needs to be removed is here + # https://github.com/llvm/llvm-project/blob/128e2e446e90c3b1827cfc7d4d19e3c0976beff3/llvm/cmake/modules/HandleLLVMOptions.cmake#L318 . The PR to do try to do this is here + # https://github.com/llvm/llvm-project/pull/123396 + set_target_properties(clangCppInterOp PROPERTIES + NO_SONAME 1 + COMPILE_FLAGS "-s SIDE_MODULE=1" + LINK_FLAGS "-s WASM_BIGINT -s SIDE_MODULE=1 ${SYMBOLS_LIST}" + SUFFIX ".wasm" + ) + # When compiling Emscripten tests the shared library it links to is expected to be in the same folder as the compiled Javascript + add_custom_command(TARGET clangCppInterOp POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_BINARY_DIR}/unittests/CppInterOp/ + ) endif() string(REPLACE ";" "\;" _VER CPPINTEROP_VERSION) diff --git a/lib/Interpreter/exports.ld b/lib/Interpreter/exports.ld new file mode 100644 index 000000000..eb74fa1fb --- /dev/null +++ b/lib/Interpreter/exports.ld @@ -0,0 +1,62 @@ +-Wl,--export=_ZN4llvm3sys2fs17getMainExecutableEPKcPv +-Wl,--export=_ZN4llvm3sys4path11parent_pathENS_9StringRefENS1_5StyleE +-Wl,--export=_ZN3Cpp11GetOperatorEPvNS_8OperatorERNSt3__26vectorIS0_NS2_9allocatorIS0_EEEENS_13OperatorArityE +-Wl,--export=_ZN4llvm11raw_ostream14flush_nonemptyEv +-Wl,--export=_ZN4llvm11raw_ostream16SetBufferAndModeEPcmNS0_10BufferKindE +-Wl,--export=_ZN4llvm11raw_ostream5writeEPKcm +-Wl,--export=_ZN4llvm11raw_ostreamD2Ev +-Wl,--export=_ZN4llvm13StringMapImpl11RehashTableEj +-Wl,--export=_ZN4llvm13StringMapImpl15LookupBucketForENS_9StringRefEj +-Wl,--export=_ZN4llvm13StringMapImpl4hashENS_9StringRefE +-Wl,--export=_ZN4llvm15SmallVectorBaseIjE8grow_podEPvmm +-Wl,--export=_ZN4llvm15allocate_bufferEmm +-Wl,--export=_ZN4llvm21logAllUnhandledErrorsENS_5ErrorERNS_11raw_ostreamENS_5TwineE +-Wl,--export=_ZN4llvm25llvm_unreachable_internalEPKcS1_j +-Wl,--export=_ZN4llvm3sys17RunningOnValgrindEv +-Wl,--export=_ZN4llvm3sys4path6appendERNS_15SmallVectorImplIcEERKNS_5TwineES7_S7_S7_ +-Wl,--export=_ZN4llvm4dbgsEv +-Wl,--export=_ZN4llvm4errsEv +-Wl,--export=_ZN4llvm5APIntC1EjNS_8ArrayRefIyEE +-Wl,--export=_ZN5clang10ASTContext19createMangleContextEPKNS_10TargetInfoE +-Wl,--export=_ZN5clang11DeclContext7classofEPKNS_4DeclE +-Wl,--export=_ZN5clang11Interpreter19getCompilerInstanceEv +-Wl,--export=_ZN5clang11Interpreter5ParseEN4llvm9StringRefE +-Wl,--export=_ZN5clang11Interpreter6createENSt3__210unique_ptrINS_16CompilerInstanceENS1_14default_deleteIS3_EEEE +-Wl,--export=_ZN5clang11Interpreter7ExecuteERNS_22PartialTranslationUnitE +-Wl,--export=_ZNK5clang4Sema15getStdNamespaceEv +-Wl,--export=_ZNK5clang4Type27getUnqualifiedDesugaredTypeEv +-Wl,--export=_ZNK5clang7TagType7getDeclEv +-Wl,--export=_ZNK5clang7VarDecl28isThisDeclarationADefinitionERNS_10ASTContextE +-Wl,--export=_ZTVN4llvm18raw_string_ostreamE +-Wl,--export=clang_Interpreter_dispose +-Wl,--export=clang_Interpreter_getClangInterpreter +-Wl,--export=clang_Interpreter_takeInterpreterAsPtr +-Wl,--export=clang_createInterpreterFromRawPtr +-Wl,--export=clang_getComplexType +-Wl,--export=clang_getTypeAsString +-Wl,--export=clang_instantiateTemplate +-Wl,--export=_ZN5clang13MangleContext10mangleNameENS_10GlobalDeclERN4llvm11raw_ostreamE +-Wl,--export=_ZN5clang13MangleContext20shouldMangleDeclNameEPKNS_9NamedDeclE +-Wl,--export=_ZN5clang26IncrementalCompilerBuilder9CreateCppEv +-Wl,--export=_ZN5clang4Decl17castToDeclContextEPKS0_ +-Wl,--export=_ZNK3Cpp7JitCall17AreArgumentsValidEPvNS0_7ArgListES1_ +-Wl,--export=_ZNK3Cpp7JitCall17ReportInvokeStartEPvNS0_7ArgListES1_ +-Wl,--export=_ZNK3Cpp7JitCall17ReportInvokeStartEPvmi +-Wl,--export=_ZNK4llvm5APInt13compareSignedERKS0_ +-Wl,--export=_ZNK4llvm5APInt4sextEj +-Wl,--export=_ZNK4llvm5APInt4zextEj +-Wl,--export=_ZNK4llvm5APInt7compareERKS0_ +-Wl,--export=_ZNK4llvm5Error19fatalUncheckedErrorEv +-Wl,--export=_ZNK5clang10ASTContext14getComplexTypeENS_8QualTypeE +-Wl,--export=_ZNK5clang10ASTContext19getTypeDeclTypeSlowEPKNS_8TypeDeclE +-Wl,--export=_ZNK5clang10RecordDecl19isInjectedClassNameEv +-Wl,--export=_ZNK5clang11DeclContext11decls_beginEv +-Wl,--export=_ZNK5clang11DeclContext6lookupENS_15DeclarationNameE +-Wl,--export=_ZNK5clang12FunctionDecl29getTemplateSpecializationArgsEv +-Wl,--export=_ZNK5clang12FunctionDecl31getTemplateInstantiationPatternEb +-Wl,--export=_ZNK5clang17ClassTemplateDecl18getSpecializationsEv +-Wl,--export=_ZNK5clang29VarTemplateSpecializationDecl22getSpecializedTemplateEv +-Wl,--export=_ZNK5clang4Decl13getASTContextEv +-Wl,--export=_ZNK5clang4Decl15hasDefiningAttrEv +-Wl,--export=_ZNK5clang4Decl8getAttrsEv +-Wl,--export=_ZN4llvm3sys2fs6accessERKNS_5TwineENS1_10AccessModeE diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 972b1e475..dddb1aaf7 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -7,10 +7,15 @@ if (NOT TARGET gtest) include(GoogleTest) endif() -set(gtest_libs gtest gtest_main) -# Clang prior than clang13 (I think) merges both gmock into gtest. -if (TARGET gmock) - list(APPEND gtest_libs gmock gmock_main) +if(EMSCRIPTEN) + set(gtest_libs gtest gmock) +else() + set(gtest_libs gtest gtest_main) + # Clang prior than clang13 (I think) merges both gmock into gtest. + if (TARGET gmock) + list(APPEND gtest_libs gmock gmock_main) + endif() + set(link_pthreads_lib pthread) endif() add_custom_target(CppInterOpUnitTests) @@ -23,12 +28,11 @@ function(add_cppinterop_unittest name) add_dependencies(CppInterOpUnitTests ${name}) target_include_directories(${name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${GTEST_INCLUDE_DIR}) set_property(TARGET ${name} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - if(WIN32) target_link_libraries(${name} PUBLIC ${ARG_LIBRARIES} ${gtest_libs}) set_property(TARGET ${name} APPEND_STRING PROPERTY LINK_FLAGS "${MSVC_EXPORTS}") else() - target_link_libraries(${name} PUBLIC ${ARG_LIBRARIES} ${gtest_libs} pthread) + target_link_libraries(${name} PRIVATE ${ARG_LIBRARIES} ${gtest_libs} ${link_pthreads_lib}) endif() add_test(NAME cppinterop-${name} COMMAND ${name}) set_tests_properties(cppinterop-${name} PROPERTIES diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 25f59b394..19a8e6e1a 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -1,9 +1,18 @@ set(LLVM_LINK_COMPONENTS Support ) +if (EMSCRIPTEN) + # Omitting CUDATest.cpp since Emscripten build currently has no GPU support + # For Emscripten builds linking to gtest_main will not suffice for gtest to run + # the tests and an explictly main.cpp is needed + set(EXTRA_TEST_SOURCE_FILES main.cpp) +else() + # Do not need main.cpp for native builds, but we do have GPU support for native builds + set(EXTRA_TEST_SOURCE_FILES CUDATest.cpp) + set(EXTRA_PATH_TEST_BINARIES /CppInterOpTests/unittests/bin/$/) +endif() add_cppinterop_unittest(CppInterOpTests - CUDATest.cpp EnumReflectionTest.cpp FunctionReflectionTest.cpp InterpreterTest.cpp @@ -12,16 +21,32 @@ add_cppinterop_unittest(CppInterOpTests TypeReflectionTest.cpp Utils.cpp VariableReflectionTest.cpp + ${EXTRA_TEST_SOURCE_FILES} ) +if(EMSCRIPTEN) + # Explaination of compile and link flags + # To dynamically link to a shared library for Emscripten builds you must use the MAIN_MODULE flag (see both https://github.com/emscripten-core/emscripten/issues/23543#issuecomment-2625334414 + # and https://emscripten.org/docs/compiling/Dynamic-Linking.html) + # Without WASM_BIGINT flag then you get fatal errors when trying to run compiled Javascript about trying to convert between BigInt and non BigInt types + # EXPORTED_RUNTIME_METHODS='[\"FS\",\"PATH\",\"LDSO\",\"loadDynamicLibrary\",\"ERRNO_CODES\"]' and --preload-file ${SYSROOT_PATH}/include@/include are not allow the Javascript that is + # compiled to have access to the standard library headers (approach taken from xeus-cpp) + # Without ALLOW_MEMORY_GROWTH=1 tests will fail with aborted(OOM). Approach to fix taken from answers to + # https://stackoverflow.com/questions/67222200/runtimeerror-abortoom-build-with-s-assertions-1-for-more-info + set_target_properties(CppInterOpTests PROPERTIES + COMPILE_FLAGS "-s MAIN_MODULE=1" + LINK_FLAGS "-s MAIN_MODULE=1 -s WASM_BIGINT -s EXPORTED_RUNTIME_METHODS='[\"FS\",\"PATH\",\"LDSO\",\"loadDynamicLibrary\",\"ERRNO_CODES\"]' --preload-file ${SYSROOT_PATH}/include@/include -s ALLOW_MEMORY_GROWTH=1" + ) +endif() + target_link_libraries(CppInterOpTests - PRIVATE - clangCppInterOp -) + PRIVATE + clangCppInterOp + ) set_output_directory(CppInterOpTests - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/CppInterOpTests/unittests/bin/$/ - LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/CppInterOpTests/unittests/bin/$/ + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES} + LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES} ) if(NOT WIN32) @@ -37,16 +62,38 @@ export_executable_symbols(CppInterOpTests) unset(LLVM_LINK_COMPONENTS) -add_cppinterop_unittest(DynamicLibraryManagerTests DynamicLibraryManagerTest.cpp) +add_cppinterop_unittest(DynamicLibraryManagerTests DynamicLibraryManagerTest.cpp ${EXTRA_TEST_SOURCE_FILES}) + target_link_libraries(DynamicLibraryManagerTests PRIVATE clangCppInterOp ) +if(EMSCRIPTEN) + # Explaination of compile and link flags + # To dynamically link to a shared library for Emscripten builds you must use the MAIN_MODULE flag (see both https://github.com/emscripten-core/emscripten/issues/23543#issuecomment-2625334414 + # and https://emscripten.org/docs/compiling/Dynamic-Linking.html) + # Without WASM_BIGINT flag then you get fatal errors when trying to run compiled Javascript about trying to convert between BigInt and non BigInt types + # EXPORTED_RUNTIME_METHODS='[\"FS\",\"PATH\",\"LDSO\",\"loadDynamicLibrary\",\"ERRNO_CODES\"]' and --preload-file ${SYSROOT_PATH}/include@/include are not allow the Javascript that is + # compiled to have access to the standard library headers (approach taken from xeus-cpp) + # Without ALLOW_MEMORY_GROWTH=1 tests will fail with aborted(OOM). Approach to fix taken from answers to + # https://stackoverflow.com/questions/67222200/runtimeerror-abortoom-build-with-s-assertions-1-for-more-info + set_target_properties(DynamicLibraryManagerTests PROPERTIES + COMPILE_FLAGS "-s MAIN_MODULE=1" + LINK_FLAGS "-s MAIN_MODULE=1 -s WASM_BIGINT -s EXPORTED_RUNTIME_METHODS='[\"FS\",\"PATH\",\"LDSO\",\"loadDynamicLibrary\",\"ERRNO_CODES\"]' --preload-file ${SYSROOT_PATH}/include@/include -s ALLOW_MEMORY_GROWTH=1" + ) +endif() + + if (NOT EMSCRIPTEN) + set(EXTRA_PATH_TEST_BINARIES /TestSharedLib/unittests/bin/$/) +endif() + set_output_directory(DynamicLibraryManagerTests - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestSharedLib/unittests/bin/$/ - LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestSharedLib/unittests/bin/$/ + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES} + LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES} ) + add_dependencies(DynamicLibraryManagerTests TestSharedLib) + #export_executable_symbols_for_plugins(TestSharedLib) add_subdirectory(TestSharedLib) diff --git a/unittests/CppInterOp/DynamicLibraryManagerTest.cpp b/unittests/CppInterOp/DynamicLibraryManagerTest.cpp index 01624ef78..c881d9fdd 100644 --- a/unittests/CppInterOp/DynamicLibraryManagerTest.cpp +++ b/unittests/CppInterOp/DynamicLibraryManagerTest.cpp @@ -18,6 +18,9 @@ std::string GetExecutablePath(const char* Argv0) { } TEST(DynamicLibraryManagerTest, Sanity) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test fails for Emscipten builds"; +#endif EXPECT_TRUE(Cpp::CreateInterpreter()); EXPECT_FALSE(Cpp::GetFunctionAddress("ret_zero")); diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index efc1ca815..0d063ad4f 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -532,6 +532,9 @@ TEST(FunctionReflectionTest, ExistsFunctionTemplate) { } TEST(FunctionReflectionTest, InstantiateTemplateFunctionFromString) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; Cpp::CreateInterpreter(); @@ -798,6 +801,9 @@ TEST(FunctionReflectionTest, IsStaticMethod) { } TEST(FunctionReflectionTest, GetFunctionAddress) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; #ifdef _WIN32 @@ -842,6 +848,9 @@ TEST(FunctionReflectionTest, IsVirtualMethod) { } TEST(FunctionReflectionTest, JitCallAdvanced) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; std::vector Decls; @@ -866,6 +875,9 @@ TEST(FunctionReflectionTest, JitCallAdvanced) { TEST(FunctionReflectionTest, GetFunctionCallWrapper) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; std::vector Decls; @@ -1127,6 +1139,9 @@ TEST(FunctionReflectionTest, GetFunctionArgDefault) { } TEST(FunctionReflectionTest, Construct) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test fails for Emscipten builds"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; #ifdef _WIN32 @@ -1167,6 +1182,9 @@ TEST(FunctionReflectionTest, Construct) { } TEST(FunctionReflectionTest, Destruct) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test fails for Emscipten builds"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; diff --git a/unittests/CppInterOp/InterpreterTest.cpp b/unittests/CppInterOp/InterpreterTest.cpp index b247ac363..a78cab24b 100644 --- a/unittests/CppInterOp/InterpreterTest.cpp +++ b/unittests/CppInterOp/InterpreterTest.cpp @@ -58,6 +58,9 @@ TEST(InterpreterTest, DebugFlag) { } TEST(InterpreterTest, Evaluate) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test fails for Emscipten builds"; +#endif #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif @@ -126,6 +129,9 @@ TEST(InterpreterTest, CreateInterpreter) { #ifdef LLVM_BINARY_DIR TEST(InterpreterTest, DetectResourceDir) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test fails for Emscipten builds"; +#endif #else TEST(InterpreterTest, DISABLED_DetectResourceDir) { #endif // LLVM_BINARY_DIR @@ -145,6 +151,9 @@ TEST(InterpreterTest, DISABLED_DetectResourceDir) { } TEST(InterpreterTest, DetectSystemCompilerIncludePaths) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test fails for Emscipten builds"; +#endif #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif diff --git a/unittests/CppInterOp/JitTest.cpp b/unittests/CppInterOp/JitTest.cpp index 310f87efe..b9c2a75c2 100644 --- a/unittests/CppInterOp/JitTest.cpp +++ b/unittests/CppInterOp/JitTest.cpp @@ -12,6 +12,9 @@ static int printf_jit(const char* format, ...) { } TEST(JitTest, InsertOrReplaceJitSymbol) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test fails for Emscipten builds"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; #ifdef _WIN32 diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index b3edf5b00..f8b4a27cb 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -161,6 +161,9 @@ TEST(ScopeReflectionTest, SizeOf) { TEST(ScopeReflectionTest, IsBuiltin) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif // static std::set g_builtins = // {"bool", "char", "signed char", "unsigned char", "wchar_t", "short", "unsigned short", // "int", "unsigned int", "long", "unsigned long", "long long", "unsigned long long", @@ -491,6 +494,9 @@ TEST(ScopeReflectionTest, GetScopefromCompleteName) { } TEST(ScopeReflectionTest, GetNamed) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif std::string code = R"(namespace N1 { namespace N2 { class C { @@ -876,6 +882,9 @@ template T TrivialFnTemplate() { return T(); } } TEST(ScopeReflectionTest, InstantiateTemplateFunctionFromString) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; Cpp::CreateInterpreter(); @@ -1016,6 +1025,9 @@ TEST(ScopeReflectionTest, GetClassTemplateInstantiationArgs) { TEST(ScopeReflectionTest, IncludeVector) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; std::string code = R"( diff --git a/unittests/CppInterOp/TestSharedLib/CMakeLists.txt b/unittests/CppInterOp/TestSharedLib/CMakeLists.txt index 05f1afb3f..bfb4e6e8b 100644 --- a/unittests/CppInterOp/TestSharedLib/CMakeLists.txt +++ b/unittests/CppInterOp/TestSharedLib/CMakeLists.txt @@ -8,4 +8,15 @@ set_output_directory(TestSharedLib BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/unittests/bin/$/ LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/unittests/bin/$/ ) + + +if (EMSCRIPTEN) + set_target_properties(TestSharedLib PROPERTIES + NO_SONAME 1 + COMPILE_FLAGS "-s SIDE_MODULE=1" + LINK_FLAGS "-s WASM_BIGINT -s SIDE_MODULE=1" + SUFFIX ".wasm" + ) +endif() + set_target_properties(TestSharedLib PROPERTIES FOLDER "Tests") diff --git a/unittests/CppInterOp/TypeReflectionTest.cpp b/unittests/CppInterOp/TypeReflectionTest.cpp index af864942e..5325ce0dd 100644 --- a/unittests/CppInterOp/TypeReflectionTest.cpp +++ b/unittests/CppInterOp/TypeReflectionTest.cpp @@ -546,6 +546,9 @@ TEST(TypeReflectionTest, IsPODType) { } TEST(TypeReflectionTest, IsSmartPtrType) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; Cpp::CreateInterpreter(); diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 379f5af89..ed41bc107 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -263,6 +263,9 @@ TEST(VariableReflectionTest, GetVariableType) { CODE TEST(VariableReflectionTest, GetVariableOffset) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif std::vector Decls; #define Stringify(s) Stringifyx(s) #define Stringifyx(...) #__VA_ARGS__ @@ -328,6 +331,9 @@ TEST(VariableReflectionTest, GetVariableOffset) { CODE TEST(VariableReflectionTest, VariableOffsetsWithInheritance) { +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test crashes gtest on Emscipten"; +#endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; diff --git a/unittests/CppInterOp/main.cpp b/unittests/CppInterOp/main.cpp new file mode 100644 index 000000000..09799f80a --- /dev/null +++ b/unittests/CppInterOp/main.cpp @@ -0,0 +1,6 @@ +#include + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file