import std support
#247
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build, Test, Release | |
| on: [ push ] | |
| env: | |
| NODE_HEADERS: 24.0.0 | |
| V8_REF: 14.2.231.21 | |
| jobs: | |
| # First, check to see if v8 has been built for each target. If not, then a more powerful `runs-on` | |
| # builder is used on EC2. | |
| # nb: Windows support w/ runs-on is beta and doesn't include the same tooling as GitHub. | |
| # https://runs-on.com | |
| # https://github.com/runs-on/runs-on | |
| configure: | |
| strategy: | |
| matrix: | |
| host: | |
| - runs-on: ubuntu-24.04-arm | |
| triplet: aarch64-alpine-linux-musl | |
| - runs-on: ubuntu-24.04-arm | |
| triplet: aarch64-unknown-linux-gnu | |
| - runs-on: ubuntu-24.04 | |
| triplet: x86_64-alpine-linux-musl | |
| - runs-on: ubuntu-24.04 | |
| triplet: x86_64-unknown-linux-gnu | |
| name: Configure [${{ matrix.host.triplet }}] | |
| runs-on: ${{ matrix.host.runs-on }} | |
| outputs: | |
| aarch64-alpine-linux-musl: ${{ steps.output.outputs.aarch64-alpine-linux-musl }} | |
| aarch64-unknown-linux-gnu: ${{ steps.output.outputs.aarch64-unknown-linux-gnu }} | |
| x86_64-alpine-linux-musl: ${{ steps.output.outputs.x86_64-alpine-linux-musl }} | |
| x86_64-unknown-linux-gnu: ${{ steps.output.outputs.x86_64-unknown-linux-gnu }} | |
| steps: | |
| - uses: actions/cache/restore@v5 | |
| id: cache | |
| with: | |
| key: v8/${{ env.V8_REF }}/${{ matrix.host.triplet }} | |
| lookup-only: true | |
| path: deps/v8/out | |
| - shell: sh | |
| id: output | |
| env: | |
| CACHE_HIT: ${{ steps.cache.outputs.cache-hit }} | |
| TRIPLET: ${{ matrix.host.triplet }} | |
| RUNS_ON: ${{ matrix.host.runs-on }} | |
| run: | | |
| set -ux | |
| if [ "$CACHE_HIT" = true ]; then | |
| echo "$TRIPLET=$RUNS_ON" >> "$GITHUB_OUTPUT" | |
| else | |
| case "$RUNS_ON" in | |
| ubuntu-24.04) | |
| echo "$TRIPLET=runs-on,runner=32cpu-linux-x64,run-id=$GITHUB_RUN_ID" >> "$GITHUB_OUTPUT" | |
| ;; | |
| ubuntu-24.04-arm) | |
| echo "$TRIPLET=runs-on,runner=32cpu-linux-arm64,run-id=$GITHUB_RUN_ID" >> "$GITHUB_OUTPUT" | |
| ;; | |
| windows-2025) | |
| echo "$TRIPLET=runs-on,image=windows22-base-x64,family=m7i,run-id=$GITHUB_RUN_ID" >> "$GITHUB_OUTPUT" | |
| ;; | |
| esac | |
| fi | |
| # Build isolated-vm | |
| build: | |
| name: Build [${{ matrix.host.triplet }}] | |
| needs: configure | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host: | |
| - runs-on: ${{ needs.configure.outputs.aarch64-alpine-linux-musl }} | |
| container: alpine:edge | |
| triplet: aarch64-alpine-linux-musl | |
| - runs-on: macos-15 | |
| triplet: aarch64-apple-darwin | |
| - runs-on: ${{ needs.configure.outputs.aarch64-unknown-linux-gnu }} | |
| container: debian:forky | |
| triplet: aarch64-unknown-linux-gnu | |
| - runs-on: ${{ needs.configure.outputs.x86_64-alpine-linux-musl }} | |
| container: alpine:edge | |
| triplet: x86_64-alpine-linux-musl | |
| - runs-on: macos-15-intel | |
| triplet: x86_64-apple-darwin | |
| - runs-on: windows-2025 | |
| triplet: x86_64-pc-windows | |
| - runs-on: ${{ needs.configure.outputs.x86_64-unknown-linux-gnu }} | |
| container: debian:forky | |
| triplet: x86_64-unknown-linux-gnu | |
| runs-on: ${{ matrix.host.runs-on }} | |
| container: ${{ matrix.host.container }} | |
| concurrency: ${{ matrix.host.triplet }} | |
| env: | |
| TRIPLET: ${{ matrix.host.triplet }} | |
| steps: | |
| - uses: laverdet/alpine-arm64@v1 | |
| if: matrix.host.triplet == 'aarch64-alpine-linux-musl' | |
| # Setup | |
| - uses: actions/checkout@v5 | |
| - shell: sh | |
| run: echo "$GITHUB_WORKSPACE/scripts" >> "$GITHUB_PATH" | |
| # GNU `tar` & `zstd` is needed for `actions/cache` | |
| - uses: laverdet/install@v0 | |
| if: runner.os == 'Linux' | |
| with: | |
| packages: tar zstd | |
| # Install toolchain | |
| - name: Sources [Debian] | |
| if: endsWith(matrix.host.triplet, '-linux-gnu') | |
| run: apt-get -qq install --no-install-recommends -y curl; curl -kfsSL https://deb.nodesource.com/setup_24.x | bash - | |
| - name: Toolchain [Linux] | |
| uses: laverdet/install@v0 | |
| if: runner.os == 'Linux' | |
| with: | |
| packages: | | |
| bash | |
| binutils | |
| build-essential | |
| clang-21 | |
| clang-tools-21 | |
| cmake | |
| curl | |
| libboost-all-dev | |
| lld-21 | |
| llvm-21 | |
| ninja-build | |
| nodejs | |
| xxd | |
| alpine#npm | |
| - name: Toolchain [macOS] | |
| if: runner.os == 'macOS' | |
| run: | | |
| set -ux | |
| brew install boost cmake lld llvm ninja node | |
| # Clever workaround for clang-scan-deps issues | |
| # /opt/homebrew/opt/llvm/bin/../include/c++/v1/__locale_dir/support/bsd_like.h:21:10: fatal error: 'time.h' file not found | |
| # https://github.com/Homebrew/homebrew-core/issues/221782#issuecomment-3245658786 | |
| ln -s $(brew --prefix)/etc/clang ~/.config/clang | |
| # On Windows, the POSIX shell in GitHub actions is Git Bash. This runs in an isolated MSYS2 | |
| # installation under `C:/Program Files/Git`. The runner comes with another MSYS2 installation | |
| # in `C:/msys64`. This action adds the root MSYS2 installation higher up in $PATH so we can | |
| # use `pacman`, and consume binaries installed by `pacman`. | |
| # nb: Do not be confused by the `/msys64` directory which exists in the default GitHub shell! | |
| # It is not the same as `C:/msys64`. | |
| # nb: LLVM uses MSVC stdlib, so incomplete c++23 support. Unofficial LLVM uses libc/UCRT but | |
| # is not supported by v8. Cross-build via Linux may be the only way. | |
| # nb: windows-11-arm does *not* have Pacman! | |
| # https://github.com/actions/partner-runner-images/blob/main/images/arm-windows-11-image.md | |
| - name: Toolchain [Windows] | |
| if: runner.os == 'Windows' | |
| shell: sh | |
| run: | | |
| set -ux | |
| echo ::group::Toolchain | |
| # Install updated LLVM (and hide spammy progress bar) | |
| # nb: clang 22 is busted | |
| winget install --accept-source-agreements --silent -e --id=LLVM.LLVM --version=21.1.8 | tr '\r' '\n' | grep -Ev --line-buffered '^[ -\/|]+$' | |
| # You want the mingw version of ninja, not the msys version. The msys version uses | |
| # `CMD.EXE` and does not work with the cmake Ninja generator. | |
| ARCH=$(triplet_util %a) | |
| /c/msys64/usr/bin/pacman -Sy --noconfirm \ | |
| mingw-w64-$ARCH-boost \ | |
| "mingw64/mingw-w64-$ARCH-cmake>=4.3.0" \ | |
| mingw64/mingw-w64-$ARCH-ninja \ | |
| ; | |
| echo "/c/msys64/mingw64/bin" >> "$GITHUB_PATH" | |
| echo "/c/msys64/usr/bin" >> "$GITHUB_PATH" | |
| echo ::endgroup:: | |
| echo ::group::import std hack | |
| # /c/Program Files/Microsoft Visual Studio/2022/Enterprise | |
| VISUAL_STUDIO_PATH=$(cygpath "$(vswhere | grep installationPath: | cut -c19-)") | |
| # /c/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC/14.44.35207 | |
| MSVC_PATH="$VISUAL_STUDIO_PATH/VC/Tools/MSVC/$(ls "$VISUAL_STUDIO_PATH/VC/Tools/MSVC" | sort -V | tail -1)" | |
| # Make the `import std` interface manifest | |
| MODULES_FRAGMENT='{ "logical-name": "std", "source-path": "'"$(cygpath -w "$MSVC_PATH/modules/std.ixx" | sed 's \\ \\\\\\\\ g')"'", "is-std-library": true }' | |
| ARGUMENTS_FRAGMENT='"local-arguments": { "system-include-directories": [ "'"$MSVC_PATH/modules"'" ] }' | |
| MANIFEST_JSON='{ "version": 1, "revision": 1, "modules": [ '"$MODULES_FRAGMENT"' ], '"$ARGUMENTS_FRAGMENT"' }' | |
| echo "$MANIFEST_JSON" > ms-stl.modules.json | |
| # Patch cmake | |
| patch --batch --forward --unified /c/msys64/mingw64/share/cmake/Modules/Compiler/Clang-CXX-CXXImportStd.cmake <<"EOF" | |
| @@ -4,8 +4,7 @@ | |
| elseif (CMAKE_CXX_STANDARD_LIBRARY STREQUAL "libstdc++") | |
| set(_clang_modules_json_impl "libstdc++") | |
| else () | |
| - set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Only `libc++` and `libstdc++` are supported" PARENT_SCOPE) | |
| - return () | |
| + set(_clang_modules_json_impl "libc++") | |
| endif () | |
| if (NOT CMAKE_CXX_STDLIB_MODULES_JSON) | |
| EOF | |
| echo ::endgroup:: | |
| echo ::group::Dependency Walker | |
| mkdir -p "$RUNNER_TOOL_CACHE/depwalker" | |
| cd "$RUNNER_TOOL_CACHE/depwalker" | |
| # `--ssl-no-revoke`: curl: (35) schannel: next InitializeSecurityContext failed: | |
| # CRYPT_E_REVOCATION_OFFLINE (0x80092013) - The revocation function was unable to check | |
| # revocation because the revocation server was offline. | |
| curl -fsSL --ssl-no-revoke -o depwalker.zip https://github.com/lucasg/Dependencies/releases/download/v1.11.1/Dependencies_x64_Release.zip | |
| unzip depwalker.zip | |
| rm depwalker.zip | |
| echo "$PWD" >> "$GITHUB_PATH" | |
| echo ::endgroup:: | |
| # Restore previously built v8 | |
| - uses: actions/cache/restore@v5 | |
| id: v8-cache | |
| with: | |
| key: v8/${{ env.V8_REF }}/${{ matrix.host.triplet }} | |
| path: deps/v8/out | |
| # Build v8 on cache miss | |
| - uses: ./.github/actions/v8 | |
| name: Build v8 | |
| if: steps.v8-cache.outputs.cache-hit != 'true' | |
| with: | |
| triplet: ${{ matrix.host.triplet }} | |
| ref: ${{ env.V8_REF }} | |
| # Cache v8 | |
| - uses: actions/cache/save@v5 | |
| if: steps.v8-cache.outputs.cache-hit != 'true' | |
| with: | |
| key: ${{ steps.v8-cache.outputs.cache-primary-key }} | |
| path: deps/v8/out | |
| # Download nodejs headers | |
| - uses: actions/cache/restore@v5 | |
| id: nodejs-headers-cache | |
| with: | |
| enableCrossOsArchive: true | |
| key: nodejs-headers-${{ env.NODE_HEADERS }} | |
| path: deps/nodejs | |
| - name: node headers | |
| id: nodejs-headers | |
| if: steps.nodejs-headers-cache.outputs.cache-hit != 'true' | |
| env: | |
| NODE_HEADERS: ${{ env.NODE_HEADERS }} | |
| run: set -u; nodejs_select "deps/nodejs/$NODE_HEADERS" | |
| - uses: actions/cache/save@v5 | |
| if: steps.nodejs-headers.outcome == 'success' | |
| with: | |
| enableCrossOsArchive: true | |
| key: ${{ steps.nodejs-headers-cache.outputs.cache-primary-key }} | |
| path: deps/nodejs | |
| # Build isolated-vm | |
| - uses: pnpm/action-setup@v4 | |
| - shell: sh | |
| run: | | |
| set -ux | |
| pnpm install --frozen-lockfile | |
| npx tsc -b | |
| - name: Configure | |
| shell: sh | |
| env: | |
| NODE_DIST_DIR: deps/nodejs/${{ env.NODE_HEADERS }} | |
| V8_REF: ${{ env.V8_REF }} | |
| run: | | |
| set -ux | |
| V8_REF_PATH=$PWD/deps/v8/out/$V8_REF | |
| CMAKE_MAKE_PROGRAM=ninja | |
| CMAKE_PREFIX_PATH= | |
| case "$TRIPLET" in | |
| *-darwin) | |
| CMAKE_C_COMPILER=$(brew --prefix llvm)/bin/clang | |
| CMAKE_CXX_COMPILER=$(brew --prefix llvm)/bin/clang++ | |
| ;; | |
| *-linux-gnu|*-linux-musl) | |
| CMAKE_C_COMPILER=$(realpath "$(which clang-21)") | |
| CMAKE_CXX_COMPILER=$(realpath "$(which clang++-21)") | |
| ;; | |
| *-windows) | |
| CMAKE_C_COMPILER=$(which clang.exe) | |
| CMAKE_CXX_COMPILER=$(which clang++.exe) | |
| CMAKE_MAKE_PROGRAM=$(which ninja.exe) | |
| CMAKE_PREFIX_PATH=C:/msys64/mingw64/lib/cmake | |
| ;; | |
| esac | |
| cmake \ | |
| -DCMAKE_MODULE_PATH=$(npm exec auto_js_cmake_include) \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_C_COMPILER="$CMAKE_C_COMPILER" \ | |
| -DCMAKE_CXX_COMPILER="$CMAKE_CXX_COMPILER" \ | |
| -DCMAKE_MAKE_PROGRAM="$CMAKE_MAKE_PROGRAM" \ | |
| -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" \ | |
| -DV8_INCLUDE_DIR="$V8_REF_PATH/include" \ | |
| -DV8_INCLUDE_GN_FILE="$V8_REF_PATH/$TRIPLET.release/include/v8-gn.h" \ | |
| -DV8_LIBRARY_TYPE=static \ | |
| -DV8_LIBRARY_PATH="$V8_REF_PATH/$TRIPLET.release" \ | |
| -DIVM_INSTALL=copy \ | |
| -B build \ | |
| -G Ninja \ | |
| ; | |
| - name: Build | |
| shell: sh | |
| run: ninja -C build backend_napi_v8 | |
| - name: Sanity Check | |
| shell: sh | |
| run: node -e "require('./build/packages/backend_napi_v8/artifacts/$(triplet_util -t "$TRIPLET" %p)')" | |
| # Diagnostics | |
| - name: Symbols [Linux] | |
| if: runner.os == 'Linux' | |
| run: | | |
| set -ux | |
| ls -la build/packages/backend_napi_v8/backend_napi_v8.node | |
| ls -lah build/packages/backend_napi_v8/backend_napi_v8.node | |
| ldd build/packages/backend_napi_v8/backend_napi_v8.node 2>&1 | grep -v 'Error relocating' | |
| nm -guC build/packages/backend_napi_v8/backend_napi_v8.node | |
| - name: Symbols [Windows] | |
| if: runner.os == 'Windows' | |
| shell: sh | |
| run: | | |
| set -ux | |
| ls -la build/packages/backend_napi_v8/backend_napi_v8.node | |
| ls -lah build/packages/backend_napi_v8/backend_napi_v8.node | |
| dependencies.exe -imports build/packages/backend_napi_v8/backend_napi_v8.node | |
| # Upload build artifacts | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.host.triplet }} | |
| path: build/packages/backend_napi_v8/artifacts | |
| if-no-files-found: error | |
| # Console on failure | |
| - uses: laverdet/console@v1 | |
| if: failure() | |
| # Run tests | |
| test: | |
| name: Test [${{ matrix.host.container || matrix.host.runs-on }} ${{ endsWith(matrix.host.runs-on, '-arm' && 'arm64') || (endsWith(matrix.host.runs-on, '-intel') && 'x64') || (startsWith(matrix.host.runs-on, 'macos') && 'arm64') || 'x64' }} node:${{ matrix.node }}] | |
| needs: build | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host: | |
| - runs-on: ubuntu-24.04-arm | |
| container: alpine:edge | |
| - runs-on: macos-15 | |
| - runs-on: ubuntu-24.04-arm | |
| container: debian:forky | |
| - runs-on: ubuntu-24.04 | |
| container: alpine:edge | |
| - runs-on: macos-15-intel | |
| - runs-on: windows-2025 | |
| - runs-on: ubuntu-24.04 | |
| container: debian:forky | |
| node: | |
| - 22 | |
| - 24 | |
| runs-on: ${{ matrix.host.runs-on }} | |
| container: ${{ matrix.host.container }} | |
| steps: | |
| - uses: laverdet/alpine-arm64@v1 | |
| if: matrix.host.container == 'alpine:edge' | |
| - uses: laverdet/install@v0 | |
| if: matrix.host.container == 'alpine:edge' | |
| with: | |
| packages: bash | |
| # Setup | |
| - uses: actions/checkout@v5 | |
| - shell: sh | |
| run: echo "$GITHUB_WORKSPACE/scripts" >> "$GITHUB_PATH" | |
| # Get triplet information and make package.json for module | |
| - shell: sh | |
| id: platform | |
| run: | | |
| echo "platform=$(triplet_util %p)" >> "$GITHUB_OUTPUT" | |
| echo "triplet=$(triplet_util %t)" >> "$GITHUB_OUTPUT" | |
| # Receive artifacts | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: ${{ steps.platform.outputs.triplet }} | |
| path: build/packages/backend_napi_v8/artifacts | |
| # Install nodejs [musl] | |
| - shell: sh | |
| id: musl | |
| if: endsWith(steps.platform.outputs.triplet, '-linux-musl') | |
| env: | |
| NODE_VERSION: ${{ matrix.node }} | |
| run: | | |
| set -ux | |
| echo https://dl-cdn.alpinelinux.org/alpine/edge/community/ >> /etc/apk/repositories | |
| echo https://dl-cdn.alpinelinux.org/alpine/edge/testing/ >> /etc/apk/repositories | |
| case "$NODE_VERSION" in | |
| 24) echo "package=nodejs-current" >> "$GITHUB_OUTPUT" ;; | |
| 22) echo "package=nodejs" >> "$GITHUB_OUTPUT" ;; | |
| *) | |
| echo "Unknown node version: $NODE_VERSION" 1>&2 | |
| exit 1 | |
| ;; | |
| esac | |
| - uses: laverdet/install@v0 | |
| if: steps.musl.outcome == 'success' | |
| with: | |
| packages: alpine#${{ steps.musl.outputs.package }} npm | |
| # Install nodejs [others] | |
| - uses: actions/setup-node@v6 | |
| if: steps.musl.outcome == 'skipped' | |
| with: | |
| node-version: ${{ matrix.node }} | |
| # Install npm dependencies, build TypeScript, check module sanity | |
| - uses: pnpm/action-setup@v4 | |
| - name: Install | |
| shell: sh | |
| env: | |
| PLATFORM: ${{ steps.platform.outputs.platform }} | |
| run: | | |
| set -ux | |
| npm config set script-shell /bin/sh | |
| pnpm install --frozen-lockfile | |
| npx tsc -b | |
| mkdir -p node_modules/@isolated-vm | |
| mv build/packages/backend_napi_v8/artifacts/$PLATFORM node_modules/@isolated-vm/experimental-$PLATFORM | |
| node -e "require('@isolated-vm/experimental-$PLATFORM')" | |
| # Run tests | |
| - name: Test | |
| run: pnpm run -s test | |
| # Console on failure | |
| - uses: laverdet/console@v1 | |
| if: failure() | |
| release: | |
| name: Release | |
| needs: test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write | |
| steps: | |
| # Setup | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-node@v6 | |
| - uses: pnpm/action-setup@v4 | |
| - name: Setup | |
| shell: sh | |
| id: setup | |
| env: | |
| COMMIT_MESSAGE: ${{ github.event.head_commit.message }} | |
| run: | | |
| set -ux | |
| npm config set --location user access=public | |
| pnpm install --frozen-lockfile | |
| npx tsc -b | |
| # Receive artifacts | |
| - uses: actions/download-artifact@v4 | |
| id: artifacts | |
| with: | |
| path: packages/isolated-vm/artifacts | |
| # Assemble @isolated-vm/experimental | |
| - name: Assemble | |
| shell: sh | |
| working-directory: packages/isolated-vm | |
| env: | |
| ARTIFACTS: ${{ steps.artifacts.outputs.download-path }} | |
| run: | | |
| set -ux | |
| npx napi create-npm-dirs | |
| npx napi artifacts | |
| # Publish | |
| - uses: changesets/action@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| createGithubReleases: false | |
| publish: pnpm publish --no-git-checks --recursive --publish-branch experimental --provenance |