I want to compile a c++ program to wasm(webassembly) and run it by wasmtime which is a wasm runtime but failed.
The c++ program utilize protobuf which is already compiled from src code using Emscripten. The program is build using Emscripten successfully but cannot run with wasmtime, neither converting to .wat file using wasm2wat.
Now the problem is:
# wasmtime person.wasm
Error: failed to run main module `person.wasm`
Caused by:
0: if you're trying to run a precompiled module, pass --allow-precompiled
1: failed to compile wasm function 79 at offset 0x293c
2: WebAssembly translation error
3: Invalid input WebAssembly code at offset 10632: threads support is not enabled
# wasm2wat person.wasm
000298a: error: unexpected opcode: 0xfe 0x10
Here is the file tree:
protobuf_wasm_test/
-lib/
-libprotobuf-lite.a
-libprotobuf.a
-libprotoc.a
-pb/
-person.pb.cc
-person.pb.h
-CMakeLists.txt
-person.cpp
The pb directory contains protofiles which define the message format, the person.proto file is:
syntax = "proto3";
message Person {
string id = 1;
string name = 2;
}
The person.cpp is:
#include <iostream>
#include "./pb/person.pb.h"
int main()
{
Person *person = (Person*)malloc(sizeof(Person));
person->set_id("12345");
person->set_name("abc");
std::cout<<"id: "<<person->id()<<", name: "<<person->name()<<std::endl;
free(person);
return 0;
}
The CMakeList.txt is:
cmake_minimum_required(VERSION 3.5)
project(protobuf_wasm_test)
add_compile_options(-sSTANDALONE_WASM -Wno-unused-command-line-argument)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/../pb")
include_directories("/home/hzb/protobuf_wasm/protobuf_src/src")
link_directories("${CMAKE_CURRENT_BINARY_DIR}/../lib")
set(proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/../pb/person.pb.cc")
set(proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/../pb/person.pb.h")
add_library(proto
${proto_srcs}
${proto_hdrs})
add_executable(person
person.cpp)
target_link_libraries(person
proto
protobuf)
I rebuild the protobuf source code with Emcsripten and generate the libprotobuf.a in ./lib/ directory,
Build successfully:
emcmake ..
emmake make
configure: cmake .. -DCMAKE_TOOLCHAIN_FILE=/home/hzb/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_CROSSCOMPILING_EMULATOR=/home/hzb/emsdk/node/14.18.2_64bit/bin/node;--experimental-wasm-bulk-memory;--experimental-wasm-threads
-- Configuring done
-- Generating done
-- Build files have been written to: /home/hzb/protobuf_wasm/protobuf_wasm_test/build
make: make
[ 25%] Building CXX object CMakeFiles/proto.dir/pb/person.pb.cc.o
[ 50%] Linking CXX static library libproto.a
[ 50%] Built target proto
[ 75%] Building CXX object CMakeFiles/person.dir/person.cpp.o
[100%] Linking CXX executable person.js
[100%] Built target person
Here is another question: I also want to know how to compile a complicate c++ program(with thirdparty libraries) to wasm and run it with wasmtime or other wasm runtime(non-web)? Does compiling each library to wasm(libxxx.a) and link them to the target work?
Noticed that the error message said "threads support is not enabled" and I tried to add --wasm-feature threads
when run wasmtime(link) like wasmtime --wasm-feature threads persom.wasm
. But still didn't work.
Besides, since I want to generate a stand alone wasm file, I added a compile parameter -sSTANDALONE_WASM
. From this page said that
emcc ... -o output.wasm omits generating either JavaScript or HTML launcher file, and produces a single Wasm file built in standalone mode as if the -sSTANDALONE_WASM settting had been used.
which means I should specify both standalone_wasm
and -o output.wasm
at the same time.
So I Specified the type of output file through set(CMAKE_EXECUTABLE_SUFFIX ".wasm")
. It works finally!
But I don't understand why I need to enable thread for wasmtime since there is no thread
code in the cpp.
Thanks for the comment from @yeputons, the thread
option may caused by protobuf atomic variables.