Skip to content

Commit c9d7ecf

Browse files
MangoPeachGraperockwotjlanfeust69
committed
c-api: Compile a component
Co-authored-by: Tyler Rockwood <[email protected]> Co-authored-by: Jean-Jacques Lafay <[email protected]>
1 parent f1383ec commit c9d7ecf

File tree

12 files changed

+230
-0
lines changed

12 files changed

+230
-0
lines changed

crates/c-api/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,6 @@ winch = ['wasmtime/winch']
5959
debug-builtins = ['wasmtime/debug-builtins']
6060
wat = ['dep:wat', 'wasmtime/wat']
6161
pooling-allocator = ["wasmtime/pooling-allocator"]
62+
component-model = ["wasmtime/component-model"]
6263
# ... if you add a line above this be sure to change the other locations
6364
# marked WASMTIME_FEATURE_LIST

crates/c-api/artifact/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ default = [
4040
'winch',
4141
'debug-builtins',
4242
'pooling-allocator',
43+
'component-model',
4344
# ... if you add a line above this be sure to change the other locations
4445
# marked WASMTIME_FEATURE_LIST
4546
]
@@ -62,5 +63,6 @@ cranelift = ["wasmtime-c-api/cranelift"]
6263
winch = ["wasmtime-c-api/winch"]
6364
debug-builtins = ["wasmtime-c-api/debug-builtins"]
6465
pooling-allocator = ["wasmtime-c-api/pooling-allocator"]
66+
component-model = ["wasmtime-c-api/component-model"]
6567
# ... if you add a line above this be sure to read the comment at the end of
6668
# `default`

crates/c-api/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const FEATURES: &[&str] = &[
2222
"DEBUG_BUILTINS",
2323
"WAT",
2424
"POOLING_ALLOCATOR",
25+
"COMPONENT_MODEL",
2526
];
2627
// ... if you add a line above this be sure to change the other locations
2728
// marked WASMTIME_FEATURE_LIST

crates/c-api/cmake/features.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ feature(cranelift ON)
4545
feature(winch ON)
4646
feature(debug-builtins ON)
4747
feature(pooling-allocator ON)
48+
feature(component-model ON)
4849
# ... if you add a line above this be sure to change the other locations
4950
# marked WASMTIME_FEATURE_LIST

crates/c-api/include/wasmtime.h

