xref: /wasmtime-44.0.1/examples/hello.c (revision adff9d9d)
13c51d3adSAlex Crichton /*
23c51d3adSAlex Crichton Example of instantiating of the WebAssembly module and invoking its exported
33c51d3adSAlex Crichton function.
43c51d3adSAlex Crichton 
59020c3e6SMasashi Yoshimura You can build using cmake:
62ba3025eSTheGreatRambler 
72ba3025eSTheGreatRambler mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-hello
83c51d3adSAlex Crichton */
93c51d3adSAlex Crichton 
103c51d3adSAlex Crichton #include <assert.h>
113c51d3adSAlex Crichton #include <stdio.h>
123c51d3adSAlex Crichton #include <stdlib.h>
133c51d3adSAlex Crichton #include <wasm.h>
143c51d3adSAlex Crichton #include <wasmtime.h>
153c51d3adSAlex Crichton 
16f8fee938STyler Rockwood static void exit_with_error(const char *message, wasmtime_error_t *error,
17f8fee938STyler Rockwood                             wasm_trap_t *trap);
183c51d3adSAlex Crichton 
hello_callback(void * env,wasmtime_caller_t * caller,const wasmtime_val_t * args,size_t nargs,wasmtime_val_t * results,size_t nresults)19f8fee938STyler Rockwood static wasm_trap_t *hello_callback(void *env, wasmtime_caller_t *caller,
20f8fee938STyler Rockwood                                    const wasmtime_val_t *args, size_t nargs,
21f8fee938STyler Rockwood                                    wasmtime_val_t *results, size_t nresults) {
22*adff9d9dSAlex Crichton   (void)env;
23*adff9d9dSAlex Crichton   (void)caller;
24*adff9d9dSAlex Crichton   (void)args;
25*adff9d9dSAlex Crichton   (void)nargs;
26*adff9d9dSAlex Crichton   (void)results;
27*adff9d9dSAlex Crichton   (void)nresults;
283c51d3adSAlex Crichton   printf("Calling back...\n");
293c51d3adSAlex Crichton   printf("> Hello World!\n");
303c51d3adSAlex Crichton   return NULL;
313c51d3adSAlex Crichton }
323c51d3adSAlex Crichton 
main()333c51d3adSAlex Crichton int main() {
343c51d3adSAlex Crichton   int ret = 0;
353c51d3adSAlex Crichton   // Set up our compilation context. Note that we could also work with a
363c51d3adSAlex Crichton   // `wasm_config_t` here to configure what feature are enabled and various
373c51d3adSAlex Crichton   // compilation settings.
383c51d3adSAlex Crichton   printf("Initializing...\n");
393c51d3adSAlex Crichton   wasm_engine_t *engine = wasm_engine_new();
403c51d3adSAlex Crichton   assert(engine != NULL);
413c51d3adSAlex Crichton 
423c51d3adSAlex Crichton   // With an engine we can create a *store* which is a long-lived group of wasm
437a1b7cdfSAlex Crichton   // modules. Note that we allocate some custom data here to live in the store,
447a1b7cdfSAlex Crichton   // but here we skip that and specify NULL.
457a1b7cdfSAlex Crichton   wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
463c51d3adSAlex Crichton   assert(store != NULL);
477a1b7cdfSAlex Crichton   wasmtime_context_t *context = wasmtime_store_context(store);
483c51d3adSAlex Crichton 
493c51d3adSAlex Crichton   // Read our input file, which in this case is a wasm text file.
503c51d3adSAlex Crichton   FILE *file = fopen("examples/hello.wat", "r");
513c51d3adSAlex Crichton   assert(file != NULL);
523c51d3adSAlex Crichton   fseek(file, 0L, SEEK_END);
533c51d3adSAlex Crichton   size_t file_size = ftell(file);
543c51d3adSAlex Crichton   fseek(file, 0L, SEEK_SET);
553c51d3adSAlex Crichton   wasm_byte_vec_t wat;
563c51d3adSAlex Crichton   wasm_byte_vec_new_uninitialized(&wat, file_size);
5793580f24SBruce Mitchener   if (fread(wat.data, file_size, 1, file) != 1) {
5893580f24SBruce Mitchener     printf("> Error loading module!\n");
5993580f24SBruce Mitchener     return 1;
6093580f24SBruce Mitchener   }
613c51d3adSAlex Crichton   fclose(file);
623c51d3adSAlex Crichton 
633c51d3adSAlex Crichton   // Parse the wat into the binary wasm format
64bd374fd6SAlex Crichton   wasm_byte_vec_t wasm;
657a1b7cdfSAlex Crichton   wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &wasm);
66bd374fd6SAlex Crichton   if (error != NULL)
67bd374fd6SAlex Crichton     exit_with_error("failed to parse wat", error, NULL);
683c51d3adSAlex Crichton   wasm_byte_vec_delete(&wat);
693c51d3adSAlex Crichton 
703c51d3adSAlex Crichton   // Now that we've got our binary webassembly we can compile our module.
713c51d3adSAlex Crichton   printf("Compiling module...\n");
727a1b7cdfSAlex Crichton   wasmtime_module_t *module = NULL;
737a1b7cdfSAlex Crichton   error = wasmtime_module_new(engine, (uint8_t *)wasm.data, wasm.size, &module);
743c51d3adSAlex Crichton   wasm_byte_vec_delete(&wasm);
75bd374fd6SAlex Crichton   if (error != NULL)
76bd374fd6SAlex Crichton     exit_with_error("failed to compile module", error, NULL);
773c51d3adSAlex Crichton 
783c51d3adSAlex Crichton   // Next up we need to create the function that the wasm module imports. Here
793c51d3adSAlex Crichton   // we'll be hooking up a thunk function to the `hello_callback` native
807a1b7cdfSAlex Crichton   // function above. Note that we can assign custom data, but we just use NULL
817a1b7cdfSAlex Crichton   // for now).
823c51d3adSAlex Crichton   printf("Creating callback...\n");
833c51d3adSAlex Crichton   wasm_functype_t *hello_ty = wasm_functype_new_0_0();
847a1b7cdfSAlex Crichton   wasmtime_func_t hello;
857a1b7cdfSAlex Crichton   wasmtime_func_new(context, hello_ty, hello_callback, NULL, NULL, &hello);
86*adff9d9dSAlex Crichton   wasm_functype_delete(hello_ty);
873c51d3adSAlex Crichton 
883c51d3adSAlex Crichton   // With our callback function we can now instantiate the compiled module,
893c51d3adSAlex Crichton   // giving us an instance we can then execute exports from. Note that
903c51d3adSAlex Crichton   // instantiation can trap due to execution of the `start` function, so we need
913c51d3adSAlex Crichton   // to handle that here too.
923c51d3adSAlex Crichton   printf("Instantiating module...\n");
933c51d3adSAlex Crichton   wasm_trap_t *trap = NULL;
947a1b7cdfSAlex Crichton   wasmtime_instance_t instance;
957a1b7cdfSAlex Crichton   wasmtime_extern_t import;
967a1b7cdfSAlex Crichton   import.kind = WASMTIME_EXTERN_FUNC;
977a1b7cdfSAlex Crichton   import.of.func = hello;
987a1b7cdfSAlex Crichton   error = wasmtime_instance_new(context, module, &import, 1, &instance, &trap);
997a1b7cdfSAlex Crichton   if (error != NULL || trap != NULL)
100bd374fd6SAlex Crichton     exit_with_error("failed to instantiate", error, trap);
1013c51d3adSAlex Crichton 
1023c51d3adSAlex Crichton   // Lookup our `run` export function
1033c51d3adSAlex Crichton   printf("Extracting export...\n");
1047a1b7cdfSAlex Crichton   wasmtime_extern_t run;
1057a1b7cdfSAlex Crichton   bool ok = wasmtime_instance_export_get(context, &instance, "run", 3, &run);
1067a1b7cdfSAlex Crichton   assert(ok);
1077a1b7cdfSAlex Crichton   assert(run.kind == WASMTIME_EXTERN_FUNC);
1083c51d3adSAlex Crichton 
1093c51d3adSAlex Crichton   // And call it!
1103c51d3adSAlex Crichton   printf("Calling export...\n");
1117a1b7cdfSAlex Crichton   error = wasmtime_func_call(context, &run.of.func, NULL, 0, NULL, 0, &trap);
112bd374fd6SAlex Crichton   if (error != NULL || trap != NULL)
113bd374fd6SAlex Crichton     exit_with_error("failed to call function", error, trap);
1143c51d3adSAlex Crichton 
1153c51d3adSAlex Crichton   // Clean up after ourselves at this point
1163c51d3adSAlex Crichton   printf("All finished!\n");
1173c51d3adSAlex Crichton   ret = 0;
1183c51d3adSAlex Crichton 
1197a1b7cdfSAlex Crichton   wasmtime_module_delete(module);
1207a1b7cdfSAlex Crichton   wasmtime_store_delete(store);
1213c51d3adSAlex Crichton   wasm_engine_delete(engine);
1223c51d3adSAlex Crichton   return ret;
1233c51d3adSAlex Crichton }
1243c51d3adSAlex Crichton 
exit_with_error(const char * message,wasmtime_error_t * error,wasm_trap_t * trap)125f8fee938STyler Rockwood static void exit_with_error(const char *message, wasmtime_error_t *error,
126f8fee938STyler Rockwood                             wasm_trap_t *trap) {
127bd374fd6SAlex Crichton   fprintf(stderr, "error: %s\n", message);
128bd374fd6SAlex Crichton   wasm_byte_vec_t error_message;
129bd374fd6SAlex Crichton   if (error != NULL) {
130bd374fd6SAlex Crichton     wasmtime_error_message(error, &error_message);
131bd374fd6SAlex Crichton     wasmtime_error_delete(error);
132bd374fd6SAlex Crichton   } else {
133bd374fd6SAlex Crichton     wasm_trap_message(trap, &error_message);
1343c51d3adSAlex Crichton     wasm_trap_delete(trap);
1353c51d3adSAlex Crichton   }
136bd374fd6SAlex Crichton   fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data);
137bd374fd6SAlex Crichton   wasm_byte_vec_delete(&error_message);
138bd374fd6SAlex Crichton   exit(1);
139bd374fd6SAlex Crichton }
140