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