+1
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@
200200
#include <wasmtime/trap.h>
201201
#include <wasmtime/val.h>
202202
#include <wasmtime/async.h>
203+
#include <wasmtime/component.h>
203204
// IWYU pragma: end_exports
204205
// clang-format on
205206

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef WASMTIME_COMPONENT_H
2+
#define WASMTIME_COMPONENT_H
3+
4+
#include <wasmtime/component/component.h>
5+
6+
#endif // WASMTIME_COMPONENT_H
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#ifndef WASMTIME_COMPONENT_COMPONENT_H
2+
#define WASMTIME_COMPONENT_COMPONENT_H
3+
4+
#ifdef WASMTIME_FEATURE_COMPONENT_MODEL
5+
6+
#include <wasm.h>
7+
#include <wasmtime/error.h>
8+
9+
#ifdef __cplusplus
10+
extern "C" {
11+
#endif
12+
13+
/// Representation of a component in the component model.
14+
typedef struct wasmtime_component_t wasmtime_component_t;
15+
16+
#ifdef WASMTIME_FEATURE_COMPILER
17+
18+
/**
19+
* \brief Compiles a WebAssembly binary into a #wasmtime_component_t
20+
*
21+
* This function will compile a WebAssembly binary into an owned
22+
#wasmtime_component_t.
23+
*
24+
* It requires a component binary, such as what is produced by Rust `cargo
25+
component` tooling.
26+
*
27+
* This function does not take ownership of any of its arguments, but the
28+
* returned error and component are owned by the caller.
29+
30+
* \param engine the #wasm_engine_t that will create the component
31+
* \param buf the address of the buffer containing the WebAssembly binary
32+
* \param len the length of the buffer containing the WebAssembly binary
33+
* \param component_out on success, contains the address of the created
34+
* component
35+
*
36+
* \return NULL on success, else a #wasmtime_error_t describing the error
37+
*/
38+
WASM_API_EXTERN wasmtime_error_t *
39+
wasmtime_component_new(const wasm_engine_t *engine, const uint8_t *buf,
40+
size_t len, wasmtime_component_t **component_out);
41+
42+
/**
43+
* \brief This function serializes compiled component artifacts as blob data.
44+
*
45+
* \param component the component
46+
* \param ret if the conversion is successful, this byte vector is filled in
47+
* with the serialized compiled component.
48+
*
49+
* \return a non-null error if parsing fails, or returns `NULL`. If parsing
50+
* fails then `ret` isn't touched.
51+
*
52+
* This function does not take ownership of `component`, and the caller is
53+
* expected to deallocate the returned #wasmtime_error_t and #wasm_byte_vec_t.
54+
*/
55+
WASM_API_EXTERN wasmtime_error_t *
56+
wasmtime_component_serialize(const wasmtime_component_t *component,
57+
wasm_byte_vec_t *ret);
58+
59+
#endif // WASMTIME_FEATURE_COMPILER
60+
61+
/**
62+
* \brief Build a component from serialized data.
63+
*
64+
* This function does not take ownership of any of its arguments, but the
65+
* returned error and component are owned by the caller.
66+
*
67+
* This function is not safe to receive arbitrary user input. See the Rust
68+
* documentation for more information on what inputs are safe to pass in here
69+
* (e.g. only that of `wasmtime_component_serialize`)
70+
*/
71+
WASM_API_EXTERN wasmtime_error_t *
72+
wasmtime_component_deserialize(const wasm_engine_t *engine, const uint8_t *buf,
73+
size_t len,
74+
wasmtime_component_t **component_out);
75+
76+
/**
77+
* \brief Deserialize a component from an on-disk file.
78+
*
79+
* This function is the same as #wasmtime_component_deserialize except that it
80+
* reads the data for the serialized component from the path on disk. This can
81+
* be faster than the alternative which may require copying the data around.
82+
*
83+
* This function does not take ownership of any of its arguments, but the
84+
* returned error and component are owned by the caller.
85+
*
86+
* This function is not safe to receive arbitrary user input. See the Rust
87+
* documentation for more information on what inputs are safe to pass in here
88+
* (e.g. only that of `wasmtime_component_serialize`)
89+
*/
90+
WASM_API_EXTERN wasmtime_error_t *
91+
wasmtime_component_deserialize_file(const wasm_engine_t *engine,
92+
const char *path,
93+
wasmtime_component_t **component_out);
94+
95+
/**
96+
* \brief Creates a shallow clone of the specified component, increasing the
97+
* internal reference count.
98+
*/
99+
WASM_API_EXTERN wasmtime_component_t *
100+
wasmtime_component_clone(const wasmtime_component_t *component);
101+
102+
/**
103+
* \brief Deletes a #wasmtime_component_t created by
104+
* #wasmtime_component_from_binary
105+
*
106+
* \param component the component to delete
107+
*/
108+
WASM_API_EXTERN void wasmtime_component_delete(wasmtime_component_t *component);
109+
110+
#ifdef __cplusplus
111+
} // extern "C"
112+
#endif
113+
114+
#endif // WASMTIME_FEATURE_COMPONENT_MODEL
115+
116+
#endif // WASMTIME_COMPONENT_COMPONENT_H

crates/c-api/include/wasmtime/conf.h.in

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#cmakedefine WASMTIME_FEATURE_WINCH
2828
#cmakedefine WASMTIME_FEATURE_DEBUG_BUILTINS
2929
#cmakedefine WASMTIME_FEATURE_POOLING_ALLOCATOR
30+
#cmakedefine WASMTIME_FEATURE_COMPONENT_MODEL
3031
// ... if you add a line above this be sure to change the other locations
3132
// marked WASMTIME_FEATURE_LIST
3233

crates/c-api/include/wasmtime/config.h

