I want to call a C++ dynamic library (*.so) from Rust, but I don't want to build it from Rust. Like this,
cc::Build::new()
.file("src/foo.cc")
.shared_flag(true)
.compile("libfoo.so");
In some cases, I only need to call several functions, not all the functions. How can I use it?
Rust can link to/call C functions via its FFI, but not C++ functions. While I don't know why you can't call C++ functions, it is probably because C++ functions are complicated. You can just define C linkage on any C++ function, making it available from C and thus also Rust. extern "C" is your friend here.
Interoperability with foreign code Rust guarantees that the layout of a struct is compatible with the platform's representation in C only if the #[repr(C)] attribute is applied to it.
The extern keyword is used in two places in Rust. One is in conjunction with the crate keyword to make your Rust code aware of other Rust crates in your project, i.e., extern crate lazy_static; . The other use is in foreign function interfaces (FFI). extern is used in two different contexts within FFI.
Before you go further, make sure you have a basic idea of Rust FFI (foreign function interface).
In Rust, it's easy to call C, but hard to call C++.
To call C functions in Rust, you just have to wrap them with extern
, do some basic type casting and sometimes unsafe
.
To call C++ functions, since Rust does not have built-in knowledge of C++ features, you may have to do a lot of manual translation. For example, here is part of the documentation from Rust-Qt:
Many things are directly translated from C++ to Rust:
- Primitive types are mapped to Rust's primitive types (like
bool
) and types provided by libc crate (likelibc::c_int
).- Fixed-size numeric types (e.g
int8_t
orqint8
) are mapped to Rust's fixed size types (e.g.i8
).- Pointers, references and values are mapped to Rust's respective types.
- C++ namespaces are mapped to Rust submodules.
- C++ classes and structs are mapped to Rust structs. This also applies to all instantiations of template classes encountered in the library's API, including template classes of dependencies.
- Free functions are mapped to free functions.
- Class methods are mapped to structs' implementations.
- Destructors are mapped to
Drop
andCppDeletable
implementations.- Function pointer types are mapped to Rust's equivalent representation. Function pointers with references or class values are not supported.
static_cast
anddynamic_cast
are available in Rust through corresponding traits.Names of Rust identifiers are modified according to Rust's naming conventions.
When direct translation is not possible:
- Contents of each include file of the C++ library are placed into a separate submodule.
- Method overloading is emulated with wrapping arguments in a tuple and creating a trait describing tuples acceptable by each method. Methods with default arguments are treated in the same way.
- Single inheritance is translated to
Deref
andDerefMut
implementation, allowing to call base class methods on derived objects. When deref coercions are not enough,static_cast
should be used to convert from derived to base class.- Getter and setter methods are created for each public class field.
Not implemented yet but planned:
- Translate C++
typedef
s to Rust type aliases.- Implement operator traits for structs based on C++ operator methods (issue). Operators are currently exposed as regular functions with
op_
prefix.- Implement Debug and Display traits for structs if applicable methods exist on C++ side.
- Implement iterator traits for collections.
- Subclassing API (issue).
- Provide access to a class's public variables (issue).
- Provide conversion from enums to int and back (used in Qt API).
- Support C++ types nested into template types, like
Class1<T>::Class2
.Not planned to support:
- Advanced template usage, like types with integer template arguments.
- Template partial specializations.
- Template methods and functions.
My suggestion is to wrap your C++ library as a C library, then call it the official FFI way, or use rust-bindgen to automatically do the wrapping.
If you still want to call C++ in Rust, rustcxx seems like a handy tool.
As to the library linking, it's pretty simple:
/usr/lib
or /usr/local/lib/
, make sure it can be found by ldconfig -p
.LD_LIBRARY_PATH
to specify the path where your library lays when you run cargo
from the CLI.According to Rust's official website, there is no official support for linkage with C++. Instead you can try and use C libraries.
There is also a thread on this issue in their users forum, where users suggest some 3rd party projects aiming to tackle this issue:
I didn't use them, so I can't recommend anything particular or share my experience, but good luck :)
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