Skip to content

Commit 1db4d5f

Browse files
bors[bot]Hywan
andauthored
Merge #2053
2053: feat(c-api) Implement `wasi_get_unordered_imports` r=Hywan a=Hywan Depend on #2083. # Description The problem I've with the C API for WASI is the following: ```c // At some point, we write this: bool success = wasi_get_imports(store, module, wasi_env, &imports_to_collect); ``` This function iterates over the module imports, and for each entry, it looks inside the (inner generated) WASI import object if a matching entry exists. If it doesn't, it fails. See: https://github.com/wasmerio/wasmer/blob/6b028410c23da088d62a6b6919e2c086931ad101/lib/c-api/src/wasm_c_api/wasi/mod.rs#L333-L356 So… if a module requires WASI and WASI only, it works like a charm of course. But, if a module requires WASI + other imports, it will fail. And I think it's a common pattern to use WASI + some other imports (like `math.random` or anything related to I/O etc etc.). What we need is an API to collect all the WASI imports, in no particular order, by module/namespace and name, so that we can implement an API like `ImportObject` to re-order the imports when needed (i.e. when passing a vec of externs to `wasm_instance_new` for example). # Review - [x] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Ivan Enderlin <ivan@mnt.io>
2 parents 1cea9cb + 98bff43 commit 1db4d5f

File tree

10 files changed

+428
-660
lines changed

10 files changed

+428
-660
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
## **[Unreleased]**
99

