Skip to content
Merged
Show file tree
Hide file tree
Changes from 38 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
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 { };
}
74 changes: 74 additions & 0 deletions packaging/wasmtime.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Stripped-down version of https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/wa/wasmtime/package.nix,
# license: https://github.com/NixOS/nixpkgs/blob/master/COPYING
{
lib,
stdenv,
rust_1_89,
fetchFromGitHub,
cmake,
enableShared ? !stdenv.hostPlatform.isStatic,
enableStatic ? stdenv.hostPlatform.isStatic,
}:
rust_1_89.packages.stable.rustPlatform.buildRustPackage (finalAttrs: {
pname = "wasmtime";
version = "40.0.2";

src = fetchFromGitHub {
owner = "bytecodealliance";
repo = "wasmtime";
tag = "v${finalAttrs.version}";
hash = "sha256-4y9WpCdyuF/Tp2k/1d5rZxwYunWNdeibEsFgHcBC52Q=";
fetchSubmodules = true;
};

# Disable cargo-auditable until https://github.com/rust-secure-code/cargo-auditable/issues/124 is solved.
auditable = false;

cargoHash = "sha256-aTPgnuBvOIqg1+Sa2ZLdMTLujm8dKGK5xpZ3qHpr3f8=";
cargoBuildFlags = [
"--package"
"wasmtime-c-api"
"--no-default-features"
"--features cranelift,wasi,pooling-allocator,wat,demangle,gc-null"
];

outputs = [
"out"
"lib"
];

nativeBuildInputs = [
cmake
];

doCheck =
with stdenv.buildPlatform;
# SIMD tests are only executed on platforms that support all
# required processor features (e.g. SSE3, SSSE3 and SSE4.1 on x86_64):
# https://github.com/bytecodealliance/wasmtime/blob/v9.0.0/cranelift/codegen/src/isa/x64/mod.rs#L220
(isx86_64 -> sse3Support && ssse3Support && sse4_1Support)
&&
# The dependency `wasi-preview1-component-adapter` fails to build because of:
# error: linker `rust-lld` not found
!isAarch64;

postInstall =
let
inherit (stdenv.hostPlatform.rust) cargoShortTarget;
in
''
moveToOutput lib $lib
${lib.optionalString (!enableShared) "rm -f $lib/lib/*.so{,.*}"}
${lib.optionalString (!enableStatic) "rm -f $lib/lib/*.a"}

# copy the build.rs generated c-api headers
# https://github.com/rust-lang/cargo/issues/9661
mkdir -p $out
cp -r target/${cargoShortTarget}/release/build/wasmtime-c-api-impl-*/out/include $out/include
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
install_name_tool -id \
$lib/lib/libwasmtime.dylib \
$lib/lib/libwasmtime.dylib
'';
})
6 changes: 6 additions & 0 deletions src/libexpr/include/nix/expr/eval.hh
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,12 @@ public:
[[nodiscard]] StringMap
realiseContext(const NixStringContext & context, StorePathSet * maybePaths = nullptr, bool isIFD = true);

/**
* Coerce `v` to a path and realise it, i.e. build anything in the value's string context using `realiseContext()`.
*/
SourcePath realisePath(
const PosIdx pos, Value & v, std::optional<SymlinkResolution> resolveSymlinks = SymlinkResolution::Full);

