The chasm gradle plugin creates a kotlin typesafe interface from a wasm binary which hides the complexities of chasms lower level virtual machine api.
You'll need to take the externally produced wasm binary and place it inside the module where you plan to generate the kotlin interface. Now where you place the binary, is really dependent on how you're planning to use it at runtime. Some people use chasm to execute code from different languages and simply bake the binary into the application. Others download the binary remotely so they can update their applications on the fly. Others do a mixture of both.
If your intention is to bake the binary into modules resources/assets at all then it would be best to place it in one of the following locations
- If you're using the kotlin.jvm plugin place it in
src/main/resources - If you're using the kotlin.multiplatform plugin place it in
src/commonMain/resources - If you're using any of the android plugins place it in
src/main/assets, you can also place different binaries in variant directories if you want to slightly different interfaces for different variants
If your intention is to only ever download a remote binary then place the binary in src/main/wasm, as this will prevent
it leaking into your compiled artifacts.
Here's an example of a configuration for a wasm binary will be baked into the module
chasm {
modules {
create("FibonacciService") {
binary = layout.projectDirectory.file("src/main/assets/fibonacci.wasm")
packageName = "com.test.chasm"
}
}
}Given the above configuration the plugin will then read the binary found at src/main/assets/fibonacci.wasm and generate an
interface and implementation from its metadata, for example
package com.test.chasm
import kotlin.Int
public interface FibonacciService {
public fun fibonacci(p0: Int): Int
}Each module declared in the extensions DSL can be individually configured, the following configuration options are available:
A file pointing to the wasm binary the codegen should use to generate the kotlin interface.
The package name for each of the code generated files
This property takes a set of strings, each string should be the name of a function appearing in the wasm binary. Each initializer function will be called once and only once on instantiation of the module.
Each function within a module is configurable through the Gradle plugin extension you can specify parameter names and String encoding strategies.
For example say you have the following wasm function:
(func $multiple_param_function (export "multiple_param_function") (param i32 f64) (result f64)
local.get 0
f64.convert_i32_s
local.get 1
f64.mul
)You can now configure the names of the params through the gradle extension
chasm {
modules {
create("FooService") {
function("multiple_param_function") {
intParam("a")
doubleParam("b")
doubleReturnType()
}
}
}
}For example say you have a function in your wasm module which returns a string encoded in two integers:
(func $string_function (export "string_function") (result i32 i32)
i32.const 1
i32.const 18
)You can now tell the codegen to produce a string by providing a function definition in the gradle plugin extension
chasm {
modules {
create("FooService") {
function("string_function") {
stringReturnType()
}
}
}
}Different compilers use different strategies to encode strings into memory, the codegen supports the following strategies:
enum class StringEncodingStrategy {
/**
* The pointer and length of the string are encoded in two I32s
*/
POINTER_AND_LENGTH,
/**
* The pointer of the string is encoded in an I32 and end of the String is the first null byte
* encountered after that pointer
*/
NULL_TERMINATED,
/**
* The pointer of the string is encoded in an I32 and length of the string is encoded in an integer (4 bytes)
* found at that pointer with the bytes of the string following
*/
LENGTH_PREFIXED,
/**
* The pointer and length of the string are encoded in a single I64
*/
PACKED_POINTER_AND_LENGTH,
}By default codegen will assume pointer and length encoding, but the encoding can optionally given in the configuration
chasm {
modules {
create("FooService") {
function("string_function") {
stringReturnType(StringEncodingStrategy.NULL_TERMINATED)
}
}
}
}You can control the output of the codegen using the CodegenConfig object
chasm {
modules {
create("") {
binary = ...
packageName = ...
codegenConfig = CodegenConfig(
generateTypesafeGlobalProperties = true,
generateSuspendingFactories = true,
)
}
}
}default = false
When set Chasm generates a suspending factory for that module. This can be configured independently for each module.
default = false
When set chasm will generate properties for globals in the interface it generates, if the global is mutable then chasm will generate a var else it will create a val.
For example the following wat
(global $mutable_global (export "mutable_global") (mut i32) (i32.const 117))
(global $immutable_global (export "immutable_global") i32 (i32.const 117))will become
var mutableGlobal: Int
val immutableGlobal: Int