10 releases
0.1.9 | Aug 6, 2024 |
---|---|
0.1.8 | Aug 6, 2024 |
0.1.7 | Jul 3, 2024 |
0.1.6 | Jun 21, 2024 |
0.1.4 | Apr 29, 2024 |
#86 in FFI
33KB
732 lines
Direct call cpp from Rust!
directcpp
is yet another method to interop c++ with rust.
It's designed to be lightweight, efficient, MSVC-friendly, no cpp side code generation, work with outer c++ build tools like visual studio.
If you're looking for a way to work with c++ and rust with Visual Studio, directcpp
might be the result.
why not use crate cxx
Crate cxx
is a powerful crate for c++/rust interop. However, in my environment visual studio is important, I need it to debug my c++ code. For MSVC, crate cxx
is not friendly enough. It has pre-compiled c++ code and cannot be compiled in the debug configuration. Specifically, it's because code compiled with the iterator debugging doesn't work together with code compiled without it.
At the same time, I do not want the code generator to make all the code required for interaction. That seems to create a natural barrier between C++ and Rust. I hope that Rust can use C++ code like a normal lib. Of course, it doesn't come without a cost, and I will try to use these interfaces as little as possible. Therefore, I hope that the interfaces that need to be used can be arbitrary and do not need to strictly follow a certain paradigm.
Of course, security is still very important, and I don't want to make too many compromises on the C++ side and make a lot of strange functions for Rust. The same goes for the rust side. Don't convert some structures into a form that can be recognized by c++ in order to call c++ -- though I did that at the beginning -- because it looked quite cumbersome. Some shitty code takes up large chunks of my text, making it difficult for me to read my own code.
Therefore, I chose to generate a small number of very free interfaces so that rust can freely call C++ code with 99% security. I dare not say it is 100%, although crate cxx does this. After all, when you call C++ from Rust, you can cache any pointer you get from C++, which is your freedom, but it is also the price you pay for your freedom.
Getting started
If you want to get started with directcpp
, you can start by reading the test code of it. They are in the directory test_proj
in github where I also demonstrate how to make visual studio and rust coexist peacefully, and debug version compilation is also supported as I used a hacker's method to allow rust to link to the msvcrtd
debugging library.
You can try the simplest one first:
use directcpp;
#[directcpp::bridge]
extern "C++" {
pub fn on_start();
}
And in your cpp file, write:
void on_start(void)
{
std::cout << "on cpp side start!" << std::endl;
}
Note extern "C"
is not needed. Rust would directly call the mangled version of the c++ function. This is why it's called directcpp
.
You can also pass a reference of a struct into c++ and get another struct back:
#[directcpp::bridge]
extern "C++" {
pub fn on_magic(magic: &MagicIn) -> MagicOut;
}
To do this , the MagicIn
and MagicOut
struct should have exactly the same memory layout between c++ and rust. I provided the rust_spt.h
in github
which you can freely include that. This is the price for no code generation on c++ side, and gives the freedom to write and compile c++ code arbitrarily.
You can also get a class object pointer from c++ side and call its member functions while keeping the safety by SharedPtr
/std::shared_ptr
in rust/c++, respectively. Check code in test_proj.
You may need to generate some code in your way, thought, as I used rust2h.py
to generate some c++ structure from rust, keeping the same memory layout of the them, like MagicIn
and MagicOut
. The rust2h.py
should not be considered be a part of directcpp
, but they with other stuff all work together to make the final product. So directcpp
is a loosely organized library which offers the most freedom, but it may take you a little time to get used to it.
I have put rust2h.py
into tools folder. However, convert such structures is not hard, you can even do that by some text manipulation tools like sed
.
Special Mappings
Normally directcpp
maps a name in argument as the same named type with C++. However, there are some special types:
&CStr
maps to:const char*
in C++&str
maps toconst char*, size_t
in C++.&[u8]
maps toconst uint8_t*, size_t
in C++.String
maps toRustString
Tested On
- windows with MSVC, x86_64
- Linux, x86_64
- MacOS, x86_64
- MacOS, aarch64
Dependencies
~2.5–4MB
~78K SLoC