xref: /wasmtime-44.0.1/examples/multi.c (revision b1f7ff3b)
1 /*
2 Example of instantiating of the WebAssembly module and invoking its exported
3 function.
4 
5 You can compile and run this example on Linux with:
6 
7    cargo build --release -p wasmtime-c-api
8    cc examples/multi.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 multi
14    ./multi
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-multi
22 
23 Also note that this example was taken from
24 https://github.com/WebAssembly/wasm-c-api/blob/master/example/multi.c
25 originally
26 */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <inttypes.h>
32 #include <wasm.h>
33 #include <wasmtime.h>
34 
35 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
36 
37 // A function to be called from Wasm code.
38 wasm_trap_t* callback(
39   void *env,
40   wasmtime_caller_t *caller,
41   const wasmtime_val_t* args,
42   size_t nargs,
43   wasmtime_val_t* results,
44   size_t nresults
45 ) {
46   printf("Calling back...\n");
47   printf("> %"PRIu32" %"PRIu64"\n", args[0].of.i32, args[1].of.i64);
48   printf("\n");
49 
50   results[0] = args[1];
51   results[1] = args[0];
52   return NULL;
53 }
54 
55 
56 // A function closure.
57 wasm_trap_t* closure_callback(
58   void* env,
59   wasmtime_caller_t *caller,
60   const wasmtime_val_t* args,
61   size_t nargs,
62   wasmtime_val_t* results,
63   size_t nresults
64 ) {
65   int i = *(int*)env;
66   printf("Calling back closure...\n");
67   printf("> %d\n", i);
68 
69   results[0].kind = WASMTIME_I32;
70   results[0].of.i32 = (int32_t)i;
71   return NULL;
72 }
73 
74 
75 int main(int argc, const char* argv[]) {
76   // Initialize.
77   printf("Initializing...\n");
78   wasm_engine_t* engine = wasm_engine_new();
79   wasmtime_store_t* store = wasmtime_store_new(engine, NULL, NULL);
80   wasmtime_context_t *context = wasmtime_store_context(store);
81 
82   // Load our input file to parse it next
83   FILE* file = fopen("examples/multi.wat", "r");
84   if (!file) {
85     printf("> Error loading file!\n");
86     return 1;
87   }
88   fseek(file, 0L, SEEK_END);
89   size_t file_size = ftell(file);
90   fseek(file, 0L, SEEK_SET);
91   wasm_byte_vec_t wat;
92   wasm_byte_vec_new_uninitialized(&wat, file_size);
93   if (fread(wat.data, file_size, 1, file) != 1) {
94     printf("> Error loading module!\n");
95     return 1;
96   }
97   fclose(file);
98 
99   // Parse the wat into the binary wasm format
100   wasm_byte_vec_t binary;
101   wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
102   if (error != NULL)
103     exit_with_error("failed to parse wat", error, NULL);
104   wasm_byte_vec_delete(&wat);
105 
106   // Compile.
107   printf("Compiling module...\n");
108   wasmtime_module_t* module = NULL;
109   error = wasmtime_module_new(engine, (uint8_t*) binary.data, binary.size, &module);
110   if (error)
111     exit_with_error("failed to compile module", error, NULL);
112   wasm_byte_vec_delete(&binary);
113 
114   // Create external print functions.
115   printf("Creating callback...\n");
116   wasm_functype_t* callback_type = wasm_functype_new_2_2(
117       wasm_valtype_new_i32(),
118       wasm_valtype_new_i64(),
119       wasm_valtype_new_i64(),
120       wasm_valtype_new_i32()
121   );
122   wasmtime_func_t callback_func;
123   wasmtime_func_new(context, callback_type, callback, NULL, NULL, &callback_func);
124   wasm_functype_delete(callback_type);
125 
126   // Instantiate.
127   printf("Instantiating module...\n");
128   wasmtime_extern_t imports[1];
129   imports[0].kind = WASMTIME_EXTERN_FUNC;
130   imports[0].of.func = callback_func;
131   wasmtime_instance_t instance;
132   wasm_trap_t* trap = NULL;
133   error = wasmtime_instance_new(context, module, imports, 1, &instance, &trap);
134   if (error != NULL || trap != NULL)
135     exit_with_error("failed to instantiate", error, trap);
136   wasmtime_module_delete(module);
137 
138   // Extract export.
139   printf("Extracting export...\n");
140   wasmtime_extern_t run;
141   bool ok = wasmtime_instance_export_get(context, &instance, "g", 1, &run);
142   assert(ok);
143   assert(run.kind == WASMTIME_EXTERN_FUNC);
144 
145   // Call.
146   printf("Calling export...\n");
147   wasmtime_val_t args[2];
148   args[0].kind = WASMTIME_I32;
149   args[0].of.i32 = 1;
150   args[1].kind = WASMTIME_I64;
151   args[1].of.i64 = 2;
152   wasmtime_val_t results[2];
153   error = wasmtime_func_call(context, &run.of.func, args, 2, results, 2, &trap);
154   if (error != NULL || trap != NULL)
155     exit_with_error("failed to call run", error, trap);
156 
157   // Print result.
158   printf("Printing result...\n");
159   printf("> %"PRIu64" %"PRIu32"\n",
160     results[0].of.i64, results[1].of.i32);
161 
162   assert(results[0].kind == WASMTIME_I64);
163   assert(results[0].of.i64 == 2);
164   assert(results[1].kind == WASMTIME_I32);
165   assert(results[1].of.i32 == 1);
166 
167   // Shut down.
168   printf("Shutting down...\n");
169   wasmtime_store_delete(store);
170   wasm_engine_delete(engine);
171 
172   // All done.
173   printf("Done.\n");
174   return 0;
175 }
176 
177 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) {
178   fprintf(stderr, "error: %s\n", message);
179   wasm_byte_vec_t error_message;
180   if (error != NULL) {
181     wasmtime_error_message(error, &error_message);
182     wasmtime_error_delete(error);
183   } else {
184     wasm_trap_message(trap, &error_message);
185     wasm_trap_delete(trap);
186   }
187   fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data);
188   wasm_byte_vec_delete(&error_message);
189   exit(1);
190 }
191