Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linking to a C++ library that has extern "C" functions

Tags:

rust

ffi

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

like image 967
Ant Manelope Avatar asked Jan 21 '15 05:01

Ant Manelope


People also ask

Can you use extern C in C?

By declaring a function with extern "C" , it changes the linkage requirements so that the C++ compiler does not add the extra mangling information to the symbol. This pattern relies on the presence of the __cplusplus definition when using the C++ compiler. If you are using the C compiler, extern "C" is not used.

What is extern C linkage?

extern "C" is a linkage specification which is used to call C functions in the Cpp source files. We can call C functions, write Variables, & include headers. Function is declared in extern entity & it is defined outside. Syntax is. Type 1: extern "language" function-prototype.

What is extern C in C?

extern "C" specifies that the function is defined elsewhere and uses the C-language calling convention. The extern "C" modifier may also be applied to multiple function declarations in a block. In a template declaration, extern specifies that the template has already been instantiated elsewhere.


2 Answers

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.

like image 72
turboladen Avatar answered Oct 21 '22 19:10

turboladen


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.

like image 34
Renato Zannon Avatar answered Oct 21 '22 21:10

Renato Zannon