snippetcppMajor
How can I build Rust code with a C++/Qt/CMake project?
Viewed 0 times
projectwithhowcmakerustcanbuildcode
Problem
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:
I'd like to add a
How can I incorporate this into the project?
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?
Solution
You can use the
So say you have your "common-rust" subdirectory and its Cargo.toml contains:
and it exposes a function
Then your top-level CMakeLists.txt could look something like this:
When you build the Rust target as a
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:
Here's a link to a working example project.
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
#include
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.
Code Snippets
[package]
name = "rust_example"
version = "0.1.0"
[lib]
name = "rust_example"
crate-type = ["staticlib"]#[no_mangle]
pub extern fn add(lhs: u32, rhs: u32) -> u32 {
lhs + rhs
}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)#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;
}Context
Stack Overflow Q#31162438, score: 93
Revisions (0)
No revisions yet.