Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
097f064
Add builtins.wasm
edolstra Sep 19, 2025
c127937
Disable AOT/JIT support in wasmedge
edolstra Sep 19, 2025
a8a6750
Fix some crashes
edolstra Sep 30, 2025
d6d322b
Merge remote-tracking branch 'detsys/main' into wasm
edolstra Dec 20, 2025
e7bfa9b
Merge remote-tracking branch 'detsys/main' into wasm
edolstra Dec 25, 2025
d049bf3
Switch to wasmtime
edolstra Dec 29, 2025
8f23575
builtins.wasm: Propagate C++ exceptions from host functions
edolstra Dec 30, 2025
0e42761
builtins.wasm: Use ValueVector
edolstra Dec 30, 2025
f1b8adf
builtins.wasm: Simplify the host interface
edolstra Dec 31, 2025
56e9167
builtins.wasm: Allow wasm to apply Nix functions
edolstra Dec 31, 2025
392c4d1
builtins.wasm: Add panic host function
edolstra Jan 1, 2026
678873b
builtins.wasm: Improve error checking
edolstra Jan 1, 2026
7fdd287
NixWasmContext: Remove functionName constructor argument
edolstra Jan 2, 2026
23fb7c4
Cache WASM instances
edolstra Jan 2, 2026
5b31e99
builtins.wasm: Use pre-instantiation to ensure deterministic execution
edolstra Jan 4, 2026
dd8f3b3
Add wasm32-wasip1 system type
edolstra Jan 5, 2026
f30e070
Rename realPathInSandbox() -> realPathInHost()
edolstra Jan 5, 2026
3936d1f
Merge remote-tracking branch 'detsys/main' into wasm
edolstra Jan 6, 2026
da8848e
Don't build the wasmtime executable
edolstra Jan 6, 2026
d977b54
Remove unneeded wasmtime features
edolstra Jan 6, 2026
65f3b44
Merge remote-tracking branch 'detsys/main' into wasm
edolstra Jan 19, 2026
6147736
Add experimental feature `wasm-builtin`
edolstra Jan 19, 2026
8bc414c
Add experimental feature `wasm-derivations`
edolstra Jan 19, 2026
7a0a233
Update wasmtime to 40.0.2, add Nixpkgs acknowledgment
edolstra Jan 19, 2026
26db0d1
builtins.wasm: Add make_app host function for creating lazy function …
edolstra Jan 19, 2026
cd76ab4
builtins.wasm: Force evaluation of the result
edolstra Jan 19, 2026
55653c8
builtins.wasm: Add basic path primitives
edolstra Jan 19, 2026
22551fa
builtins.wasm: Add a read_file host function that supports binary files
edolstra Jan 19, 2026
bff5696
builtins.wasm: Add get_attr host function
edolstra Jan 20, 2026
b878824
WASM -> Wasm
edolstra Jan 20, 2026
e201484
builtins.wasm: Reserve value ID 0
edolstra Jan 20, 2026
4cfd6f2
Fix misleading variable name
edolstra Jan 21, 2026
9e1a9be
builtins.wasm: Replace assertions
edolstra Jan 21, 2026
0ec1c42
builtins.wasm: Check memory export
edolstra Jan 21, 2026
aab9373
builtins.wasm: Catch all exceptions
edolstra Jan 21, 2026
a303760
builtins.wasm: Check return type
edolstra Jan 21, 2026
7761fb0
builtins.wasm: Check file size
edolstra Jan 21, 2026
57ac520
realisePath(): Move into EvalState
edolstra Jan 21, 2026
a4dc41c
Document the Wasm host interface
edolstra Jan 22, 2026
7ab6777
builtins.wasm: Check ValueIds
edolstra Jan 23, 2026
3aa4799
builtins.wasm: Fix endianness issues
edolstra Jan 23, 2026
bc707ee
builtins.wasm: Make thread-safe
edolstra Jan 23, 2026
094b65a
WASI: Enable access to $TMPDIR
edolstra Jan 23, 2026
ea1beab
Revert "builtins.wasm: Fix endianness issues"
edolstra Jan 23, 2026
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
1 change: 1 addition & 0 deletions doc/manual/source/SUMMARY.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
- [Store Path Specification](protocols/store-path.md)
- [Nix Archive (NAR) Format](protocols/nix-archive/index.md)
- [Derivation "ATerm" file format](protocols/derivation-aterm.md)
- [`builtins.wasm` Host Interface](protocols/wasm.md)
- [C API](c-api.md)
- [Glossary](glossary.md)
- [Development](development/index.md)
Expand Down
324 changes: 324 additions & 0 deletions doc/manual/source/protocols/wasm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
# `builtins.wasm` Host Interface

The `builtins.wasm` function allows Nix expressions to call WebAssembly functions. This enables extending Nix with custom functionality written in languages that compile to WebAssembly (such as Rust).

