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