1010
### Added
11+
- [#2053](https://github.com/wasmerio/wasmer/pull/2053) Implement the non-standard `wasi_get_unordered_imports` function in the C API.
1112
- [#2059](https://github.com/wasmerio/wasmer/pull/2059) Ability to capture `stdout` and `stderr` with WASI in the C API.
1213
- [#2040](https://github.com/wasmerio/wasmer/pull/2040) Add `InstanceHandle::vmoffsets` to expose the offsets of the `vmctx` region.
1314
- [#2026](https://github.com/wasmerio/wasmer/pull/2010) Expose trap code of a `RuntimeError`, if it's a `Trap`.
1415
- [#2054](https://github.com/wasmerio/wasmer/pull/2054) Add `wasm_config_delete` to the Wasm C API.
1516

1617
### Changed
18+
- [#2083](https://github.com/wasmerio/wasmer/pull/2083) Mark `wasi_env_set_(instance|memory)` as deprecated. You may simply remove them with no side-effect.
1719
- [#2056](https://github.com/wasmerio/wasmer/pull/2056) Change back to depend on the `enumset` crate instead of `wasmer_enumset`
1820

1921
### Fixed

lib/c-api/build.rs

+75-25
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,21 @@ macro_rules! map_feature_as_c_define {
6161
}
6262

6363
fn main() {
64+
if !running_self() {
65+
return;
66+
}
67+
6468
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
6569
let out_dir = env::var("OUT_DIR").unwrap();
6670

67-
if building_c_api_headers() {
68-
build_wasm_c_api_headers(&crate_dir, &out_dir);
69-
build_wasmer_c_api_headers(&crate_dir, &out_dir);
70-
}
71-
71+
build_wasm_c_api_headers(&crate_dir, &out_dir);
72+
build_wasmer_c_api_headers(&crate_dir, &out_dir);
7273
build_inline_c_env_vars();
7374
}
7475

75-
/// Check whether we should build the C API headers.
76-
///
77-
/// For the moment, it's always enabled, unless if the `DOCS_RS`
78-
/// environment variable is present.
79-
fn building_c_api_headers() -> bool {
80-
env::var("DOCS_RS").is_err()
76+
/// Check whether we should build the C API headers or set `inline-c` up.
77+
fn running_self() -> bool {
78+
env::var("DOCS_RS").is_err() && env::var("_CBINDGEN_IS_RUNNING").is_err()
8179
}
8280

8381
/// Build the header files for the `wasm_c_api` API.
@@ -89,8 +87,41 @@ fn build_wasm_c_api_headers(crate_dir: &str, out_dir: &str) {
8987
out_header_file.push("wasmer_wasm");
9088

9189
let mut pre_header = format!(
92-
r#"// The Wasmer C/C++ header file compatible with the `wasm-c-api` standard API.
93-
// This file is generated by lib/c-api/build.rs.
90+
r#"// The Wasmer C/C++ header file compatible with the [`wasm-c-api`]
91+
// standard API, as `wasm.h` (included here).
92+
//
93+
// This file is automatically generated by `lib/c-api/build.rs` of the
94+
// [`wasmer-c-api`] Rust crate.
95+
//
96+
// # Stability
97+
//
98+
// The [`wasm-c-api`] standard API is a _living_ standard. There is no
99+
// commitment for stability yet. We (Wasmer) will try our best to keep
100+
// backward compatibility as much as possible. Nonetheless, some
101+
// necessary API aren't yet standardized, and as such, we provide a
102+
// custom API, e.g. `wasi_*` types and functions.
103+
//
104+
// The documentation makes it clear whether a function is unstable.
105+
//
106+
// When a type or a function will be deprecated, it will be marked as
107+
// such with the appropriated compiler warning, and will be removed at
108+
// the next release round.
109+
//
110+
// # Documentation
111+
//
112+
// At the time of writing, the [`wasm-c-api`] standard has no
113+
// documentation. This file also does not include inline
114+
// documentation. However, we have made (and we continue to make) an
115+
// important effort to document everything. [See the documentation
116+
// online][documentation]. Please refer to this page for the real
117+
// canonical documentation. It also contains numerous examples.
118+
//
119+
// To generate the documentation locally, run `cargo doc --open` from
120+
// within the [`wasmer-c-api`] Rust crate.
121+
//
122+
// [`wasm-c-api`]: https://github.com/WebAssembly/wasm-c-api
123+
// [`wasmer-c-api`]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api
124+
// [documentation]: https://wasmerio.github.io/wasmer/crates/wasmer_c_api/
94125
95126
#if !defined(WASMER_WASM_H_PRELUDE)
96127
@@ -184,10 +215,12 @@ fn build_wasmer_c_api_headers(crate_dir: &str, out_dir: &str) {
184215
out_header_file.set_extension("h");
185216

186217
// Build and generate the header file.
187-
exclude_items_from_wasm_c_api(new_builder(Language::C, crate_dir, guard, &pre_header))
188-
.generate()
189-
.expect("Unable to generate C bindings")
190-
.write_to_file(out_header_file.as_path());
218+
exclude_items_from_wasm_c_api(
219+
new_builder(Language::C, crate_dir, guard, &pre_header).with_documentation(true),
220+
)
221+
.generate()
222+
.expect("Unable to generate C bindings")
223+
.write_to_file(out_header_file.as_path());
191224

192225
// Copy the generated bindings from `OUT_DIR` to
193226
// `CARGO_MANIFEST_DIR`.
@@ -203,10 +236,12 @@ fn build_wasmer_c_api_headers(crate_dir: &str, out_dir: &str) {
203236
out_header_file.set_extension("hh");
204237

205238
// Build and generate the header file.
206-
exclude_items_from_wasm_c_api(new_builder(Language::Cxx, crate_dir, guard, &pre_header))
207-
.generate()
208-
.expect("Unable to generate C++ bindings")
209-
.write_to_file(out_header_file.as_path());
239+
exclude_items_from_wasm_c_api(
240+
new_builder(Language::Cxx, crate_dir, guard, &pre_header).with_documentation(true),
241+
)
242+
.generate()
243+
.expect("Unable to generate C++ bindings")
244+
.write_to_file(out_header_file.as_path());
210245

211246
// Copy the generated bindings from `OUT_DIR` to
212247
// `CARGO_MANIFEST_DIR`.
@@ -237,7 +272,7 @@ fn add_wasmer_version(pre_header: &mut String) {
237272

238273
/// Create a fresh new `Builder`, already pre-configured.
239274
fn new_builder(language: Language, crate_dir: &str, include_guard: &str, header: &str) -> Builder {
240-
Builder::new()
275+
let builder = Builder::new()
241276
.with_config(cbindgen::Config {
242277
sort_by: cbindgen::SortKey::Name,
243278
cpp_compat: true,
@@ -247,13 +282,19 @@ fn new_builder(language: Language, crate_dir: &str, include_guard: &str, header:
247282
.with_crate(crate_dir)
248283
.with_include_guard(include_guard)
249284
.with_header(header)
250-
.with_documentation(true)
285+
.with_documentation(false)
286+
.with_parse_expand(&[env::var("CARGO_PKG_NAME").unwrap()])
251287
.with_define("target_family", "windows", "_WIN32")
252288
.with_define("target_arch", "x86_64", "ARCH_X86_64")
253289
.with_define("feature", "jit", JIT_FEATURE_AS_C_DEFINE)
254290
.with_define("feature", "compiler", COMPILER_FEATURE_AS_C_DEFINE)
255291
.with_define("feature", "wasi", WASI_FEATURE_AS_C_DEFINE)
256-
.with_define("feature", "emscripten", EMSCRIPTEN_FEATURE_AS_C_DEFINE)
292+
.with_define("feature", "emscripten", EMSCRIPTEN_FEATURE_AS_C_DEFINE);
293+
294+
#[cfg(feature = "system-libffi")]
295+
let builder = builder.with_parse_expand_features(&["system-libffi"]);
296+
297+
builder
257298
}
258299

259300
/// Exclude types and functions from the `deprecated` API.
@@ -421,14 +462,23 @@ fn exclude_items_from_wasm_c_api(builder: Builder) -> Builder {
421462
.exclude_item("wasi_env_set_memory")
422463
.exclude_item("wasi_env_t")
423464
.exclude_item("wasi_get_imports")
424-
.exclude_item("wasi_get_imports_inner")
425465
.exclude_item("wasi_get_start_function")
466+
.exclude_item("wasi_get_unordered_imports")
426467
.exclude_item("wasi_get_wasi_version")
427468
.exclude_item("wasi_version_t")
428469
.exclude_item("wasm_config_set_compiler")
429470
.exclude_item("wasm_config_set_engine")
430471
.exclude_item("wasm_module_name")
431472
.exclude_item("wasm_module_set_name")
473+
.exclude_item("wasm_named_extern_module")
474+
.exclude_item("wasm_named_extern_name")
475+
.exclude_item("wasm_named_extern_t")
476+
.exclude_item("wasm_named_extern_unwrap")
477+
.exclude_item("wasm_named_extern_vec_copy")
478+
.exclude_item("wasm_named_extern_vec_delete")
479+
.exclude_item("wasm_named_extern_vec_new")
480+
.exclude_item("wasm_named_extern_vec_new_empty")
481+
.exclude_item("wasm_named_extern_vec_new_uninitialized")
432482
.exclude_item("wasmer_compiler_t")
433483
.exclude_item("wasmer_engine_t")
434484
.exclude_item("wat2wasm")

lib/c-api/src/wasm_c_api/externals/mod.rs

+67
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ pub struct wasm_extern_t {
2020

2121
wasm_declare_boxed_vec!(extern);
2222

23+
/// Copy a `wasm_extern_t`.
24+
#[no_mangle]
25+
pub unsafe extern "C" fn wasm_extern_copy(r#extern: &wasm_extern_t) -> Box<wasm_extern_t> {
26+
Box::new(r#extern.clone())
27+
}
28+
29+
/// Delete an extern.
30+
#[no_mangle]
31+
pub unsafe extern "C" fn wasm_extern_delete(_extern: Option<Box<wasm_extern_t>>) {}
32+
2333
#[no_mangle]
2434
pub unsafe extern "C" fn wasm_func_as_extern(
2535
func: Option<&wasm_func_t>,
@@ -125,3 +135,60 @@ pub unsafe extern "C" fn wasm_extern_as_table(
125135
None
126136
}
127137
}
138+
139+
#[cfg(test)]
140+
mod tests {
141+
use inline_c::assert_c;
142+
143+
#[test]
144+
fn test_extern_copy() {
145+
(assert_c! {
146+
#include "tests/wasmer_wasm.h"
147+
148+
int main() {
149+
wasm_engine_t* engine = wasm_engine_new();
150+
wasm_store_t* store = wasm_store_new(engine);
151+
152+
wasm_byte_vec_t wat;
153+
wasmer_byte_vec_new_from_string(
154+
&wat,
155+
"(module\n"
156+
" (func (export \"function\")))"
157+
);
158+
wasm_byte_vec_t wasm;
159+
wat2wasm(&wat, &wasm);
160+
161+
wasm_module_t* module = wasm_module_new(store, &wasm);
162+
assert(module);
163+
164+
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
165+
wasm_trap_t* traps = NULL;
166+
167+
wasm_instance_t* instance = wasm_instance_new(store, module, &imports, &traps);
168+
assert(instance);
169+
170+
wasm_extern_vec_t exports;
171+
wasm_instance_exports(instance, &exports);
172+
173+
assert(exports.size == 1);
174+
175+
wasm_extern_t* function = exports.data[0];
176+
assert(wasm_extern_kind(function) == WASM_EXTERN_FUNC);
177+
178+
wasm_extern_t* function_copy = wasm_extern_copy(function);
179+
assert(wasm_extern_kind(function_copy) == WASM_EXTERN_FUNC);
180+
181+
wasm_extern_delete(function_copy);
182+
wasm_instance_delete(instance);
183+
wasm_module_delete(module);
184+
wasm_byte_vec_delete(&wasm);
185+
wasm_byte_vec_delete(&wat);
186+
wasm_store_delete(store);
187+
wasm_engine_delete(engine);
188+
189+
return 0;
190+
}
191+
})
192+
.success();
193+
}
194+
}

lib/c-api/src/wasm_c_api/types/export.rs

+2-14
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,8 @@ impl From<ExportType> for wasm_exporttype_t {
4242

4343
impl From<&ExportType> for wasm_exporttype_t {
4444
fn from(other: &ExportType) -> Self {
45-
let name = {
46-
let mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
47-
let char_ptr = heap_str.as_mut_ptr();
48-
let str_len = heap_str.bytes().len();
49-
let name_inner = wasm_name_t {
50-
size: str_len,
51-
data: char_ptr,
52-
};
53-
Box::leak(heap_str);
54-
55-
Box::new(name_inner)
56-
};
57-
58-
let extern_type = Box::new(other.ty().into());
45+
let name: Box<wasm_name_t> = Box::new(other.name().to_string().into());
46+
let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into());
5947

6048
wasm_exporttype_t { name, extern_type }
6149
}

lib/c-api/src/wasm_c_api/types/import.rs

+4-28
Original file line numberDiff line numberDiff line change
@@ -50,37 +50,13 @@ impl From<ImportType> for wasm_importtype_t {
5050

5151
impl From<&ImportType> for wasm_importtype_t {
5252
fn from(other: &ImportType) -> Self {
53-
let module = {
54-
let mut heap_str: Box<str> = other.module().to_string().into_boxed_str();
55-
let char_ptr = heap_str.as_mut_ptr();
56-
let str_len = heap_str.bytes().len();
57-
let module_inner = wasm_name_t {
58-
size: str_len,
59-
data: char_ptr,
60-
};
61-
Box::leak(heap_str);
62-
63-
Box::new(module_inner)
64-
};
65-
66-
let name = {
67-
let mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
68-
let char_ptr = heap_str.as_mut_ptr();
69-
let str_len = heap_str.bytes().len();
70-
let name_inner = wasm_name_t {
71-
size: str_len,
72-
data: char_ptr,
73-
};
74-
Box::leak(heap_str);
75-
76-
Box::new(name_inner)
77-
};
78-
79-
let extern_type = Box::new(other.ty().into());
53+
let module: Box<wasm_name_t> = Box::new(other.module().to_string().into());
54+
let name: Box<wasm_name_t> = Box::new(other.name().to_string().into());
55+
let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into());
8056

8157
wasm_importtype_t {
82-
name,
8358
module,
59+
name,
8460
extern_type,
8561
}
8662
}

lib/c-api/src/wasm_c_api/types/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ wasm_declare_vec!(byte);
2828
#[allow(non_camel_case_types)]
2929
pub type wasm_name_t = wasm_byte_vec_t;
3030

31+
impl From<String> for wasm_name_t {
32+
fn from(string: String) -> Self {
33+
let mut boxed_str: Box<str> = string.into_boxed_str();
34+
let data = boxed_str.as_mut_ptr();
35+
let size = boxed_str.bytes().len();
36+
let wasm_name = Self { data, size };
37+
38+
Box::leak(boxed_str);
39+
40+
wasm_name
41+
}
42+
}
43+
3144
// opaque type over `ExternRef`?
3245
#[allow(non_camel_case_types)]
3346
pub struct wasm_ref_t;

0 commit comments

Comments
 (0)