Kival M
Kival M

Reputation: 202

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.

Upvotes: 1

Views: 825

Answers (1)

zahical
zahical

Reputation: 276

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.

Upvotes: 1

Related Questions