Chi Wei Shen
Chi Wei Shen

Reputation: 337

How to call a C++ dynamic library from Rust?

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?

Upvotes: 17

Views: 52856

Answers (3)

Galaxy
Galaxy

Reputation: 1279

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 (like libc::c_int).
  • Fixed-size numeric types (e.g int8_t or qint8) 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 and CppDeletable implementations.
  • Function pointer types are mapped to Rust's equivalent representation. Function pointers with references or class values are not supported.
  • static_cast and dynamic_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 and DerefMut 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++ typedefs 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. (Update: rustcxx has been archived, try CXX instead.)

As to the library linking, it's pretty simple:

  • Put the library into your system library searching paths like /usr/lib or /usr/local/lib/, make sure it can be found by ldconfig -p.
  • Or use the environment variable LD_LIBRARY_PATH to specify the path where your library lays when you run cargo from the CLI.

Upvotes: 40

Erik
Erik

Reputation: 3218

I feel it's worth mentioning as of now there is CXX library in crate

https://docs.rs/cxx/latest/cxx/

https://cxx.rs/

This is what I will be using going forward in order to interoperate with a C++ Library from a vendor.

The assigned answer has a link but it's publicly archived and all active work is likely here :

https://github.com/dtolnay/cxx

Upvotes: 8

Daniel Trugman
Daniel Trugman

Reputation: 8511

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:

  • bindgen - Auto generation of FFI for Rust
  • cpp-to-rust - Allows to use C++ libraries from Rust. The main target of this project is Qt.

I didn't use them, so I can't recommend anything particular or share my experience, but good luck :)

Upvotes: 9

Related Questions