+6
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,12 @@ WASM_API_EXTERN void wasmtime_pooling_allocation_strategy_set(
764764

765765
#endif // WASMTIME_FEATURE_POOLING_ALLOCATOR
766766

767+
#ifdef WASMTIME_FEATURE_COMPONENT_MODEL
768+
769+
WASMTIME_CONFIG_PROP(void, component_model, bool)
770+
771+
#endif // WASMTIME_FEATURE_COMPONENT_MODEL
772+
767773
#ifdef __cplusplus
768774
} // extern "C"
769775
#endif
+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use std::ffi::{c_char, CStr};
2+
3+
use anyhow::Context;
4+
use wasmtime::component::Component;
5+
6+
use crate::{wasm_byte_vec_t, wasm_config_t, wasm_engine_t, wasmtime_error_t};
7+
8+
#[unsafe(no_mangle)]
9+
pub unsafe extern "C" fn wasmtime_config_component_model_set(c: &mut wasm_config_t, enable: bool) {
10+
c.config.wasm_component_model(enable);
11+
}
12+
13+
#[derive(Clone)]
14+
#[repr(transparent)]
15+
pub struct wasmtime_component_t {
16+
component: Component,
17+
}
18+
19+
#[unsafe(no_mangle)]
20+
#[cfg(any(feature = "cranelift", feature = "winch"))]
21+
pub unsafe extern "C" fn wasmtime_component_new(
22+
engine: &wasm_engine_t,
23+
buf: *const u8,
24+
len: usize,
25+
component_out: &mut *mut wasmtime_component_t,
26+
) -> Option<Box<wasmtime_error_t>> {
27+
let binary = unsafe { crate::slice_from_raw_parts(buf, len) };
28+
crate::handle_result(
29+
Component::from_binary(&engine.engine, binary),
30+
|component| {
31+
*component_out = Box::into_raw(Box::new(wasmtime_component_t { component }));
32+
},
33+
)
34+
}
35+
36+
#[unsafe(no_mangle)]
37+
#[cfg(any(feature = "cranelift", feature = "winch"))]
38+
pub unsafe extern "C" fn wasmtime_component_serialize(
39+
component: &wasmtime_component_t,
40+
ret: &mut wasm_byte_vec_t,
41+
) -> Option<Box<wasmtime_error_t>> {
42+
crate::handle_result(component.component.serialize(), |buffer| {
43+
ret.set_buffer(buffer);
44+
})
45+
}
46+
47+
#[unsafe(no_mangle)]
48+
pub unsafe extern "C" fn wasmtime_component_deserialize(
49+
engine: &wasm_engine_t,
50+
buf: *const u8,
51+
len: usize,
52+
component_out: &mut *mut wasmtime_component_t,
53+
) -> Option<Box<wasmtime_error_t>> {
54+
let binary = unsafe { crate::slice_from_raw_parts(buf, len) };
55+
crate::handle_result(
56+
unsafe { Component::deserialize(&engine.engine, binary) },
57+
|component| {
58+
*component_out = Box::into_raw(Box::new(wasmtime_component_t { component }));
59+
},
60+
)
61+
}
62+
63+
#[unsafe(no_mangle)]
64+
pub unsafe extern "C" fn wasmtime_component_deserialize_file(
65+
engine: &wasm_engine_t,
66+
path: *const c_char,
67+
component_out: &mut *mut wasmtime_component_t,
68+
) -> Option<Box<wasmtime_error_t>> {
69+
let path = unsafe { CStr::from_ptr(path) };
70+
let result = path
71+
.to_str()
72+
.context("input path is not valid utf-8")
73+
.and_then(|path| unsafe { Component::deserialize_file(&engine.engine, path) });
74+
crate::handle_result(result, |component| {
75+
*component_out = Box::into_raw(Box::new(wasmtime_component_t { component }));
76+
})
77+
}
78+
79+
#[unsafe(no_mangle)]
80+
pub unsafe extern "C" fn wasmtime_component_clone(
81+
component: &wasmtime_component_t,
82+
) -> Box<wasmtime_component_t> {
83+
Box::new(component.clone())
84+
}
85+
86+
#[unsafe(no_mangle)]
87+
pub unsafe extern "C" fn wasmtime_component_delete(_component: Box<wasmtime_component_t>) {}

crates/c-api/src/component/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mod component;
2+
3+
pub use component::*;

crates/c-api/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ mod wat2wasm;
7171
#[cfg(feature = "wat")]
7272
pub use crate::wat2wasm::*;
7373

74+
#[cfg(feature = "component-model")]
75+
mod component;
76+
#[cfg(feature = "component-model")]
77+
pub use crate::component::*;
78+
7479
/// Initialize a `MaybeUninit<T>`
7580
///
7681
/// TODO: Replace calls to this function with

0 commit comments

Comments
 (0)