Skip to content

Create Custom Environments

Erik McClure edited this page Nov 7, 2019 · 2 revisions

inNative embedding environments are really just standard C libraries that expose their C functions to the WebAssembly modules they are being compiled with. However, inNative also supports creating C libraries that expose WebAssembly-compatible functions by exporting specifically named functions based on the Name Mangling rules.

Exporting C Functions

Compile a static (or shared) library that exports the C functions you want to expose to your WebAssembly modules. If you're using C++, make sure you use extern "C" to prevent any C++ name-mangling. Then, simply compile your WebAssembly modules while referencing the library.

Windows Example

./innative-cmd.exe your_module.wasm -l your_library.lib

Because Windows generates .lib files for DLLs, you should do this for either a DLL or a static library.

Linux Example

./innative-cmd your_module.wasm -l your_library.a

OR

./innative-cmd your_module.wasm -L your_shared_library

Linux has a special -L option that tells it to link against a shared library that should be used. Remember that, in the example above, the real file name would be libyour_shared_library.so, which is what the linker will look for in the current path. Sometimes the linker can be finicky about library paths, in which case you might want to specify the entire absolute path instead.


If you have followed the instructions above, your C functions can now be imported using the basic C import method:

(import "" "your_function" (func $yourfunc (result i32)))

It's usually a good idea to use the standard C calling convention, but for C functions, you can also use other calling conventions. See Name Mangling for more details on how to call C functions with unusual calling conventions.

Exporting WebAssembly Functions

It is also possible to create a library that exposes WebAssembly functions, but only if they follow a strict set of rules. The Name Mangling article details how name mangling works for transforming a module + function name pair into a single C symbol: [module]_WASM_[function]. This mangling can be done in reverse to acquire a WebAssembly module + function name pair out of a C function declaration.

int64_t your_module_WASM_your_function(int64_t a, double b, float c, int32_t d)
{
  return 1;
}

Once again, make sure you add extern "C" if you are working with C++. If you compile a library with this function and add it to the inNative command line when compiling, you will be able to import it into your WebAssembly modules like so:

(import "your_module" "your_function" (func $functest (param i64 f64 f32 i32) (result i64)))

However, some restrictions apply: the function must have a default C calling convention! If it uses any other calling convention, the behavior is undefined and unsafe. In addition, only 5 types can be used:

  • int32_t <-> i32
  • int64_t <-> i64
  • float <-> f32
  • double <-> f64
  • void* <-> i64/i32/cref

Naturally, you can substitute uint32_t for int32_t and uint64_t for int64_t without a problem. You can also substitute any pointer type for void*. However, void* must either be mapped to an i64 on 64-bit architectures, an i32 on 32-bit architectures, or cref if you want to use inNative's cref extension. Be very careful when matching C function signatures with WebAssembly equivalents, because a mismatched signature can break the sandbox or just crash the program entirely.

Keep in mind that WebAssembly functions trump C functions - if you export a C function masquerading as a WebAssembly import, but another WebAssembly module with the same name and function definition exists, the WebAssembly version wins. Make sure you pick a unique name for your fake module when exporting C functions as WebAssembly imports.