## Overview

WebAssembly modules can interact with Nix values through a host interface that provides functions for creating and inspecting Nix values. The WASM module receives Nix values as opaque `ValueId` handles and uses host functions to work with them.

## Value IDs

Nix values are represented in Wasm code as a `u32` referred to below as a `ValueId`. These are opaque handles that reference values managed by the Nix evaluator. Value ID 0 is reserved to represent a missing attribute lookup result.

## Entry Point

Every Wasm module must export:
- A `memory` object that the host can use to read/write data.
- `nix_wasm_init_v1()`, a function that is called once when the module is instantiated.
- The entry point of the Wasm function, its name corresponding to the second argument to `builtins.wasm`. It takes a single `ValueId` and returns a single `ValueId` (i.e. it has type `fn(arg: u32) -> u32`).

## Host Functions

All host functions are imported from the `env` module provided by `builtins.wasm`.

### Error Handling

#### `panic(ptr: u32, len: u32)`

Aborts execution with an error message.

**Parameters:**
- `ptr` - Pointer to UTF-8 encoded error message in Wasm memory
- `len` - Length of the error message in bytes

#### `warn(ptr: u32, len: u32)`

Emits a warning message.

**Parameters:**
- `ptr` - Pointer to UTF-8 encoded warning message in Wasm memory
- `len` - Length of the warning message in bytes

### Type Inspection

#### `get_type(value: ValueId) -> u32`

Returns the type of a Nix value.

**Parameters:**
- `value` - ID of a Nix value

**Return values:**
- `1` - Integer
- `2` - Float
- `3` - Boolean
- `4` - String
- `5` - Path
- `6` - Null
- `7` - Attribute set
- `8` - List
- `9` - Function

**Note:** Forces evaluation of the value.

### Integer Operations

#### `make_int(n: i64) -> ValueId`

Creates a Nix integer value.

**Parameters:**
- `n` - The integer value

**Returns:** Value ID of the created integer

#### `get_int(value: ValueId) -> i64`

Extracts an integer from a Nix value. Throws an error if the value is not an integer.

**Parameters:**
- `value` - ID of a Nix integer value

**Returns:** The integer value

### Float Operations

#### `make_float(x: f64) -> ValueId`

Creates a Nix float value.

**Parameters:**
- `x` - The float value

**Returns:** Value ID of the created float

#### `get_float(value: ValueId) -> f64`

Extracts a float from a Nix value. Throws an error if the value is not a float.

**Parameters:**
- `value` - ID of a Nix float value

**Returns:** The float value

### Boolean Operations

#### `make_bool(b: i32) -> ValueId`

Creates a Nix Boolean value.

**Parameters:**
- `b` - Boolean value (0 = false, non-zero = true)

**Returns:** Value ID of the created Boolean

#### `get_bool(value: ValueId) -> i32`

Extracts a Boolean from a Nix value. Throws an error if the value is not a Boolean.

**Parameters:**
- `value` - ID of a Nix Boolean value

**Returns:** 0 for false, 1 for true

### Null Operations

#### `make_null() -> ValueId`

Creates a Nix null value.

**Returns:** Value ID of the null value

### String Operations

#### `make_string(ptr: u32, len: u32) -> ValueId`

Creates a Nix string value from Wasm memory.

**Parameters:**
- `ptr` - Pointer to a string in Wasm memory
- `len` - Length of the string in bytes

**Note:** Strings do not require a null terminator.

**Returns:** Value ID of the created string

#### `copy_string(value: ValueId, ptr: u32, max_len: u32) -> u32`

Copies a Nix string value into Wasm memory.

**Parameters:**
- `value` - ID of a string value
- `ptr` - Pointer to buffer in Wasm memory
- `max_len` - Maximum number of bytes to copy

**Returns:** The actual length of the string in bytes

**Note:** If the returned length is greater than `max_len`, no data is copied. Call again with a larger buffer to get the full string.

### Path Operations

#### `make_path(base: ValueId, ptr: u32, len: u32) -> ValueId`

Creates a Nix path value relative to a base path.

**Parameters:**
- `base` - ID of a path value
- `ptr` - Pointer to a string in Wasm memory
- `len` - Length of the path string in bytes

**Returns:** ID of a new path value

**Note:** The path string is interpreted relative to the base path. The resulting path is in the same source tree ("source accessor") as the original path.

#### `copy_path(value: ValueId, ptr: u32, max_len: u32) -> u32`

Copies a Nix path value into Wasm memory as an absolute path string.

**Parameters:**
- `value` - ID of a path value
- `ptr` - Pointer to buffer in Wasm memory
- `max_len` - Maximum number of bytes to copy

**Returns:** The actual length of the path string in bytes

**Note:** If the returned length is greater than `max_len`, no data is copied.

### List Operations

