8 releases (3 stable)

1.0.2 Feb 5, 2021
1.0.1 Jan 13, 2021
1.0.0-rc1 Dec 23, 2020
1.0.0-alpha5 Nov 6, 2020
1.0.0-alpha4 Oct 9, 2020

#1457 in WebAssembly

29 downloads per month

MIT license

1MB
17K SLoC

Wasmer Engine Object File

This is an engine for the wasmer WebAssembly VM.

This engine is used to produce a native object file that can be linked against providing a sandboxed WebAssembly runtime environment for the compiled module with no need for runtime compilation.

Example of use

First we compile our WebAssembly file with Wasmer

wasmer compile path/to/wasm/file.wasm --llvm --object-file -o my_wasm.o --header my_wasm.h

You will then see output like:

Engine: objectfile
Compiler: llvm
Target: x86_64-apple-darwin
✔ File compiled successfully to `my_wasm.o`.
✔ Header file generated successfully at `my_wasm.h`.

Now lets create a program to link with this object file.

#ifdef __cplusplus
extern "C" {
#endif

#include "wasmer_wasm.h"
#include "wasm.h"
#include "my_wasm.h"

#include <stdio.h>
#include <stdlib.h>

#define own

#ifdef __cplusplus
}
#endif

void print_wasmer_error()
{
    int error_len = wasmer_last_error_length();
    printf("Error len: `%d`\n", error_len);
    char* error_str = (char*) malloc(error_len);
    wasmer_last_error_message(error_str, error_len);
    printf("Error str: `%s`\n", error_str);
}

int main() {
        printf("Initializing...\n");
        wasm_config_t* config = wasm_config_new();
        wasm_config_set_engine(config, OBJECT_FILE);
        wasm_engine_t* engine = wasm_engine_new_with_config(config);
        wasm_store_t* store = wasm_store_new(engine);

        wasm_module_t* module = wasmer_object_file_engine_new(store, "qjs.wasm");
        if (! module) {
                printf("Failed to create module\n");
                print_wasmer_error();
                return -1;
        }
        
        // We have now finished the memory buffer book keeping and we have a valid Module.

        // In this example we're passing some JavaScript source code as a command line argument
        // to a WASI module that can evaluate JavaScript.
        wasi_config_t* wasi_config = wasi_config_new("constant_value_here");
        const char* js_string = "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));";
        wasi_config_arg(wasi_config, "--eval");
        wasi_config_arg(wasi_config, js_string);
        wasi_env_t* wasi_env = wasi_env_new(wasi_config);
        if (!wasi_env) {
                printf("> Error building WASI env!\n");
                print_wasmer_error();
                return 1;
        }

        wasm_importtype_vec_t import_types;
        wasm_module_imports(module, &import_types);
        int num_imports = import_types.size;
        wasm_extern_t** imports = (wasm_extern_t**) malloc(num_imports * sizeof(wasm_extern_t*));
        wasm_importtype_vec_delete(&import_types);
        
        bool get_imports_result = wasi_get_imports(store, module, wasi_env, imports);
        wasi_env_delete(wasi_env);
        if (!get_imports_result) {
                printf("> Error getting WASI imports!\n");
                print_wasmer_error();
                return 1;
        }

        wasm_instance_t* instance = wasm_instance_new(store, module, (const wasm_extern_t* const*) imports, NULL);
        if (! instance) {
                printf("Failed to create instance\n");
                print_wasmer_error();
                return -1;
        }
        wasi_env_set_instance(wasi_env, instance);
        
        // WASI is now set up.
        own wasm_func_t* start_function = wasi_get_start_function(instance);
        if (!start_function) {
                fprintf(stderr, "`_start` function not found\n");
                print_wasmer_error();
                return -1;
        }

        fflush(stdout);
        own wasm_trap_t* trap = wasm_func_call(start_function, NULL, NULL);
        if (trap) {
                fprintf(stderr, "Trap is not NULL: TODO:\n");
                return -1;
        }

        wasm_instance_delete(instance);
        wasm_module_delete(module);
        wasm_store_delete(store);
        wasm_engine_delete(engine);
        return 0;
}

We save that source code into test.c and run:

clang -O2 -c test.c -o test.o

Now we just need to link everything together:

clang -O2 test.o my_wasm.o libwasmer_c_api.a

We link the object file we created with our C code, the object file we generated with Wasmer, and libwasmer_c_api together and produce an executable that can call into our compiled WebAssembly!

Dependencies

~8–18MB
~272K SLoC