Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I build Rust code with a C++/Qt/CMake project?

Tags:

c++

rust

cmake

qt

I have an existing C++/Qt project built with CMake. I'd like to start adding Rust code which I can invoke from inside the main C++ codebase.

What's the right way to structure the project?

Current project structure:

./CMakeLists.txt ./subproject-foo/CMakeLists.txt ./subproject-foo/src/... ./subproject-bar/CmakeLists.txt ./subproject-bar/src/... ./common/CMakeLists.txt ./common/src/... 

I'd like to add a common-rust/... directory with similar structure.

How can I incorporate this into the project?

like image 335
Daenyth Avatar asked Jul 01 '15 13:07

Daenyth


People also ask

Does CMake work with Rust?

Corrosion, formerly known as cmake-cargo, is a tool for integrating Rust into an existing CMake project. Corrosion is capable of importing executables, static libraries, and dynamic libraries from a crate.

What are CMake projects?

1. Basic CMake project CMake is a meta build system that uses scripts called CMakeLists to generate build files for a specific environment (for example, makefiles on Unix machines). When you create a new CMake project in CLion, a CMakeLists. txt file is automatically generated under the project root.


Video Answer


2 Answers

You can use the ExternalProject module for this. It's designed to allow building of external dependencies - even ones which don't use CMake. Here's a useful article on using it.

So say you have your "common-rust" subdirectory and its Cargo.toml contains:

[package] name = "rust_example" version = "0.1.0"  [lib] name = "rust_example" crate-type = ["staticlib"] 

and it exposes a function add via its lib.rs:

#[no_mangle] pub extern fn add(lhs: u32, rhs: u32) -> u32 {     lhs + rhs } 

Then your top-level CMakeLists.txt could look something like this:

add_executable(Example cpp/main.cpp)  # Enable ExternalProject CMake module include(ExternalProject)  # Set default ExternalProject root directory set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/Rust)  # Add rust_example as a CMake target ExternalProject_Add(     rust_example     DOWNLOAD_COMMAND ""     CONFIGURE_COMMAND ""     BUILD_COMMAND cargo build COMMAND cargo build --release     BINARY_DIR "${CMAKE_SOURCE_DIR}/common-rust"     INSTALL_COMMAND ""     LOG_BUILD ON)  # Create dependency of Example on rust_example add_dependencies(Example rust_example)  # Specify Example's link libraries target_link_libraries(Example     debug "${CMAKE_SOURCE_DIR}/common-rust/target/debug/librust_example.a"     optimized "${CMAKE_SOURCE_DIR}/common-rust/target/release/librust_example.a"     ws2_32 userenv advapi32)  set_target_properties(Example PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON) 

When you build the Rust target as a staticlib it outputs which other libraries should be linked. I've only tried this on Windows, hence ws2_32, userenv, and advapi32 are linked. This won't be cross-platform obviously, but you can handle that easily enough (e.g. set a variable to the list of dependencies appropriate to each platform inside an if..else block and append that in the target_link_libraries call).

Also note that this depends on Cargo being available in the path.

You should be good to go now. The file "cpp/main.cpp" could contain something like:

#include <cstdint> #include <iostream>  extern "C" {   uint32_t add(uint32_t lhs, uint32_t rhs); }  int main() {   std::cout << "1300 + 14 == " << add(1300, 14) << '\n';   return 0; } 

Here's a link to a working example project.

like image 167
Fraser Avatar answered Sep 29 '22 20:09

Fraser


There is now a project that can be used to build: Corrosion https://github.com/corrosion-rs/corrosion

So your CMakeLists.txt would just have this:

# See the Corrosion README to find more ways to get Corrosion find_package(Corrosion REQUIRED)  corrosion_import_crate(MANIFEST_PATH ${CMAKE_SOURCE_DIR}/common-rust) 
like image 42
Olivier Goffart Avatar answered Sep 29 '22 19:09

Olivier Goffart