Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-and-test-on-freebsd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
shell: freebsd {0}
run: |
cd $GITHUB_WORKSPACE;
sed -i '' 's/test_http_server/%test_http_server/g' tests/libs/eavmlib/tests.erl
sed -i '' 's/test_http_server, //g' tests/libs/eavmlib/tests.erl

- name: "Build: create build dir"
shell: freebsd {0}
Expand Down
183 changes: 183 additions & 0 deletions .github/workflows/wasi-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#
# Copyright 2026 Paul Guyot <pguyot@kallisys.net>
#
# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
#

name: WASI Build

on:
push:
paths:
- '.github/workflows/wasi-build.yaml'
- 'CMakeLists.txt'
- 'CMakeModules/**'
- 'libs/**'
- 'src/platforms/wasi/**'
- 'src/libAtomVM/**'
pull_request:
paths:
- '.github/workflows/wasi-build.yaml'
- 'CMakeLists.txt'
- 'CMakeModules/**'
- 'libs/**'
- 'src/platforms/wasi/**'
- 'src/libAtomVM/**'

permissions:
contents: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }}
cancel-in-progress: true

jobs:

compile_tests:

runs-on: ubuntu-24.04
container: erlang:28
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: ["c-cpp"]

steps:
- name: Checkout repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install required packages
run: apt update && apt install -y gperf zlib1g-dev cmake ninja-build

- name: "Git config safe.directory for codeql"
run: git config --global --add safe.directory /__w/AtomVM/AtomVM

- name: "Initialize CodeQL"
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: ${{matrix.language}}
build-mode: manual
queries: +./code-queries/term-to-non-term-func.ql,./code-queries/non-term-to-term-func.ql,./code-queries/mismatched-atom-string-length.ql,./code-queries/mismatched-free-type.ql,./code-queries/term-use-after-gc.ql,./code-queries/allocations-exceeding-ensure-free.ql,./code-queries/allocations-without-ensure-free.ql

- name: Compile AtomVM and test modules
run: |
set -e
mkdir build
cd build
cmake .. -G Ninja -DAVM_WARNINGS_ARE_ERRORS=ON
ninja AtomVM atomvmlib erlang_test_modules test_etest test_alisp test_estdlib test_eavmlib

- name: "Perform CodeQL Analysis"
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4

- name: Upload AtomVM and test modules
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: atomvm-and-test-modules
path: |
build/**/*.avm
build/**/*.beam
build/src/AtomVM
retention-days: 1

wasi_build_and_test:
needs: compile_tests
runs-on: ubuntu-24.04

strategy:
fail-fast: false
matrix:
include:
# No SMP, no networking - minimal stable target.
- target: wasm32-wasip1
disable_smp: ON
wasmtime_flags: ""
# SMP via wasi-threads, no networking. Needs shared-memory in wasmtime.
- target: wasm32-wasip1-threads
disable_smp: OFF
wasmtime_flags: "-W threads -W shared-memory -S threads"
# No SMP, networking via wasi:sockets@0.2.x - exercises BSD sockets and SSL.
- target: wasm32-wasip2
disable_smp: ON
wasmtime_flags: "-S inherit-network -S allow-ip-name-lookup"

steps:
- name: Checkout repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install required packages
run: sudo apt-get update -y && sudo apt-get install -y cmake ninja-build gperf

- name: Install WASI SDK
run: |
set -euo pipefail
WASI_SDK_VERSION=33
wget -q "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux.tar.gz"
sudo mkdir -p /opt/wasi-sdk
sudo tar xzf "wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux.tar.gz" --strip-components=1 -C /opt/wasi-sdk

- name: Install wasmtime
run: |
set -euo pipefail
WASMTIME_VERSION=44.0.1
WASMTIME_TARBALL="wasmtime-v${WASMTIME_VERSION}-x86_64-linux.tar.xz"
WASMTIME_SHA256="afd58715f105e3a7f454169daed22168c5736ec5f225fb04c4ac62c54c9508a3"
wget -q "https://github.com/bytecodealliance/wasmtime/releases/download/v${WASMTIME_VERSION}/${WASMTIME_TARBALL}"
echo "${WASMTIME_SHA256} ${WASMTIME_TARBALL}" | sha256sum -c -
sudo mkdir -p /opt/wasmtime
sudo tar xf "${WASMTIME_TARBALL}" --strip-components=1 -C /opt/wasmtime
echo "/opt/wasmtime" >> $GITHUB_PATH

