简体   繁体   中英

Issue Linking C++ Library to Rust code in wasi

I am trying to compile a C++ library to wasm32 wasi for use inside my rust application. However I am running into this issue.

Error: failed to run main module `target/wasm32-wasi/release/so.wasm`

Caused by:
    0: failed to instantiate "target/wasm32-wasi/release/so.wasm"
    1: unknown import: `env::_ZdlPv` has not been defined

This error relates to line 5 in my mylib.cpp. Which just declares a variable

#include "OpenXLSX/OpenXLSX.hpp"

extern "C" int test() {
  std::string i = "";
  OpenXLSX::XLXmlData s;
  return 0;
}

my main.rs


#[link(name = "mylib")]
extern "C" {
    pub fn test() -> i32;
}

pub fn main() {
    let res = unsafe { test() };
    println!("test code: {}", res);
}

and my build.rs, where I assume the error is

use std::env;

fn main() {
    cc::Build::new()
        .cpp_link_stdlib(None)
        .cpp(true)
        .flag("-std=c++17")
        .archiver("llvm-ar")
        .include("OpenXLSX/external/pugixml")
        .include("OpenXLSX/external/nowide")
        .include("OpenXLSX/external/zippy")
        .include("OpenXLSX/headers")
        .include("OpenXLSX")
        .flag("--sysroot=/opt/wasi-sysroot")
        .flag("-fvisibility=default")
        .file("OpenXLSX/sources/XLCell.cpp")
        .file("OpenXLSX/sources/XLCellIterator.cpp")
        .file("OpenXLSX/sources/XLCellRange.cpp")
        .file("OpenXLSX/sources/XLCellReference.cpp")
        .file("OpenXLSX/sources/XLCellValue.cpp")
        .file("OpenXLSX/sources/XLColor.cpp")
        .file("OpenXLSX/sources/XLColumn.cpp")
        .file("OpenXLSX/sources/XLContentTypes.cpp")
        .file("OpenXLSX/sources/XLDateTime.cpp")
        .file("OpenXLSX/sources/XLDocument.cpp")
        .file("OpenXLSX/sources/XLFormula.cpp")
        .file("OpenXLSX/sources/XLProperties.cpp")
        .file("OpenXLSX/sources/XLRelationships.cpp")
        .file("OpenXLSX/sources/XLRow.cpp")
        .file("OpenXLSX/sources/XLRowData.cpp")
        .file("OpenXLSX/sources/XLSharedStrings.cpp")
        .file("OpenXLSX/sources/XLSheet.cpp")
        .file("OpenXLSX/sources/XLWorkbook.cpp")
        .file("OpenXLSX/sources/XLXmlData.cpp")
        .file("OpenXLSX/sources/XLXmlFile.cpp")
        .file("OpenXLSX/sources/XLZipArchive.cpp")
        .file("OpenXLSX/external/pugixml/pugixml.cpp")
        .compile("OpenXLSX");

    cc::Build::new()
        .archiver("llvm-ar")
        .cpp_link_stdlib(None)
        .cpp(true)
        .flag("-fvisibility=default")
        .flag("-std=c++17")
        .include("OpenXLSX/external/pugixml")
        .include("OpenXLSX/headers")
        .include("OpenXLSX")
        .flag("--sysroot=/opt/wasi-sysroot")
        .file("mylib.cpp")
        .compile("libmylib.a");
}

In a separate attempt, Instead of step 1 in my build.rs where I try to link the OpenXLSX files, I have also used cmake to generate a single.a file compiled for wasm32-wasi with wasi sysroot, that I tried loading.

 let src_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
 println!("cargo:rustc-link-lib=static=OpenXLSX");
 println!("cargo:rustc-link-search=native={}/wasm-libs", src_dir);

And I tried to generate the bindings with Bindgen, it gave me duplicate definition errors. Which is the main reason I am writing my code in a c++ function and trying to call that from rust. I assume there would still be a linking issue,even if I get bindgen to work.

In short, your c++ code is using operator delete(void*) but you are not linking the c++ standard library that usually provides the implementation for it.

In a bit more detail:

  • _ZdlPv is the mangled name of operator delete(void*) . That's the standard C++ delete operator that's used to free objects allocated on the heap with new . Check this SO answer . You can also check the name on Demangler.com .
  • On line 5 OpenXLSX::XLXmlData s; you are creating an XLXmlData instance. XLXmlData has a std::unique_ptr as a member. So, when a XLXmlData object goes out of scope (at the end of test() ) its destructor ~XLXmlData() is called and in it, the compiler generates code to clean-up all members, including the unique_ptr. This code, contains a call to the delete operator.
    Check this (abridged) godbolt.org version of XLXmlData to see what code gets generated. The call to delete is on line 38.
  • Even though delete is a C++ keyword, under the hood, the compiler emits just a regular function call (under the mangled _ZdlPv name, as we already saw), so something needs to provide the implementation for that symbol. This "something" typically is the C++ standard library.
  • However, your build.rs passes None to .cpp_link_stdlib() . According to the docs this disables automatic linking, so the linker will not look for the implementation of delete in the standard library. As nothing else implements delete , this ultimately leads to the unknown import error you are seeing.

To recap, you should link with the standard library. A lot of C++ stuff simply will not work without it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM