webassembly - 将 protobuf c++ 程序编译为 wasm(WebAssembly)

标签 webassembly emscripten wasmtime

我想将一个 C++ 程序编译为 wasm(webassemble) 并通过 wasmtime(wasm 运行时)运行它,但失败了。

C++ 程序使用 protobuf,它已经使用 Emscripten 从 src 代码编译而来。该程序使用 Emscripten 成功构建,但无法使用 wasmtime 运行,也无法使用 wasm2wat 转换为 .wat 文件。

现在问题是:

  1. 使用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/

    相关文章:

    webassembly - 是否可以向实例化的 Webassemble 模块添加新功能?

    c - 如何在 Rust WASI 中链接 C 库

    emscripten - emscripten 生成的 invoke_* 函数的用途

    rust - 如何在Yew应用程序中包括 sleep 功能?

    c++ - 当我在调用project()之前设置(CMAKE_EXECUTABLE_SUFFIX)时,CMake中的Emscripten不会输出html文件。为什么?我该如何修复它?

    emscripten - WebAssembly 链接错误 : _sprintf function import requires a callable

    c - 使用 wasmtime 运行 wasm 文件时无法调用函数

    javascript - 将基于 JIT 的 lang 编译为 Webassembly

    webassembly - 学习 WebAssembly Uncaught (in Promise) TypeError : m. _init is not a function

    llvm - 最新的emscripten使用什么版本的LLVM?