diff --git a/.github/workflows/build_llvm.yml b/.github/workflows/build_llvm.yml index 49383bcc..9b505e6a 100644 --- a/.github/workflows/build_llvm.yml +++ b/.github/workflows/build_llvm.yml @@ -19,6 +19,7 @@ on: - ".github/workflows/build_llvm.yml" - "build_tools/cmake/llvm_cache.cmake" - "build_tools/cmake/llvm_wasm_cache.cmake" + - "build_tools/cmake/llvm_wasm_project_include.cmake" - "build_tools/build_llvm.sh" - "build_tools/build_llvm_wasi.sh" - "third_party/llvm-project" @@ -28,6 +29,7 @@ on: paths: - "build_tools/cmake/llvm_cache.cmake" - "build_tools/cmake/llvm_wasm_cache.cmake" + - "build_tools/cmake/llvm_wasm_project_include.cmake" - "build_tools/build_llvm.sh" - "build_tools/build_llvm_wasi.sh" - "third_party/llvm-project" diff --git a/build_tools/build_llvm_wasi.sh b/build_tools/build_llvm_wasi.sh index de27195b..c3041a86 100755 --- a/build_tools/build_llvm_wasi.sh +++ b/build_tools/build_llvm_wasi.sh @@ -32,20 +32,22 @@ echo "*********************** BUILDING LLVM *********************************" # https://stackoverflow.com/a/75596433/9045206 sed -i.bak 's/CMAKE_EXECUTABLE_SUFFIX ".js"/CMAKE_EXECUTABLE_SUFFIX ".html"/g' "$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" +# all emscripten settings here https://github.com/emscripten-core/emscripten/blob/main/src/settings.js +# wasm-ld exports https://lld.llvm.org/WebAssembly.html#exports +# -sLINKABLE=1 combined with CMAKE_CXX_VISIBILITY_PRESET=default will cause all symbols to be exported +# -sEXPORT_ALL=1 put all of the exported function in the wasm on the JS module cmake_options=( -GNinja -S "${LLVM_SOURCE_DIR}/llvm" -B "${LLVM_BUILD_DIR}" - # optimize for size - -DCMAKE_C_FLAGS="-Os" - -DCMAKE_CXX_FLAGS="-Os" -DCMAKE_BUILD_TYPE=Release - -DCMAKE_EXE_LINKER_FLAGS="--emit-symbol-map -sSTANDALONE_WASM=1 -sWASM=1 -sWASM_BIGINT=1 -sEXPORT_ALL=0 -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,getValue,setValue,writeAsciiToMemory,wasmTable -lembind" + -DCMAKE_EXE_LINKER_FLAGS="--demangle --emit-symbol-map -sSTANDALONE_WASM=1 -sWASM=1 -sWASM_BIGINT=1 -sLINKABLE=1 -sEXPORT_ALL=1 -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,getValue,setValue,writeAsciiToMemory,wasmTable --minify 0 -lembind" -DCMAKE_INSTALL_PREFIX="${LLVM_INSTALL_DIR}" -DCMAKE_SYSTEM_NAME=Emscripten -DCMAKE_TOOLCHAIN_FILE="$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" -DCROSS_TOOLCHAIN_FLAGS_NATIVE="-DCMAKE_C_COMPILER=$CC;-DCMAKE_CXX_COMPILER=$CXX" -C "$TD/cmake/llvm_wasm_cache.cmake" + -DCMAKE_PROJECT_INCLUDE="$TD/cmake/llvm_wasm_project_include.cmake" ) echo "Source Directory: ${LLVM_SOURCE_DIR}" @@ -59,4 +61,10 @@ cmake --build "${LLVM_BUILD_DIR}" \ sed -i.bak 's/CMAKE_EXECUTABLE_SUFFIX ".html"/CMAKE_EXECUTABLE_SUFFIX ".js"/g' "$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" # wasi files aren't installed for some reason -cp "${LLVM_BUILD_DIR}"/bin/* "${LLVM_INSTALL_DIR}/bin" +cp "${LLVM_BUILD_DIR}"/bin/mlir-opt.* "${LLVM_INSTALL_DIR}/bin" +# cp "${LLVM_BUILD_DIR}"/lib/*.symbols "${LLVM_INSTALL_DIR}/lib" + +# prevent symbol collisions +# sed -i.bak 's/if(LLVM_ENABLE_PIC)/if(LLVM_ENABLE_PIC)\nreturn()\nendif()\nif(LLVM_ENABLE_PIC)/g' "${LLVM_SOURCE_DIR}/mlir/lib/ExecutionEngine/CMakeLists.txt" +# https://stackoverflow.com/a/1252191/9045206 +# sed -i.bak -e ':a' -e 'N' -e '$!ba' -e 's/if(LLVM_ENABLE_PIC)\nreturn()\nendif()\n//g' "${LLVM_SOURCE_DIR}/mlir/lib/ExecutionEngine/CMakeLists.txt" diff --git a/build_tools/cmake/llvm_wasm_cache.cmake b/build_tools/cmake/llvm_wasm_cache.cmake index 67109679..99fa1dfc 100644 --- a/build_tools/cmake/llvm_wasm_cache.cmake +++ b/build_tools/cmake/llvm_wasm_cache.cmake @@ -13,7 +13,15 @@ set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "") set(LLVM_ENABLE_LIBPFM OFF CACHE BOOL "") set(LLVM_ENABLE_LIBXML2 OFF CACHE BOOL "") set(LLVM_ENABLE_OCAMLDOC OFF CACHE BOOL "") + +set(LLVM_BUILD_LLVM_DYLIB OFF CACHE BOOL "") +set(MLIR_BUILD_MLIR_C_DYLIB OFF CACHE BOOL "") +# when building libLLVM +# relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol set(LLVM_ENABLE_PIC OFF CACHE BOOL "") +set(MLIR_ENABLE_SPIRV_CPU_RUNNER OFF) +set(MLIR_ENABLE_EXECUTION_ENGINE OFF) + set(LLVM_ENABLE_THREADS OFF CACHE BOOL "") set(LLVM_ENABLE_UNWIND_TABLES OFF CACHE BOOL "") set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "") @@ -33,7 +41,7 @@ set(LLVM_MlirDevelopment_DISTRIBUTION_COMPONENTS llvm-headers llvm-libraries cmake-exports - opt + # opt # triggers LLVMMlirDevelopmentExports.cmake mlirdevelopment-cmake-exports # triggers MLIRMlirDevelopmentTargets.cmake @@ -43,7 +51,7 @@ set(LLVM_MlirDevelopment_DISTRIBUTION_COMPONENTS mlir-headers mlir-libraries mlir-opt - mlir-reduce - mlir-tblgen - mlir-translate + # mlir-reduce + # mlir-tblgen + # mlir-translate CACHE STRING "") \ No newline at end of file diff --git a/build_tools/cmake/llvm_wasm_project_include.cmake b/build_tools/cmake/llvm_wasm_project_include.cmake new file mode 100644 index 00000000..d110518c --- /dev/null +++ b/build_tools/cmake/llvm_wasm_project_include.cmake @@ -0,0 +1,27 @@ +# everything in here gets run at the end of the project loading +# https://github.com/emscripten-core/emscripten/issues/15276#issuecomment-1039349267 +set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) +# __ELF__ so that the correct LLVM_ABI macros get set +# https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md#function-arguments-and-return-values +# Similarly, types can either be returned directly from WebAssembly functions or returned indirectly via a pointer parameter prepended to the parameter list. +# https://github.com/llvm/llvm-project/blob/6d973b4548e281d0b8e75e85833804bb45b6a0e8/clang/lib/CodeGen/Targets/WebAssembly.cpp#L135 +# https://github.com/llvm/llvm-project/commit/c285307e1457c4db2346443a4336e672d7487111#diff-b83bb889340990fea25762060e144b5cd4b4652a6fa737aaea9555d456344219 +# https://github.com/llvm/llvm-project/blame/63534779b4ef1816e2961246011e2ec3be110d27/clang/lib/CodeGen/TargetInfo.cpp +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__ELF__") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__ELF__") +set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-sLINKABLE=1 -sEXPORT_ALL=1") +set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-sLINKABLE=1 -sEXPORT_ALL=1") +# prevent duplicated libs from being linked +# will need to be renamed to DEDUPLICATION when CMake version catches up +# https://github.com/Kitware/CMake/commit/5617c34c3135f7ec203d5a48b803eb323f458bc3#diff-17fc647759070cdaddd99e9ad994c4478860d9c301ed9a9a9f061a8825c8b690L20 +set(CMAKE_C_LINK_LIBRARIES_PROCESSING ORDER=FORWARD UNICITY=ALL) +set(CMAKE_CXX_LINK_LIBRARIES_PROCESSING ORDER=FORWARD UNICITY=ALL) + +## hack to prevent -Bsymbolic +#set(LLVM_LINKER_IS_SOLARISLD_ILLUMOS ON) + +set(CMAKE_SHARED_LIBRARY_SUFFIX ".wasm") +set(CMAKE_STRIP FALSE) +set(LLVM_NO_DEAD_STRIP ON) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_CXX_VISIBILITY_PRESET default) diff --git a/projects/js/embindings/CMakeLists.txt b/projects/js/embindings/CMakeLists.txt new file mode 100644 index 00000000..527088f0 --- /dev/null +++ b/projects/js/embindings/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.29) +project(eudsl-embindings LANGUAGES CXX C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR EUDSL_OUT_OF_TREE_BUILD) + find_package(MLIR REQUIRED CONFIG) + find_package(LLVM REQUIRED CONFIG) + message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) + set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") + list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") + include(TableGen) + include(AddLLVM) + include(AddMLIR) + include(HandleLLVMOptions) +else() + set(MLIR_MAIN_SRC_DIR ${LLVM_MAIN_SRC_DIR}/../mlir) + set(MLIR_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/../mlir/include) + set(MLIR_GENERATED_INCLUDE_DIR ${LLVM_BINARY_DIR}/tools/mlir/include) + set(MLIR_INCLUDE_DIRS "${MLIR_INCLUDE_DIR};${MLIR_GENERATED_INCLUDE_DIR}") +endif() +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${MLIR_INCLUDE_DIRS}) + +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) # used by default in pybind11 on .so modules + +add_library(example SHARED example.cpp) +target_link_libraries(example PUBLIC MLIRIR) \ No newline at end of file diff --git a/projects/js/embindings/example.cpp b/projects/js/embindings/example.cpp new file mode 100644 index 00000000..5f0dae0c --- /dev/null +++ b/projects/js/embindings/example.cpp @@ -0,0 +1,37 @@ +// +// Created by maksim on 11/14/24. +// + +#include +#include +#include +#include + +using namespace emscripten; + +std::vector returnVectorData () { + std::vector v(10, 1); + return v; +} + +std::map returnMapData () { + std::map m; + m.insert(std::pair(10, "This is a string.")); + return m; +} + +std::optional returnOptionalData() { + return "hello"; +} + +EMSCRIPTEN_BINDINGS(module) { + function("returnVectorData", &returnVectorData); + function("returnMapData", &returnMapData); + function("returnOptionalData", &returnOptionalData); + + // register bindings for std::vector, std::map, and + // std::optional. + register_vector("vector"); + register_map("map"); + register_optional(); +}