If you need WASM-compiled libraries for protobuf
and protobuf-c
you can download them from the releases in Github. Or you can build them here (use the devcontainer in VSCode or read the config to find out the dependencies you need):
$ make
$ ls -l *.tgz
-rw-r--r-- 1 vscode vscode 27920925 Mar 1 10:23 protobuf-wasm.tgz
$ tar -tzvf *.tgz
drwxr-xr-x vscode/vscode 0 2022-03-01 10:23 include/
drwxr-xr-x vscode/vscode 0 2022-03-01 10:28 include/protobuf-c/
-rwxr-xr-x vscode/vscode 33675 2022-03-01 10:23 include/protobuf-c/protobuf-c.h
drwxr-xr-x vscode/vscode 0 2022-03-01 10:23 lib/
-rw-r--r-- vscode/vscode 134310 2022-03-01 10:23 lib/libprotobuf-c.a
-rw-r--r-- vscode/vscode 5408500 2022-03-01 10:23 lib/libprotobuf-lite.a
-rw-r--r-- vscode/vscode 40387580 2022-03-01 10:23 lib/libprotobuf.a
-rw-r--r-- vscode/vscode 57765044 2022-03-01 10:23 lib/libprotoc.a
Some of the libraries are rather large, so the release tarball is likely to be 30MB or so.
Those library archives have WASM blobs instead of object files and you can link them using a WASM compiler (e.g. emscripten
). Example
syntax = "proto3";
message Person {
string id = 1;
string name = 2;
}
Then we can generate some C code:
$ protoc-c --c_out=. person.proto
which gives us person.pb-c.c
and person.pb-c.h
.
Then let's create a simple person.c
:
#include <stdio.h>
#include <stdlib.h>
#include "person.pb-c.h"
int main() {
Person *person = malloc(sizeof(Person));
person->id = "54321";
person->name = "Juergen";
printf("%s %s\n", person->id, person->name);
return 0;
}
We can compile it with gcc
and run it:
$ gcc person.pb-c.c person.c -lprotobuf-c -o person
$ ./person
54321 Juergen
Unpack the library release:
$ tar -zxvf protobuf-wasm.tgz
NOTE: The Ubuntu system
emscripten
fails to compile ourperson.c
("Error: Cannot find module 'acorn'"), but if you get the latestemcc
fromemsdk
it works ().
Compile the WASM and run it:
$ emcc -Os -I ./include -s STANDALONE_WASM -s EXPORTED_FUNCTIONS="['_main']" ./lib/libprotobuf-c.a ./lib/libprotobuf.a person.c person.pb-c.c -o person.wasm
$ wasmtime person.wasm
54321 Juergen
Building protobuf
for WASM (https://github.com/protocolbuffers/protobuf) using emscripten wasn't too complicated. First let's set up a build area:
$ mkdir build
$ cd build
$ git clone https://github.com/protocolbuffers/protobuf
$ cd protobuf
Check the PROTOBUF_VERSION
in the system:
$ grep PROTOBUF_VERSION /usr/include/google/protobuf/stubs/common.h
#define GOOGLE_PROTOBUF_VERSION 3012004
That means 3.12.4
is installed, so we'll grab that and compile it:
$ git checkout v3.12.4
$ ./autogen.sh
$ emconfigure ./configure --host=none-none-none
$ emmake make
$ find . -name \*.a
./src/.libs/libprotobuf-lite.a
./src/.libs/libprotobuf.a
./src/.libs/libprotoc.a
There are loads of warnings about LLVM version appears incorrect (seeing "12.0", expected "11.0")
but it seems to work.
Checkout and prepare:
$ cd ..
$ git clone https://github.com/protobuf-c/protobuf-c
$ cd protobuf-c
Building protobuf-c
is trickier because it has to point back to the protobuf
build, and also has to be a compatible version (hence the 3.12.4
tag in protobuf
):
$ ./autogen.sh
$ EMMAKEN_CFLAGS=-I../protobuf/src EM_PKG_CONFIG_PATH=../protobuf emconfigure ./configure --host=none-none-none
$ EMMAKEN_CFLAGS='-I../protobuf/src -L../protobuf/src/.libs' emmake make
The make
command above most likely will fail a couple of times, while it tries to run tests. You can't ignore it, but you can work around it. The first time it fails because protoc-gen-c
is not executable (it's a WASM), but you can copy the system executable with the same name into the same location (and set the executable bit) to move past that by running the same make command again. The second failure is another non-executable WASM used in tests in t/generated-code2/cxx-generate-packed-data
. You can get a binary executable to swap with that by running ./autogen.sh && ./configure && make
in a fresh clone. Copy the generated executable on top of the WASM and set the executable bit, then make again:
$ EMMAKEN_CFLAGS='-I../protobuf/src -L../protobuf/src/.libs' emmake make
$ find . -name \*.a
./protobuf-c/.libs/libprotobuf-c.a