C and C++ have been very popular programming languages for a long time and still are today. Many consolidated program approaches and libraries exists. With
Emscripten is it possbile to transfer existing C / C++ projects into
WebAssembly (Wasm). Wasm is a binary instruction format and it is designed as a portable compilation for different targets. This means different architectures, different operating systems, different execution environments such as browser, desktop or server - one for all. This makes Wasm a very interesting approach.
Dylibso, a group of software builders, has set itself the target of making Wasm to everyone's favorite binary format. Among other interesting products, they are developing
Chicory, a JVM native Wasm runtime. It allows to run Wasm programs with zero native dependencies on any Java system. So this approach can also be used with VCF Automation. This is described in this blog post.
Use C / C++ Language via JShell
First, the necessary Java archive (Jar) files must be
downloaded from the MVN repository.
Store Jar and Wasm Binaries as Action
The jar files are zip packages. They are only available as a binary format. To use them in VCF Automation, they must be encoded with base64 and can then be saved as an action. The base64 encoded content can simply be copied and pasted into the action. This also applies to the Wasm file, which was built by compiling the C code.
References
C Code
Here a tiny C program with one function, named hello. It delivers a Hello World message, depending on whether a name is passed as a parameter. If a name is passed it is used, otherwise a standard text.
#include <emscripten.h>
#include <stdlib.h>
#include <string.h>
EMSCRIPTEN_KEEPALIVE
void hello(char* name, char* result) {
if (name == NULL) {
char* ret = "Hello World from WebAssembly in C Language\n";
strcpy(result, ret);
} else {
char* ret = "Hello ";
strcat(ret, name);
strcat(ret, " from WebAssembly in C Language\n");
strcpy(result, ret);
}
}
|
Compile the C Code to WebAssembly
Now we compile the code with the following command:
@emcc hello.c -o hello.c.wasm --no-entry -s EXPORTED_FUNCTIONS=_malloc,_free
After compilation we have a new file, hello.c.wasm.
Hint: This file must also be encoded as base64 and saved as an action, as described above.
Java Code in JShell
The following Java code contains seven steps. The wasm is instantiated and the functions are determined. The memory, for the parameter and the return value, is then allocated and the parameter is set. The function is executed and the return value is read. Finally the allocated memory is released.
/env --class-path /lib/vco/app-server/temp/log-0.0.10.jar:/lib/vco/app-server/temp/runtime-0.0.10.jar:/lib/vco/app-server/temp/wasi-0.0.10.jar:/lib/vco/app-server/temp/wasm-0.0.10.jar
/**
* Example Java code in JShell to execute WebAssembly via Chicory
*
* @author Stefan Schnell <mail@stefan-schnell.de>
* @license MIT
* @version 0.1.0
*
* Checked with Aria Automation 8.17.0
*/
import com.dylibso.chicory.runtime.ExportFunction;
import com.dylibso.chicory.runtime.Instance;
import com.dylibso.chicory.runtime.Memory;
import com.dylibso.chicory.runtime.Module;
import com.dylibso.chicory.wasm.types.Value;
import java.io.File;
// Instantiate Wasm
File file = new File("/lib/vco/app-server/temp/hello.c.wasm");
Module module = Module.builder(file).build();
Instance instance = module.instantiate();
// Get functions from Wasm
ExportFunction hello = instance.export("hello");
ExportFunction malloc = instance.export("malloc");
ExportFunction free = instance.export("free");
Memory memory = instance.memory();
// Allocate memory for parameter and set the parameter
String name = "Stefan";
int ptrName = malloc.apply(Value.i32(name.length()))[0].asInt();
memory.writeString(ptrName, name);
// Allocate memory for return value
int ptrResult = malloc.apply(Value.i32(128))[0].asInt();
// Invoke Wasm function
hello.apply(Value.i32(ptrName), Value.i32(ptrResult));
// Get return value
String result = memory.readString(ptrResult, 128);
java.lang.System.out.println(result.trim());
// Free memory
free.apply(Value.i32(ptrResult));
free.apply(Value.i32(ptrName));
/exit
|
VCF Automation JavaScript Action
The action writes all the necessary files to the temporary directory. Then the JShell command is invoked with the Java code and the return value is output.
function main() {
System.getModule("de.stschnell").writeActionAsFileInTempDirectory(
"de.stschnell",
"log_0_0_10_jar_base64",
"log-0.0.10.jar",
true,
"application/java-archive"
);
System.getModule("de.stschnell").writeActionAsFileInTempDirectory(
"de.stschnell",
"runtime_0_0_10_jar_base64",
"runtime-0.0.10.jar",
true,
"application/java-archive"
);
System.getModule("de.stschnell").writeActionAsFileInTempDirectory(
"de.stschnell",
"wasi_0_0_10_jar_base64",
"wasi-0.0.10.jar",
true,
"application/java-archive"
);
System.getModule("de.stschnell").writeActionAsFileInTempDirectory(
"de.stschnell",
"wasm_0_0_10_jar_base64",
"wasm-0.0.10.jar",
true,
"application/java-archive"
);
System.getModule("de.stschnell").writeActionAsFileInTempDirectory(
"de.stschnell",
"hello_c_wasm_base64",
"hello.c.wasm",
true,
"application/wasm"
);
System.getModule("de.stschnell").writeActionAsFileInTempDirectory(
"de.stschnell",
"hello_jsh",
"hello.jsh"
);
var jshFileName = System.getTempDirectory() + "/hello.jsh";
var output = System.getModule("de.stschnell").executeCommand(
["jshell", jshFileName], 10000
).output;
System.log(output);
}
// Main
main();
|
Here a part of the code and the log output in VCF Automation.
Conclusion
With Emscripten it is very easy to convert C / C++ functions into Wasm and with Chicory it is also very easy to use Wasm inside Aria Automation with the JavaScript runtime environment. This approach offers possibilities to use and reuse C / C++ code seamlessly in Aria Automation.