Exporting function for host environment
You can expose a Swift function for host environment using special attribute and linker option.
@_cdecl("add")
func add(_ lhs: Int, _ rhs: Int) -> Int {
return lhs + rhs
}
You need to compile the Swift code with linker option --export
.
To call the exported function as a library multiple times, you need to:
- Compile it as a WASI reactor execution model.
The default execution model is command, so you need to pass
-mexec-model=reactor
to linker. - Call
_initialize
function before interacting with the instance.
If your code has any top-level code, you need to export main
function as well, and call it after _initialize
function.
$ swiftc \
-target wasm32-unknown-wasi \
lib.swift -o lib.wasm \
-Xlinker --export=add \
-Xclang-linker -mexec-model=reactor \
-Xlinker --export=main # Optional
Then, you can use the exported function from host environment.
const WASI = require("@wasmer/wasi").WASI;
const WasmFs = require("@wasmer/wasmfs").WasmFs;
const promisify = require("util").promisify;
const fs = require("fs");
const readFile = promisify(fs.readFile);
const main = async () => {
// Instantiate a new WASI Instance
const wasmFs = new WasmFs();
let wasi = new WASI({
args: [],
env: {},
bindings: {
...WASI.defaultBindings,
fs: wasmFs.fs,
},
});
const wasmBinary = await readFile("lib.wasm");
// Instantiate the WebAssembly file
const { instance } = await WebAssembly.instantiate(wasmBinary, {
wasi_snapshot_preview1: wasi.wasiImport,
});
// Initialize the instance by following WASI reactor ABI
instance.exports._initialize();
// (Optional) Run the top-level code
instance.exports.main();
// Get the exported function
const addFn = instance.exports.add;
console.log("2 + 3 = " + addFn(2, 3))
};
main()
If you use SwiftPM package, you can omit linker flag using clang's __atribute__
. Please see swiftwasm/JavaScriptKit#91 for more detail info