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:
Am I screwed because this is C++ and you can't link Rust to C++ yet?
Should the application consuming the FFI library deal with the linking issue somehow, and if so, how?
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.
put your own solution here
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With