Подтвердить что ты не робот

Как я могу создать код Rust с проектом С++/Qt/CMake?

У меня есть существующий проект С++/Qt созданный с помощью CMake. Я хотел бы начать добавлять код Rust, который я могу вызвать из основной базы кода на С++.

Каков правильный способ структурирования проекта?

Текущая структура проекта:

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

Я хотел бы добавить каталог common-rust/... с аналогичной структурой.

Как я могу включить это в проект?

4b9b3361

Ответ 1

Для этого вы можете использовать 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 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).

Также обратите внимание, что это зависит от доступности Cargo на пути.

Вы должны быть хорошими, чтобы идти сейчас. Файл "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;
}

Здесь ссылка на рабочий проект .