Support WASI snapshot0 in the C API.
This commit adds support for snapshot0 in the WASI C API. A name parameter was added to `wasi_instance_new` to accept which WASI module is being instantiated. Additionally, the C# API now supports constructing a WASI instance based on the WASI module name. Fixes #1221.
This commit is contained in:
@@ -52,6 +52,7 @@ WASI_DECLARE_OWN(instance)
|
||||
|
||||
WASI_API_EXTERN own wasi_instance_t* wasi_instance_new(
|
||||
wasm_store_t* store,
|
||||
const char* name,
|
||||
own wasi_config_t* config,
|
||||
own wasm_trap_t** trap
|
||||
);
|
||||
|
||||
@@ -185,7 +185,7 @@ pub unsafe extern "C" fn wasmtime_linker_define_wasi(
|
||||
instance: *const wasi_instance_t,
|
||||
) -> bool {
|
||||
let linker = &mut (*linker).linker;
|
||||
(*instance).wasi.add_to_linker(linker).is_ok()
|
||||
(*instance).add_to_linker(linker).is_ok()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
//! The WASI embedding API definitions for Wasmtime.
|
||||
use crate::{wasm_extern_t, wasm_importtype_t, wasm_store_t, wasm_trap_t, ExternHost, ExternType};
|
||||
use anyhow::Result;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::slice;
|
||||
use wasi_common::{preopen_dir, WasiCtxBuilder};
|
||||
use wasmtime::{HostRef, Trap};
|
||||
use wasmtime_wasi::Wasi;
|
||||
use wasi_common::{
|
||||
old::snapshot_0::WasiCtxBuilder as WasiSnapshot0CtxBuilder, preopen_dir,
|
||||
WasiCtxBuilder as WasiPreview1CtxBuilder,
|
||||
};
|
||||
use wasmtime::{HostRef, Linker, Store, Trap};
|
||||
use wasmtime_wasi::{old::snapshot_0::Wasi as WasiSnapshot0, Wasi as WasiPreview1};
|
||||
|
||||
unsafe fn cstr_to_path<'a>(path: *const c_char) -> Option<&'a Path> {
|
||||
CStr::from_ptr(path).to_str().map(Path::new).ok()
|
||||
@@ -22,18 +26,32 @@ unsafe fn create_file(path: *const c_char) -> Option<File> {
|
||||
File::create(cstr_to_path(path)?).ok()
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct wasi_config_t {
|
||||
builder: WasiCtxBuilder,
|
||||
pub enum WasiModule {
|
||||
Snapshot0(WasiSnapshot0),
|
||||
Preview1(WasiPreview1),
|
||||
}
|
||||
|
||||
impl wasi_config_t {}
|
||||
impl WasiModule {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct wasi_config_t {
|
||||
args: Vec<Vec<u8>>,
|
||||
env: Vec<(Vec<u8>, Vec<u8>)>,
|
||||
stdin: Option<File>,
|
||||
stdout: Option<File>,
|
||||
stderr: Option<File>,
|
||||
preopens: Vec<(File, PathBuf)>,
|
||||
inherit_args: bool,
|
||||
inherit_env: bool,
|
||||
inherit_stdin: bool,
|
||||
inherit_stdout: bool,
|
||||
inherit_stderr: bool,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasi_config_new() -> *mut wasi_config_t {
|
||||
Box::into_raw(Box::new(wasi_config_t {
|
||||
builder: WasiCtxBuilder::new(),
|
||||
}))
|
||||
Box::into_raw(Box::new(wasi_config_t::default()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -47,16 +65,17 @@ pub unsafe extern "C" fn wasi_config_set_argv(
|
||||
argc: c_int,
|
||||
argv: *const *const c_char,
|
||||
) {
|
||||
(*config).builder.args(
|
||||
slice::from_raw_parts(argv, argc as usize)
|
||||
.iter()
|
||||
.map(|a| slice::from_raw_parts(*a as *const u8, CStr::from_ptr(*a).to_bytes().len())),
|
||||
);
|
||||
(*config).args = slice::from_raw_parts(argv, argc as usize)
|
||||
.iter()
|
||||
.map(|p| CStr::from_ptr(*p).to_bytes().to_owned())
|
||||
.collect();
|
||||
(*config).inherit_args = false;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasi_config_inherit_argv(config: *mut wasi_config_t) {
|
||||
(*config).builder.inherit_args();
|
||||
(*config).args.clear();
|
||||
(*config).inherit_args = true;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -69,17 +88,22 @@ pub unsafe extern "C" fn wasi_config_set_env(
|
||||
let names = slice::from_raw_parts(names, envc as usize);
|
||||
let values = slice::from_raw_parts(values, envc as usize);
|
||||
|
||||
(*config).builder.envs(
|
||||
names
|
||||
.iter()
|
||||
.map(|p| CStr::from_ptr(*p).to_bytes())
|
||||
.zip(values.iter().map(|p| CStr::from_ptr(*p).to_bytes())),
|
||||
);
|
||||
(*config).env = names
|
||||
.iter()
|
||||
.map(|p| CStr::from_ptr(*p).to_bytes().to_owned())
|
||||
.zip(
|
||||
values
|
||||
.iter()
|
||||
.map(|p| CStr::from_ptr(*p).to_bytes().to_owned()),
|
||||
)
|
||||
.collect();
|
||||
(*config).inherit_env = false;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasi_config_inherit_env(config: *mut wasi_config_t) {
|
||||
(*config).builder.inherit_env();
|
||||
(*config).env.clear();
|
||||
(*config).inherit_env = true;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -92,14 +116,16 @@ pub unsafe extern "C" fn wasi_config_set_stdin_file(
|
||||
None => return false,
|
||||
};
|
||||
|
||||
(*config).builder.stdin(file);
|
||||
(*config).stdin = Some(file);
|
||||
(*config).inherit_stdin = false;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasi_config_inherit_stdin(config: *mut wasi_config_t) {
|
||||
(*config).builder.inherit_stdin();
|
||||
(*config).stdin = None;
|
||||
(*config).inherit_stdin = true;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -112,14 +138,16 @@ pub unsafe extern "C" fn wasi_config_set_stdout_file(
|
||||
None => return false,
|
||||
};
|
||||
|
||||
(*config).builder.stdout(file);
|
||||
(*config).stdout = Some(file);
|
||||
(*config).inherit_stdout = false;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasi_config_inherit_stdout(config: *mut wasi_config_t) {
|
||||
(*config).builder.inherit_stdout();
|
||||
(*config).stdout = None;
|
||||
(*config).inherit_stdout = true;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -132,14 +160,16 @@ pub unsafe extern "C" fn wasi_config_set_stderr_file(
|
||||
None => return false,
|
||||
};
|
||||
|
||||
(*config).builder.stderr(file);
|
||||
(*config).stderr = Some(file);
|
||||
(*config).inherit_stderr = false;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasi_config_inherit_stderr(config: *mut wasi_config_t) {
|
||||
(*config).builder.inherit_stderr();
|
||||
(*config).stderr = None;
|
||||
(*config).inherit_stderr = true;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -161,29 +191,110 @@ pub unsafe extern "C" fn wasi_config_preopen_dir(
|
||||
None => return false,
|
||||
};
|
||||
|
||||
(*config).builder.preopened_dir(dir, guest_path);
|
||||
(*config).preopens.push((dir, guest_path.to_owned()));
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
enum WasiInstance {
|
||||
Preview1(WasiPreview1),
|
||||
Snapshot0(WasiSnapshot0),
|
||||
}
|
||||
|
||||
macro_rules! config_to_builder {
|
||||
($builder:ident, $config:ident) => {{
|
||||
let mut builder = $builder::new();
|
||||
|
||||
if $config.inherit_args {
|
||||
builder.inherit_args();
|
||||
} else if !$config.args.is_empty() {
|
||||
builder.args($config.args);
|
||||
}
|
||||
|
||||
if $config.inherit_env {
|
||||
builder.inherit_env();
|
||||
} else if !$config.env.is_empty() {
|
||||
builder.envs($config.env);
|
||||
}
|
||||
|
||||
if $config.inherit_stdin {
|
||||
builder.inherit_stdin();
|
||||
} else if let Some(file) = $config.stdin {
|
||||
builder.stdin(file);
|
||||
}
|
||||
|
||||
if $config.inherit_stdout {
|
||||
builder.inherit_stdout();
|
||||
} else if let Some(file) = $config.stdout {
|
||||
builder.stdout(file);
|
||||
}
|
||||
|
||||
if $config.inherit_stderr {
|
||||
builder.inherit_stderr();
|
||||
} else if let Some(file) = $config.stderr {
|
||||
builder.stderr(file);
|
||||
}
|
||||
|
||||
for preopen in $config.preopens {
|
||||
builder.preopened_dir(preopen.0, preopen.1);
|
||||
}
|
||||
|
||||
builder
|
||||
}};
|
||||
}
|
||||
|
||||
fn create_snapshot0_instance(store: &Store, config: wasi_config_t) -> Result<WasiInstance, String> {
|
||||
Ok(WasiInstance::Snapshot0(WasiSnapshot0::new(
|
||||
store,
|
||||
config_to_builder!(WasiSnapshot0CtxBuilder, config)
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?,
|
||||
)))
|
||||
}
|
||||
|
||||
fn create_preview1_instance(store: &Store, config: wasi_config_t) -> Result<WasiInstance, String> {
|
||||
Ok(WasiInstance::Preview1(WasiPreview1::new(
|
||||
store,
|
||||
config_to_builder!(WasiPreview1CtxBuilder, config)
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?,
|
||||
)))
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct wasi_instance_t {
|
||||
pub wasi: Wasi,
|
||||
wasi: WasiInstance,
|
||||
export_cache: HashMap<String, Box<wasm_extern_t>>,
|
||||
}
|
||||
|
||||
impl wasi_instance_t {
|
||||
pub fn add_to_linker(&self, linker: &mut Linker) -> Result<()> {
|
||||
match &self.wasi {
|
||||
WasiInstance::Snapshot0(w) => w.add_to_linker(linker),
|
||||
WasiInstance::Preview1(w) => w.add_to_linker(linker),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasi_instance_new(
|
||||
store: *mut wasm_store_t,
|
||||
name: *const c_char,
|
||||
config: *mut wasi_config_t,
|
||||
trap: *mut *mut wasm_trap_t,
|
||||
) -> *mut wasi_instance_t {
|
||||
let store = &(*store).store.borrow();
|
||||
let mut config = Box::from_raw(config);
|
||||
let config = Box::from_raw(config);
|
||||
|
||||
match config.builder.build() {
|
||||
Ok(ctx) => Box::into_raw(Box::new(wasi_instance_t {
|
||||
wasi: Wasi::new(store, ctx),
|
||||
let result = match CStr::from_ptr(name).to_str().unwrap_or("") {
|
||||
"wasi_snapshot_preview1" => create_preview1_instance(store, *config),
|
||||
"wasi_unstable" => create_snapshot0_instance(store, *config),
|
||||
_ => Err("unsupported WASI version".into()),
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(wasi) => Box::into_raw(Box::new(wasi_instance_t {
|
||||
wasi,
|
||||
export_cache: HashMap::new(),
|
||||
})),
|
||||
Err(e) => {
|
||||
@@ -206,20 +317,32 @@ pub unsafe extern "C" fn wasi_instance_bind_import(
|
||||
instance: *mut wasi_instance_t,
|
||||
import: *const wasm_importtype_t,
|
||||
) -> *const wasm_extern_t {
|
||||
// TODO: support previous versions?
|
||||
if (*import).ty.module() != "wasi_snapshot_preview1" {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
// The import should be a function (WASI only exports functions)
|
||||
let func_type = match (*import).ty.ty() {
|
||||
ExternType::Func(f) => f,
|
||||
_ => return std::ptr::null_mut(),
|
||||
};
|
||||
|
||||
let module = (*import).ty.module();
|
||||
let name = (*import).ty.name();
|
||||
|
||||
match (*instance).wasi.get_export(name) {
|
||||
let import = match &(*instance).wasi {
|
||||
WasiInstance::Preview1(wasi) => {
|
||||
if module != "wasi_snapshot_preview1" {
|
||||
return std::ptr::null();
|
||||
}
|
||||
wasi.get_export(name)
|
||||
}
|
||||
WasiInstance::Snapshot0(wasi) => {
|
||||
if module != "wasi_unstable" {
|
||||
return std::ptr::null();
|
||||
}
|
||||
|
||||
wasi.get_export(name)
|
||||
}
|
||||
};
|
||||
|
||||
match import {
|
||||
Some(export) => {
|
||||
if export.ty() != func_type {
|
||||
return std::ptr::null_mut();
|
||||
|
||||
@@ -936,6 +936,7 @@ namespace Wasmtime
|
||||
[DllImport(LibraryName)]
|
||||
public static extern WasiInstanceHandle wasi_instance_new(
|
||||
StoreHandle store,
|
||||
[MarshalAs(UnmanagedType.LPUTF8Str)] string name,
|
||||
WasiConfigHandle config,
|
||||
out IntPtr trap
|
||||
);
|
||||
|
||||
@@ -9,18 +9,26 @@ namespace Wasmtime
|
||||
/// <summary>
|
||||
/// Creates a default <see cref="Wasi"/> instance.
|
||||
/// </summary>
|
||||
public Wasi(Store store) :
|
||||
/// <param name="store">The store to use for the new WASI instance.</param>
|
||||
/// <param name="name">The name of the WASI module to create.</param>
|
||||
public Wasi(Store store, string name) :
|
||||
this(
|
||||
(store ?? throw new ArgumentNullException(nameof(store))).Handle,
|
||||
Interop.wasi_config_new()
|
||||
Interop.wasi_config_new(),
|
||||
name
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
internal Wasi(Interop.StoreHandle store, Interop.WasiConfigHandle config)
|
||||
internal Wasi(Interop.StoreHandle store, Interop.WasiConfigHandle config, string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new ArgumentException("Name cannot be null or empty.", nameof(name));
|
||||
}
|
||||
|
||||
IntPtr trap;
|
||||
Handle = Interop.wasi_instance_new(store, config, out trap);
|
||||
Handle = Interop.wasi_instance_new(store, name, config, out trap);
|
||||
config.SetHandleAsInvalid();
|
||||
|
||||
if (trap != IntPtr.Zero)
|
||||
|
||||
@@ -12,10 +12,22 @@ namespace Wasmtime
|
||||
/// <summary>
|
||||
/// Constructs a new <see cref="WasiBuilder" />.
|
||||
/// </summary>
|
||||
public WasiBuilder()
|
||||
public WasiBuilder(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new ArgumentException("Name cannot be null or empty.", nameof(name));
|
||||
}
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the WASI module being built.
|
||||
/// </summary>
|
||||
/// <value>The name of the WASI module.</value>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command line argument to the builder.
|
||||
/// </summary>
|
||||
@@ -271,7 +283,7 @@ namespace Wasmtime
|
||||
SetStandardError(config);
|
||||
SetPreopenDirectories(config);
|
||||
|
||||
return new Wasi(store.Handle, config);
|
||||
return new Wasi(store.Handle, config, Name);
|
||||
}
|
||||
|
||||
private unsafe void SetConfigArgs(Interop.WasiConfigHandle config)
|
||||
|
||||
66
crates/misc/dotnet/tests/Modules/WasiSnapshot0.wat
Normal file
66
crates/misc/dotnet/tests/Modules/WasiSnapshot0.wat
Normal file
@@ -0,0 +1,66 @@
|
||||
(module
|
||||
(type $t0 (func (param i32 i32) (result i32)))
|
||||
(type $t1 (func (param i32 i32 i32 i32) (result i32)))
|
||||
(type $t2 (func (param i32) (result i32)))
|
||||
(type $t3 (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
|
||||
(import "wasi_unstable" "environ_sizes_get" (func $wasi_unstable.environ_sizes_get (type $t0)))
|
||||
(import "wasi_unstable" "environ_get" (func $wasi_unstable.environ_get (type $t0)))
|
||||
(import "wasi_unstable" "args_sizes_get" (func $wasi_unstable.args_sizes_get (type $t0)))
|
||||
(import "wasi_unstable" "args_get" (func $wasi_unstable.args_get (type $t0)))
|
||||
(import "wasi_unstable" "fd_write" (func $wasi_unstable.fd_write (type $t1)))
|
||||
(import "wasi_unstable" "fd_read" (func $wasi_unstable.fd_read (type $t1)))
|
||||
(import "wasi_unstable" "fd_close" (func $wasi_unstable.fd_close (type $t2)))
|
||||
(import "wasi_unstable" "path_open" (func $wasi_unstable.path_open (type $t3)))
|
||||
(memory $memory 1)
|
||||
(export "memory" (memory 0))
|
||||
(func $call_environ_sizes_get (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
call $wasi_unstable.environ_sizes_get)
|
||||
(func $call_environ_get (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
call $wasi_unstable.environ_get)
|
||||
(func $call_args_sizes_get (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
call $wasi_unstable.args_sizes_get)
|
||||
(func $call_args_get (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
call $wasi_unstable.args_get)
|
||||
(func $call_fd_write (type $t1) (param $p0 i32) (param $p1 i32) (param $p2 i32) (param $p3 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
local.get $p2
|
||||
local.get $p3
|
||||
call $wasi_unstable.fd_write)
|
||||
(func $call_fd_read (type $t1) (param $p0 i32) (param $p1 i32) (param $p2 i32) (param $p3 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
local.get $p2
|
||||
local.get $p3
|
||||
call $wasi_unstable.fd_read)
|
||||
(func $call_fd_close (type $t2) (param $p0 i32) (result i32)
|
||||
local.get $p0
|
||||
call $wasi_unstable.fd_close)
|
||||
(func $call_path_open (type $t3) (param $p0 i32) (param $p1 i32) (param $p2 i32) (param $p3 i32) (param $p4 i32) (param $p5 i64) (param $p6 i64) (param $p7 i32) (param $p8 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
local.get $p2
|
||||
local.get $p3
|
||||
local.get $p4
|
||||
local.get $p5
|
||||
local.get $p6
|
||||
local.get $p7
|
||||
local.get $p8
|
||||
call $wasi_unstable.path_open)
|
||||
(export "call_environ_sizes_get" (func $call_environ_sizes_get))
|
||||
(export "call_environ_get" (func $call_environ_get))
|
||||
(export "call_args_sizes_get" (func $call_args_sizes_get))
|
||||
(export "call_args_get" (func $call_args_get))
|
||||
(export "call_fd_write" (func $call_fd_write))
|
||||
(export "call_fd_read" (func $call_fd_read))
|
||||
(export "call_fd_close" (func $call_fd_close))
|
||||
(export "call_path_open" (func $call_path_open))
|
||||
)
|
||||
246
crates/misc/dotnet/tests/WasiSnapshot0Tests.cs
Normal file
246
crates/misc/dotnet/tests/WasiSnapshot0Tests.cs
Normal file
@@ -0,0 +1,246 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace Wasmtime.Tests
|
||||
{
|
||||
public class WasiSnapshot0Fixture : ModuleFixture
|
||||
{
|
||||
protected override string ModuleFileName => "WasiSnapshot0.wat";
|
||||
}
|
||||
|
||||
public class WasiSnapshot0Tests : IClassFixture<WasiSnapshot0Fixture>
|
||||
{
|
||||
public WasiSnapshot0Tests(WasiSnapshot0Fixture fixture)
|
||||
{
|
||||
Fixture = fixture;
|
||||
}
|
||||
|
||||
private WasiSnapshot0Fixture Fixture { get; set; }
|
||||
|
||||
[Fact]
|
||||
public void ItHasNoEnvironmentByDefault()
|
||||
{
|
||||
using var instance = Fixture.Module.Instantiate(new Wasi(Fixture.Module.Store, "wasi_unstable"));
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_environ_sizes_get(0, 4));
|
||||
Assert.Equal(0, memory.ReadInt32(0));
|
||||
Assert.Equal(0, memory.ReadInt32(4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItHasSpecifiedEnvironment()
|
||||
{
|
||||
var env = new Dictionary<string, string>() {
|
||||
{"FOO", "BAR"},
|
||||
{"WASM", "IS"},
|
||||
{"VERY", "COOL"},
|
||||
};
|
||||
|
||||
var wasi = new WasiBuilder("wasi_unstable")
|
||||
.WithEnvironmentVariables(env.Select(kvp => (kvp.Key, kvp.Value)))
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_environ_sizes_get(0, 4));
|
||||
Assert.Equal(env.Count, memory.ReadInt32(0));
|
||||
Assert.Equal(env.Sum(kvp => kvp.Key.Length + kvp.Value.Length + 2), memory.ReadInt32(4));
|
||||
Assert.Equal(0, inst.call_environ_get(0, 4 * env.Count));
|
||||
|
||||
for (int i = 0; i < env.Count; ++i)
|
||||
{
|
||||
var kvp = memory.ReadNullTerminatedString(memory.ReadInt32(i * 4)).Split("=");
|
||||
Assert.Equal(env[kvp[0]], kvp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItInheritsEnvironment()
|
||||
{
|
||||
var wasi = new WasiBuilder("wasi_unstable")
|
||||
.WithInheritedEnvironment()
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_environ_sizes_get(0, 4));
|
||||
Assert.Equal(Environment.GetEnvironmentVariables().Keys.Count, memory.ReadInt32(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItHasNoArgumentsByDefault()
|
||||
{
|
||||
using var instance = Fixture.Module.Instantiate(new Wasi(Fixture.Module.Store, "wasi_unstable"));
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_args_sizes_get(0, 4));
|
||||
Assert.Equal(0, memory.ReadInt32(0));
|
||||
Assert.Equal(0, memory.ReadInt32(4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItHasSpecifiedArguments()
|
||||
{
|
||||
var args = new List<string>() {
|
||||
"WASM",
|
||||
"IS",
|
||||
"VERY",
|
||||
"COOL"
|
||||
};
|
||||
|
||||
var wasi = new WasiBuilder("wasi_unstable")
|
||||
.WithArgs(args)
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_args_sizes_get(0, 4));
|
||||
Assert.Equal(args.Count, memory.ReadInt32(0));
|
||||
Assert.Equal(args.Sum(a => a.Length + 1), memory.ReadInt32(4));
|
||||
Assert.Equal(0, inst.call_args_get(0, 4 * args.Count));
|
||||
|
||||
for (int i = 0; i < args.Count; ++i)
|
||||
{
|
||||
var arg = memory.ReadNullTerminatedString(memory.ReadInt32(i * 4));
|
||||
Assert.Equal(args[i], arg);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItInheritsArguments()
|
||||
{
|
||||
var wasi = new WasiBuilder("wasi_unstable")
|
||||
.WithInheritedArgs()
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_args_sizes_get(0, 4));
|
||||
Assert.Equal(Environment.GetCommandLineArgs().Length, memory.ReadInt32(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItSetsStdIn()
|
||||
{
|
||||
const string MESSAGE = "WASM IS VERY COOL";
|
||||
|
||||
using var file = new TempFile();
|
||||
File.WriteAllText(file.Path, MESSAGE);
|
||||
|
||||
var wasi = new WasiBuilder("wasi_unstable")
|
||||
.WithStandardInput(file.Path)
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
memory.WriteInt32(0, 8);
|
||||
memory.WriteInt32(4, MESSAGE.Length);
|
||||
|
||||
Assert.Equal(0, inst.call_fd_read(0, 0, 1, 32));
|
||||
Assert.Equal(MESSAGE.Length, memory.ReadInt32(32));
|
||||
Assert.Equal(MESSAGE, memory.ReadString(8, MESSAGE.Length));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
public void ItSetsStdOutAndStdErr(int fd)
|
||||
{
|
||||
const string MESSAGE = "WASM IS VERY COOL";
|
||||
|
||||
using var file = new TempFile();
|
||||
|
||||
var builder = new WasiBuilder("wasi_unstable");
|
||||
if (fd == 1)
|
||||
{
|
||||
builder.WithStandardOutput(file.Path);
|
||||
}
|
||||
else if (fd == 2)
|
||||
{
|
||||
builder.WithStandardError(file.Path);
|
||||
}
|
||||
|
||||
var wasi = builder.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
memory.WriteInt32(0, 8);
|
||||
memory.WriteInt32(4, MESSAGE.Length);
|
||||
memory.WriteString(8, MESSAGE);
|
||||
|
||||
Assert.Equal(0, inst.call_fd_write(fd, 0, 1, 32));
|
||||
Assert.Equal(MESSAGE.Length, memory.ReadInt32(32));
|
||||
Assert.Equal(0, inst.call_fd_close(fd));
|
||||
Assert.Equal(MESSAGE, File.ReadAllText(file.Path));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItSetsPreopenDirectories()
|
||||
{
|
||||
const string MESSAGE = "WASM IS VERY COOL";
|
||||
|
||||
using var file = new TempFile();
|
||||
|
||||
var wasi = new WasiBuilder("wasi_unstable")
|
||||
.WithPreopenedDirectory(Path.GetDirectoryName(file.Path), "/foo")
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
var fileName = Path.GetFileName(file.Path);
|
||||
memory.WriteString(0, fileName);
|
||||
|
||||
Assert.Equal(0, inst.call_path_open(
|
||||
3,
|
||||
0,
|
||||
0,
|
||||
fileName.Length,
|
||||
0,
|
||||
0x40 /* RIGHTS_FD_WRITE */,
|
||||
0,
|
||||
0,
|
||||
64
|
||||
)
|
||||
);
|
||||
|
||||
var fileFd = (int) memory.ReadInt32(64);
|
||||
Assert.True(fileFd > 3);
|
||||
|
||||
memory.WriteInt32(0, 8);
|
||||
memory.WriteInt32(4, MESSAGE.Length);
|
||||
memory.WriteString(8, MESSAGE);
|
||||
|
||||
Assert.Equal(0, inst.call_fd_write(fileFd, 0, 1, 64));
|
||||
Assert.Equal(MESSAGE.Length, memory.ReadInt32(64));
|
||||
Assert.Equal(0, inst.call_fd_close(fileFd));
|
||||
Assert.Equal(MESSAGE, File.ReadAllText(file.Path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace Wasmtime.Tests
|
||||
[Fact]
|
||||
public void ItHasNoEnvironmentByDefault()
|
||||
{
|
||||
using var instance = Fixture.Module.Instantiate(new Wasi(Fixture.Module.Store));
|
||||
using var instance = Fixture.Module.Instantiate(new Wasi(Fixture.Module.Store, "wasi_snapshot_preview1"));
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
@@ -43,7 +43,7 @@ namespace Wasmtime.Tests
|
||||
{"VERY", "COOL"},
|
||||
};
|
||||
|
||||
var wasi = new WasiBuilder()
|
||||
var wasi = new WasiBuilder("wasi_snapshot_preview1")
|
||||
.WithEnvironmentVariables(env.Select(kvp => (kvp.Key, kvp.Value)))
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Wasmtime.Tests
|
||||
[Fact]
|
||||
public void ItInheritsEnvironment()
|
||||
{
|
||||
var wasi = new WasiBuilder()
|
||||
var wasi = new WasiBuilder("wasi_snapshot_preview1")
|
||||
.WithInheritedEnvironment()
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Wasmtime.Tests
|
||||
[Fact]
|
||||
public void ItHasNoArgumentsByDefault()
|
||||
{
|
||||
using var instance = Fixture.Module.Instantiate(new Wasi(Fixture.Module.Store));
|
||||
using var instance = Fixture.Module.Instantiate(new Wasi(Fixture.Module.Store, "wasi_snapshot_preview1"));
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
@@ -103,7 +103,7 @@ namespace Wasmtime.Tests
|
||||
"COOL"
|
||||
};
|
||||
|
||||
var wasi = new WasiBuilder()
|
||||
var wasi = new WasiBuilder("wasi_snapshot_preview1")
|
||||
.WithArgs(args)
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace Wasmtime.Tests
|
||||
[Fact]
|
||||
public void ItInheritsArguments()
|
||||
{
|
||||
var wasi = new WasiBuilder()
|
||||
var wasi = new WasiBuilder("wasi_snapshot_preview1")
|
||||
.WithInheritedArgs()
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Wasmtime.Tests
|
||||
using var file = new TempFile();
|
||||
File.WriteAllText(file.Path, MESSAGE);
|
||||
|
||||
var wasi = new WasiBuilder()
|
||||
var wasi = new WasiBuilder("wasi_snapshot_preview1")
|
||||
.WithStandardInput(file.Path)
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace Wasmtime.Tests
|
||||
|
||||
using var file = new TempFile();
|
||||
|
||||
var builder = new WasiBuilder();
|
||||
var builder = new WasiBuilder("wasi_snapshot_preview1");
|
||||
if (fd == 1)
|
||||
{
|
||||
builder.WithStandardOutput(file.Path);
|
||||
@@ -206,7 +206,7 @@ namespace Wasmtime.Tests
|
||||
|
||||
using var file = new TempFile();
|
||||
|
||||
var wasi = new WasiBuilder()
|
||||
var wasi = new WasiBuilder("wasi_snapshot_preview1")
|
||||
.WithPreopenedDirectory(Path.GetDirectoryName(file.Path), "/foo")
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
|
||||
@@ -101,46 +101,46 @@ impl PendingCString {
|
||||
|
||||
/// A builder allowing customizable construction of `WasiCtx` instances.
|
||||
pub struct WasiCtxBuilder {
|
||||
stdin: PendingEntry,
|
||||
stdout: PendingEntry,
|
||||
stderr: PendingEntry,
|
||||
preopens: Vec<(PathBuf, File)>,
|
||||
args: Vec<PendingCString>,
|
||||
env: HashMap<PendingCString, PendingCString>,
|
||||
stdin: Option<PendingEntry>,
|
||||
stdout: Option<PendingEntry>,
|
||||
stderr: Option<PendingEntry>,
|
||||
preopens: Option<Vec<(PathBuf, File)>>,
|
||||
args: Option<Vec<PendingCString>>,
|
||||
env: Option<HashMap<PendingCString, PendingCString>>,
|
||||
}
|
||||
|
||||
impl WasiCtxBuilder {
|
||||
/// Builder for a new `WasiCtx`.
|
||||
pub fn new() -> Self {
|
||||
let stdin = PendingEntry::Thunk(Entry::null);
|
||||
let stdout = PendingEntry::Thunk(Entry::null);
|
||||
let stderr = PendingEntry::Thunk(Entry::null);
|
||||
Self {
|
||||
stdin,
|
||||
stdout,
|
||||
stderr,
|
||||
preopens: Vec::new(),
|
||||
args: vec![],
|
||||
env: HashMap::new(),
|
||||
stdin: Some(PendingEntry::Thunk(Entry::null)),
|
||||
stdout: Some(PendingEntry::Thunk(Entry::null)),
|
||||
stderr: Some(PendingEntry::Thunk(Entry::null)),
|
||||
preopens: Some(Vec::new()),
|
||||
args: Some(Vec::new()),
|
||||
env: Some(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add arguments to the command-line arguments list.
|
||||
///
|
||||
/// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail.
|
||||
pub fn args<S: AsRef<[u8]>>(mut self, args: impl IntoIterator<Item = S>) -> Self {
|
||||
self.args = args
|
||||
.into_iter()
|
||||
.map(|arg| arg.as_ref().to_vec().into())
|
||||
.collect();
|
||||
pub fn args<S: AsRef<[u8]>>(&mut self, args: impl IntoIterator<Item = S>) -> &mut Self {
|
||||
self.args
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.extend(args.into_iter().map(|a| a.as_ref().to_vec().into()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an argument to the command-line arguments list.
|
||||
///
|
||||
/// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail.
|
||||
pub fn arg<S: AsRef<[u8]>>(mut self, arg: S) -> Self {
|
||||
self.args.push(arg.as_ref().to_vec().into());
|
||||
pub fn arg<S: AsRef<[u8]>>(&mut self, arg: S) -> &mut Self {
|
||||
self.args
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.push(arg.as_ref().to_vec().into());
|
||||
self
|
||||
}
|
||||
|
||||
@@ -148,16 +148,36 @@ impl WasiCtxBuilder {
|
||||
///
|
||||
/// If any arguments from the host process contain invalid UTF-8, `WasiCtxBuilder::build()` will
|
||||
/// fail.
|
||||
pub fn inherit_args(mut self) -> Self {
|
||||
self.args = env::args_os().map(PendingCString::OsString).collect();
|
||||
pub fn inherit_args(&mut self) -> &mut Self {
|
||||
let args = self.args.as_mut().unwrap();
|
||||
args.clear();
|
||||
args.extend(env::args_os().map(PendingCString::OsString));
|
||||
self
|
||||
}
|
||||
|
||||
/// Inherit stdin from the host process.
|
||||
pub fn inherit_stdin(&mut self) -> &mut Self {
|
||||
self.stdin = Some(PendingEntry::Thunk(Entry::duplicate_stdin));
|
||||
self
|
||||
}
|
||||
|
||||
/// Inherit stdout from the host process.
|
||||
pub fn inherit_stdout(&mut self) -> &mut Self {
|
||||
self.stdout = Some(PendingEntry::Thunk(Entry::duplicate_stdout));
|
||||
self
|
||||
}
|
||||
|
||||
/// Inherit stdout from the host process.
|
||||
pub fn inherit_stderr(&mut self) -> &mut Self {
|
||||
self.stderr = Some(PendingEntry::Thunk(Entry::duplicate_stderr));
|
||||
self
|
||||
}
|
||||
|
||||
/// Inherit the stdin, stdout, and stderr streams from the host process.
|
||||
pub fn inherit_stdio(mut self) -> Self {
|
||||
self.stdin = PendingEntry::Thunk(Entry::duplicate_stdin);
|
||||
self.stdout = PendingEntry::Thunk(Entry::duplicate_stdout);
|
||||
self.stderr = PendingEntry::Thunk(Entry::duplicate_stderr);
|
||||
pub fn inherit_stdio(&mut self) -> &mut Self {
|
||||
self.stdin = Some(PendingEntry::Thunk(Entry::duplicate_stdin));
|
||||
self.stdout = Some(PendingEntry::Thunk(Entry::duplicate_stdout));
|
||||
self.stderr = Some(PendingEntry::Thunk(Entry::duplicate_stderr));
|
||||
self
|
||||
}
|
||||
|
||||
@@ -165,10 +185,10 @@ impl WasiCtxBuilder {
|
||||
///
|
||||
/// If any environment variables from the host process contain invalid Unicode (UTF-16 for
|
||||
/// Windows, UTF-8 for other platforms), `WasiCtxBuilder::build()` will fail.
|
||||
pub fn inherit_env(mut self) -> Self {
|
||||
self.env = std::env::vars_os()
|
||||
.map(|(k, v)| (k.into(), v.into()))
|
||||
.collect();
|
||||
pub fn inherit_env(&mut self) -> &mut Self {
|
||||
let env = self.env.as_mut().unwrap();
|
||||
env.clear();
|
||||
env.extend(std::env::vars_os().map(|(k, v)| (k.into(), v.into())));
|
||||
self
|
||||
}
|
||||
|
||||
@@ -176,8 +196,10 @@ impl WasiCtxBuilder {
|
||||
///
|
||||
/// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else
|
||||
/// `WasiCtxBuilder::build()` will fail.
|
||||
pub fn env<S: AsRef<[u8]>>(mut self, k: S, v: S) -> Self {
|
||||
pub fn env<S: AsRef<[u8]>>(&mut self, k: S, v: S) -> &mut Self {
|
||||
self.env
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.insert(k.as_ref().to_vec().into(), v.as_ref().to_vec().into());
|
||||
self
|
||||
}
|
||||
@@ -187,40 +209,40 @@ impl WasiCtxBuilder {
|
||||
/// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else
|
||||
/// `WasiCtxBuilder::build()` will fail.
|
||||
pub fn envs<S: AsRef<[u8]>, T: Borrow<(S, S)>>(
|
||||
mut self,
|
||||
&mut self,
|
||||
envs: impl IntoIterator<Item = T>,
|
||||
) -> Self {
|
||||
self.env = envs
|
||||
.into_iter()
|
||||
.map(|t| {
|
||||
let (k, v) = t.borrow();
|
||||
(k.as_ref().to_vec().into(), v.as_ref().to_vec().into())
|
||||
})
|
||||
.collect();
|
||||
) -> &mut Self {
|
||||
self.env.as_mut().unwrap().extend(envs.into_iter().map(|t| {
|
||||
let (k, v) = t.borrow();
|
||||
(k.as_ref().to_vec().into(), v.as_ref().to_vec().into())
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
/// Provide a File to use as stdin
|
||||
pub fn stdin(mut self, file: File) -> Self {
|
||||
self.stdin = PendingEntry::File(file);
|
||||
pub fn stdin(&mut self, file: File) -> &mut Self {
|
||||
self.stdin = Some(PendingEntry::File(file));
|
||||
self
|
||||
}
|
||||
|
||||
/// Provide a File to use as stdout
|
||||
pub fn stdout(mut self, file: File) -> Self {
|
||||
self.stdout = PendingEntry::File(file);
|
||||
pub fn stdout(&mut self, file: File) -> &mut Self {
|
||||
self.stdout = Some(PendingEntry::File(file));
|
||||
self
|
||||
}
|
||||
|
||||
/// Provide a File to use as stderr
|
||||
pub fn stderr(mut self, file: File) -> Self {
|
||||
self.stderr = PendingEntry::File(file);
|
||||
pub fn stderr(&mut self, file: File) -> &mut Self {
|
||||
self.stderr = Some(PendingEntry::File(file));
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a preopened directory.
|
||||
pub fn preopened_dir<P: AsRef<Path>>(mut self, dir: File, guest_path: P) -> Self {
|
||||
self.preopens.push((guest_path.as_ref().to_owned(), dir));
|
||||
pub fn preopened_dir<P: AsRef<Path>>(&mut self, dir: File, guest_path: P) -> &mut Self {
|
||||
self.preopens
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.push((guest_path.as_ref().to_owned(), dir));
|
||||
self
|
||||
}
|
||||
|
||||
@@ -228,17 +250,21 @@ impl WasiCtxBuilder {
|
||||
///
|
||||
/// If any of the arguments or environment variables in this builder cannot be converted into
|
||||
/// `CString`s, either due to NUL bytes or Unicode conversions, this returns an error.
|
||||
pub fn build(self) -> WasiCtxBuilderResult<WasiCtx> {
|
||||
pub fn build(&mut self) -> WasiCtxBuilderResult<WasiCtx> {
|
||||
// Process arguments and environment variables into `CString`s, failing quickly if they
|
||||
// contain any NUL bytes, or if conversion from `OsString` fails.
|
||||
let args = self
|
||||
.args
|
||||
.take()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|arg| arg.into_utf8_cstring())
|
||||
.collect::<WasiCtxBuilderResult<Vec<CString>>>()?;
|
||||
|
||||
let env = self
|
||||
.env
|
||||
.take()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
k.into_string().and_then(|mut pair| {
|
||||
@@ -257,12 +283,12 @@ impl WasiCtxBuilder {
|
||||
let mut fd_pool = FdPool::new();
|
||||
let mut entries: HashMap<wasi::__wasi_fd_t, Entry> = HashMap::new();
|
||||
// Populate the non-preopen fds.
|
||||
for pending in vec![self.stdin, self.stdout, self.stderr] {
|
||||
for pending in &mut [&mut self.stdin, &mut self.stdout, &mut self.stderr] {
|
||||
let fd = fd_pool
|
||||
.allocate()
|
||||
.ok_or(WasiCtxBuilderError::TooManyFilesOpen)?;
|
||||
log::debug!("WasiCtx inserting ({:?}, {:?})", fd, pending);
|
||||
match pending {
|
||||
match pending.take().unwrap() {
|
||||
PendingEntry::Thunk(f) => {
|
||||
entries.insert(fd, f()?);
|
||||
}
|
||||
@@ -272,7 +298,7 @@ impl WasiCtxBuilder {
|
||||
}
|
||||
}
|
||||
// Then add the preopen fds.
|
||||
for (guest_path, dir) in self.preopens {
|
||||
for (guest_path, dir) in self.preopens.take().unwrap() {
|
||||
// We do the increment at the beginning of the loop body, so that we don't overflow
|
||||
// unnecessarily if we have exactly the maximum number of file descriptors.
|
||||
let preopen_fd = fd_pool
|
||||
|
||||
@@ -33,14 +33,19 @@ pub fn define_struct(args: TokenStream) -> TokenStream {
|
||||
let mut get_exports = Vec::new();
|
||||
let mut ctor_externs = Vec::new();
|
||||
let mut ctor_fields = Vec::new();
|
||||
let mut linker_add = Vec::new();
|
||||
|
||||
for module in doc.modules() {
|
||||
let module_name = module.name.as_str();
|
||||
for func in module.funcs() {
|
||||
let name = func.name.as_str();
|
||||
let name_ident = Ident::new(func.name.as_str(), Span::call_site());
|
||||
let name_ident = Ident::new(name, Span::call_site());
|
||||
fields.push(quote! { pub #name_ident: wasmtime::Func });
|
||||
get_exports.push(quote! { #name => Some(&self.#name_ident) });
|
||||
ctor_fields.push(name_ident.clone());
|
||||
linker_add.push(quote! {
|
||||
linker.define(#module_name, #name, self.#name_ident.clone())?;
|
||||
});
|
||||
|
||||
let mut shim_arg_decls = Vec::new();
|
||||
let mut params = Vec::new();
|
||||
@@ -249,6 +254,12 @@ pub fn define_struct(args: TokenStream) -> TokenStream {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds all wasi items to the specified `Linker`.
|
||||
pub fn add_to_linker(&self, linker: &mut wasmtime::Linker) -> anyhow::Result<()> {
|
||||
#(#linker_add)*
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,10 +281,10 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream {
|
||||
|
||||
for module in doc.modules() {
|
||||
let module_name = module.name.as_str();
|
||||
let module_id = Ident::new(module.name.as_str(), Span::call_site());
|
||||
let module_id = Ident::new(module_name, Span::call_site());
|
||||
for func in module.funcs() {
|
||||
let name = func.name.as_str();
|
||||
let name_ident = Ident::new(func.name.as_str(), Span::call_site());
|
||||
let name_ident = Ident::new(name, Span::call_site());
|
||||
fields.push(quote! { pub #name_ident: wasmtime::Func });
|
||||
get_exports.push(quote! { #name => Some(&self.#name_ident) });
|
||||
ctor_fields.push(name_ident.clone());
|
||||
|
||||
@@ -336,13 +336,12 @@ impl ModuleRegistry {
|
||||
|
||||
let cx1 = cx1.build()?;
|
||||
|
||||
let mut cx2 = wasi_common::old::snapshot_0::WasiCtxBuilder::new()
|
||||
.inherit_stdio()
|
||||
.args(argv)
|
||||
.envs(vars);
|
||||
let mut cx2 = wasi_common::old::snapshot_0::WasiCtxBuilder::new();
|
||||
|
||||
cx2.inherit_stdio().args(argv).envs(vars);
|
||||
|
||||
for (name, file) in preopen_dirs {
|
||||
cx2 = cx2.preopened_dir(file.try_clone()?, name);
|
||||
cx2.preopened_dir(file.try_clone()?, name);
|
||||
}
|
||||
|
||||
let cx2 = cx2.build()?;
|
||||
|
||||
Reference in New Issue
Block a user