#### `make_list(ptr: u32, len: u32) -> ValueId`

Creates a Nix list from an array of value IDs in Wasm memory.

**Parameters:**
- `ptr` - Pointer to array of `ValueId` (u32) in Wasm memory
- `len` - Number of elements in the array

**Returns:** Value ID of the created list

**Note:** The array must contain `len * 4` bytes (each ValueId is 4 bytes).

#### `copy_list(value: ValueId, ptr: u32, max_len: u32) -> u32`

Copies a Nix list into Wasm memory as an array of value IDs.

**Parameters:**
- `value` - ID of a list value
- `ptr` - Pointer to buffer in Wasm memory
- `max_len` - Maximum number of elements to copy

**Returns:** The actual number of elements in the list

**Note:** If the returned length is greater than `max_len`, no data is copied. Each element is written as a `ValueId` (4 bytes). The buffer must be `max_len * 4` bytes large.

### Attribute Set Operations

#### `make_attrset(ptr: u32, len: u32) -> ValueId`

Creates a Nix attribute set from an array of attributes in Wasm memory.

**Parameters:**
- `ptr` - Pointer to array of attribute structures in Wasm memory
- `len` - Number of attributes

**Returns:** Value ID of the created attribute set

**Attribute structure format:**
```c
struct Attr {
name_ptr: u32, // Pointer to attribute name
name_len: u32, // Length of attribute name in bytes
value_id: u32, // ID of the attribute value
}
```

Each `Attr` element is 12 bytes (3 × 4 bytes).

#### `copy_attrset(value: ValueId, ptr: u32, max_len: u32) -> u32`

Copies a Nix attribute set into Wasm memory as an array of attribute structures.

**Parameters:**
- `value` - ID of a Nix attribute set value
- `ptr` - Pointer to buffer in Wasm memory
- `max_len` - Maximum number of attributes to copy

**Returns:** The actual number of attributes in the set

**Note:** If the returned length is greater than `max_len`, no data is copied.

**Output structure format:**
```c
struct Attr {
value_id: u32, // ID of the attribute value
name_len: u32, // Length of attribute name in bytes
}
```

Each attribute is 8 bytes (2 × 4 bytes). Use `copy_attrname` to retrieve attribute names.

#### `copy_attrname(value: ValueId, attr_idx: u32, ptr: u32, len: u32)`

Copies an attribute name into Wasm memory.

**Parameters:**
- `value` - ID of a Nix attribute set value
- `attr_idx` - Index of the attribute (from `copy_attrset`)
- `ptr` - Pointer to buffer in Wasm memory
- `len` - Length of the buffer (must exactly match the attribute name length)

**Note:** Throws an error if `len` doesn't match the attribute name length or if `attr_idx` is out of bounds.

#### `get_attr(value: ValueId, ptr: u32, len: u32) -> ValueId`

Gets an attribute value from an attribute set by name.

**Parameters:**
- `value` - ID of a Nix attribute set value
- `ptr` - Pointer to the attribute name in Wasm memory
- `len` - Length of the attribute name in bytes

**Returns:** Value ID of the attribute value, or 0 if the attribute doesn't exist

### Function Operations

#### `call_function(fun: ValueId, ptr: u32, len: u32) -> ValueId`

Calls a Nix function with arguments.

**Parameters:**
- `fun` - ID of a Nix function value
- `ptr` - Pointer to array of `ValueId` arguments in Wasm memory
- `len` - Number of arguments

**Returns:** Value ID of the function result

#### `make_app(fun: ValueId, ptr: u32, len: u32) -> ValueId`

Creates a lazy or partially applied function application.

**Parameters:**
- `fun` - ID of a Nix function value
- `ptr` - Pointer to array of `ValueId` arguments in Wasm memory
- `len` - Number of arguments

**Returns:** Value ID of the unevaluated application

### File I/O

#### `read_file(path: ValueId, ptr: u32, len: u32) -> u32`

Reads a file into Wasm memory.

**Parameters:**
- `path` - Value ID of a Nix path value
- `ptr` - Pointer to buffer in Wasm memory
- `len` - Maximum number of bytes to read

**Returns:** The actual file size in bytes

**Note:** Similar to `builtins.readFile`, but can handle files that cannot be represented as Nix strings (in particular, files containing NUL bytes). If the returned size is greater than `len`, no data is copied.

## Example Usage

For Rust bindings to this interface and several examples, see https://github.com/DeterminateSystems/nix-wasm-rust/.
2 changes: 2 additions & 0 deletions packaging/dependencies.nix
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,6 @@ scope: {
buildPhase = lib.replaceStrings [ "--without-python" ] [ "" ] old.buildPhase;
installPhase = lib.replaceStrings [ "--without-python" ] [ "" ] old.installPhase;
});

wasmtime = pkgs.callPackage ./wasmtime.nix { };
}
Loading