- name: Build (${{ matrix.target }})
working-directory: ./src/platforms/wasi/
run: |
set -euo pipefail
mkdir build
cd build
cmake -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=../wasi-sdk.cmake \
-DAVM_DISABLE_JIT=ON \
-DAVM_DISABLE_SMP=${{ matrix.disable_smp }} \
-DWASI_TARGET=${{ matrix.target }} \
..
ninja

- name: Download AtomVM and test modules
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: atomvm-and-test-modules
path: build

- name: Test (${{ matrix.target }})
working-directory: ./build
run: |
set -euxo pipefail
WASM=../src/platforms/wasi/build/src/AtomVM.wasm
FLAGS="${{ matrix.wasmtime_flags }}"
wasmtime run ${FLAGS} --dir=. ${WASM} tests/libs/alisp/test_alisp.avm
wasmtime run ${FLAGS} --dir=. ${WASM} tests/libs/estdlib/test_estdlib.avm
wasmtime run ${FLAGS} --dir=. ${WASM} tests/libs/etest/test_etest.avm
wasmtime run ${FLAGS} --dir=. ${WASM} tests/libs/eavmlib/test_eavmlib.avm

- name: "Rename and write sha256sum"
if: startsWith(github.ref, 'refs/tags/')
working-directory: src/platforms/wasi/build/src
run: |
ATOMVM_WASM=AtomVM-${{ matrix.target }}-${{ github.ref_name }}.wasm
mv AtomVM.wasm "${ATOMVM_WASM}"
sha256sum "${ATOMVM_WASM}" > "${ATOMVM_WASM}.sha256"

- name: "Release"
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
if: startsWith(github.ref, 'refs/tags/')
with:
draft: true
fail_on_unmatched_files: true
files: |
src/platforms/wasi/build/src/AtomVM-${{ matrix.target }}-${{ github.ref_name }}.wasm
src/platforms/wasi/build/src/AtomVM-${{ matrix.target }}-${{ github.ref_name }}.wasm.sha256
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added UART API to rp2 platform
- Added `"USB_SERIAL_JTAG"` peripheral to the ESP32 `uart` module on chips with a built-in
USB-Serial-JTAG controller (C3/C5/C6/C61/H2/H21/H4/P4/S3)
- Added WASI platform, with `wasm32-wasip1` (no SMP, no networking),
`wasm32-wasip1-threads` (SMP, no networking) and `wasm32-wasip2` (no SMP,
networking via `wasi:sockets@0.2.x`) target triples

### Changed
- Updated network type db() to dbm() to reflect the actual representation of the type
Expand All @@ -38,6 +41,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
longer lines return `{error, {parser, {line_too_long, Prefix}}}` with the first 128 bytes of
the offending line. Callers whose upstream servers emit unusually large headers must account
for this limit
- `socket:setopt(Socket, {socket, reuseaddr}, _Value)` and
`socket:setopt(Socket, {socket, linger}, _Value)` are accepted on platforms
that do not implement the options

### Removed
- Removed `ahttp_client` support for obsolete line folding (RFC 9112 §5.2); folded header and
Expand All @@ -55,6 +61,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed a bug in `supervisor` handling of failing child
- Fixed two bugs related to closing fds in `atomvm:subprocess/4`
- Fixed `erlang:localtime/1` memory leak, use-after-free, and TZ restore bugs on newlib/picolibc
- `socket:recv/3` and `socket:recvfrom/3` now tolerate spurious select wakeups
- `gen_tcp_socket` and `gen_udp_socket` no longer leak `pending_selects` entries
- `socket:send/2` and `socket:sendto/3` now wait via select
- `socket:bind`, `socket:listen`, `socket:accept`, `socket:connect`,
`socket:shutdown`, `socket:sockname`, `socket:peername`, `socket:recv`,
`socket:recvfrom`, `socket:send` and `socket:sendto` operating on a fd
that was already closed by another process now return `{error, closed}`
rather than `{error, ebadf}`
- `gen_tcp_socket` and `gen_udp_socket` now return proper result (`ok` or
`{error, closed}`) when the underlying process exited.