/**
* Realise the given string with context, and return the string with outputs instead of downstream output
* placeholders.
Expand Down
2 changes: 1 addition & 1 deletion src/libexpr/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ this_library = library(
soversion : nix_soversion,
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
link_args : linker_export_flags,
link_args : linker_export_flags + [ '-lwasmtime' ],
link_whole : [ parser_library ],
prelink : true, # For C++ static initializers
install : true,
Expand Down
2 changes: 2 additions & 0 deletions src/libexpr/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
boehmgc,
nlohmann_json,
toml11,
wasmtime,

# Configuration Options

Expand Down Expand Up @@ -64,6 +65,7 @@ mkMesonLibrary (finalAttrs: {

buildInputs = [
toml11
wasmtime
];

propagatedBuildInputs = [
Expand Down
28 changes: 12 additions & 16 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -165,24 +165,20 @@ StringMap EvalState::realiseContext(const NixStringContext & context, StorePathS
return res;
}

static SourcePath realisePath(
EvalState & state,
const PosIdx pos,
Value & v,
std::optional<SymlinkResolution> resolveSymlinks = SymlinkResolution::Full)
SourcePath EvalState::realisePath(const PosIdx pos, Value & v, std::optional<SymlinkResolution> resolveSymlinks)
{
NixStringContext context;

auto path = state.coerceToPath(noPos, v, context, "while realising the context of a path");
auto path = coerceToPath(noPos, v, context, "while realising the context of a path");

try {
if (!context.empty() && path.accessor == state.rootFS) {
auto rewrites = state.realiseContext(context);
if (!context.empty() && path.accessor == rootFS) {
auto rewrites = realiseContext(context);
path = {path.accessor, CanonPath(rewriteStrings(path.path.abs(), rewrites))};
}
return resolveSymlinks ? path.resolveSymlinks(*resolveSymlinks) : path;
} catch (Error & e) {
e.addTrace(state.positions[pos], "while realising the context of path '%s'", path);
e.addTrace(positions[pos], "while realising the context of path '%s'", path);
throw;
}
}
Expand Down Expand Up @@ -302,7 +298,7 @@ static void scopedImport(EvalState & state, const PosIdx pos, SourcePath & path,
argument. */
static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * vScope, Value & v)
{
auto path = realisePath(state, pos, vPath, std::nullopt);
auto path = state.realisePath(pos, vPath, std::nullopt);
auto path2 = path.path.abs();

// FIXME
Expand Down Expand Up @@ -456,7 +452,7 @@ extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v);
/* Load a ValueInitializer from a DSO and return whatever it initializes */
void prim_importNative(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
auto path = state.realisePath(pos, *args[0]);

std::string sym(
state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.importNative"));
Expand Down Expand Up @@ -2003,7 +1999,7 @@ static void prim_pathExists(EvalState & state, const PosIdx pos, Value ** args,
arg.type() == nString && (arg.string_view().ends_with("/") || arg.string_view().ends_with("/."));

auto symlinkResolution = mustBeDir ? SymlinkResolution::Full : SymlinkResolution::Ancestors;
auto path = realisePath(state, pos, arg, symlinkResolution);
auto path = state.realisePath(pos, arg, symlinkResolution);

auto st = path.maybeLstat();
auto exists = st && (!mustBeDir || st->type == SourceAccessor::tDirectory);
Expand Down Expand Up @@ -2110,7 +2106,7 @@ static RegisterPrimOp primop_dirOf({
/* Return the contents of a file as a string. */
static void prim_readFile(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
auto path = state.realisePath(pos, *args[0]);
auto s = path.readFile();
if (s.find((char) 0) != std::string::npos)
state.error<EvalError>("the contents of the file '%1%' cannot be represented as a Nix string", path)
Expand Down Expand Up @@ -2348,7 +2344,7 @@ static void prim_hashFile(EvalState & state, const PosIdx pos, Value ** args, Va
if (!ha)
state.error<EvalError>("unknown hash algorithm '%1%'", algo).atPos(pos).debugThrow();

auto path = realisePath(state, pos, *args[1]);
auto path = state.realisePath(pos, *args[1]);

v.mkString(hashString(*ha, path.readFile()).to_string(HashFormat::Base16, false), state.mem);
}
Expand Down Expand Up @@ -2400,7 +2396,7 @@ static const Value & fileTypeToString(EvalState & state, SourceAccessor::Type ty

static void prim_readFileType(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
auto path = realisePath(state, pos, *args[0], std::nullopt);
auto path = state.realisePath(pos, *args[0], std::nullopt);
/* Retrieve the directory entry type and stringize it. */
v = fileTypeToString(state, path.lstat().type);
}
Expand All @@ -2418,7 +2414,7 @@ static RegisterPrimOp primop_readFileType({
/* Read a directory (without . or ..) */
static void prim_readDir(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
auto path = state.realisePath(pos, *args[0]);

// Retrieve directory entries for all nodes in a directory.
// This is similar to `getFileType` but is optimized to reduce system calls
Expand Down
1 change: 1 addition & 0 deletions src/libexpr/primops/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ sources += files(
'fetchMercurial.cc',
'fetchTree.cc',
'fromTOML.cc',
'wasm.cc',
)
Loading