- Notifications
You must be signed in to change notification settings - Fork5
Extism C++ Host SDK - easily run WebAssembly modules / plugins from C++ applications
License
extism/cpp-sdk
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
The C++ SDK for integrating with theExtism runtime. Add this library in your host C++ applications to run Extism plugins.
Join theExtism Discord and chat with us!
- libextism
- cmake and jsoncpp
- Debian:
sudo apt install cmake jsoncpp - macOS:
brew install cmake jsoncpp
- Debian:
If you wish to do link jsoncpp statically, or do an in-tree build, SeeAlternative Dependency Strategies.
cmake -B buildcmake --build build -jsudo cmake --install build
To add the cpp-sdk to a CMake project:
find_package(extism-cpp)target_link_libraries(getting-started extism-cpp)
The primary concept in Extism is theplug-in. A plug-in is a code module stored in a.wasm file.
Plug-in code can come from a file on disk, object storage or any number of places. Since you may not have one handy, let's load a demo plug-in from the web. Let'sstart by creating a main function that loads a plug-in:
#include<extism.hpp>intmain(void) {constauto manifest =extism::Manifest::wasmURL("https://github.com/extism/plugins/releases/""latest/download/count_vowels.wasm"); extism::Pluginplugin(manifest,true);}
This plug-in was written in Rust and it does one thing, it counts vowels in a string. It exposes one "export" function:count_vowels. We can call exports usingPlugin::call.Let's add code to callcount_vowels to our main func:
#include<extism.hpp>#include<iostream>#include<string>intmain(void) {// ...const std::stringhello("Hello, World!");auto out = plugin.call("count_vowels", hello); std::stringresponse(out.string()); std::cout << response << std::endl;// => {"count":3,"total":3,"vowels":"aeiouAEIOU"}}
Build it:
cmake -B build&& cmake --build buildRunning this should print out the JSON vowel count report:
./build/getting-started{"count":3,"total":3,"vowels":"aeiouAEIOU"}All exports have the same interface, optional bytes in and optional bytes out. This plug-in happens to take a string and return a JSON encoded string with a report of results.
Plug-ins may be stateful or stateless. Plug-ins can maintain state between calls using variables. Our count vowels plug-in remembers the total number of counted vowels in the "total" key in the result. You can see this by making subsequent calls to the export:
const std::stringhello("Hello, World!");auto out = plugin.call("count_vowels", hello); std::stringresponse(out.string()); std::cout << response << std::endl;// => {"count":3,"total":3,"vowels":"aeiouAEIOU"} out = plugin.call("count_vowels", hello); response = out.string(); std::cout << response << std::endl;// => {"count":3,"total":6,"vowels":"aeiouAEIOU"}
The state variables will persist until the plug-in is freed or reinitialized.
Plug-ins may optionally take a configuration object. This is a static way to configure the plug-in. Our count-vowels plugin takes an optional configuration to change out which characters are considered vowels. Example:
#include<extism.hpp>intmain(void) {auto manifest =extism::Manifest::wasmURL("https://github.com/extism/plugins/releases/""latest/download/count_vowels.wasm"); manifest.setConfig("vowels","aeiouyAEIOUY"); extism::Pluginplugin(manifest,true);const std::stringhello("Yellow, World!");auto out = plugin.call("count_vowels", hello); std::stringresponse(out.string()); std::cout << response << std::endl;// => {"count":4,"total":4,"vowels":"aeiouyAEIOUY"}}
Let's extend our count-vowels example a little bit: Instead of storing thetotal in an ephemeral plug-in var, let's store it in a persistent key-value store!
Wasm can't use our KV store on it's own. This is whereHost Functions come in.
Host functions allow us to grant new capabilities to our plug-ins from our application. In this case, they are native C++ functions that are passed to and can can be invoked by the plug-in.
Let's load the manifest like usual but load up thecount_vowels_kvstore plug-in:
constauto manifest =extism::Manifest::wasmURL("https://github.com/extism/plugins/releases/""latest/download/count_vowels_kvstore.wasm");
Note: The source code for this ishere and is written in rust, but it could be written in any of our PDK languages.
Unlike our previous plug-in, this plug-in expects you to provide host functions that satisfy its import interface for a KV store.
We want to expose two functions to our plugin,kv_write which writes a bytes value to a key andkv_read which reads the bytes at the given key:
// pretend this is Redis or something :) std::map<std::string, std::vector<uint8_t>> kvStore;auto t = std::vector<extism::ValType>{extism::ValType::I64};auto kvRead = extism::Function("kv_read", t, t, [&kvStore](extism::CurrentPlugin plugin,void *user_data) {constauto it = kvStore.find(plugin.inputString());if (it == kvStore.end()) {const std::vector<uint8_t> zeros{0,0,0,0}; plugin.output(zeros.data(), zeros.size());return; } plugin.output(it->second.data(), it->second.size()); });auto kvWrite = extism::Function("kv_write", {extism::ValType::I64, extism::ValType::I64}, {}, [&kvStore](extism::CurrentPlugin plugin,void *user_data) {constauto key = plugin.inputString(0);auto value = plugin.inputBuffer(1); kvStore[key] = value.vector(); });
We need to pass these imports to the plug-in to create them. All imports of a plug-in must be satisfied for it to be initialized:
extism::Pluginplugin(manifest,true, {kvRead, kvWrite});
Now, we can demo it:
const std::stringhello("Hello, World!");auto out = plugin.call("count_vowels", hello); std::stringresponse(out.string()); std::cout << response << std::endl;// => {"count":3,"total":3,"vowels":"aeiouAEIOU"} out = plugin.call("count_vowels", hello); response = out.string(); std::cout << response << std::endl;// => {"count":3,"total":6,"vowels":"aeiouAEIOU"}
find_package(extism-cpp)target_link_libraries(target_name extism-cpp)
or statically:
find_package(extism-cpp)target_link_libraries(target_name extism-cpp-static)
pkg-config --libs extism-cpp
or statically:
pkg-config --static --libs extism-cpp-static
For builds usingextism-cpp-static to be static other than glibc, etc. jsoncppmust be linked statically. jsoncpp provided by package managers often isn'tprovided as a static library.
Building and installing jsoncpp from source (includingjsoncpp_static):
git clone https://github.com/open-source-parsers/jsoncppcd jsoncppcmake -B build&& cmake --build build -jmake -C build install
If you wish, instead of using installed deps, you can do an in-tree build!
For example:
mkdir extism-cpp-projectcd extism-cpp-projectgit initgit submodule add https://github.com/extism/extism.gitgit submodule add https://github.com/open-source-parsers/jsoncpp.gitgit submodule add https://github.com/extism/cpp-sdk.gitcd cpp-sdkcmake -DEXTISM_CPP_BUILD_IN_TREE=1 -B build&& cmake --build build
IfEXTISM_CPP_BUILD_IN_TREE is not set andfind_package fails, the dependency is fetched from the internet usingFetchContent and built from source.
The author believes this is the worst way to deal with the deps as it requires building them from source and doesn't use a centrally managed, flat tree of dependencies. It's provided just as a cross-platform convenience.
cmake --build build --targettestAbout
Extism C++ Host SDK - easily run WebAssembly modules / plugins from C++ applications
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.