xref: /wasmtime-44.0.1/examples/linking.c (revision eb650f6f)
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 
20 #include <assert.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <wasm.h>
24 #include <wasi.h>
25 #include <wasmtime.h>
26 
27 #define MIN(a, b) ((a) < (b) ? (a) : (b))
28 
29 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
30 static void read_wat_file(wasm_engine_t *engine, wasm_byte_vec_t *bytes, const char *file);
31 
32 int main() {
33   int ret = 0;
34   // Set up our context
35   wasm_engine_t *engine = wasm_engine_new();
36   assert(engine != NULL);
37   wasm_store_t *store = wasm_store_new(engine);
38   assert(store != NULL);
39 
40   wasm_byte_vec_t linking1_wasm, linking2_wasm;
41   read_wat_file(engine, &linking1_wasm, "examples/linking1.wat");
42   read_wat_file(engine, &linking2_wasm, "examples/linking2.wat");
43 
44   // Compile our two modules
45   wasmtime_error_t *error;
46   wasm_module_t *linking1_module = NULL;
47   wasm_module_t *linking2_module = NULL;
48   error = wasmtime_module_new(engine, &linking1_wasm, &linking1_module);
49   if (error != NULL)
50     exit_with_error("failed to compile linking1", error, NULL);
51   error = wasmtime_module_new(engine, &linking2_wasm, &linking2_module);
52   if (error != NULL)
53     exit_with_error("failed to compile linking2", error, NULL);
54   wasm_byte_vec_delete(&linking1_wasm);
55   wasm_byte_vec_delete(&linking2_wasm);
56 
57   // Instantiate wasi
58   wasi_config_t *wasi_config = wasi_config_new();
59   assert(wasi_config);
60   wasi_config_inherit_argv(wasi_config);
61   wasi_config_inherit_env(wasi_config);
62   wasi_config_inherit_stdin(wasi_config);
63   wasi_config_inherit_stdout(wasi_config);
64   wasi_config_inherit_stderr(wasi_config);
65   wasm_trap_t *trap = NULL;
66   wasi_instance_t *wasi = wasi_instance_new(store, "wasi_snapshot_preview1", wasi_config, &trap);
67   if (wasi == NULL)
68     exit_with_error("failed to instantiate wasi", NULL, trap);
69 
70   // Create our linker which will be linking our modules together, and then add
71   // our WASI instance to it.
72   wasmtime_linker_t *linker = wasmtime_linker_new(store);
73   error = wasmtime_linker_define_wasi(linker, wasi);
74   if (error != NULL)
75     exit_with_error("failed to link wasi", error, NULL);
76 
77   // Instantiate `linking2` with our linker.
78   wasm_instance_t *linking2;
79   error = wasmtime_linker_instantiate(linker, linking2_module, &linking2, &trap);
80   if (error != NULL || trap != NULL)
81     exit_with_error("failed to instantiate linking2", error, trap);
82 
83   // Register our new `linking2` instance with the linker
84   wasm_name_t linking2_name;
85   linking2_name.data = "linking2";
86   linking2_name.size = strlen(linking2_name.data);
87   error = wasmtime_linker_define_instance(linker, &linking2_name, linking2);
88   if (error != NULL)
89     exit_with_error("failed to link linking2", error, NULL);
90 
91   // Instantiate `linking1` with the linker now that `linking2` is defined
92   wasm_instance_t *linking1;
93   error = wasmtime_linker_instantiate(linker, linking1_module, &linking1, &trap);
94   if (error != NULL || trap != NULL)
95     exit_with_error("failed to instantiate linking1", error, trap);
96 
97   // Lookup our `run` export function
98   wasm_extern_vec_t linking1_externs;
99   wasm_instance_exports(linking1, &linking1_externs);
100   assert(linking1_externs.size == 1);
101   wasm_func_t *run = wasm_extern_as_func(linking1_externs.data[0]);
102   assert(run != NULL);
103   error = wasmtime_func_call(run, NULL, 0, NULL, 0, &trap);
104   if (error != NULL || trap != NULL)
105     exit_with_error("failed to call run", error, trap);
106 
107   // Clean up after ourselves at this point
108   wasm_extern_vec_delete(&linking1_externs);
109   wasm_instance_delete(linking1);
110   wasm_instance_delete(linking2);
111   wasmtime_linker_delete(linker);
112   wasm_module_delete(linking1_module);
113   wasm_module_delete(linking2_module);
114   wasm_store_delete(store);
115   wasm_engine_delete(engine);
116   return 0;
117 }
118 
119 static void read_wat_file(
120   wasm_engine_t *engine,
121   wasm_byte_vec_t *bytes,
122   const char *filename
123 ) {
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, 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, wasm_trap_t *trap) {
149   fprintf(stderr, "error: %s\n", message);
150   wasm_byte_vec_t error_message;
151   if (error != NULL) {
152     wasmtime_error_message(error, &error_message);
153     wasmtime_error_delete(error);
154   } else {
155     wasm_trap_message(trap, &error_message);
156     wasm_trap_delete(trap);
157   }
158   fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data);
159   wasm_byte_vec_delete(&error_message);
160   exit(1);
161 }
162