1 /*
2 Example of compiling, instantiating, and linking two WebAssembly modules
3 together.
4
5 You can build using cmake:
6
7 mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-linking
8 */
9
10 #include <assert.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <wasi.h>
14 #include <wasm.h>
15 #include <wasmtime.h>
16
17 #define MIN(a, b) ((a) < (b) ? (a) : (b))
18
19 static void exit_with_error(const char *message, wasmtime_error_t *error,
20 wasm_trap_t *trap);
21 static void read_wat_file(wasm_byte_vec_t *bytes, const char *file);
22
main()23 int main() {
24 // Set up our context
25 wasm_engine_t *engine = wasm_engine_new();
26 assert(engine != NULL);
27 wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
28 assert(store != NULL);
29 wasmtime_context_t *context = wasmtime_store_context(store);
30
31 wasm_byte_vec_t linking1_wasm, linking2_wasm;
32 read_wat_file(&linking1_wasm, "examples/linking1.wat");
33 read_wat_file(&linking2_wasm, "examples/linking2.wat");
34
35 // Compile our two modules
36 wasmtime_error_t *error;
37 wasmtime_module_t *linking1_module = NULL;
38 wasmtime_module_t *linking2_module = NULL;
39 error = wasmtime_module_new(engine, (uint8_t *)linking1_wasm.data,
40 linking1_wasm.size, &linking1_module);
41 if (error != NULL)
42 exit_with_error("failed to compile linking1", error, NULL);
43 error = wasmtime_module_new(engine, (uint8_t *)linking2_wasm.data,
44 linking2_wasm.size, &linking2_module);
45 if (error != NULL)
46 exit_with_error("failed to compile linking2", error, NULL);
47 wasm_byte_vec_delete(&linking1_wasm);
48 wasm_byte_vec_delete(&linking2_wasm);
49
50 // Configure WASI and store it within our `wasmtime_store_t`
51 wasi_config_t *wasi_config = wasi_config_new();
52 assert(wasi_config);
53 wasi_config_inherit_argv(wasi_config);
54 wasi_config_inherit_env(wasi_config);
55 wasi_config_inherit_stdin(wasi_config);
56 wasi_config_inherit_stdout(wasi_config);
57 wasi_config_inherit_stderr(wasi_config);
58 wasm_trap_t *trap = NULL;
59 error = wasmtime_context_set_wasi(context, wasi_config);
60 if (error != NULL)
61 exit_with_error("failed to instantiate wasi", NULL, trap);
62
63 // Create our linker which will be linking our modules together, and then add
64 // our WASI instance to it.
65 wasmtime_linker_t *linker = wasmtime_linker_new(engine);
66 error = wasmtime_linker_define_wasi(linker);
67 if (error != NULL)
68 exit_with_error("failed to link wasi", error, NULL);
69
70 // Instantiate `linking2` with our linker.
71 wasmtime_instance_t linking2;
72 error = wasmtime_linker_instantiate(linker, context, linking2_module,
73 &linking2, &trap);
74 if (error != NULL || trap != NULL)
75 exit_with_error("failed to instantiate linking2", error, trap);
76
77 // Register our new `linking2` instance with the linker
78 error = wasmtime_linker_define_instance(linker, context, "linking2",
79 strlen("linking2"), &linking2);
80 if (error != NULL)
81 exit_with_error("failed to link linking2", error, NULL);
82
83 // Instantiate `linking1` with the linker now that `linking2` is defined
84 wasmtime_instance_t linking1;
85 error = wasmtime_linker_instantiate(linker, context, linking1_module,
86 &linking1, &trap);
87 if (error != NULL || trap != NULL)
88 exit_with_error("failed to instantiate linking1", error, trap);
89
90 // Lookup our `run` export function
91 wasmtime_extern_t run;
92 bool ok = wasmtime_instance_export_get(context, &linking1, "run", 3, &run);
93 assert(ok);
94 assert(run.kind == WASMTIME_EXTERN_FUNC);
95 error = wasmtime_func_call(context, &run.of.func, NULL, 0, NULL, 0, &trap);
96 if (error != NULL || trap != NULL)
97 exit_with_error("failed to call run", error, trap);
98
99 // Clean up after ourselves at this point
100 wasmtime_linker_delete(linker);
101 wasmtime_module_delete(linking1_module);
102 wasmtime_module_delete(linking2_module);
103 wasmtime_store_delete(store);
104 wasm_engine_delete(engine);
105 return 0;
106 }
107
read_wat_file(wasm_byte_vec_t * bytes,const char * filename)108 static void read_wat_file(wasm_byte_vec_t *bytes, const char *filename) {
109 wasm_byte_vec_t wat;
110 // Load our input file to parse it next
111 FILE *file = fopen(filename, "r");
112 if (!file) {
113 printf("> Error loading file!\n");
114 exit(1);
115 }
116 fseek(file, 0L, SEEK_END);
117 size_t file_size = ftell(file);
118 wasm_byte_vec_new_uninitialized(&wat, file_size);
119 fseek(file, 0L, SEEK_SET);
120 if (fread(wat.data, file_size, 1, file) != 1) {
121 printf("> Error loading module!\n");
122 exit(1);
123 }
124 fclose(file);
125
126 // Parse the wat into the binary wasm format
127 wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, bytes);
128 if (error != NULL)
129 exit_with_error("failed to parse wat", error, NULL);
130 wasm_byte_vec_delete(&wat);
131 }
132
exit_with_error(const char * message,wasmtime_error_t * error,wasm_trap_t * trap)133 static void exit_with_error(const char *message, wasmtime_error_t *error,
134 wasm_trap_t *trap) {
135 fprintf(stderr, "error: %s\n", message);
136 wasm_byte_vec_t error_message;
137 if (error != NULL) {
138 wasmtime_error_message(error, &error_message);
139 wasmtime_error_delete(error);
140 } else {
141 wasm_trap_message(trap, &error_message);
142 wasm_trap_delete(trap);
143 }
144 fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data);
145 wasm_byte_vec_delete(&error_message);
146 exit(1);
147 }
148