diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index df9e956d..d251ec64 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,16 +24,46 @@ jobs: strategy: fail-fast: false matrix: - build: [release, debug, weval] + build: [release, debug] os: [ubuntu-latest] + outputs: + SM_TAG_EXISTS: ${{ steps.check-sm-release.outputs.SM_TAG_EXISTS }} + SM_TAG: ${{ steps.check-sm-release.outputs.SM_TAG }} + SM_CACHE_KEY_debug: ${{ steps.check-sm-release.outputs.SM_CACHE_KEY_debug }} + SM_CACHE_KEY_release: ${{ steps.check-sm-release.outputs.SM_CACHE_KEY_release }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - - name: Install Rust 1.80.0 + - name: Check if SpiderMonkey Release Exists + id: check-sm-release run: | - rustup toolchain install 1.80.0 - rustup target add wasm32-wasip1 --toolchain 1.80.0 + SM_TAG="libspidermonkey_$(awk '/^set\(SM_TAG/ {gsub(/set\(SM_TAG |\)/, ""); print}' cmake/spidermonkey.cmake)" + echo "SM_TAG=${SM_TAG}" >> "$GITHUB_OUTPUT" + if gh release view "${SM_TAG}" >/dev/null 2>&1; then + echo "Found existing SpiderMonkey release tag: ${SM_TAG}" + echo "SM_TAG_EXISTS=true" >> "$GITHUB_OUTPUT" + else + echo "SM_TAG_EXISTS=false" >> "$GITHUB_OUTPUT" + echo "SM_CACHE_KEY_${{ matrix.build }}=spidermonkey-cache-${{ matrix.build }}-${{ hashFiles('cmake/spidermonkey.cmake') }}" >> "$GITHUB_OUTPUT" + fi + env: + GH_TOKEN: ${{ github.token }} + + - name: Cache SpiderMonkey tarball + if: steps.check-sm-release.outputs.SM_TAG_EXISTS == 'false' + uses: actions/cache@v4 + id: sm-cache + with: + path: | + spidermonkey-dist-${{ matrix.build }} + key: spidermonkey-cache-${{ matrix.build }}-${{ hashFiles('cmake/spidermonkey.cmake') }} + + - name: Set env var to use cached SpiderMonkey tarball + if: steps.check-sm-release.outputs.SM_TAG_EXISTS == 'false' && steps.sm-cache.outputs.cache-hit == 'true' + run: | + tree spidermonkey-dist-${{ matrix.build }} + echo "SPIDERMONKEY_BINARIES=$(pwd)/spidermonkey-dist-${{ matrix.build }}" >> $GITHUB_ENV - uses: actions/setup-node@v2 with: @@ -64,3 +94,63 @@ jobs: - name: StarlingMonkey E2E, Integration, and WPT Tests run: | CTEST_OUTPUT_ON_FAILURE=1 ctest --test-dir cmake-build-${{ matrix.build }} -j$(nproc) --verbose + + - name: Set up cacheable SpiderMonkey artifacts + if: steps.check-sm-release.outputs.SM_TAG_EXISTS == 'false' && steps.sm-cache.outputs.cache-hit != 'true' + run: | + mkdir -p spidermonkey-dist-${{ matrix.build }} + cp -a cmake-build-${{ matrix.build }}/spidermonkey-obj/dist/libspidermonkey.a spidermonkey-dist-${{ matrix.build }}/ + cp -aL cmake-build-${{ matrix.build }}/spidermonkey-obj/dist/include spidermonkey-dist-${{ matrix.build }}/ + tree spidermonkey-dist-${{ matrix.build }} + + # Upload tarball as an artifact of the github action run, so the output + # can be inspected for pull requests. + - name: Upload SpiderMonkey tarball + uses: actions/upload-artifact@v4 + if: (github.event_name != 'push' || (github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/v'))) + && steps.check-sm-release.outputs.SM_TAG_EXISTS == 'false' && steps.sm-cache.outputs.cache-hit != 'true' + with: + name: spidermonkey-${{ matrix.build }} + path: spidermonkey-dist-${{ matrix.build }}/* + + release-spidermonkey: + needs: test + if: needs.test.outputs.SM_TAG_EXISTS == 'false' && (github.event_name == 'push' && + (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))) + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Restore SpiderMonkey Debug Cache + uses: actions/cache/restore@v4 + id: sm-cache-debug + with: + path: | + spidermonkey-dist-debug + key: ${{ needs.test.outputs.SM_CACHE_KEY_debug }} + fail-on-cache-miss: true + - name: Restore SpiderMonkey Release Cache + uses: actions/cache/restore@v4 + id: sm-cache-release + with: + path: | + spidermonkey-dist-release + key: ${{ needs.test.outputs.SM_CACHE_KEY_release }} + fail-on-cache-miss: true + + - name: Create SpiderMonkey Tar Balls + run: | + mkdir -p release-artifacts + tar -a -cf release-artifacts/spidermonkey-static-debug.tar.gz spidermonkey-dist-debug/* + tar -a -cf release-artifacts/spidermonkey-static-release.tar.gz spidermonkey-dist-release/* + tree release-artifacts + + - name: Do the Release + uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 #2.3.2 + with: + body: | + This release contains pre-built SpiderMonkey artifacts to be used by the StarlingMonkey + build system. It's not meant for general public consumption and doesn't come with any + stability or availability guarantees. + tag_name: ${{ needs.test.outputs.SM_TAG }} + files: release-artifacts/* diff --git a/.gitignore b/.gitignore index a01f0f57..827ef5dd 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ /tests/e2e/*/*.log /tests/integration/*/*.wasm /tests/integration/*/*.log +/deps/*.lock +/deps/*-source diff --git a/CMakeLists.txt b/CMakeLists.txt index 5696c4ec..2f24aa77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,10 @@ else() endif() message(STATUS "Using host API: ${HOST_API}") +# Ensure that the CPM cache is created outside the build dir, even if no location is specified by the developer. +if(NOT DEFINED ENV{CPM_SOURCE_CACHE}) + set(ENV{CPM_SOURCE_CACHE} ${CMAKE_CURRENT_SOURCE_DIR}/deps/cpm_cache) +endif() include("CPM") include("toolchain") @@ -32,8 +36,8 @@ include("binaryen") include("wizer") include("weval") include("wasmtime") +include("cbindgen") -include("fmt") include("spidermonkey") include("openssl") include("${HOST_API}/host_api.cmake") diff --git a/README.md b/README.md index 87f0676b..3502118f 100644 --- a/README.md +++ b/README.md @@ -71,43 +71,60 @@ cmake -S . -B cmake-build-debug -DCMAKE_BUILD_TYPE=Debug 3. Build the runtime -Building the runtime is done in two phases: first, cmake is used to build a raw version as a -WebAssembly core module. Then, that module is turned into a [WebAssembly Component][wasm-component] -using the `componentize.sh` script generated by the build. +The build system provides two targets for the runtime: `starling-raw.wasm` and `starling.wasm`. The former is a raw WebAssembly core module that can be used to build a WebAssembly Component, while the latter is the final componentized runtime that can be used directly with a WebAssembly Component-aware runtime like [wasmtime](https://wasmtime.dev/). -The following command will build the `starling-raw.wasm` runtime module in the `cmake-build-release` +A key difference is that `starling.wasm` can only be used for runtime-evaluation of JavaScript code, +while `starling-raw.wasm` can be used to build a WebAssembly Component that is specialized for a specific +JavaScript application, and as a result has much faster startup times. + +## Using StarlingMonkey with dynamically loaded JS code + +The following command will build the `starling.wasm` runtime module in the `cmake-build-release` directory: ```console # Use cmake-build-debug for the debug build -# Change the value for `--parallel` to match the number of CPU cores in your system -cmake --build cmake-build-release --parallel 8 +cmake --build cmake-build-release -t starling --parallel $(nproc) ``` -Then, the `starling-raw.wasm` module can be turned into a component with the following command: +The resulting runtime can be used to load and evaluate JS code dynamically: ```console -cd cmake-build-release -./componentize.sh -o starling.wasm +wasmtime -S http cmake-build-release/starling.wasm -e "console.log('hello world')" +# or, to load a file: +wasmtime -S http --dir . starling.wasm index.js ``` -The resulting runtime can be used to load and evaluate JS code dynamically: + +## Creating a specialized runtime for your JS code + +To create a specialized version of the runtime, first build a raw, unspecialized core wasm version of StarlingMonkey: ```console -wasmtime -S http starling.wasm -e "console.log('hello world')" -# or, to load a file: -wasmtime -S http --dir . starling.wasm index.js +# Use cmake-build-debug for the debug build +cmake --build cmake-build-release -t starling-raw.wasm --parallel $(nproc) ``` -Alternatively, a JS file can be provided during componentization: +Then, the `starling-raw.wasm` module can be turned into a component specialized for your code with the following command: ```console cd cmake-build-release -./componentize.sh index.js -o starling.wasm +./componentize.sh index.js -o index.wasm ``` -This way, the JS file will be loaded during componentization, and the top-level code will be -executed, and can e.g. register a handler for the `fetch` event to serve HTTP requests. +This mode currently only supports the creation of HTTP server components, which means that the `index.js` file must register a `fetch` event handler. For example, your `index.js` could contain the following code: + +```javascript +addEventListener('fetch', event => { + event.respondWith(new Response('Hello, world!')); +}); +``` + +Componentizing this code like above allows running it like this: + +```console +wasmtime serve -S cli --dir . index.wasm +``` [cmake]: https://cmake.org/ [gh-pages]: https://bytecodealliance.github.io/StarlingMonkey/ diff --git a/builtins/web/base64.cpp b/builtins/web/base64.cpp index 76106543..fee32521 100644 --- a/builtins/web/base64.cpp +++ b/builtins/web/base64.cpp @@ -212,7 +212,7 @@ JS::Result forgivingBase64Decode(std::string_view data, auto hasWhitespace = std::find_if(data.begin(), data.end(), &isAsciiWhitespace); std::string dataWithoutAsciiWhitespace; - if (hasWhitespace) { + if (*hasWhitespace) { dataWithoutAsciiWhitespace = data; dataWithoutAsciiWhitespace.erase(std::remove_if(dataWithoutAsciiWhitespace.begin() + std::distance(data.begin(), hasWhitespace), diff --git a/builtins/web/console.cpp b/builtins/web/console.cpp index afc2d680..19086865 100644 --- a/builtins/web/console.cpp +++ b/builtins/web/console.cpp @@ -468,7 +468,7 @@ static bool console_out(JSContext *cx, unsigned argc, JS::Value *vp) { // https://console.spec.whatwg.org/#assert // assert(condition, ...data) -static bool assert(JSContext *cx, unsigned argc, JS::Value *vp) { +static bool assert_(JSContext *cx, unsigned argc, JS::Value *vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); args.rval().setUndefined(); auto condition = args.get(0).toBoolean(); @@ -811,7 +811,7 @@ static bool trace(JSContext *cx, unsigned argc, JS::Value *vp) { } const JSFunctionSpec Console::methods[] = { - JS_FN("assert", assert, 0, JSPROP_ENUMERATE), + JS_FN("assert", assert_, 0, JSPROP_ENUMERATE), JS_FN("clear", no_op, 0, JSPROP_ENUMERATE), JS_FN("count", count, 0, JSPROP_ENUMERATE), JS_FN("countReset", countReset, 0, JSPROP_ENUMERATE), diff --git a/builtins/web/crypto/uuid.cpp b/builtins/web/crypto/uuid.cpp index f6c211c7..771b0596 100644 --- a/builtins/web/crypto/uuid.cpp +++ b/builtins/web/crypto/uuid.cpp @@ -1,8 +1,6 @@ #include "uuid.h" #include "host_api.h" -#include - namespace builtins { namespace web { namespace crypto { diff --git a/builtins/web/event/event-target.cpp b/builtins/web/event/event-target.cpp index f369bfba..844d8b3d 100644 --- a/builtins/web/event/event-target.cpp +++ b/builtins/web/event/event-target.cpp @@ -105,7 +105,7 @@ bool default_passive_value() { namespace JS { -template struct JS::GCPolicy> { +template struct GCPolicy> { static void trace(JSTracer *trc, RefPtr *tp, const char *name) { if (T *target = tp->get()) { GCPolicy::trace(trc, target, name); diff --git a/builtins/web/fetch/fetch-utils.cpp b/builtins/web/fetch/fetch-utils.cpp index efc91200..2d08a6ab 100644 --- a/builtins/web/fetch/fetch-utils.cpp +++ b/builtins/web/fetch/fetch-utils.cpp @@ -160,7 +160,7 @@ std::optional> extract_range(std::string_view range_q auto to_size = [](std::string_view s) -> std::optional { size_t v; - auto [ptr, ec] = std::from_chars(s.begin(), s.end(), v); + auto [ptr, ec] = std::from_chars(&*s.begin(), &*s.end(), v); return ec == std::errc() ? std::optional(v) : std::nullopt; }; diff --git a/builtins/web/fetch/fetch_event.cpp b/builtins/web/fetch/fetch_event.cpp index f9f30a18..0a886912 100644 --- a/builtins/web/fetch/fetch_event.cpp +++ b/builtins/web/fetch/fetch_event.cpp @@ -132,7 +132,7 @@ bool FetchEvent::init_incoming_request(JSContext *cx, JS::HandleObject self, bool is_head = !is_get && method_str == "HEAD"; if (!is_get) { - JS::RootedString method(cx, JS_NewStringCopyN(cx, method_str.cbegin(), method_str.length())); + JS::RootedString method(cx, JS_NewStringCopyN(cx, &*method_str.cbegin(), method_str.length())); if (!method) { return false; } diff --git a/builtins/web/fetch/request-response.cpp b/builtins/web/fetch/request-response.cpp index 51374429..9af0cbf8 100644 --- a/builtins/web/fetch/request-response.cpp +++ b/builtins/web/fetch/request-response.cpp @@ -85,7 +85,7 @@ class BodyFutureTask final : public api::AsyncTask { auto body = RequestOrResponse::incoming_body_handle(owner); auto read_res = body->read(HANDLE_READ_CHUNK_SIZE); - if (auto *err = read_res.to_err()) { + if (read_res.to_err()) { auto receiver = Request::is_instance(owner) ? "request" : "response"; api::throw_error(cx, FetchErrors::IncomingBodyStreamError, receiver); return error_stream_controller_with_pending_exception(cx, stream); diff --git a/builtins/web/form-data/form-data-encoder.cpp b/builtins/web/form-data/form-data-encoder.cpp index 013626d7..1aa3775c 100644 --- a/builtins/web/form-data/form-data-encoder.cpp +++ b/builtins/web/form-data/form-data-encoder.cpp @@ -658,7 +658,7 @@ JSObject *MultipartFormData::create(JSContext *cx, HandleObject form_data) { } auto res = host_api::Random::get_bytes(12); - if (auto *err = res.to_err()) { + if (res.to_err()) { return nullptr; } diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake index 157aa974..d61eaeea 100644 --- a/cmake/CPM.cmake +++ b/cmake/CPM.cmake @@ -2,28 +2,23 @@ # # SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors -set(CPM_DOWNLOAD_VERSION 0.40.5) -set(CPM_HASH_SUM "c46b876ae3b9f994b4f05a4c15553e0485636862064f1fcc9d8b4f832086bc5d") +set(CPM_DOWNLOAD_VERSION 0.42.0) +set(CPM_HASH_SUM "2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a") -# Ensure that the CPM_SOURCE_CACHE is defined and in sync with ENV{CPM_SOURCE_CACHE} -if (NOT DEFINED CPM_SOURCE_CACHE) - if(DEFINED ENV{CPM_SOURCE_CACHE}) - set(CPM_SOURCE_CACHE $ENV{CPM_SOURCE_CACHE}) - else() - set(CPM_SOURCE_CACHE ${CMAKE_CURRENT_SOURCE_DIR}/deps/cpm_cache) - endif() +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") endif() -set(ENV{CPM_SOURCE_CACHE} ${CPM_SOURCE_CACHE}) - -set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") -set(CPM_USE_NAMED_CACHE_DIRECTORIES ON) # Expand relative path. This is important if the provided path contains a tilde (~) get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) file(DOWNLOAD - https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake - ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} ) include(${CPM_DOWNLOAD_LOCATION}) diff --git a/cmake/binaryen.cmake b/cmake/binaryen.cmake index 23c8f07f..dbd20dd1 100644 --- a/cmake/binaryen.cmake +++ b/cmake/binaryen.cmake @@ -1,4 +1,4 @@ -set(BINARYEN_VERSION 117) +set(BINARYEN_VERSION 123) set(BINARYEN_ARCH ${HOST_ARCH}) if(HOST_OS STREQUAL "macos" AND HOST_ARCH STREQUAL "aarch64") diff --git a/cmake/builtins.cmake b/cmake/builtins.cmake index cbae419f..d7799438 100644 --- a/cmake/builtins.cmake +++ b/cmake/builtins.cmake @@ -42,7 +42,7 @@ add_builtin( builtins/web/form-data/form-data-parser.cpp DEPENDENCIES multipart - fmt) +) add_builtin( builtins::web::dom_exception @@ -102,7 +102,7 @@ add_builtin( builtins/web/fetch/headers.cpp builtins/web/fetch/request-response.cpp DEPENDENCIES - fmt) +) add_builtin( builtins::web::fetch::fetch_event @@ -124,6 +124,5 @@ add_builtin( builtins/web/crypto/uuid.cpp DEPENDENCIES OpenSSL::Crypto - fmt INCLUDE_DIRS runtime) diff --git a/cmake/cbindgen.cmake b/cmake/cbindgen.cmake new file mode 100644 index 00000000..a5ef3a84 --- /dev/null +++ b/cmake/cbindgen.cmake @@ -0,0 +1,16 @@ +set(CBINDGEN_VERSION 0.29.0) + +# cbindgen doesn't have pre-built binaries for all platforms, so we install it via cargo-binstall. Which we install first, too. +find_program(CBINDGEN_EXECUTABLE cbindgen) +if(NOT CBINDGEN_EXECUTABLE) + find_program(CARGO_BINSTALL_EXECUTABLE cargo-binstall) + if(NOT CARGO_BINSTALL_EXECUTABLE) + execute_process( + COMMAND curl -L --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh + COMMAND bash + ) + endif() + execute_process( + COMMAND cargo binstall -y cbindgen + ) +endif() diff --git a/cmake/compile-flags.cmake b/cmake/compile-flags.cmake index ca4660c2..219b2f05 100644 --- a/cmake/compile-flags.cmake +++ b/cmake/compile-flags.cmake @@ -12,7 +12,7 @@ list(APPEND CMAKE_EXE_LINKER_FLAGS list(JOIN CMAKE_EXE_LINKER_FLAGS " " CMAKE_EXE_LINKER_FLAGS) list(APPEND CMAKE_CXX_FLAGS - -std=gnu++20 -Wall -Werror -Qunused-arguments -Wimplicit-fallthrough + -std=gnu++20 -Wall -Werror -Qunused-arguments -Wimplicit-fallthrough -Wno-unknown-warning-option -fno-sized-deallocation -fno-aligned-new -mthread-model single -fPIC -fno-rtti -fno-exceptions -fno-math-errno -pipe -fno-omit-frame-pointer -funwind-tables -m32 diff --git a/cmake/fmt.cmake b/cmake/fmt.cmake deleted file mode 100644 index a160d910..00000000 --- a/cmake/fmt.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(FMT_OS OFF) -set(FMT_INSTALL OFF) -CPMAddPackage(NAME fmt URL https://github.com/fmtlib/fmt/releases/download/10.1.1/fmt-10.1.1.zip) diff --git a/cmake/init-corrosion.cmake b/cmake/init-corrosion.cmake index dfaa07a8..a98a25fa 100644 --- a/cmake/init-corrosion.cmake +++ b/cmake/init-corrosion.cmake @@ -9,7 +9,7 @@ set(Rust_CARGO_TARGET_LINK_NATIVE_LIBS "") file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/rust-toolchain.toml" Rust_TOOLCHAIN REGEX "^channel ?=") string(REGEX MATCH "[0-9.]+" Rust_TOOLCHAIN "${Rust_TOOLCHAIN}") execute_process(COMMAND rustup toolchain install ${Rust_TOOLCHAIN}) -execute_process(COMMAND rustup target add --toolchain ${Rust_TOOLCHAIN} wasm32-wasi) +execute_process(COMMAND rustup target add --toolchain ${Rust_TOOLCHAIN} wasm32-wasip1) CPMAddPackage("gh:corrosion-rs/corrosion@0.5.1") string(TOLOWER ${Rust_CARGO_HOST_ARCH} HOST_ARCH) diff --git a/cmake/manage-git-source.cmake b/cmake/manage-git-source.cmake new file mode 100644 index 00000000..50cef2c9 --- /dev/null +++ b/cmake/manage-git-source.cmake @@ -0,0 +1,98 @@ +# Function to manage git-based source dependencies with shallow cloning and tag management +function(manage_git_source) + cmake_parse_arguments( + GIT_SRC + "" + "NAME;REPO_URL;TAG;SOURCE_DIR" + "" + ${ARGN} + ) + + if(NOT DEFINED GIT_SRC_NAME OR NOT DEFINED GIT_SRC_REPO_URL OR NOT DEFINED GIT_SRC_TAG OR NOT DEFINED GIT_SRC_SOURCE_DIR) + message(FATAL_ERROR "manage_git_source requires NAME, REPO_URL, TAG, and SOURCE_DIR arguments") + endif() + + set(LOCK_FILE ${CMAKE_SOURCE_DIR}/deps/.${GIT_SRC_NAME}-clone.lock) + + # Use file locking to prevent concurrent clone operations + file(LOCK ${LOCK_FILE} GUARD FUNCTION) + + # Check if source directory already exists and has the correct tag + set(NEED_CLONE TRUE) + set(NEED_CHECKOUT FALSE) + + if(EXISTS ${GIT_SRC_SOURCE_DIR}/.git) + # Check current tag + execute_process( + COMMAND git -C ${GIT_SRC_SOURCE_DIR} describe --tags --exact-match HEAD + OUTPUT_VARIABLE CURRENT_TAG + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE TAG_CHECK_RESULT + ) + + if(TAG_CHECK_RESULT EQUAL 0 AND CURRENT_TAG STREQUAL ${GIT_SRC_TAG}) + set(NEED_CLONE FALSE) + message(STATUS "${GIT_SRC_NAME} source already at correct tag ${GIT_SRC_TAG}") + else() + # Repository exists but wrong tag - fetch and checkout instead of re-cloning + set(NEED_CLONE FALSE) + set(NEED_CHECKOUT TRUE) + message(STATUS "${GIT_SRC_NAME} source not at correct tag, checking out ${GIT_SRC_TAG}") + endif() + endif() + + if(NEED_CLONE) + message(STATUS "Cloning ${GIT_SRC_NAME} source at tag ${GIT_SRC_TAG}") + # Remove existing directory if it exists but isn't a git repo + if(EXISTS ${GIT_SRC_SOURCE_DIR}) + file(REMOVE_RECURSE ${GIT_SRC_SOURCE_DIR}) + endif() + + # Perform shallow clone of specific tag + execute_process( + COMMAND git clone --depth 1 --branch ${GIT_SRC_TAG} + ${GIT_SRC_REPO_URL} + ${GIT_SRC_SOURCE_DIR} + RESULT_VARIABLE CLONE_RESULT + ERROR_VARIABLE CLONE_ERROR + ) + + if(NOT CLONE_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to clone ${GIT_SRC_NAME} source: ${CLONE_ERROR}") + endif() + elseif(NEED_CHECKOUT) + # Check if the tag already exists locally + execute_process( + COMMAND git -C ${GIT_SRC_SOURCE_DIR} rev-parse --verify "refs/tags/${GIT_SRC_TAG}" + OUTPUT_QUIET + ERROR_QUIET + RESULT_VARIABLE TAG_EXISTS_RESULT + ) + + if(NOT TAG_EXISTS_RESULT EQUAL 0) + # Tag doesn't exist locally, fetch it + message(STATUS "Fetching tag ${GIT_SRC_TAG}") + execute_process( + COMMAND git -C ${GIT_SRC_SOURCE_DIR} fetch --depth 1 origin tag ${GIT_SRC_TAG} + RESULT_VARIABLE FETCH_RESULT + ERROR_VARIABLE FETCH_ERROR + ) + + if(NOT FETCH_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to fetch tag ${GIT_SRC_TAG}: ${FETCH_ERROR}") + endif() + endif() + + # Checkout the tag (whether it was already local or just fetched) + execute_process( + COMMAND git -C ${GIT_SRC_SOURCE_DIR} checkout ${GIT_SRC_TAG} + RESULT_VARIABLE CHECKOUT_RESULT + ERROR_VARIABLE CHECKOUT_ERROR + ) + + if(NOT CHECKOUT_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to checkout tag ${GIT_SRC_TAG}: ${CHECKOUT_ERROR}") + endif() + endif() +endfunction() diff --git a/cmake/openssl.cmake b/cmake/openssl.cmake index f69cabb3..23153bec 100644 --- a/cmake/openssl.cmake +++ b/cmake/openssl.cmake @@ -1,6 +1,6 @@ # Based on https://stackoverflow.com/a/72187533 -set(OPENSSL_VERSION 3.0.16) -set(OPENSSL_HASH "SHA256=57e03c50feab5d31b152af2b764f10379aecd8ee92f16c985983ce4a99f7ef86") +set(OPENSSL_VERSION 3.0.17) +set(OPENSSL_HASH "SHA256=dfdd77e4ea1b57ff3a6dbde6b0bdc3f31db5ac99e7fdd4eaf9e1fbb6ec2db8ce") set(OPENSSL_INSTALL_DIR ${CMAKE_BINARY_DIR}/deps/OpenSSL) set(OPENSSL_INCLUDE_DIR ${OPENSSL_INSTALL_DIR}/include) include(ExternalProject) diff --git a/cmake/spidermonkey.cmake b/cmake/spidermonkey.cmake index b496692f..838b76f4 100644 --- a/cmake/spidermonkey.cmake +++ b/cmake/spidermonkey.cmake @@ -1,16 +1,16 @@ -set(SM_REV b02d76023a15a3fa8c8f54bff5dac91099669003) +set(SM_TAG FIREFOX_140_0_4_RELEASE_STARLING) + +include("manage-git-source") if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(SM_BUILD_TYPE debug) else() set(SM_BUILD_TYPE release) endif() -set(SM_BUILD_TYPE_DASH ${SM_BUILD_TYPE}) option(WEVAL "Build with a SpiderMonkey variant that supports weval-based AOT compilation" OFF) if (WEVAL) - set(SM_BUILD_TYPE_DASH "${SM_BUILD_TYPE}-weval") set(SM_BUILD_TYPE "${SM_BUILD_TYPE}_weval") endif() @@ -21,24 +21,184 @@ endif() # This can be set, for example, to the output directly (`release/` or `debug/`) # under a local clone of the `spidermonkey-wasi-embedding` repo. if (DEFINED ENV{SPIDERMONKEY_BINARIES}) - set(SM_SOURCE_DIR $ENV{SPIDERMONKEY_BINARIES}) + set(SM_LIB_DIR $ENV{SPIDERMONKEY_BINARIES}) + message(STATUS "Using pre-built SpiderMonkey artifacts from local directory ${SM_LIB_DIR}") else() - CPMAddPackage(NAME spidermonkey-${SM_BUILD_TYPE} - URL https://github.com/bytecodealliance/spidermonkey-wasi-embedding/releases/download/rev_${SM_REV}/spidermonkey-wasm-static-lib_${SM_BUILD_TYPE}.tar.gz - DOWNLOAD_ONLY YES + set(SM_URL https://github.com/bytecodealliance/starlingmonkey/releases/download/libspidermonkey_${SM_TAG}/spidermonkey-static-${SM_BUILD_TYPE}.tar.gz) + message(STATUS "Checking for pre-built SpiderMonkey artifacts at ${SM_URL}") + execute_process( + COMMAND curl -sIL -o /dev/null -w "%{http_code}" ${SM_URL} + RESULT_VARIABLE CURL_RESULT + OUTPUT_VARIABLE HTTP_STATUS ) - set(SM_SOURCE_DIR ${CPM_PACKAGE_spidermonkey-${SM_BUILD_TYPE}_SOURCE_DIR} CACHE STRING "Path to spidermonkey ${SM_BUILD_TYPE} build" FORCE) + if (CURL_RESULT EQUAL 0 AND HTTP_STATUS STREQUAL "200") + message(STATUS "Using pre-built SpiderMonkey artifacts from ${SM_URL}") + CPMAddPackage(NAME spidermonkey-${SM_BUILD_TYPE} + URL ${SM_URL} + DOWNLOAD_ONLY YES + ) + set(SM_LIB_DIR ${CPM_PACKAGE_spidermonkey-${SM_BUILD_TYPE}_SOURCE_DIR} CACHE STRING "Path to spidermonkey ${SM_BUILD_TYPE} build" FORCE) + else() + message(STATUS "No pre-built ${SM_BUILD_TYPE} SpiderMonkey artifacts available for tag ${SM_TAG}. Building from source.") + endif() endif() -set(SM_INCLUDE_DIR ${SM_SOURCE_DIR}/include) - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/null.cpp "") -file(GLOB SM_OBJS ${SM_SOURCE_DIR}/lib/*.o) -add_library(spidermonkey STATIC) -target_sources(spidermonkey PRIVATE ${SM_OBJS} ${CMAKE_CURRENT_BINARY_DIR}/null.cpp) -target_include_directories(spidermonkey PUBLIC ${SM_INCLUDE_DIR}) -target_link_libraries(spidermonkey PUBLIC ${SM_SOURCE_DIR}/lib/libjs_static.a) +if (DEFINED SM_LIB_DIR) + set(SM_INCLUDE_DIR ${SM_LIB_DIR}/include) + + add_library(spidermonkey INTERFACE) + target_include_directories(spidermonkey INTERFACE ${SM_INCLUDE_DIR}) + target_link_libraries(spidermonkey INTERFACE ${SM_LIB_DIR}/libspidermonkey.a) +else() + # Clone SpiderMonkey source using git directly for shallow clone + # Use deps folder in project root for shared access across build directories + set(SM_SOURCE_DIR ${CMAKE_SOURCE_DIR}/deps/spidermonkey-source) + + manage_git_source( + NAME spidermonkey + REPO_URL https://github.com/bytecodealliance/firefox.git + TAG ${SM_TAG} + SOURCE_DIR ${SM_SOURCE_DIR} + ) + + # Each build configuration gets its own object directory + set(SM_OBJ_DIR ${CMAKE_CURRENT_BINARY_DIR}/spidermonkey-obj) + set(SM_LIB_DIR "${SM_OBJ_DIR}/dist") + set(SM_INCLUDE_DIR "${SM_LIB_DIR}/include") + + # Additional obj files needed, but not part of libjs_static.a + set(SM_OBJ_FILES + memory/build/Unified_cpp_memory_build0.o + memory/mozalloc/Unified_cpp_memory_mozalloc0.o + mfbt/Unified_cpp_mfbt0.o + mfbt/Unified_cpp_mfbt1.o + mozglue/misc/AutoProfilerLabel.o + mozglue/misc/ConditionVariable_noop.o + mozglue/misc/Debug.o + mozglue/misc/Decimal.o + mozglue/misc/MmapFaultHandler.o + mozglue/misc/Mutex_noop.o + mozglue/misc/Now.o + mozglue/misc/Printf.o + mozglue/misc/SIMD.o + mozglue/misc/StackWalk.o + mozglue/misc/TimeStamp.o + mozglue/misc/TimeStamp_posix.o + mozglue/misc/Uptime.o + mozglue/static/lz4.o + mozglue/static/lz4frame.o + mozglue/static/lz4hc.o + mozglue/static/xxhash.o + third_party/fmt/Unified_cpp_third_party_fmt0.o + ) + set(SM_OBJS) + foreach(obj_file ${SM_OBJ_FILES}) + list(APPEND SM_OBJS ${SM_OBJ_DIR}/${obj_file}) + endforeach() + + # Set up compiler environment + find_program(SM_HOST_CC clang c REQUIRED DOCS "C compiler for building SpiderMonkey") + find_program(SM_HOST_CXX clang++ c++ REQUIRED DOCS "C++ compiler for building") + + set(MOZCONFIG "${CMAKE_CURRENT_BINARY_DIR}/mozconfig-${SM_BUILD_TYPE}") + set(MOZCONFIG_CONTENT "ac_add_options --enable-project=js +ac_add_options --disable-js-shell +ac_add_options --target=wasm32-unknown-wasi +ac_add_options --without-system-zlib +ac_add_options --without-intl-api +ac_add_options --disable-jit +ac_add_options --disable-shared-js +ac_add_options --disable-shared-memory +ac_add_options --disable-tests +ac_add_options --disable-clang-plugin +ac_add_options --enable-jitspew +ac_add_options --enable-optimize=-O3 +ac_add_options --enable-js-streams +ac_add_options --enable-portable-baseline-interp +ac_add_options --prefix=${SM_OBJ_DIR}/dist +mk_add_options MOZ_OBJDIR=${SM_OBJ_DIR} +mk_add_options AUTOCLOBBER=1 +") + + # Add WASI sysroot if available + if(DEFINED ENV{WASI_SYSROOT}) + string(APPEND MOZCONFIG_CONTENT "ac_add_options --with-sysroot=\"$ENV{WASI_SYSROOT}\"\n") + endif() -add_compile_definitions("MOZ_JS_STREAMS") + # Platform-specific configuration + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + string(APPEND MOZCONFIG_CONTENT "ac_add_options --disable-stdcxx-compat\n") + elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + string(APPEND MOZCONFIG_CONTENT "ac_add_options --host=aarch64-apple-darwin\n") + else() + message(FATAL_ERROR "Unsupported build platform: ${CMAKE_HOST_SYSTEM_NAME}") + endif() + + # Mode-specific configuration + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + string(APPEND MOZCONFIG_CONTENT "ac_add_options --enable-debug\n") + else() + string(APPEND MOZCONFIG_CONTENT "ac_add_options --disable-debug\n") + string(APPEND MOZCONFIG_CONTENT "ac_add_options --enable-lto=thin\n") + endif() + + # Weval-specific configuration + if(WEVAL) + string(APPEND MOZCONFIG_CONTENT "ac_add_options --enable-portable-baseline-interp-force\n") + string(APPEND MOZCONFIG_CONTENT "ac_add_options --enable-aot-ics\n") + string(APPEND MOZCONFIG_CONTENT "ac_add_options --enable-aot-ics-force\n") + string(APPEND MOZCONFIG_CONTENT "ac_add_options --enable-pbl-weval\n") + endif() + + file(GENERATE OUTPUT ${MOZCONFIG} CONTENT "${MOZCONFIG_CONTENT}") + + add_custom_command( + OUTPUT ${SM_OBJS} ${SM_LIB_DIR}/libjs_static.a + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E env + CC=${CMAKE_C_COMPILER} + CXX=${CMAKE_CXX_COMPILER} + AR=${CMAKE_AR} + HOST_CC=${SM_HOST_CC} + HOST_CXX=${SM_HOST_CXX} + MOZCONFIG=${MOZCONFIG} + SM_SOURCE_DIR=${SM_SOURCE_DIR} + SM_OBJ_DIR=${SM_OBJ_DIR} + python3 ${SM_SOURCE_DIR}/mach --no-interactive build + COMMAND ${CMAKE_COMMAND} -E rm -f ${SM_INCLUDE_DIR}/js-confdefs.h + COMMAND ${CMAKE_COMMAND} -E create_symlink ${SM_OBJ_DIR}/js/src/js-confdefs.h ${SM_INCLUDE_DIR}/js-confdefs.h + COMMAND ${CMAKE_COMMAND} -E create_symlink ${SM_OBJ_DIR}/js/src/build/libjs_static.a ${SM_LIB_DIR}/libjs_static.a + DEPENDS ${MOZCONFIG} + COMMENT "Building SpiderMonkey for WASI" + VERBATIM + ) + + # Create combined static library including everything needed for embedding SpiderMonkey. + set(LIB_SM ${SM_LIB_DIR}/libspidermonkey.a) + add_custom_command( + OUTPUT ${LIB_SM} + COMMAND ${CMAKE_COMMAND} -E copy ${SM_LIB_DIR}/libjs_static.a ${LIB_SM} + COMMAND ${CMAKE_AR} -q ${LIB_SM} ${SM_OBJS} + DEPENDS ${SM_OBJS} ${SM_LIB_DIR}/libjs_static.a + COMMENT "Creating combined SpiderMonkey library" + VERBATIM + ) + add_custom_target(spidermonkey_build DEPENDS ${LIB_SM}) + + add_library(spidermonkey INTERFACE) + add_dependencies(spidermonkey spidermonkey_build) + target_include_directories(spidermonkey INTERFACE ${SM_INCLUDE_DIR}) + target_link_libraries(spidermonkey INTERFACE ${LIB_SM}) +endif() + +# SpiderMonkey's builds include a header that defines some configuration options that need to be set +# to ensure e.g. object layout is identical to the one used in the build. +# We include this header in all compilations. +## (And because that file doesn't exist until the SpiderMonkey build is complete, we create a placeholder for now.) +if (NOT EXISTS ${SM_INCLUDE_DIR}/js-confdefs.h) + file(WRITE ${SM_INCLUDE_DIR}/js-confdefs.h "// Placeholder\n") +endif() +target_compile_options(spidermonkey INTERFACE -include ${SM_INCLUDE_DIR}/js-confdefs.h) diff --git a/cmake/wasi-sdk.cmake b/cmake/wasi-sdk.cmake index e25595f1..ba5f79c6 100644 --- a/cmake/wasi-sdk.cmake +++ b/cmake/wasi-sdk.cmake @@ -1,6 +1,6 @@ -set(WASI_SDK_VERSION 20 CACHE STRING "Version of wasi-sdk to use") +set(WASI_SDK_VERSION 25 CACHE STRING "Version of wasi-sdk to use" FORCE) -set(WASI_SDK_URL "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-${HOST_OS}.tar.gz") +set(WASI_SDK_URL "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-${HOST_CPU}-${HOST_OS}.tar.gz") CPMAddPackage(NAME wasi-sdk URL ${WASI_SDK_URL}) set(WASI_SDK_PREFIX ${CPM_PACKAGE_wasi-sdk_SOURCE_DIR}) -set(CMAKE_TOOLCHAIN_FILE ${CPM_PACKAGE_wasi-sdk_SOURCE_DIR}/share/cmake/wasi-sdk.cmake) +set(CMAKE_TOOLCHAIN_FILE ${WASI_SDK_PREFIX}/share/cmake/wasi-sdk.cmake) diff --git a/cmake/wasm-tools.cmake b/cmake/wasm-tools.cmake index a8e03b9f..40f8dd73 100644 --- a/cmake/wasm-tools.cmake +++ b/cmake/wasm-tools.cmake @@ -1,6 +1,6 @@ -set(WASM_TOOLS_VERSION 1.0.54) +set(WASM_TOOLS_VERSION 1.235.0) -set(WASM_TOOLS_URL https://github.com/bytecodealliance/wasm-tools/releases/download/wasm-tools-${WASM_TOOLS_VERSION}/wasm-tools-${WASM_TOOLS_VERSION}-${HOST_ARCH}-${HOST_OS}.tar.gz) +set(WASM_TOOLS_URL https://github.com/bytecodealliance/wasm-tools/releases/download/v${WASM_TOOLS_VERSION}/wasm-tools-${WASM_TOOLS_VERSION}-${HOST_ARCH}-${HOST_OS}.tar.gz) CPMAddPackage(NAME wasm-tools URL ${WASM_TOOLS_URL} DOWNLOAD_ONLY TRUE) set(WASM_TOOLS_DIR ${CPM_PACKAGE_wasm-tools_SOURCE_DIR}) set(WASM_TOOLS_BIN ${WASM_TOOLS_DIR}/wasm-tools CACHE FILEPATH "Path to wasm-tools binary") diff --git a/cmake/wizer.cmake b/cmake/wizer.cmake index f429e8a2..142cd68f 100644 --- a/cmake/wizer.cmake +++ b/cmake/wizer.cmake @@ -1,4 +1,4 @@ -set(WIZER_VERSION v3.0.1 CACHE STRING "Version of wizer to use") +set(WIZER_VERSION v9.0.0 CACHE STRING "Version of wizer to use") set(WIZER_URL https://github.com/bytecodealliance/wizer/releases/download/${WIZER_VERSION}/wizer-${WIZER_VERSION}-${HOST_ARCH}-${HOST_OS}.tar.xz) CPMAddPackage(NAME wizer URL ${WIZER_URL} DOWNLOAD_ONLY TRUE) diff --git a/host-apis/wasi-0.2.0/host_api.cpp b/host-apis/wasi-0.2.0/host_api.cpp index dccbd72b..40d9507e 100644 --- a/host-apis/wasi-0.2.0/host_api.cpp +++ b/host-apis/wasi-0.2.0/host_api.cpp @@ -643,12 +643,12 @@ wasi_http_types_method_t http_method_to_host(string_view method_str) { auto method = method_str.begin(); for (uint8_t i = 0; i < WASI_HTTP_TYPES_METHOD_OTHER; i++) { auto name = http_method_names[i]; - if (strcasecmp(method, name) == 0) { + if (strcasecmp(&*method, name) == 0) { return wasi_http_types_method_t{i}; } } - auto val = bindings_string_t{reinterpret_cast(const_cast(method)), + auto val = bindings_string_t{reinterpret_cast(const_cast(&*method)), method_str.length()}; return wasi_http_types_method_t{WASI_HTTP_TYPES_METHOD_OTHER, {val}}; } diff --git a/runtime/debugger.cpp b/runtime/debugger.cpp index bc14aa56..0fa98718 100644 --- a/runtime/debugger.cpp +++ b/runtime/debugger.cpp @@ -37,7 +37,7 @@ bool print_location(JSContext *cx, FILE *fp = stdout) { JS::AutoFilename filename; uint32_t lineno; JS::ColumnNumberOneOrigin column; - if (!DescribeScriptedCaller(cx, &filename, &lineno, &column)) { + if (!DescribeScriptedCaller(&filename, cx, &lineno, &column)) { return false; } fprintf(fp, "%s@%u:%u: ", filename.get(), lineno, column.oneOriginValue()); diff --git a/runtime/engine.cpp b/runtime/engine.cpp index 484dc28e..341dc3b7 100644 --- a/runtime/engine.cpp +++ b/runtime/engine.cpp @@ -256,7 +256,8 @@ bool create_content_global(JSContext * cx) { JS::RealmOptions options; options.creationOptions().setStreamsEnabled(true); - JS::DisableIncrementalGC(cx); + // TODO: restore + // JS::DisableIncrementalGC(cx); // JS_SetGCParameter(cx, JSGC_MAX_EMPTY_CHUNK_COUNT, 1); RootedObject global( diff --git a/runtime/js.cpp b/runtime/js.cpp index deeb6f72..a5cf05c7 100644 --- a/runtime/js.cpp +++ b/runtime/js.cpp @@ -12,8 +12,6 @@ #include #endif -extern "C" void __wasm_call_ctors(); - api::Engine *engine; api::Engine* initialize(std::vector args) { @@ -77,8 +75,6 @@ void wizen() { WIZER_INIT(wizen); -extern "C" void __wasm_call_ctors(); - /** * The main entry function for the runtime. * @@ -89,8 +85,6 @@ extern "C" void __wasm_call_ctors(); * load the file `./index.js` and run it as the top-level module script. */ extern "C" bool exports_wasi_cli_run_run() { - __wasm_call_ctors(); - auto arg_strings = host_api::environment_get_arguments(); std::vector args; for (auto& arg : arg_strings) args.push_back(arg); @@ -109,8 +103,6 @@ extern "C" bool exports_wasi_cli_run_run() { * command line. */ extern "C" bool init_from_environment() { - __wasm_call_ctors(); - auto config_parser = starling::ConfigParser(); config_parser.apply_env(); ENGINE = new api::Engine(config_parser.take()); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 4c21f8c7..e7a439c8 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.80.0" +channel = "1.88.0" targets = [ "wasm32-wasip1" ] profile = "minimal" diff --git a/tests/tests.cmake b/tests/tests.cmake index 5416374e..f4f11876 100644 --- a/tests/tests.cmake +++ b/tests/tests.cmake @@ -12,22 +12,35 @@ function(test_e2e TEST_NAME) set_tests_properties(e2e-${TEST_NAME} PROPERTIES TIMEOUT 120) endfunction() -add_custom_target(integration-test-server DEPENDS test-server.wasm) - function(test_integration TEST_NAME) get_target_property(RUNTIME_DIR starling-raw.wasm BINARY_DIR) + add_test(integration-${TEST_NAME} ${BASH_PROGRAM} ${CMAKE_SOURCE_DIR}/tests/test.sh ${RUNTIME_DIR} ${CMAKE_SOURCE_DIR}/tests/integration/${TEST_NAME} test-server.wasm ${TEST_NAME}) + set_property(TEST integration-${TEST_NAME} PROPERTY ENVIRONMENT "WASMTIME=${WASMTIME};WIZER=${WIZER_DIR}/wizer;WASM_TOOLS=${WASM_TOOLS_DIR}/wasm-tools;") + set_tests_properties(integration-${TEST_NAME} PROPERTIES TIMEOUT 120) +endfunction() + +function(integration_tests) + get_target_property(RUNTIME_DIR starling-raw.wasm BINARY_DIR) + set(TESTS_DIR ${CMAKE_SOURCE_DIR}/tests/integration) + set(DEPS ${RUNTIME_DIR}/componentize.sh starling-raw.wasm ${TESTS_DIR}/test-server.js ${TESTS_DIR}/handlers.js + ) + foreach(TEST_NAME ${ARGV}) + list(APPEND DEPS ${TESTS_DIR}/${TEST_NAME}/${TEST_NAME}.js) + endforeach() + add_custom_command( - OUTPUT test-server.wasm - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E env "WASM_TOOLS=${WASM_TOOLS_DIR}/wasm-tools" env "WIZER=${WIZER_DIR}/wizer" env "PREOPEN_DIR=${CMAKE_SOURCE_DIR}/tests" ${RUNTIME_DIR}/componentize.sh ${CMAKE_SOURCE_DIR}/tests/integration/test-server.js test-server.wasm - DEPENDS ${ARG_SOURCES} ${RUNTIME_DIR}/componentize.sh starling-raw.wasm - VERBATIM + OUTPUT test-server.wasm + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E env "WASM_TOOLS=${WASM_TOOLS_DIR}/wasm-tools" env "WIZER=${WIZER_DIR}/wizer" env "PREOPEN_DIR=${CMAKE_SOURCE_DIR}/tests" ${RUNTIME_DIR}/componentize.sh ${TESTS_DIR}/test-server.js test-server.wasm + DEPENDS ${DEPS} + VERBATIM ) + add_custom_target(integration-test-server DEPENDS test-server.wasm) - add_test(integration-${TEST_NAME} ${BASH_PROGRAM} ${CMAKE_SOURCE_DIR}/tests/test.sh ${RUNTIME_DIR} ${CMAKE_SOURCE_DIR}/tests/integration/${TEST_NAME} ${RUNTIME_DIR}/test-server.wasm ${TEST_NAME}) - set_property(TEST integration-${TEST_NAME} PROPERTY ENVIRONMENT "WASMTIME=${WASMTIME};WIZER=${WIZER_DIR}/wizer;WASM_TOOLS=${WASM_TOOLS_DIR}/wasm-tools;") - set_tests_properties(integration-${TEST_NAME} PROPERTIES TIMEOUT 120) + foreach(TEST_NAME ${ARGV}) + test_integration(${TEST_NAME}) + endforeach() endfunction() test_e2e(blob) @@ -44,10 +57,12 @@ test_e2e(multi-stream-forwarding) test_e2e(teed-stream-as-outgoing-body) test_e2e(init-script) -test_integration(blob) -test_integration(btoa) -test_integration(crypto) -test_integration(event) -test_integration(fetch) -test_integration(performance) -test_integration(timers) +integration_tests( + blob + btoa + crypto + event + fetch + performance + timers +) diff --git a/tests/wpt-harness/wpt.cmake b/tests/wpt-harness/wpt.cmake index b5361597..58b67fe5 100644 --- a/tests/wpt-harness/wpt.cmake +++ b/tests/wpt-harness/wpt.cmake @@ -1,7 +1,10 @@ +set(WPT_TAG "epochs/daily/2024-10-02_01H") + enable_testing() include("wasmtime") include("weval") +include("manage-git-source") if(WEVAL) set(COMPONENTIZE_FLAGS "--aot") @@ -12,13 +15,15 @@ endif() if(DEFINED ENV{WPT_ROOT}) set(WPT_ROOT $ENV{WPT_ROOT}) else() - CPMAddPackage( - NAME wpt-suite - GITHUB_REPOSITORY web-platform-tests/wpt - GIT_TAG 04d2e6c42ddce90925d73a076f6cfdd5786e8e54 - DOWNLOAD_ONLY TRUE + # Use deps folder in project root for shared access across build directories + set(WPT_ROOT ${CMAKE_SOURCE_DIR}/deps/wpt-source) + + manage_git_source( + NAME wpt + REPO_URL https://github.com/web-platform-tests/wpt.git + TAG ${WPT_TAG} + SOURCE_DIR ${WPT_ROOT} ) - set(WPT_ROOT ${CPM_PACKAGE_wpt-suite_SOURCE_DIR}) endif() add_builtin(wpt_support