У меня есть C ++ / Qt проект построен с CMake. Я хотел бы начать добавлять код Rust, который я могу вызывать из основной кодовой базы C ++.
Как правильно структурировать проект?
Текущая структура проекта:
./CMakeLists.txt
./subproject-foo/CMakeLists.txt
./subproject-foo/src/...
./subproject-bar/CmakeLists.txt
./subproject-bar/src/...
./common/CMakeLists.txt
./common/src/...
Я хотел бы добавить common-rust/...
каталог с аналогичной структурой.
Как я могу включить это в проект?
Вы можете использовать ExternalProject
модуль за это. Он предназначен для построения внешних зависимостей — даже тех, которые не используют CMake. Вот полезная статья на его использовании.
Допустим, у вас есть подкаталог «common-rust», а его Cargo.toml содержит:
[package]
name = "rust_example"version = "0.1.0"
[lib]
name = "rust_example"crate-type = ["staticlib"]
и это выставляет функцию add
через его lib.rs:
#[no_mangle]
pub extern fn add(lhs: u32, rhs: u32) -> u32 {
lhs + rhs
}
Тогда ваш CMakeLists.txt верхнего уровня может выглядеть примерно так:
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)
Когда вы строите цель Rust как staticlib
он выводит, какие другие библиотеки должны быть связаны. Я только попробовал это на Windows, следовательно ws2_32
, userenv
, а также advapi32
связаны. Очевидно, это не будет кроссплатформенным, но вы можете справиться с этим достаточно легко (например, установите переменную в списке зависимостей, соответствующих каждой платформе внутри if..else
заблокировать и добавить, что в target_link_libraries
вызов).
Также обратите внимание, что это зависит от наличия груза на пути.
Тебе должно быть хорошо идти. Файл «cpp / main.cpp» может содержать что-то вроде:
#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;
}
Вот ссылка на рабочий пример проекта.