12

So I'm writing a Rust FFI to a C++ library that has an extern "C" block with C-style function headers within it. And my low-level FFI builds.

However, when I use my FFI in another project, it doesn't link properly, and I get undefined reference to operator new(), delete(), etc.

My question is:

  1. Am I screwed because this is C++ and you can't link Rust to C++ yet?

  2. Should the application consuming the FFI library deal with the linking issue somehow, and if so, how?

  3. Can my libsomething.a be built somehow to include these C++ components, and if so, how? I'm currently using the gcc crate rather generically.

  4. put your own solution here

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Ant Manelope
  • 531
  • 1
  • 6
  • 15

2 Answers2

6

You need to dynamically link to libstdc++ to get the symbols your C++ code will need. You can instruct rustc to do so in your build script:

extern crate gcc;
use std::default::Default;

fn main() {
    gcc::compile_library("libhello.a", &Default::default(), &["cpp/hello.cpp"]);
    println!("cargo:rustc-flags=-l dylib=stdc++");
}

See full example on github

For more info on build scripts, see the Cargo guide.

Renato Zannon
  • 28,805
  • 6
  • 38
  • 42
  • This worked for me as option 3 above. I've since got it working w/o the gcc crate, but needed to add `-L native=$outdir -l static=$libname` to the rustc-flags in the println!() – Ant Manelope Jan 22 '15 at 06:15
  • 1
    The linked example repo is broken, as `Cargo.toml` specifies `*` for the `gcc` crate version without providing `Cargo.lock`. Back when the example was created, that would have resulted in using `v0.1.5` of the crate, but the code will now try to use the last release `v0.3.55`. Additionally, `gcc` has been deprecated and replaced by the `cc` crate. – Herohtar Oct 08 '21 at 19:24
3

This worked for me on macOS using the cmake crate.

// build.rs
extern crate cmake;

fn main() {
    let dst = cmake::Config::new("my_c_lib")
        .no_build_target(true)
        .always_configure(true)
        .build();

    // This was the fix
    println!("cargo:rustc-flags=-l dylib=c++");

    // The cmake crate outputs the static lib in the build subdir in the cargo $OUT_DIR,
    // which is a little different than their docs show.
    println!("cargo:rustc-link-search=native={}/build", dst.display());
    println!("cargo:rustc-link-lib=static=my_c_lib");
}

Note that I have the C/C++ code as a git submodule under native/, and that project is using cmake.

This answer also helped.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
turboladen
  • 698
  • 1
  • 9
  • 14