我想将一个 C++ 程序编译为 wasm(webassemble) 并通过 wasmtime(wasm 运行时)运行它,但失败了。
c++ 程序使用 protobuf,它已经使用 Emscripten 从 src 代码编译而来。该程序使用 Emscripten 成功构建,但无法使用 wasmtime 运行,也无法使用 wasm2wat 转换为 .wat 文件。
现在问题是:
# 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
这是文件树:
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 threads
,如 wasmtime --wasm-feature threads persom.wasm
。但还是没成功。
此外,由于我想生成一个独立的wasm文件,所以我添加了一个编译参数
-sSTANDALONE_WASM
。从this页面说
emcc ... -o output.wasm 忽略生成 JavaScript 或 HTML 启动器文件,并生成以独立模式构建的单个 Wasm 文件,就像使用了 -sSTANDALONE_WASM 设置一样。
这意味着我应该同时指定
standalone_wasm
和 -o output.wasm
。
所以我通过
set(CMAKE_EXECUTABLE_SUFFIX ".wasm")
指定了输出文件的类型。终于可以用了!
但是我不明白为什么我需要为 wasmtime 启用线程,因为 cpp 中没有
thread
代码。
感谢@yeputons的评论,
thread
选项可能是由protobuf原子变量引起的。
韩老师,你好!您可以上传这些文件吗:
-libprotobuf-lite.a
-libprotobuf.a
-libprotoc.a
我尝试编译我的文件,但出现错误:
undefined symbol: absl::lts_20240722::log_internal::LogMessageFatal::LogMessageFatal(char const*, int, absl::lts_20240722::string_view)
我认为我的 protobuf 库编译不正确
谢谢!