我想将一个 C++ 程序编译为 wasm(webassemble) 并通过 wasmtime(wasm 运行时)运行它,但失败了。
C++ 程序使用 protobuf,它已经使用 Emscripten 从 src 代码编译而来。该程序使用 Emscripten 成功构建,但无法使用 wasmtime 运行,也无法使用 wasm2wat 转换为 .wat 文件。
现在问题是:
- 使用wasmtime运行时的错误消息是:
# 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
- 转换为.wat格式时,出现另一个错误:
# wasm2wat person.wasm
000298a: error: unexpected opcode: 0xfe 0x10
这是文件树:
protobuf_wasm_test/
-lib/
-libprotobuf-lite.a
-libprotobuf.a
-libprotoc.a
-pb/
-person.pb.cc
-person.pb.h
-CMakeLists.txt
-person.cpp
pb目录包含定义消息格式的proto文件,person.proto文件是:
syntax = "proto3";
message Person {
string id = 1;
string name = 2;
}
person.cpp 是:
#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;
}
CMakeList.txt 是:
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)
我用Emcsripten重建protobuf源代码并在./lib/目录中生成libprotobuf.a,
构建成功:
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
这是另一个问题:我还想知道如何将复杂的c++程序(带有第三方库)编译为wasm并使用wasmtime或其他wasm运行时(非Web)运行它?将每个库编译为 wasm(libxxx.a) 并将它们链接到目标是否有效?
最佳答案
注意到错误消息显示“未启用线程支持”,我尝试在运行 wasmtime( link ) 时添加 --wasm-feature 线程
,如 wasmtime --wasm -功能线程 persom.wasm
。但还是没成功。
此外,由于我想生成一个独立的wasm文件,所以我添加了一个编译参数-sSTANDALONE_WASM
。来自 this页面说的是
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.
这意味着我应该同时指定standalone_wasm
和-o output.wasm
。
所以我通过set(CMAKE_EXECUTABLE_SUFFIX ".wasm")
指定了输出文件的类型。终于可以用了!
但是我不明白为什么我需要为 wasmtime 启用线程,因为 cpp 中没有 thread
代码。
感谢@yeputons的评论,thread
选项可能是由protobuf原子变量引起的。
关于webassembly - 将 protobuf c++ 程序编译为 wasm(WebAssembly),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75057884/