## [0.7.0-alpha.1] - 2026-04-06

Expand Down
6 changes: 4 additions & 2 deletions README.Md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Supported Platforms
* STM32 MCUs (with official ST HAL/LL SDK, see [stm32](https://doc.atomvm.org/main/getting-started-guide.html#getting-started-on-the-stm32-platform))
* Raspberry Pi Pico and Pico 2 (see [rp2](https://doc.atomvm.org/main/getting-started-guide.html#getting-started-on-the-raspberry-pi-pico-platform))
* Browsers and NodeJS with WebAssembly (see [emscripten](https://doc.atomvm.org/main/getting-started-guide.html#getting-started-with-atomvm-webassembly))
* Standalone WebAssembly runtimes such as wasmtime (see [wasi](https://doc.atomvm.org/main/build-instructions.html#building-for-wasi))

AtomVM aims to be easily portable to new platforms with a minimum effort, so additional platforms
might be supported in a near future.
Expand Down Expand Up @@ -72,8 +73,9 @@ available in the documentation for
[ESP32](https://doc.atomvm.org/main/build-instructions.html#building-for-esp32),
[STM32](https://doc.atomvm.org/main/build-instructions.html#building-for-stm32),
[Raspberry Pi Pico and Pico 2](https://doc.atomvm.org/main/build-instructions.html#building-for-raspberry-pi-pico)
(rp2), and
[WASM](https://doc.atomvm.org/main/build-instructions.html#building-for-nodejs-web) (NodeJS/Web).
(rp2),
[WASM](https://doc.atomvm.org/main/build-instructions.html#building-for-nodejs-web) (NodeJS/Web), and
[WASI](https://doc.atomvm.org/main/build-instructions.html#building-for-wasi) (standalone WebAssembly).

Project Status
==============
Expand Down
103 changes: 102 additions & 1 deletion doc/src/build-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The native C parts of AtomVM compile to machine code on MacOS, Linux, and FreeBS

The Erlang and Elixir parts are compiled to BEAM byte-code using the Erlang (`erlc`) and Elixir compilers. For information about specific versions of required software, see the [Release Notes](./release-notes.md).

This guide provides information about how to build AtomVM for the various supported platforms (Generic UNIX, ESP32, and STM32).
This guide provides information about how to build AtomVM for the various supported platforms (Generic UNIX, ESP32, STM32, RP2, Emscripten WASM, and WASI).

```{attention}
In order to build AtomVM AVM files for ESP32 and STM32 platforms, you will also need to build
Expand Down Expand Up @@ -92,6 +92,7 @@ It is possible to use a local copy of `uf2tool` source code by setting `UF2TOOL_
* [STM32](#building-for-stm32)
* [RP2](#building-for-rp2) (including Pico boards)
* [WASM](#building-for-emscripten) (NodeJS or web)
* [WASI](#building-for-wasi) (WebAssembly System Interface, wasmtime/wasmer)

## Building for Generic UNIX

Expand Down Expand Up @@ -1218,3 +1219,103 @@ $ cd src/platforms/emscripten/tests/
$ npm install cypress
$ npx cypress open
```

## Building for WASI

WASI (WebAssembly System Interface) allows AtomVM to run as a pure WebAssembly module without JavaScript dependencies. Unlike the Emscripten build, WASI targets standalone runtimes such as wasmtime, WasmEdge, and wasmer.

### WASI Prerequisites

* [WASI SDK](https://github.com/WebAssembly/wasi-sdk/releases) at version 33 or
newer recommended
* A WASI runtime, such as [wasmtime](https://wasmtime.dev) (recommended)
* `cmake` 3.13 or later
* Erlang/OTP

### WASI Target Modes

The build supports three target triples, picked automatically from `AVM_DISABLE_SMP`. SMP and networking sit on different targets and are currently mutually exclusive:

| Target triple | SMP | Networking | Selection |
| ------------------------- | --- | ---------------------------------- | ------------------------------------------------------ |
| `wasm32-wasip1-threads` | yes | no | default (`-DAVM_DISABLE_SMP=OFF`) |
| `wasm32-wasip2` | no | yes (`wasi:sockets@0.2.x`) | `-DAVM_DISABLE_SMP=ON` |
| `wasm32-wasip1` | no | no | `-DAVM_DISABLE_SMP=ON -DWASI_TARGET=wasm32-wasip1` |

`erlang:system_info(system_architecture)` reports the active triple (e.g. `wasm32-wasip2`).

### WASI Build Instructions

Default (SMP, no networking):

```shell
$ cd src/platforms/wasi/
$ mkdir build
$ cd build
$ cmake -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=../wasi-sdk.cmake \
-DAVM_DISABLE_JIT=ON \
..
$ ninja
```

For networking (single-threaded `wasm32-wasip2`):

```shell
$ cmake -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=../wasi-sdk.cmake \
-DAVM_DISABLE_JIT=ON \
-DAVM_DISABLE_SMP=ON \
..
```

The WASI SDK location is detected automatically from the `WASI_SDK_PATH` environment variable, `/opt/local/libexec/wasi-sdk` (MacPorts), or `/opt/wasi-sdk`.

### Running AtomVM on WASI

WASI uses capability-based security. Grant directory access with `--dir` when running:

```shell
$ wasmtime run --dir=. build/src/AtomVM.wasm myapp.avm
```

For SMP (`wasm32-wasip1-threads`) wasmtime needs the threads proposal:

```shell
$ wasmtime run -W threads -W shared-memory --dir=. build/src/AtomVM.wasm myapp.avm
```

For networking (`wasm32-wasip2`) grant socket and DNS capabilities:

```shell
$ wasmtime run -S inherit-network -S allow-ip-name-lookup --dir=. \
build/src/AtomVM.wasm myapp.avm
```

You can load multiple AVM or BEAM files by listing them as additional arguments:

```shell
$ wasmtime run --dir=. build/src/AtomVM.wasm myapp.avm libs/atomvmlib.avm
```

### Running tests with WASI

Build the test modules first using the Generic UNIX build (see above). Then run:

```shell
$ cd build
$ wasmtime run --dir=. ../src/platforms/wasi/build/src/AtomVM.wasm \
tests/libs/alisp/test_alisp.avm
$ wasmtime run --dir=. ../src/platforms/wasi/build/src/AtomVM.wasm \
tests/libs/estdlib/test_estdlib.avm
$ wasmtime run --dir=. ../src/platforms/wasi/build/src/AtomVM.wasm \
tests/libs/etest/test_etest.avm
```

### WASI Platform Limitations

* JIT compilation is not supported; the WebAssembly sandbox prohibits executable memory.
* Networking requires the `wasm32-wasip2` target; the WASI Preview 1 targets (`wasm32-wasip1` and `wasm32-wasip1-threads`) have no sockets.
* SMP requires the `wasm32-wasip1-threads` target; `wasm32-wasip2` does not provide threads.
* Process creation (fork/exec) is not supported on any WASI target.
* Directory access requires explicit capability grants via `--dir`.
2 changes: 1 addition & 1 deletion doc/src/welcome-to-atomvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ AtomVM is licensed under the terms of the [Apache2](https://www.apache.org/licen

## Source Code

The [AtomVM Github Repository](https://github.com/atomvm/AtomVM) contains the AtomVM source code, including the AtomVM virtual machine and core libraries. The AtomVM [Build Instructions](./build-instructions.md) contains instructions for building AtomVM for Generic UNIX, ESP32, and STM32 platforms.
The [AtomVM Github Repository](https://github.com/atomvm/AtomVM) contains the AtomVM source code, including the AtomVM virtual machine and core libraries. The AtomVM [Build Instructions](./build-instructions.md) contains instructions for building AtomVM for Generic UNIX, ESP32, STM32, RP2, Emscripten, and WASI platforms.

## Contributing

Expand Down
Loading
Loading