diff --git a/.github/workflows/wasm_wabt_tests_ci.yml b/.github/workflows/wasm_wabt_tests_ci.yml new file mode 100644 index 0000000000..868d7deeb3 --- /dev/null +++ b/.github/workflows/wasm_wabt_tests_ci.yml @@ -0,0 +1,73 @@ +name: wasm wabt validate tests CI + +on: + push: + paths: + - '!**' + - '!**.md' + - 'vlib/builtin/**.v' + - 'vlib/wasm/**.v' + - 'vlib/wasm/tests/**.v' + pull_request: + paths: + - '!**' + - '!**.md' + - 'vlib/builtin/**.v' + - 'vlib/wasm/**.v' + - 'vlib/wasm/tests/**.v' + +concurrency: + group: wasm-wabt-ci-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + wasm-wabt-ubuntu: + runs-on: ubuntu-22.04 + if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' + timeout-minutes: 31 + steps: + - uses: actions/checkout@v3 + + - name: Build V + run: make && ./v symlink -githubci + + - name: Install wabt to get the wasm-validate executable + run: v cmd/tools/install_wabt.vsh + + - name: Test the WASM backend + run: v test vlib/wasm/ + + wasm-wabt-macos: + runs-on: macOS-12 + if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' + timeout-minutes: 31 + steps: + - uses: actions/checkout@v3 + + - name: Build V + run: make && ./v symlink -githubci + + - name: Install wabt to get the wasm-validate executable + run: v cmd/tools/install_wabt.vsh + + - name: Test the WASM backend + run: v test vlib/wasm/ + + wasm-wabt-windows: + runs-on: windows-2022 + if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' + timeout-minutes: 31 + steps: + - uses: actions/checkout@v3 + + - name: Build V + run: .\make.bat -msvc + + - name: Symlink V + run: .\v.exe symlink -githubci + + - name: Install wabt to get the wasm-validate executable + run: v cmd/tools/install_wabt.vsh + + - name: Test the WASM backend + run: v test vlib/wasm/ diff --git a/.gitignore b/.gitignore index 2ce7e04499..ebc7eabd20 100644 --- a/.gitignore +++ b/.gitignore @@ -109,6 +109,7 @@ flake.nix thirdparty/stdatomic/nix/cpp/*.h thirdparty/binaryen* +thirdparty/wabt* # ignore VLS log vls.log diff --git a/cmd/tools/install_wabt.vsh b/cmd/tools/install_wabt.vsh new file mode 100644 index 0000000000..0b983b12e1 --- /dev/null +++ b/cmd/tools/install_wabt.vsh @@ -0,0 +1,52 @@ +#!/usr/bin/env -S v -raw-vsh-tmp-prefix tmp + +import os +import net.http + +const root = @VROOT + +fn main() { + os.chdir(root)! // make sure that the workfolder is stable + + tloc := os.join_path(root, 'thirdparty') + loc := os.join_path(tloc, 'wabt') + + if os.exists(loc) { + eprintln('thirdparty/wabt exists, will not overwrite') + eprintln('delete the folder, and execute again') + exit(1) + } + tag := '1.0.32' + fname := 'wabt-${tag}' + platform := $if windows { + 'windows' + } $else $if macos { + 'macos-12' + } $else $if linux { + 'ubuntu' + } $else { + eprintln('A premade binary library is not available for your system.') + eprintln('Build it from source, following the documentation here: https://github.com/WebAssembly/wabt/') + exit(1) + } + url := 'https://github.com/WebAssembly/wabt/releases/download/${tag}/${fname}-${platform}.tar.gz' + saveloc := os.join_path(tloc, '${fname}.tar.gz') + if !os.exists(saveloc) { + println('Downloading archive: ${saveloc}, from url: ${url} ...') + http.download_file(url, saveloc)! + // defer { os.rm(saveloc) or {}! } + } + + println('Extracting `${tloc}/${fname}` to `${tloc}/wabt` ...') + cmd := 'tar -xvf ${saveloc} --directory ${tloc}' + if os.system(cmd) != 0 { + eprintln('`${cmd}` exited with a non zero exit code') + exit(1) + } + + println(cmd) + println('Moving `${tloc}/${fname}` to `${tloc}/wabt` ...') + + os.rename_dir('${tloc}/${fname}', loc)! + println('Done. You can now use `v test vlib/wasm` .') +} diff --git a/vlib/wasm/tests/arith_test.v b/vlib/wasm/tests/arith_test.v index 8f601cf4f0..2c03d0c740 100644 --- a/vlib/wasm/tests/arith_test.v +++ b/vlib/wasm/tests/arith_test.v @@ -1,26 +1,6 @@ +module main + import wasm -import os - -const exe = os.find_abs_path_of_executable('wasm-validate') or { exit(0) } - -fn validate(mod []u8) ! { - mut proc := os.new_process(exe) - proc.set_args(['-']) - proc.set_redirect_stdio() - proc.run() - { - os.fd_write(proc.stdio_fd[0], mod.bytestr()) - os.fd_close(proc.stdio_fd[0]) - } - proc.wait() - if proc.status != .exited { - return error('wasm-validate exited abormally') - } - if proc.code != 0 { - return error('wasm-validate exited with a non zero exit code') - } - proc.close() -} fn test_add() { mut m := wasm.Module{} diff --git a/vlib/wasm/tests/block_test.v b/vlib/wasm/tests/block_test.v index b478d48f1c..f843364780 100644 --- a/vlib/wasm/tests/block_test.v +++ b/vlib/wasm/tests/block_test.v @@ -1,26 +1,6 @@ +module main + import wasm -import os - -const exe = os.find_abs_path_of_executable('wasm-validate') or { exit(0) } - -fn validate(mod []u8) ! { - mut proc := os.new_process(exe) - proc.set_args(['-']) - proc.set_redirect_stdio() - proc.run() - { - os.fd_write(proc.stdio_fd[0], mod.bytestr()) - os.fd_close(proc.stdio_fd[0]) - } - proc.wait() - if proc.status != .exited { - return error('wasm-validate exited abormally') - } - if proc.code != 0 { - return error('wasm-validate exited with a non zero exit code') - } - proc.close() -} fn test_block() { mut m := wasm.Module{} diff --git a/vlib/wasm/tests/call_test.v b/vlib/wasm/tests/call_test.v index 00ada214de..5d41e646fc 100644 --- a/vlib/wasm/tests/call_test.v +++ b/vlib/wasm/tests/call_test.v @@ -1,26 +1,6 @@ +module main + import wasm -import os - -const exe = os.find_abs_path_of_executable('wasm-validate') or { exit(0) } - -fn validate(mod []u8) ! { - mut proc := os.new_process(exe) - proc.set_args(['-']) - proc.set_redirect_stdio() - proc.run() - { - os.fd_write(proc.stdio_fd[0], mod.bytestr()) - os.fd_close(proc.stdio_fd[0]) - } - proc.wait() - if proc.status != .exited { - return error('wasm-validate exited abormally') - } - if proc.code != 0 { - return error('wasm-validate exited with a non zero exit code') - } - proc.close() -} fn test_call() { mut m := wasm.Module{} diff --git a/vlib/wasm/tests/common.v b/vlib/wasm/tests/common.v new file mode 100644 index 0000000000..04c504b14b --- /dev/null +++ b/vlib/wasm/tests/common.v @@ -0,0 +1,38 @@ +module main + +import os + +const pid = os.getpid() + +const wasm_validate_exe = find_wasm_validate() or { + println('>>> Skipping test, since wasm-validate could not be found, error: ${err}') + exit(0) +} + +fn find_wasm_validate() !string { + // Prefer to find our own version first, if it was installed already + // through install_wabt.vsh, since it is more likely to be known, recent, and stable: + thirdpart_wasm_validate_folder := os.join_path(@VROOT, 'thirdparty', 'wabt', 'bin') + extension := $if windows { '.exe' } $else { '' } + wasm_validate_executable := os.join_path(thirdpart_wasm_validate_folder, 'wasm-validate${extension}') + if os.exists(wasm_validate_executable) { + return wasm_validate_executable + } + if path := os.find_abs_path_of_executable('wasm-validate') { + return path + } + return error('could not find wasm-validate executable in thirdparty/ as well, try first `v run cmd/tools/install_wabt.vsh`') +} + +pub fn validate(code []u8) ! { + println('validating using: ${wasm_validate_exe}') + outfile := os.join_path(os.temp_dir(), 'code_${pid}.wasm') + os.write_file(outfile, code.bytestr())! + validation_cmd := '${os.quoted_path(wasm_validate_exe)} ${os.quoted_path(outfile)}' + res := os.execute(validation_cmd) + if res.exit_code != 0 { + eprintln('failed exit code: ${res.exit_code} | command:\n${validation_cmd}') + return error('wasm-validate exited with a non zero exit code: ${res.exit_code}') + } + os.rm(outfile)! +} diff --git a/vlib/wasm/tests/var_test.v b/vlib/wasm/tests/var_test.v index 055a6b9710..195c43150a 100644 --- a/vlib/wasm/tests/var_test.v +++ b/vlib/wasm/tests/var_test.v @@ -1,26 +1,6 @@ +module main + import wasm -import os - -const exe = os.find_abs_path_of_executable('wasm-validate') or { exit(0) } - -fn validate(mod []u8) ! { - mut proc := os.new_process(exe) - proc.set_args(['-']) - proc.set_redirect_stdio() - proc.run() - { - os.fd_write(proc.stdio_fd[0], mod.bytestr()) - os.fd_close(proc.stdio_fd[0]) - } - proc.wait() - if proc.status != .exited { - return error('wasm-validate exited abormally') - } - if proc.code != 0 { - return error('wasm-validate exited with a non zero exit code') - } - proc.close() -} fn test_globals() { mut m := wasm.Module{}