Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tomcat-42/conan_cmake_rust_integration
simple example project to show how to safely call C++ code from Rust
https://github.com/tomcat-42/conan_cmake_rust_integration
Last synced: 25 days ago
JSON representation
simple example project to show how to safely call C++ code from Rust
- Host: GitHub
- URL: https://github.com/tomcat-42/conan_cmake_rust_integration
- Owner: Tomcat-42
- Created: 2023-11-28T18:26:29.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2023-11-28T19:14:53.000Z (about 1 year ago)
- Last Synced: 2023-12-03T22:25:00.096Z (about 1 year ago)
- Language: Rust
- Size: 2.17 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: Readme.md
Awesome Lists containing this project
README
## Conan/CMake Rust integration example
This is a simple example project to show how to safely call C++ code from Rust
using [conan-rs](https://github.com/Devolutions/conan-rs) and
[autocxx](https://github.com/google/autocxx).### Project Structure
![image](https://github.com/Tomcat-42/conan_cmake_rust_migration/assets/44649669/61ddd7f2-03a1-4a99-bf8c-2b449e533136)
#### cpp
The c++ targets uses [conan1](https://docs.conan.io/en/1.6/introduction.html) as the package manager and [CMake](https://cmake.org/). This is a very common setup in _enterprise_/_legacy_ c++ codebases.
In this example, we have a static library, that answers the ultimate question to _life, universe and everything_, and a command line interface to it:
![image](https://github.com/Tomcat-42/conan_cmake_rust_migration/assets/44649669/b9f0dbf0-690b-4b6d-ba96-2c9fd1d52953)
* Static lib:
```c++
#includenamespace deep_thought {
int answer() {
return 42;
}
} // namespace deep_thought
```* Cli:
```c++
#include#include
#include
#includeauto main() -> int {
auto task = []() {
std::cout << "Thinking..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(10));
std::cout << "The answer is " << deep_thought::answer() << std::endl;
};std::thread thread(task);
thread.join();
return 0;
}
```After building it, we have the following:
![image](https://github.com/Tomcat-42/conan_cmake_rust_migration/assets/44649669/cde44334-405a-4aa6-940b-11a0a8c3d124)
#### Rust
We can take advantage of the many application areas that Rust is more suited than C++ for extending the codebase. For example, [Writing C++ desktop applications is a very painful process](https://www.reddit.com/r/linuxmasterrace/comments/7xkcwo/why_does_everyone_hate_gtk/), so we can resource to the marvelous Rust [Tauri Framework](https://tauri.app/) for developing a good user experience, while maintaining the existing c++ code:
![image](https://github.com/Tomcat-42/conan_cmake_rust_migration/assets/44649669/dd72102e-4267-4bf4-8b6f-5d634da7afb3)
1. Here we use the [conan-rs](https://github.com/Devolutions/conan-rs) crate to abstract the deps instalation, building and packaging of our c++ artifacs. Also, we automatically generate Rust bindings "reading" the codebase header files using the wonderful google [autocxx](https://github.com/google/autocxx) crate. Finally, we link the c++ static lib to our Tauri binary to have a working application.
2. In the "Tauri backend"(in the `./src/app-rs/src/ext.rs` file) we actually tell _autocxx_ which c++ functions we want to generate code:
```rust
use autocxx::prelude::*;include_cpp! {
#include "deep_thought/answer.hpp"
safety!(unsafe_ffi)
generate!("deep_thought::answer")
}pub fn answer() -> i32 {
ffi::deep_thought::answer().into()
}
```And in the main Tauri binary file we can enroll this function to be used as a Tauri command:
```rust
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]use app_rs::ext;
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
fn answer() -> String {
ext::answer().to_string()
}fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![answer])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```3. Finally, we can invoke this file in the Tauri frontend (`./src/app-rs/src/app.rs`file):
```rust
...
let answer = {
let answer_msg_rc = answer_msg_rc.clone();
Callback::from(move |e: MouseEvent| {
e.prevent_default();
let answer_msg = answer_msg_rc.clone();spawn_local(async move {
let new_msg = invoke("answer", JsValue::UNDEFINED)
.await
.as_string()
.unwrap();
answer_msg.set(new_msg);
});
})
};
...
```With this, we have a fully fledged application, combining the strenghts of both Rust and C++:
![image](https://github.com/Tomcat-42/conan_cmake_rust_migration/assets/44649669/7dd7760d-431c-44f3-864f-8bf787ab5020)
## See more
For more details, read the full [article](https://tomcat0x42.me/conan_cmake_rust_migration).
## References
- [conan](https://docs.conan.io/en/1.6/introduction.html)
- [cmake](https://cmake.org/)
- [autocxx](https://github.com/google/autocxx)
- [conan-rs](https://github.com/Devolutions/conan-rs)
- [Tauri](https://tauri.app/)
- [cargo build scripts](https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)