diff --git a/.github/workflows/build-assets.yml b/.github/workflows/build-assets.yml index 4754b9b7763..29163fe97a7 100644 --- a/.github/workflows/build-assets.yml +++ b/.github/workflows/build-assets.yml @@ -55,7 +55,7 @@ jobs: echo "internal_tag=$(echo $community_tag | sed 's/community/internal/')" >> $GITHUB_OUTPUT community_base_ref=${{ github.event.base_ref || github.ref }} echo "community_branch=$(echo $community_base_ref | cut -d'/' -f3)" >> $GITHUB_OUTPUT - echo "cmake_docker_config=-DCMAKE_BUILD_TYPE=RelWithDebInfo -DVCPKG_FILES_DIR=/hpcc-dev -DCPACK_THREADS=0 -DUSE_OPTIONAL=OFF -DSIGN_MODULES=ON" >> $GITHUB_OUTPUT + echo "cmake_docker_config=-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK_THREADS=0 -DUSE_OPTIONAL=OFF -DSIGN_MODULES=ON" >> $GITHUB_OUTPUT echo 'gpg_import=gpg --batch --import /hpcc-dev/build/private.key' >> $GITHUB_OUTPUT - name: Print vars @@ -155,12 +155,16 @@ jobs: tags: | build-${{ matrix.os }}:latest + - name: Prepare build folder + run: | + mkdir -p ${{ needs.preamble.outputs.folder_build }} + docker run --rm --mount ${{ needs.preamble.outputs.mount_platform }} --mount ${{ needs.preamble.outputs.mount_build }} $docker_label "cp /hpcc-dev/vcpkg_installed /hpcc-dev/build" + - name: CMake Packages if: ${{ !matrix.container && !matrix.ln && !matrix.documentation }} run: | - mkdir -p ${{ needs.preamble.outputs.folder_build }} echo "${{ secrets.SIGNING_SECRET }}" > ${{ needs.preamble.outputs.folder_build }}/private.key - plugins=("CASSANDRAEMBED" "COUCHBASEEMBED" "ECLBLAS" "H3" "JAVAEMBED" "KAFKA" "MEMCACHED" "MONGODBEMBED" "MYSQLEMBED" "NLP" "REDIS" "REMBED" "SQLITE3EMBED" "SQS" "PLATFORM") + plugins=("CASSANDRAEMBED" "COUCHBASEEMBED" "ECLBLAS" "H3" "JAVAEMBED" "KAFKA" "MEMCACHED" "MONGODBEMBED" "MYSQLEMBED" "NLP" "REDIS" "REMBED" "SQLITE3EMBED" "SQS" "WASMEMBED" "PLATFORM") for plugin in "${plugins[@]}"; do sudo rm -f ${{ needs.preamble.outputs.folder_build }}/CMakeCache.txt sudo rm -rf ${{ needs.preamble.outputs.folder_build }}/CMakeFiles @@ -175,7 +179,6 @@ jobs: - name: CMake Containerized Packages if: ${{ matrix.container }} run: | - mkdir -p ${{ needs.preamble.outputs.folder_build }} echo "${{ secrets.SIGNING_SECRET }}" > ${{ needs.preamble.outputs.folder_build }}/private.key sudo rm -f ${{ needs.preamble.outputs.folder_build }}/CMakeCache.txt sudo rm -rf ${{ needs.preamble.outputs.folder_build }}/CMakeFiles @@ -209,7 +212,6 @@ jobs: - name: CMake LN Packages if: ${{ matrix.ln }} run: | - mkdir -p ${{ needs.preamble.outputs.folder_build }} echo "${{ secrets.SIGNING_SECRET }}" > ${{ needs.preamble.outputs.folder_build }}/private.key sudo rm -f ${{ needs.preamble.outputs.folder_build }}/CMakeCache.txt sudo rm -rf ${{ needs.preamble.outputs.folder_build }}/CMakeFiles diff --git a/.github/workflows/build-vcpkg.yml b/.github/workflows/build-vcpkg.yml index fd66e3b01b7..122382bf195 100644 --- a/.github/workflows/build-vcpkg.yml +++ b/.github/workflows/build-vcpkg.yml @@ -58,7 +58,7 @@ jobs: echo "internal_tag=$(echo $community_tag | sed 's/community/internal/')" >> $GITHUB_OUTPUT community_base_ref=${{ github.event.base_ref || github.ref }} echo "community_branch=$(echo $community_base_ref | cut -d'/' -f3)" >> $GITHUB_OUTPUT - echo "cmake_docker_config=-DCMAKE_BUILD_TYPE=RelWithDebInfo -DVCPKG_FILES_DIR=/hpcc-dev -DCPACK_THREADS=0 -DUSE_OPTIONAL=OFF" >> $GITHUB_OUTPUT + echo "cmake_docker_config=-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK_THREADS=0 -DUSE_OPTIONAL=OFF" >> $GITHUB_OUTPUT - id: skip_check uses: hpcc-systems/github-actions/changed-modules@main @@ -147,13 +147,17 @@ jobs: tags: | build-${{ matrix.os }}:latest + - name: Prepare build folder + run: | + mkdir -p ${{ needs.preamble.outputs.folder_build }} + docker run --rm --mount ${{ needs.preamble.outputs.mount_platform }} --mount ${{ needs.preamble.outputs.mount_build }} $docker_label "cp /hpcc-dev/vcpkg_installed /hpcc-dev/build" + - name: CMake Packages if: ${{ !matrix.container && !matrix.ln && contains(matrix.event_name, github.event_name) && needs.preamble.outputs.platform }} run: | - mkdir -p ${{ needs.preamble.outputs.folder_build }} declare -a plugins if [ ${{ needs.preamble.outputs.include_plugins }} == "ON" ]; then - plugins=("CASSANDRAEMBED" "COUCHBASEEMBED" "ECLBLAS" "H3" "JAVAEMBED" "KAFKA" "MEMCACHED" "MONGODBEMBED" "MYSQLEMBED" "NLP" "REDIS" "REMBED" "SQLITE3EMBED" "SQS" "PLATFORM") + plugins=("CASSANDRAEMBED" "COUCHBASEEMBED" "ECLBLAS" "H3" "JAVAEMBED" "KAFKA" "MEMCACHED" "MONGODBEMBED" "MYSQLEMBED" "NLP" "REDIS" "REMBED" "SQLITE3EMBED" "SQS" "WASMEMBED" "PLATFORM") else plugins=("PLATFORM") fi @@ -171,7 +175,6 @@ jobs: - name: CMake Containerized Packages if: ${{ matrix.container && contains(matrix.event_name, github.event_name) && needs.preamble.outputs.platform }} run: | - mkdir -p ${{ needs.preamble.outputs.folder_build }} sudo rm -f ${{ needs.preamble.outputs.folder_build }}/CMakeCache.txt sudo rm -rf ${{ needs.preamble.outputs.folder_build }}/CMakeFiles docker_label=build-${{ matrix.os }}:latest @@ -182,7 +185,6 @@ jobs: - name: CMake LN Packages if: ${{ matrix.ln && contains(matrix.event_name, github.event_name) && needs.preamble.outputs.platform }} run: | - mkdir -p ${{ needs.preamble.outputs.folder_build }} sudo rm -f ${{ needs.preamble.outputs.folder_build }}/CMakeCache.txt sudo rm -rf ${{ needs.preamble.outputs.folder_build }}/CMakeFiles docker_label=build-${{ matrix.os }}:latest diff --git a/CMakeLists.txt b/CMakeLists.txt index e226b94631f..951990812c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,6 +169,7 @@ if ( PLUGIN ) HPCC_ADD_SUBDIRECTORY (dali/base) HPCC_ADD_SUBDIRECTORY (plugins/Rembed "REMBED") HPCC_ADD_SUBDIRECTORY (plugins/v8embed "V8EMBED") + HPCC_ADD_SUBDIRECTORY (plugins/wasmembed "WASMEMBED") HPCC_ADD_SUBDIRECTORY (plugins/memcached "MEMCACHED") HPCC_ADD_SUBDIRECTORY (plugins/redis "REDIS") HPCC_ADD_SUBDIRECTORY (plugins/javaembed "JAVAEMBED") diff --git a/cmake_modules/plugins.cmake b/cmake_modules/plugins.cmake index 88a5cdbbc1b..5be884d4c03 100644 --- a/cmake_modules/plugins.cmake +++ b/cmake_modules/plugins.cmake @@ -41,6 +41,7 @@ set(PLUGINS_LIST SQLITE3EMBED SQS V8EMBED + WASMEMBED EXAMPLEPLUGIN ) diff --git a/dockerfiles/vcpkg/amazonlinux.dockerfile b/dockerfiles/vcpkg/amazonlinux/Dockerfile similarity index 100% rename from dockerfiles/vcpkg/amazonlinux.dockerfile rename to dockerfiles/vcpkg/amazonlinux/Dockerfile diff --git a/dockerfiles/vcpkg/build.sh b/dockerfiles/vcpkg/build.sh index 1e9a51dbea4..0aca57d0cac 100755 --- a/dockerfiles/vcpkg/build.sh +++ b/dockerfiles/vcpkg/build.sh @@ -25,22 +25,28 @@ echo "DOCKER_PASSWORD: $DOCKER_PASSWORD" # docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD function doBuild() { - docker build --progress plain --pull --rm -f "$SCRIPT_DIR/$1.dockerfile" \ + docker build --progress plain -f "$SCRIPT_DIR/$1/Dockerfile" \ -t build-$1:$GITHUB_REF \ -t build-$1:latest \ --build-arg DOCKER_NAMESPACE=$DOCKER_USERNAME \ --build-arg VCPKG_REF=$VCPKG_REF \ - "$SCRIPT_DIR/." + "$SCRIPT_DIR/$1/." + + mkdir -p build-$1 + + docker run --rm --mount source="$(pwd)",target=/hpcc-dev/HPCC-Platform,type=bind,consistency=cached build-$1:$GITHUB_REF \ + "mkdir -p /hpcc-dev/HPCC-Platform/build-$1 && cp -r /hpcc-dev/vcpkg_installed /hpcc-dev/HPCC-Platform/build-$1/vcpkg_installed" docker run --rm --mount source="$(pwd)",target=/hpcc-dev/HPCC-Platform,type=bind,consistency=cached build-$1:$GITHUB_REF \ "cmake -S /hpcc-dev/HPCC-Platform -B /hpcc-dev/HPCC-Platform/build-$1 ${CMAKE_OPTIONS}" + docker run --rm --mount source="$(pwd)",target=/hpcc-dev/HPCC-Platform,type=bind,consistency=cached build-$1:$GITHUB_REF \ "cmake --build /hpcc-dev/HPCC-Platform/build-$1 --parallel $(nproc)" # docker run -it --mount source="$(pwd)",target=/hpcc-dev/HPCC-Platform,type=bind,consistency=cached build-ubuntu-22.04:latest bash } -CMAKE_OPTIONS="-G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVCPKG_FILES_DIR=/hpcc-dev -DCPACK_THREADS=0 -DUSE_OPTIONAL=OFF -DINCLUDE_PLUGINS=ON -DSUPPRESS_V8EMBED=ON" +CMAKE_OPTIONS="-G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK_THREADS=0 -DUSE_OPTIONAL=OFF -DINCLUDE_PLUGINS=ON -DSUPPRESS_V8EMBED=ON" doBuild centos-7 doBuild centos-8 diff --git a/dockerfiles/vcpkg/centos-7.dockerfile b/dockerfiles/vcpkg/centos-7/Dockerfile similarity index 90% rename from dockerfiles/vcpkg/centos-7.dockerfile rename to dockerfiles/vcpkg/centos-7/Dockerfile index 83791b07498..ada68b274a4 100644 --- a/dockerfiles/vcpkg/centos-7.dockerfile +++ b/dockerfiles/vcpkg/centos-7/Dockerfile @@ -1,11 +1,12 @@ ARG VCPKG_REF=latest -FROM hpccsystems/platform-build-base-centos-7:$VCPKG_REF +FROM hpccsystems/platform-build-base-centos-7:$VCPKG_REF RUN yum install -y \ java-11-openjdk-devel \ python3-devel \ wget \ epel-release + RUN yum update -y && yum install -y R-core-devel ENV Rcpp_package=Rcpp_0.12.19.tar.gz diff --git a/dockerfiles/vcpkg/centos-8.dockerfile b/dockerfiles/vcpkg/centos-8/Dockerfile similarity index 99% rename from dockerfiles/vcpkg/centos-8.dockerfile rename to dockerfiles/vcpkg/centos-8/Dockerfile index 1e22c7c3466..7b84289abcf 100644 --- a/dockerfiles/vcpkg/centos-8.dockerfile +++ b/dockerfiles/vcpkg/centos-8/Dockerfile @@ -5,6 +5,7 @@ RUN yum remove -y java-1.* && yum install -y \ java-11-openjdk-devel \ python3-devel \ epel-release + RUN yum install -y \ R-core-devel \ R-Rcpp-devel \ diff --git a/dockerfiles/vcpkg/ubuntu-20.04.dockerfile b/dockerfiles/vcpkg/ubuntu-20.04/Dockerfile similarity index 99% rename from dockerfiles/vcpkg/ubuntu-20.04.dockerfile rename to dockerfiles/vcpkg/ubuntu-20.04/Dockerfile index 7211cccebde..a7ca25103c6 100644 --- a/dockerfiles/vcpkg/ubuntu-20.04.dockerfile +++ b/dockerfiles/vcpkg/ubuntu-20.04/Dockerfile @@ -9,8 +9,11 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ wget \ r-base \ r-cran-rcpp + RUN wget https://cran.r-project.org/src/contrib/Archive/RInside/${RInside_package} + RUN R CMD INSTALL ${RInside_package} + RUN rm -f ${RInside_package} WORKDIR /hpcc-dev diff --git a/dockerfiles/vcpkg/ubuntu-22.04.dockerfile b/dockerfiles/vcpkg/ubuntu-22.04/Dockerfile similarity index 100% rename from dockerfiles/vcpkg/ubuntu-22.04.dockerfile rename to dockerfiles/vcpkg/ubuntu-22.04/Dockerfile diff --git a/dockerfiles/vcpkg/ubuntu-22.10.dockerfile b/dockerfiles/vcpkg/ubuntu-22.10/Dockerfile similarity index 100% rename from dockerfiles/vcpkg/ubuntu-22.10.dockerfile rename to dockerfiles/vcpkg/ubuntu-22.10/Dockerfile diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 98fad1db96f..56b5618d4c4 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -30,6 +30,7 @@ add_subdirectory (proxies) add_subdirectory (sqlite3) add_subdirectory (mysql) add_subdirectory (v8embed) +add_subdirectory (wasmembed) HPCC_ADD_SUBDIRECTORY (py3embed "USE_PYTHON3") HPCC_ADD_SUBDIRECTORY (pyembed "USE_PYTHON2") add_subdirectory (javaembed) diff --git a/plugins/wasmembed/CMakeLists.txt b/plugins/wasmembed/CMakeLists.txt new file mode 100644 index 00000000000..476fdbf18de --- /dev/null +++ b/plugins/wasmembed/CMakeLists.txt @@ -0,0 +1,48 @@ +project(wasmembed) + +if(WASMEMBED) + ADD_PLUGIN(wasmembed) + if(MAKE_WASMEMBED) + + add_subdirectory(secure-enclave) + + include_directories( + ./../../common/thorhelper + ./../../dali/base + ./../../rtl/eclrtl + ./../../rtl/include + ./../../rtl/nbcd + ./../../system/include + ./../../system/jlib + ./../../system/mp + ) + + add_definitions(-D_USRDLL -DWASMEMBED_EXPORTS) + + add_library(wasmembed SHARED + wasmembed.cpp + ) + + target_link_libraries(wasmembed + roxiemem + eclrtl + jlib + secure-enclave + ) + + install( + TARGETS wasmembed + DESTINATION plugins + ) + + else() + message(WARNING "Cannot build wasmembed plugin") + endif() +endif() + +if(PLATFORM OR CLIENTTOOLS_ONLY) + install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/wasm.ecllib + DESTINATION plugins + COMPONENT Runtime) +endif() diff --git a/plugins/wasmembed/secure-enclave/CMakeLists.txt b/plugins/wasmembed/secure-enclave/CMakeLists.txt new file mode 100644 index 00000000000..b4247b79d9b --- /dev/null +++ b/plugins/wasmembed/secure-enclave/CMakeLists.txt @@ -0,0 +1,41 @@ +project(secure-enclave) + +set(CMAKE_CXX_STANDARD 20) + +find_path(WASMTIME_CPP_API_INCLUDE_DIRS "wasmtime-cpp-api/wasmtime.hh" + PATHS ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET} +) +if (WIN32) + find_library(WASMTIME_LIB NAMES wasmtime.dll + PATHS ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET} + ) +else() + find_library(WASMTIME_LIB NAMES wasmtime + PATHS ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET} + ) +endif() + +include_directories( + ${WASMTIME_CPP_API_INCLUDE_DIRS}/wasmtime-c-api + ${WASMTIME_CPP_API_INCLUDE_DIRS}/wasmtime-cpp-api + ./../../../system/include + ./../../../rtl/eclrtl + ./../../../system/jlib +) + +add_definitions(-D_USRDLL -DSECUREENCLAVE_EXPORTS) + +add_library(secure-enclave SHARED + secure-enclave.cpp +) + +target_link_libraries(secure-enclave PRIVATE + ${WASMTIME_LIB} +) + +install( + TARGETS secure-enclave + DESTINATION plugins + CALC_DEPS +) + diff --git a/plugins/wasmembed/secure-enclave/abi.hpp b/plugins/wasmembed/secure-enclave/abi.hpp new file mode 100644 index 00000000000..c547a9fd29a --- /dev/null +++ b/plugins/wasmembed/secure-enclave/abi.hpp @@ -0,0 +1,157 @@ +/* + See: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md + https://github.com/WebAssembly/component-model/blob/main/design/mvp/canonical-abi/definitions.py +*/ + +#include +#include +#include +#include +#include + +auto UTF16_TAG = 1 << 31; + +int align_to(int ptr, int alignment) +{ + return std::ceil(ptr / alignment) * alignment; +} + +// loading --- + +int load_int(const wasmtime::Span &data, int32_t ptr, int32_t nbytes, bool is_signed = false) +{ + int result = 0; + for (int i = 0; i < nbytes; i++) + { + int b = data[ptr + i]; + if (i == 3 && is_signed && b >= 0x80) + { + b -= 0x100; + } + result += b << (i * 8); + } + return result; +} + +std::string global_encoding = "utf8"; +std::string load_string_from_range(const wasmtime::Span &data, uint32_t ptr, uint32_t tagged_code_units) +{ + std::string encoding = "utf-8"; + uint32_t byte_length = tagged_code_units; + uint32_t alignment = 1; + if (global_encoding.compare("utf8") == 0) + { + alignment = 1; + byte_length = tagged_code_units; + encoding = "utf-8"; + } + else if (global_encoding.compare("utf16") == 0) + { + alignment = 2; + byte_length = 2 * tagged_code_units; + encoding = "utf-16-le"; + } + else if (global_encoding.compare("latin1+utf16") == 0) + { + alignment = 2; + if (tagged_code_units & UTF16_TAG) + { + byte_length = 2 * (tagged_code_units ^ UTF16_TAG); + encoding = "utf-16-le"; + } + else + { + byte_length = tagged_code_units; + encoding = "latin-1"; + } + } + + if (ptr != align_to(ptr, alignment)) + { + throw std::runtime_error("Invalid alignment"); + } + if (ptr + byte_length > data.size()) + { + throw std::runtime_error("Out of bounds"); + } + + std::string s; + s.resize(byte_length); + memcpy(&s[0], &data[ptr], byte_length); + return s; +} + +std::string load_string(const wasmtime::Span &data, uint32_t ptr) +{ + uint32_t begin = load_int(data, ptr, 4); + uint32_t tagged_code_units = load_int(data, ptr + 4, 4); + return load_string_from_range(data, begin, tagged_code_units); +} + +// Storing --- +void store_int(const wasmtime::Span &data, int64_t v, size_t ptr, size_t nbytes, bool _signed = false) +{ + // convert v to little-endian byte array + std::vector bytes(nbytes); + for (size_t i = 0; i < nbytes; i++) + { + bytes[i] = (v >> (i * 8)) & 0xFF; + } + // copy bytes to memory + memcpy(&data[ptr], bytes.data(), nbytes); +} + +// Other --- +std::vector read_wasm_binary_to_buffer(const std::string &filename) +{ + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file) + { + throw std::runtime_error("Failed to open file"); + } + + std::streamsize size = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector buffer(size); + if (!file.read(reinterpret_cast(buffer.data()), size)) + { + throw std::runtime_error("Failed to read file"); + } + + return buffer; +} + +std::string extractContentInDoubleQuotes(const std::string &input) +{ + + int firstQuote = input.find_first_of('"'); + int secondQuote = input.find('"', firstQuote + 1); + if (firstQuote == std::string::npos || secondQuote == std::string::npos) + { + return ""; + } + return input.substr(firstQuote + 1, secondQuote - firstQuote - 1); +} + +std::pair splitQualifiedID(const std::string &qualifiedName) +{ + std::istringstream iss(qualifiedName); + std::vector tokens; + std::string token; + + while (std::getline(iss, token, '.')) + { + tokens.push_back(token); + } + if (tokens.size() != 2) + { + throw std::runtime_error("Invalid import function " + qualifiedName + ", expected format: ."); + } + return std::make_pair(tokens[0], tokens[1]); +} + +std::string createQualifiedID(const std::string &wasmName, const std::string &funcName) +{ + return wasmName + "." + funcName; +} \ No newline at end of file diff --git a/plugins/wasmembed/secure-enclave/hpcc-platform.wit b/plugins/wasmembed/secure-enclave/hpcc-platform.wit new file mode 100644 index 00000000000..036df840a23 --- /dev/null +++ b/plugins/wasmembed/secure-enclave/hpcc-platform.wit @@ -0,0 +1,11 @@ +package hpcc-systems:hpcc-platform + +world wasmembed { + // guests dispose all params as needed + // guests should dispose "results" as needed + import dbglog: func(msg: string) + + // guests dispose all params as needed + // hosts call cabi_post_XXX to dispose "results" as needed + // export myfunc(params: string) -> string +} diff --git a/plugins/wasmembed/secure-enclave/secure-enclave.cpp b/plugins/wasmembed/secure-enclave/secure-enclave.cpp new file mode 100644 index 00000000000..d8dd157f21c --- /dev/null +++ b/plugins/wasmembed/secure-enclave/secure-enclave.cpp @@ -0,0 +1,502 @@ +#include "secure-enclave.hpp" + +#include "abi.hpp" + +#include +#include + +std::shared_ptr embedContextCallbacks; + +#define NENABLE_TRACE + +#ifdef ENABLE_TRACE +#define TRACE(format, ...) embedContextCallbacks->DBGLOG(format, ##__VA_ARGS__) +#else +#define TRACE(format, ...) \ + do \ + { \ + } while (0) +#endif + +class WasmEngine +{ +protected: + wasmtime::Engine engine; + + std::map wasmInstances; + std::map wasmMems; + std::map wasmFuncs; + +public: + wasmtime::Store store; + + WasmEngine() : store(engine) + { + } + + ~WasmEngine() + { + } + + bool hasInstance(const std::string &wasmName) + { + return wasmInstances.find(wasmName) != wasmInstances.end(); + } + + wasmtime::Instance getInstance(const std::string &wasmName) + { + auto instanceItr = wasmInstances.find(wasmName); + if (instanceItr == wasmInstances.end()) + throw std::runtime_error("Wasm instance not found: " + wasmName); + return instanceItr->second; + } + + void registerInstance(const std::string &wasmName, const std::variant> &wasm) + { + TRACE("registerInstance %s", wasmName.c_str()); + auto instanceItr = wasmInstances.find(wasmName); + if (instanceItr == wasmInstances.end()) + { + TRACE("resolveModule %s", wasmName.c_str()); + auto module = std::holds_alternative(wasm) ? wasmtime::Module::compile(engine, std::get(wasm)).unwrap() : wasmtime::Module::compile(engine, std::get>(wasm)).unwrap(); + TRACE("resolveModule2 %s", wasmName.c_str()); + + wasmtime::WasiConfig wasi; + wasi.inherit_argv(); + wasi.inherit_env(); + wasi.inherit_stdin(); + wasi.inherit_stdout(); + wasi.inherit_stderr(); + store.context().set_wasi(std::move(wasi)).unwrap(); + TRACE("resolveModule3 %s", wasmName.c_str()); + + wasmtime::Linker linker(engine); + linker.define_wasi().unwrap(); + TRACE("resolveModule4 %s", wasmName.c_str()); + + auto callback = [this, wasmName](wasmtime::Caller caller, uint32_t msg, uint32_t msg_len) + { + TRACE("callback: %i %i", msg_len, msg); + + auto data = this->getData(wasmName); + auto msg_ptr = (char *)&data[msg]; + std::string str(msg_ptr, msg_len); + embedContextCallbacks->DBGLOG("from wasm: %s", str.c_str()); + }; + auto host_func = linker.func_wrap("$root", "dbglog", callback).unwrap(); + + auto newInstance = linker.instantiate(store, module).unwrap(); + linker.define_instance(store, "linking2", newInstance).unwrap(); + + TRACE("resolveModule5 %s", wasmName.c_str()); + + wasmInstances.insert(std::make_pair(wasmName, newInstance)); + + for (auto exportItem : module.exports()) + { + auto externType = wasmtime::ExternType::from_export(exportItem); + std::string name(exportItem.name()); + if (std::holds_alternative(externType)) + { + TRACE("Exported function: %s", name.c_str()); + auto func = std::get(*newInstance.get(store, name)); + wasmFuncs.insert(std::make_pair(wasmName + "." + name, func)); + } + else if (std::holds_alternative(externType)) + { + TRACE("Exported memory: %s", name.c_str()); + auto memory = std::get(*newInstance.get(store, name)); + wasmMems.insert(std::make_pair(wasmName + "." + name, memory)); + } + else if (std::holds_alternative(externType)) + { + TRACE("Exported table: %s", name.c_str()); + } + else if (std::holds_alternative(externType)) + { + TRACE("Exported global: %s", name.c_str()); + } + else + { + TRACE("Unknown export type"); + } + } + } + } + + bool hasFunc(const std::string &qualifiedID) + { + return wasmFuncs.find(qualifiedID) != wasmFuncs.end(); + } + + wasmtime::Func getFunc(const std::string &qualifiedID) + { + auto found = wasmFuncs.find(qualifiedID); + if (found == wasmFuncs.end()) + throw std::runtime_error("Wasm function not found: " + qualifiedID); + return found->second; + } + + wasmtime::ValType::ListRef getFuncParams(const std::string &qualifiedID) + { + auto func = getFunc(qualifiedID); + wasmtime::FuncType funcType = func.type(store.context()); + return funcType->params(); + } + + wasmtime::ValType::ListRef getFuncResults(const std::string &qualifiedID) + { + auto func = getFunc(qualifiedID); + wasmtime::FuncType funcType = func.type(store.context()); + return funcType->results(); + } + + std::vector call(const std::string &qualifiedID, const std::vector ¶ms) + { + return getFunc(qualifiedID).call(store, params).unwrap(); + } + + std::vector callRealloc(const std::string &wasmName, const std::vector ¶ms) + { + return call(createQualifiedID(wasmName, "cabi_realloc"), params); + } + + wasmtime::Span getData(const std::string &wasmName) + { + auto found = wasmMems.find(createQualifiedID(wasmName, "memory")); + if (found == wasmMems.end()) + throw std::runtime_error("Wasm memory not found: " + wasmName); + return found->second.data(store.context()); + } +}; +std::unique_ptr wasmEngine; + +class SecureFunction : public ISecureEnclave +{ + std::string wasmName; + std::string funcName; + std::string qualifiedID; + + const IThorActivityContext *activityCtx = nullptr; + std::vector args; + std::vector results; + +public: + SecureFunction() + { + TRACE("se:constructor"); + } + + virtual ~SecureFunction() override + { + TRACE("se:destructor"); + + // Garbage Collection --- + // Function results --- + auto gc_func_name = createQualifiedID(wasmName, "cabi_post_" + funcName); + if (wasmEngine->hasFunc(gc_func_name)) + { + auto func = wasmEngine->getFunc(gc_func_name); + for (auto &result : results) + { + func.call(wasmEngine->store, {result}).unwrap(); + } + } + } + + // IEmbedFunctionContext --- + void setActivityContext(const IThorActivityContext *_activityCtx) + { + activityCtx = _activityCtx; + } + + virtual void Link() const + { + } + + virtual bool Release() const + { + return false; + }; + + virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name) + { + TRACE("paramWriterCommit"); + return NULL; + } + virtual void paramWriterCommit(IInterface *writer) + { + TRACE("paramWriterCommit"); + } + virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer) + { + TRACE("writeResult"); + } + virtual void bindBooleanParam(const char *name, bool val) + { + TRACE("bindBooleanParam %s %i", name, val); + args.push_back(val); + } + virtual void bindDataParam(const char *name, size32_t len, const void *val) + { + TRACE("bindDataParam %s %d", name, len); + } + virtual void bindFloatParam(const char *name, float val) + { + TRACE("bindFloatParam %s %f", name, val); + args.push_back(val); + } + virtual void bindRealParam(const char *name, double val) + { + TRACE("bindRealParam %s %f", name, val); + args.push_back(val); + } + virtual void bindSignedSizeParam(const char *name, int size, __int64 val) + { + TRACE("bindSignedSizeParam %s %i %lld", name, size, val); + if (size <= 4) + args.push_back(static_cast(val)); + else + args.push_back(static_cast(val)); + } + virtual void bindSignedParam(const char *name, __int64 val) + { + TRACE("bindSignedParam %s %lld", name, val); + args.push_back(static_cast(val)); + } + virtual void bindUnsignedSizeParam(const char *name, int size, unsigned __int64 val) + { + TRACE("bindUnsignedSizeParam %s %i %llu", name, size, val); + if (size <= 4) + args.push_back(static_cast(val)); + else + args.push_back(static_cast(val)); + } + virtual void bindUnsignedParam(const char *name, unsigned __int64 val) + { + TRACE("bindUnsignedParam %s %llu", name, val); + args.push_back(static_cast(val)); + } + virtual void bindStringParam(const char *paramName, size32_t len, const char *val) + { + TRACE("bindStringParam %s %d %s", paramName, len, val); + auto memIdxVar = wasmEngine->callRealloc(wasmName, {0, 0, 1, (int32_t)len}); + auto memIdx = memIdxVar[0].i32(); + auto mem = wasmEngine->getData(wasmName); + for (int i = 0; i < len; i++) + { + mem[memIdx + i] = val[i]; + } + args.push_back(memIdx); + args.push_back((int32_t)len); + } + virtual void bindVStringParam(const char *name, const char *val) + { + TRACE("bindVStringParam %s %s", name, val); + auto len = strlen(val); + auto memIdxVar = wasmEngine->callRealloc(wasmName, {0, 0, 1, (int32_t)len}); + auto memIdx = memIdxVar[0].i32(); + auto mem = wasmEngine->getData(wasmName); + for (int i = 0; i < len; i++) + { + mem[memIdx + i] = val[i]; + } + args.push_back(memIdx); + args.push_back((int32_t)len); + } + virtual void bindUTF8Param(const char *name, size32_t chars, const char *val) + { + TRACE("bindUTF8Param %s %d %s", name, chars, val); + auto memIdxVar = wasmEngine->callRealloc(wasmName, {0, 0, 1, (int32_t)chars}); + auto memIdx = memIdxVar[0].i32(); + auto mem = wasmEngine->getData(wasmName); + for (int i = 0; i < chars; i++) + { + mem[memIdx + i] = val[i]; + } + args.push_back(memIdx); + args.push_back((int32_t)chars); + } + virtual void bindUnicodeParam(const char *name, size32_t chars, const UChar *val) + { + TRACE("bindUnicodeParam %s %d %S", name, chars, reinterpret_cast(val)); + auto memIdxVar = wasmEngine->callRealloc(wasmName, {0, 0, 2, (int32_t)chars * 2}); + auto memIdx = memIdxVar[0].i32(); + auto mem = wasmEngine->getData(wasmName); + for (int i = 0; i < chars * 2; i += 2) + { + mem[memIdx + i] = val[i]; + } + args.push_back(memIdx); + args.push_back((int32_t)chars); + } + virtual void bindSetParam(const char *name, int elemType, size32_t elemSize, bool isAll, size32_t totalBytes, const void *setData) + { + TRACE("bindSetParam %s %d %d %d %d %p", name, elemType, elemSize, isAll, totalBytes, setData); + } + virtual void bindRowParam(const char *name, IOutputMetaData &metaVal, const byte *val) override + { + TRACE("bindRowParam %s %p", name, val); + } + virtual void bindDatasetParam(const char *name, IOutputMetaData &metaVal, IRowStream *val) + { + TRACE("bindDatasetParam %s %p", name, val); + } + virtual bool getBooleanResult() + { + TRACE("getBooleanResult"); + return results[0].i32(); + } + virtual void getDataResult(size32_t &__len, void *&__result) + { + TRACE("getDataResult"); + } + virtual double getRealResult() + { + TRACE("getRealResult"); + if (results[0].kind() == wasmtime::ValKind::F64) + return (int32_t)results[0].f64(); + return results[0].f32(); + } + virtual __int64 getSignedResult() + { + TRACE("getSignedResult"); + if (results[0].kind() == wasmtime::ValKind::I64) + return (int32_t)results[0].i64(); + return results[0].i32(); + } + virtual unsigned __int64 getUnsignedResult() + { + TRACE("getUnsignedResult"); + if (results[0].kind() == wasmtime::ValKind::I64) + return (int32_t)results[0].i64(); + return results[0].i32(); + } + virtual void getStringResult(size32_t &__chars, char *&__result) + { + TRACE("getStringResult %zu", results.size()); + auto ptr = results[0].i32(); + auto data = wasmEngine->getData(wasmName); + + uint32_t begin = load_int(data, ptr, 4); + TRACE("begin %u", begin); + uint32_t tagged_code_units = load_int(data, ptr + 4, 4); + TRACE("tagged_code_units %u", tagged_code_units); + std::string s = load_string(data, ptr); + TRACE("load_string %s", s.c_str()); + __chars = s.length(); + __result = reinterpret_cast(embedContextCallbacks->rtlMalloc(__chars)); + s.copy(__result, __chars); + } + virtual void getUTF8Result(size32_t &__chars, char *&__result) + { + TRACE("getUTF8Result"); + } + virtual void getUnicodeResult(size32_t &__chars, UChar *&__result) + { + TRACE("getUnicodeResult"); + } + virtual void getSetResult(bool &__isAllResult, size32_t &__resultBytes, void *&__result, int elemType, size32_t elemSize) + { + TRACE("getSetResult"); + } + virtual IRowStream *getDatasetResult(IEngineRowAllocator *_resultAllocator) + { + TRACE("getDatasetResult"); + return NULL; + } + virtual byte *getRowResult(IEngineRowAllocator *_resultAllocator) + { + TRACE("getRowResult"); + return NULL; + } + virtual size32_t getTransformResult(ARowBuilder &builder) + { + TRACE("getTransformResult"); + return 0; + } + virtual void loadCompiledScript(size32_t chars, const void *_script) override + { + TRACE("loadCompiledScript %p", _script); + } + virtual void enter() override + { + TRACE("enter"); + } + virtual void reenter(ICodeContext *codeCtx) override + { + TRACE("reenter"); + } + virtual void exit() override + { + TRACE("exit"); + } + virtual void compileEmbeddedScript(size32_t lenChars, const char *_utf) override + { + TRACE("compileEmbeddedScript"); + std::string utf(_utf, lenChars); + funcName = extractContentInDoubleQuotes(utf); + wasmName = "embed_" + funcName; + qualifiedID = createQualifiedID(wasmName, funcName); + wasmEngine->registerInstance(wasmName, utf); + } + virtual void importFunction(size32_t lenChars, const char *qualifiedName) override + { + TRACE("importFunction: %s", qualifiedName); + + qualifiedID = std::string(qualifiedName, lenChars); + auto [_wasmName, _funcName] = splitQualifiedID(qualifiedID); + wasmName = _wasmName; + funcName = _funcName; + + if (!wasmEngine->hasInstance(wasmName)) + { + std::string fullPath = embedContextCallbacks->resolveManifestPath((wasmName + ".wasm").c_str()); + auto wasmFile = read_wasm_binary_to_buffer(fullPath); + wasmEngine->registerInstance(wasmName, wasmFile); + } + } + virtual void callFunction() + { + TRACE("callFunction %s", qualifiedID.c_str()); + results = wasmEngine->call(qualifiedID, args); + } +}; + +SECUREENCLAVE_API void init(std::shared_ptr embedContext) +{ + embedContextCallbacks = embedContext; + wasmEngine = std::make_unique(); + TRACE("init"); +} + +SECUREENCLAVE_API void kill() +{ + TRACE("kill"); + wasmEngine.reset(); + embedContextCallbacks.reset(); +} + +SECUREENCLAVE_API std::unique_ptr createISecureEnclave() +{ + return std::make_unique(); +} + +SECUREENCLAVE_API void syntaxCheck(size32_t &__lenResult, char *&__result, const char *funcname, size32_t charsBody, const char *body, const char *argNames, const char *compilerOptions, const char *persistOptions) +{ + std::string errMsg = ""; + try + { + wasmtime::Engine engine; + wasmtime::Store store(engine); + auto module = wasmtime::Module::compile(engine, body); + } + catch (const wasmtime::Error &e) + { + errMsg = e.message(); + } + + __lenResult = errMsg.length(); + __result = reinterpret_cast(embedContextCallbacks->rtlMalloc(__lenResult)); + errMsg.copy(__result, __lenResult); +} diff --git a/plugins/wasmembed/secure-enclave/secure-enclave.hpp b/plugins/wasmembed/secure-enclave/secure-enclave.hpp new file mode 100644 index 00000000000..82e8c800fb2 --- /dev/null +++ b/plugins/wasmembed/secure-enclave/secure-enclave.hpp @@ -0,0 +1,28 @@ +#include "platform.h" +#include "eclrtl.hpp" + +#ifdef SECUREENCLAVE_EXPORTS + #define SECUREENCLAVE_API DECL_EXPORT +#else + #define SECUREENCLAVE_API DECL_IMPORT +#endif + +#include + +interface IWasmEmbedCallback +{ + virtual inline void DBGLOG(char const *format, ...) __attribute__((format(printf, 2, 3))) = 0; + virtual void *rtlMalloc(size32_t size) = 0; + + virtual const char *resolveManifestPath(const char *leafName) = 0; +}; + +interface ISecureEnclave : extends IEmbedFunctionContext +{ + virtual ~ISecureEnclave() = default; +}; + +SECUREENCLAVE_API void init(std::shared_ptr embedContext); +SECUREENCLAVE_API void kill(); +SECUREENCLAVE_API std::unique_ptr createISecureEnclave(); +SECUREENCLAVE_API void syntaxCheck(size32_t &__lenResult, char *&__result, const char *funcname, size32_t charsBody, const char *body, const char *argNames, const char *compilerOptions, const char *persistOptions); diff --git a/plugins/wasmembed/wasm.ecllib b/plugins/wasmembed/wasm.ecllib new file mode 100644 index 00000000000..eb5d8313c02 --- /dev/null +++ b/plugins/wasmembed/wasm.ecllib @@ -0,0 +1,10 @@ +EXPORT Language := SERVICE : plugin('wasmembed') + integer getEmbedContext() : cpp, pure, fold, namespace='wasmLanguageHelper', entrypoint='getEmbedContext', prototype='IEmbedContext* getEmbedContext()'; + string syntaxCheck(const varstring funcname, UTF8 body, const varstring argnames, const varstring compileOptions, const varstring persistOptions) : cpp, pure, fold, namespace='wasmLanguageHelper', entrypoint='syntaxCheck'; +END; +EXPORT getEmbedContext := Language.getEmbedContext; +EXPORT syntaxCheck := Language.syntaxCheck; +EXPORT boolean supportsImport := true; +EXPORT boolean supportsScript := true; +EXPORT boolean prebind := false; +EXPORT boolean singletonEmbedContext := false; \ No newline at end of file diff --git a/plugins/wasmembed/wasmembed.cpp b/plugins/wasmembed/wasmembed.cpp new file mode 100644 index 00000000000..717e4958d95 --- /dev/null +++ b/plugins/wasmembed/wasmembed.cpp @@ -0,0 +1,145 @@ +#include "platform.h" +#include "hqlplugins.hpp" +#include "rtlfield.hpp" +#include "enginecontext.hpp" + +#include "secure-enclave/secure-enclave.hpp" + +static const char *compatibleVersions[] = { + "WASM Embed Helper 1.0.0", + NULL}; + +static const char *version = "WASM Embed Helper 1.0.0"; + +extern "C" DECL_EXPORT bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb) +{ + if (pb->size == sizeof(ECLPluginDefinitionBlockEx)) + { + ECLPluginDefinitionBlockEx *pbx = (ECLPluginDefinitionBlockEx *)pb; + pbx->compatibleVersions = compatibleVersions; + } + else if (pb->size != sizeof(ECLPluginDefinitionBlock)) + return false; + pb->magicVersion = PLUGIN_VERSION; + pb->version = version; + pb->moduleName = "wasm"; + pb->ECL = NULL; + pb->flags = PLUGIN_MULTIPLE_VERSIONS; + pb->description = "WASM Embed Helper"; + return true; +} + +namespace wasmLanguageHelper +{ + class Callbacks : public IWasmEmbedCallback + { + protected: + bool manifestAdded = false; + StringArray manifestModules; + + public: + Callbacks() + { + } + ~Callbacks() + { + } + void manifestPaths(ICodeContext *codeCtx) + { + if (codeCtx && !manifestAdded) + { + manifestAdded = true; + IEngineContext *engine = codeCtx->queryEngineContext(); + if (engine) + { + engine->getManifestFiles("wasm", manifestModules); + } + } + } + + // IWasmEmbedCallback --- + virtual inline void DBGLOG(char const *format, ...) override + { + va_list args; + va_start(args, format); + VALOG(MCdebugInfo, unknownJob, format, args); + va_end(args); + } + + virtual void *rtlMalloc(size32_t size) override + { + return ::rtlMalloc(size); + } + + virtual const char *resolveManifestPath(const char *leafName) override + { + if (leafName && *leafName) + { + ForEachItemIn(idx, manifestModules) + { + const char *path = manifestModules.item(idx); + if (endsWith(path, leafName)) + return path; + } + } + return nullptr; + } + }; + std::shared_ptr callbacks; + + class WasmEmbedContext : public CInterfaceOf + { + std::unique_ptr enclave; + + public: + WasmEmbedContext() + { + enclave = createISecureEnclave(); + } + virtual ~WasmEmbedContext() override + { + } + // IEmbedContext --- + virtual IEmbedFunctionContext *createFunctionContext(unsigned flags, const char *options) override + { + return createFunctionContextEx(nullptr, nullptr, flags, options); + } + virtual IEmbedFunctionContext *createFunctionContextEx(ICodeContext *ctx, const IThorActivityContext *activityContext, unsigned flags, const char *options) override + { + callbacks->manifestPaths(ctx); + return enclave.get(); + } + virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options) override + { + throwUnexpected(); + return nullptr; + } + }; + + extern DECL_EXPORT IEmbedContext *getEmbedContext() + { + return new WasmEmbedContext(); + } + + extern DECL_EXPORT void syntaxCheck(size32_t &__lenResult, char *&__result, const char *funcname, size32_t charsBody, const char *body, const char *argNames, const char *compilerOptions, const char *persistOptions) + { + StringBuffer result; + // MORE - ::syntaxCheck(__lenResult, __result, funcname, charsBody, body, argNames, compilerOptions, persistOptions); + __lenResult = result.length(); + __result = result.detach(); + } + +} // namespace + +MODULE_INIT(INIT_PRIORITY_STANDARD) +{ + wasmLanguageHelper::callbacks = std::make_shared(); + init(wasmLanguageHelper::callbacks); + return true; +} + +MODULE_EXIT() +{ + kill(); + wasmLanguageHelper::callbacks.reset(); +} \ No newline at end of file diff --git a/testing/regress/ecl/key/wasmembed.xml b/testing/regress/ecl/key/wasmembed.xml new file mode 100644 index 00000000000..5f862a9d026 --- /dev/null +++ b/testing/regress/ecl/key/wasmembed.xml @@ -0,0 +1,51 @@ + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + diff --git a/testing/regress/ecl/wasmembed.ecl b/testing/regress/ecl/wasmembed.ecl new file mode 100644 index 00000000000..143b04598aa --- /dev/null +++ b/testing/regress/ecl/wasmembed.ecl @@ -0,0 +1,34 @@ +import wasm; + +boolean boolTest (boolean a, boolean b) := IMPORT(wasm, 'wasmembed.bool-test'); +real4 float32Test (real4 a, real4 b) := IMPORT(wasm, 'wasmembed.float32-test'); +real8 float64Test (real8 a, real8 b) := IMPORT(wasm, 'wasmembed.float64-test'); +unsigned1 u8Test (unsigned1 a, unsigned1 b) := IMPORT(wasm, 'wasmembed.u8-test'); +unsigned2 u16Test (unsigned2 a, unsigned2 b) := IMPORT(wasm, 'wasmembed.u16-test'); +unsigned4 u32Test (unsigned4 a, unsigned4 b) := IMPORT(wasm, 'wasmembed.u32-test'); +unsigned8 u64Test (unsigned8 a, unsigned8 b) := IMPORT(wasm, 'wasmembed.u64-test'); +integer1 s8Test (integer1 a, integer1 b) := IMPORT(wasm, 'wasmembed.s8-test'); +integer2 s16Test (integer2 a, integer2 b) := IMPORT(wasm, 'wasmembed.s16-test'); +integer4 s32Test (integer4 a, integer4 b) := IMPORT(wasm, 'wasmembed.s32-test'); +integer8 s64Test (integer8 a, integer8 b) := IMPORT(wasm, 'wasmembed.s64-test'); +string stringTest (string a, string b) := IMPORT(wasm, 'wasmembed.string-test'); +string7 string5Test (string5 a, string5 b) := IMPORT(wasm, 'wasmembed.string-test'); +varstring varstringTest (varstring a, varstring b) := IMPORT(wasm, 'wasmembed.string-test'); + +boolTest(false, false) = (false AND false); +boolTest(false, true) = (false AND true); +boolTest(true, false) = (true AND false); +boolTest(true, true) = (true AND true); +float32Test(1.0, 2.0) = (1.0 + 2.0); +float64Test(1.0, 2.0) = (1.0 + 2.0); +u8Test(1, 2) = (1 + 2); +u16Test(1, 2) = (1 + 2); +u32Test(1, 2) = (1 + 2); +u64Test(1, 2) = (1 + 2); +s8Test(1, 2) = (1 + 2); +s16Test(1, 2) = (1 + 2); +s32Test(1, 2) = (1 + 2); +s64Test(1, 2) = (1 + 2); +stringTest('aaa', 'bbbb') = ('aaa' + 'bbbb'); +string5Test('aaa', 'bbbb') = (string7)((string5)'aaa' + (string5)'bbbb'); +varstringTest('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') = ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); diff --git a/testing/regress/ecl/wasmembed.manifest b/testing/regress/ecl/wasmembed.manifest new file mode 100644 index 00000000000..8a2d68eb5c2 --- /dev/null +++ b/testing/regress/ecl/wasmembed.manifest @@ -0,0 +1,3 @@ + + + diff --git a/testing/regress/ecl/wasmembed.wasm b/testing/regress/ecl/wasmembed.wasm new file mode 100644 index 00000000000..bb27b76cb85 Binary files /dev/null and b/testing/regress/ecl/wasmembed.wasm differ diff --git a/vcpkg.json.in b/vcpkg.json.in index 5a726abe692..ffb4cc02a02 100644 --- a/vcpkg.json.in +++ b/vcpkg.json.in @@ -170,6 +170,10 @@ "name": "tbb", "platform": "@VCPKG_TBB@" }, + { + "name": "wasmtime-cpp-api", + "platform": "@VCPKG_WASMEMBED@" + }, { "name": "winflexbison", "platform": "windows" diff --git a/vcpkg_overlays/wasmtime-c-api/portfile.cmake b/vcpkg_overlays/wasmtime-c-api/portfile.cmake new file mode 100644 index 00000000000..fa605e69608 --- /dev/null +++ b/vcpkg_overlays/wasmtime-c-api/portfile.cmake @@ -0,0 +1,37 @@ +if (WIN32) + vcpkg_download_distfile(ARCHIVE + URLS "https://github.com/bytecodealliance/wasmtime/releases/download/v${VERSION}/wasmtime-v${VERSION}-x86_64-windows-c-api.zip" + FILENAME "wasmtime-v${VERSION}-x86_64-windows-c-api.zip" + SHA512 419a11498f3853764e9285650ef12bbf597445f1e97980ab2b7634a28ad7c81c78502320be23ca4f25302d3408161a9a712ad4a088eb57052cfa21da885e369f + ) +elseif (APPLE) + vcpkg_download_distfile(ARCHIVE + URLS "https://github.com/bytecodealliance/wasmtime/releases/download/v${VERSION}/wasmtime-v${VERSION}-x86_64-macos-c-api.tar.xz" + FILENAME "wasmtime-v${VERSION}-x86_64-macos-c-api.tar.xz" + SHA512 aed34569c3063b44b5a7acda53b274851d2ef8597b7819221d1a550ee2c408b51315bba95ffd9f495feceab3c3825db9ef53c432bdf565cfacfe31c76328f795 + ) +elseif (LINUX) + vcpkg_download_distfile(ARCHIVE + URLS "https://github.com/bytecodealliance/wasmtime/releases/download/v${VERSION}/wasmtime-v${VERSION}-x86_64-linux-c-api.tar.xz" + FILENAME "wasmtime-v${VERSION}-x86_64-linux-c-api.tar.xz" + SHA512 ad590bceeb6b20520275f96a8cdb737792502f581d4ae3c152f9a6c2602090e5d6aa80f27c77b707e31169d12f6daf176cb7260d16af31b4a83afa7ed6991ded + ) +endif() + +vcpkg_extract_source_archive_ex( + OUT_SOURCE_PATH SOURCE_PATH + ARCHIVE ${ARCHIVE} +) + +file(COPY ${SOURCE_PATH}/include/. DESTINATION ${CURRENT_PACKAGES_DIR}/include/wasmtime-c-api) +if (WIN32) + file(COPY ${SOURCE_PATH}/lib/. DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin) + file(COPY ${SOURCE_PATH}/lib/. DESTINATION ${CURRENT_PACKAGES_DIR}/bin) +else () + file(COPY ${SOURCE_PATH}/lib/. DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib) + file(COPY ${SOURCE_PATH}/lib/. DESTINATION ${CURRENT_PACKAGES_DIR}/lib) +endif () + +# Handle copyright +file(INSTALL ${SOURCE_PATH}/LICENSE DESTINATION ${CURRENT_PACKAGES_DIR}/share/wasmtime-c-api RENAME copyright) + diff --git a/vcpkg_overlays/wasmtime-c-api/vcpkg.json b/vcpkg_overlays/wasmtime-c-api/vcpkg.json new file mode 100644 index 00000000000..d3b68533a0a --- /dev/null +++ b/vcpkg_overlays/wasmtime-c-api/vcpkg.json @@ -0,0 +1,7 @@ +{ + "name": "wasmtime-c-api", + "version-string": "10.0.1", + "description": "Wasmtime is a standalone runtime for WebAssembly, using Cranelift to JIT-compile from WebAssembly to native code.", + "homepage": "https://wasmtime.dev/", + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/vcpkg_overlays/wasmtime-cpp-api/portfile.cmake b/vcpkg_overlays/wasmtime-cpp-api/portfile.cmake new file mode 100644 index 00000000000..fd39c6bb1ce --- /dev/null +++ b/vcpkg_overlays/wasmtime-cpp-api/portfile.cmake @@ -0,0 +1,16 @@ +vcpkg_download_distfile(ARCHIVE + URLS "https://github.com/bytecodealliance/wasmtime-cpp/archive/refs/tags/v${VERSION}.tar.gz" + FILENAME "v${VERSION}.tar.gz" + SHA512 6440472084198572b2f00f455e100c9cc0f8a6c76f5f6278432756335f4a340e1af347d6a88ad2e06e0d22a5b84f240a210a9ecfcab1699c1b0fa21cedb8574d +) + +vcpkg_extract_source_archive_ex( + OUT_SOURCE_PATH SOURCE_PATH + ARCHIVE ${ARCHIVE} +) + +file(COPY ${SOURCE_PATH}/include/. DESTINATION ${CURRENT_PACKAGES_DIR}/include/wasmtime-cpp-api) + +# Handle copyright +file(INSTALL ${SOURCE_PATH}/LICENSE DESTINATION ${CURRENT_PACKAGES_DIR}/share/wasmtime-cpp-api RENAME copyright) + diff --git a/vcpkg_overlays/wasmtime-cpp-api/vcpkg.json b/vcpkg_overlays/wasmtime-cpp-api/vcpkg.json new file mode 100644 index 00000000000..2838e70c667 --- /dev/null +++ b/vcpkg_overlays/wasmtime-cpp-api/vcpkg.json @@ -0,0 +1,10 @@ +{ + "name": "wasmtime-cpp-api", + "version-string": "9.0.0", + "description": "Wasmtime is a standalone runtime for WebAssembly, using Cranelift to JIT-compile from WebAssembly to native code.", + "homepage": "https://wasmtime.dev/", + "license": "Apache-2.0", + "dependencies": [ + "wasmtime-c-api" + ] +} \ No newline at end of file