Skip to content

Commit 32e6e13

Browse files
Proof of concept C host
TODO deduplicate with add.wasm see #333 ```sh cd component-model/examples/example-c-host gcc -o host host.c -lwasmtime && ./host 6 7 adder.wasm ``` Co-authored-by: Shelley <shelley@exe.dev>
1 parent 7c1b5a9 commit 32e6e13

File tree

4 files changed

+131
-0
lines changed

4 files changed

+131
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
host
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../tutorial/c/adder/adder.wasm
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* C host for the adder WebAssembly component.
3+
*
4+
* Uses the Wasmtime C API's component model support to load and run
5+
* a component that exports: docs:adder/add.add(u32, u32) -> u32
6+
*/
7+
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
#include <string.h>
11+
#include <wasmtime.h>
12+
13+
static void exit_if_error(const char *step, wasmtime_error_t *error) {
14+
if (error == NULL)
15+
return;
16+
wasm_byte_vec_t error_message;
17+
wasmtime_error_message(error, &error_message);
18+
wasmtime_error_delete(error);
19+
fprintf(stderr, "error: failed to %s\n%.*s\n", step, (int)error_message.size,
20+
error_message.data);
21+
wasm_byte_vec_delete(&error_message);
22+
exit(1);
23+
}
24+
25+
int main(int argc, char *argv[]) {
26+
if (argc != 4) {
27+
fprintf(stderr, "Usage: %s <x> <y> <component.wasm>\n", argv[0]);
28+
return 1;
29+
}
30+
31+
uint32_t x = (uint32_t)atoi(argv[1]);
32+
uint32_t y = (uint32_t)atoi(argv[2]);
33+
const char *path = argv[3];
34+
35+
// 1. Create engine with component model enabled
36+
wasm_config_t *config = wasm_config_new();
37+
wasmtime_config_wasm_component_model_set(config, true);
38+
wasm_engine_t *engine = wasm_engine_new_with_config(config);
39+
40+
// 2. Read the component file
41+
FILE *f = fopen(path, "rb");
42+
if (!f) {
43+
fprintf(stderr, "error: could not open %s\n", path);
44+
return 1;
45+
}
46+
fseek(f, 0, SEEK_END);
47+
long fsize = ftell(f);
48+
fseek(f, 0, SEEK_SET);
49+
uint8_t *wasm_bytes = malloc(fsize);
50+
fread(wasm_bytes, 1, fsize, f);
51+
fclose(f);
52+
53+
// 3. Compile the component
54+
wasmtime_component_t *component = NULL;
55+
exit_if_error("compile component",
56+
wasmtime_component_new(engine, wasm_bytes, fsize, &component));
57+
free(wasm_bytes);
58+
59+
// 4. Create linker and add WASI P2
60+
wasmtime_component_linker_t *linker =
61+
wasmtime_component_linker_new(engine);
62+
exit_if_error("add WASI to linker",
63+
wasmtime_component_linker_add_wasip2(linker));
64+
65+
// 5. Create store with WASI config
66+
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
67+
wasmtime_context_t *context = wasmtime_store_context(store);
68+
exit_if_error("set WASI config",
69+
wasmtime_context_set_wasi(context, wasi_config_new()));
70+
71+
// 6. Instantiate
72+
wasmtime_component_instance_t instance;
73+
exit_if_error("instantiate component",
74+
wasmtime_component_linker_instantiate(linker, context, component, &instance));
75+
76+
// 7. Look up the exported "add" function.
77+
// The export is nested: first find the "docs:adder/add@0.1.0" instance,
78+
// then the "add" function within it.
79+
wasmtime_component_export_index_t *iface_idx =
80+
wasmtime_component_instance_get_export_index(
81+
&instance, context, NULL,
82+
"docs:adder/add@0.1.0", strlen("docs:adder/add@0.1.0"));
83+
if (iface_idx == NULL) {
84+
fprintf(stderr, "error: could not find export 'docs:adder/add@0.1.0'\n");
85+
return 1;
86+
}
87+
88+
wasmtime_component_export_index_t *func_idx =
89+
wasmtime_component_instance_get_export_index(
90+
&instance, context, iface_idx,
91+
"add", strlen("add"));
92+
wasmtime_component_export_index_delete(iface_idx);
93+
if (func_idx == NULL) {
94+
fprintf(stderr, "error: could not find function 'add'\n");
95+
return 1;
96+
}
97+
98+
wasmtime_component_func_t func;
99+
bool found = wasmtime_component_instance_get_func(
100+
&instance, context, func_idx, &func);
101+
wasmtime_component_export_index_delete(func_idx);
102+
if (!found) {
103+
fprintf(stderr, "error: could not get function handle for 'add'\n");
104+
return 1;
105+
}
106+
107+
// 8. Call the function: add(x, y) -> u32
108+
wasmtime_component_val_t args[2] = {
109+
{.kind = WASMTIME_COMPONENT_U32, .of.u32 = x},
110+
{.kind = WASMTIME_COMPONENT_U32, .of.u32 = y},
111+
};
112+
wasmtime_component_val_t results[1] = {0};
113+
114+
exit_if_error("call 'add'",
115+
wasmtime_component_func_call(&func, context, args, 2, results, 1));
116+
117+
printf("%u + %u = %u\n", x, y, results[0].of.u32);
118+
119+
// 9. Cleanup
120+
wasmtime_component_val_delete(&results[0]);
121+
wasmtime_store_delete(store);
122+
wasmtime_component_linker_delete(linker);
123+
wasmtime_component_delete(component);
124+
wasm_engine_delete(engine);
125+
126+
return 0;
127+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@_default:
2+
echo "TODO"; exit 1

0 commit comments

Comments
 (0)