Перейти к содержанию

Сборка vozduxan через CMake

vozduxan — это статическая библиотека C++ (libvozduxan.a), оборачивающая libtorrent-rasterbar. Она находится в Git-субмодуле vozduxan/ и собирается из Rust build.rs через крейт cmake.

Источники: vozduxan/CMakeLists.txt, src-tauri/build.rs


Структура CMakeLists.txt

project(vozduxan VERSION 1.0.8 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15")  # минимальная версия macOS

Обнаружение libtorrent: трёхуровневая стратегия

1. find_package(LibtorrentRasterbar CONFIG)     # установленный CMake-пакет
   └─ не найден ──▶
2. pkg_check_modules(LIBTORRENT libtorrent-rasterbar)  # pkg-config
   └─ не найден ──▶
3. FetchContent: github.com/arvidn/libtorrent v2.0.10  # сборка из исходников
   BUILD_SHARED_LIBS = OFF
   OPENSSL_USE_STATIC_LIBS = ON
   install(TARGETS torrent-rasterbar ARCHIVE DESTINATION lib)

Вызов install() в пути FetchContent критически важен: он помещает libtorrent-rasterbar.a в <cmake_dst>/lib/, откуда build.rs может найти его через cargo:rustc-link-search.

Цель библиотеки vozduxan

add_library(vozduxan STATIC
    src/session.cpp
    src/api.cpp
)
target_link_libraries(vozduxan PRIVATE ${LT_TARGET})
install(TARGETS vozduxan ARCHIVE DESTINATION lib)
install(DIRECTORY include/ DESTINATION include)

Библиотека устанавливается в <cmake_dst>/lib/libvozduxan.a. build.rs линкует её как cargo:rustc-link-lib=static=vozduxan.


Интеграция с build.rs

fn build_vozduxan() {
    let vozduxan_dir = manifest_dir.parent().unwrap().join("vozduxan");

    let dst = cmake::Config::new(&vozduxan_dir)
        .profile("Release")
        .define("CMAKE_BUILD_TYPE", "Release")
        .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
        .define("OPENSSL_USE_STATIC_LIBS", "ON")  // только macOS
        .build();

    println!("cargo:rustc-link-search=native={}", dst.join("lib").display());
    println!("cargo:rustc-link-lib=static=vozduxan");
    // ...
}

cmake::Config::build() запускает CMake configure + build + install в директории, управляемой build-скриптом, внутри target/. Результирующий <dst>/lib/ добавляется в путь поиска линкера.

Платформо-зависимое линкование

После libvozduxan.a build.rs линкует её зависимости:

macOS:

cargo:rustc-link-lib=static=torrent-rasterbar      (статическая FetchContent)
  OR
cargo:rustc-link-lib=static=torrent-rasterbar      (Homebrew /opt/homebrew/lib)
  OR
cargo:rustc-link-lib=dylib=torrent-rasterbar        (Homebrew динамическая, запасной вариант)

cargo:rustc-link-lib=static=ssl
cargo:rustc-link-lib=static=crypto    ← Homebrew OpenSSL (предпочитает статическую .a)

cargo:rustc-link-lib=framework=SystemConfiguration
cargo:rustc-link-lib=framework=CoreFoundation
cargo:rustc-link-lib=framework=IOKit

OpenSSL предпочтительно линкуется как статический .a, чтобы избежать ошибок Library not loaded: .../libssl.dylib на машинах без Homebrew или с другими путями OpenSSL.

Linux:

cargo:rustc-link-lib=dylib=torrent-rasterbar  (или через pkg-config)
cargo:rustc-link-lib=dylib=ssl
cargo:rustc-link-lib=dylib=crypto
cargo:rustc-link-lib=dylib=pthread

Windows:

cargo:rustc-link-lib=static=torrent-rasterbar
cargo:rustc-link-lib=dylib=ws2_32
cargo:rustc-link-lib=dylib=iphlpapi

Стандартная библиотека C++ (link_cxx_stdlib) линкуется до libtorrent в порядке линкования, чтобы линкер разрешал символы C++ из libvozduxan.a перед обработкой символов libtorrent.

rerun-if-changed — ошибка с mtime директорий на macOS

rerun-if-changed Cargo на директорию реагирует только при изменении mtime директории. macOS (APFS) не обновляет mtime родительской директории при изменении файла внутри неё. Поэтому изменение vozduxan/src/session.cpp не вызвало бы пересборку.

build.rs перечисляет отдельные файлы C++ вместо этого:

for entry in std::fs::read_dir(vozduxan_dir.join("src")).flatten().flatten() {
    println!("cargo:rerun-if-changed={}", entry.path().display());
}
for entry in std::fs::read_dir(vozduxan_dir.join("include")).flatten().flatten() {
    println!("cargo:rerun-if-changed={}", entry.path().display());
}
println!("cargo:rerun-if-changed={}", vozduxan_dir.join("CMakeLists.txt").display());

Это гарантирует, что cargo tauri dev (режим наблюдения) корректно обнаруживает изменения в исходниках C++ на macOS.


Стандартная библиотека C++

fn link_cxx_stdlib() {
    #[cfg(target_os = "macos")]
    println!("cargo:rustc-link-lib=dylib=c++");    // libc++ (системная)
    #[cfg(target_os = "linux")]
    println!("cargo:rustc-link-lib=dylib=stdc++");  // libstdc++
    // Windows: MSVC CRT линкуется автоматически
}

Должна идти до libtorrent в порядке линкования.