Библиотеки Rust
Интеграция библиотек Rust будет описана на основе интеграции функции хеширования BLAKE3.
Первый шаг интеграции - это добавление библиотеки в папку /rust. Для этого необходимо создать пустой проект Rust и включить необходимую библиотеку в Cargo.toml. Также необходимо настроить компиляцию новой библиотеки как статическую, добавив crate-type = ["staticlib"]
в Cargo.toml.
Далее необходимо связать библиотеку с CMake с помощью библиотеки Corrosion. Первый шаг - это добавить папку библиотеки в CMakeLists.txt внутри папки /rust. После этого следует добавить файл CMakeLists.txt в каталог библиотеки. В нем нужно вызвать функцию импорта Corrosion. Эти строки использовались для импорта BLAKE3:
Таким образом, мы создадим правильную цель CMake с использованием Corrosion, а затем переименуем ее в более удобное название. Обратите внимание, что имя _ch_rust_blake3
происходит из Cargo.toml, где оно используется как имя проекта (name = "_ch_rust_blake3"
).
Поскольку типы данных Rust не совместимы с типами данных C/C++, мы будем использовать наш пустой проект библиотеки для создания шим-методов для преобразования данных, полученных из C/C++, вызова методов библиотеки и обратного преобразования для выходных данных. Например, этот метод был написан для BLAKE3:
Этот метод получает C-совместимую строку, её размер и указатель на выходную строку в качестве входных данных. Затем он преобразует C-совместимые вводимые данные в типы, используемые фактическими методами библиотеки, и вызывает их. После этого следует преобразовать выходные данные методов библиотеки обратно в C-совместимый тип. В данном случае библиотека поддерживала прямую запись в указатель с помощью метода fill(), поэтому преобразование не понадобилось. Главное здесь - создавать меньше методов, чтобы вам не пришлось делать много преобразований при каждом вызове метода и не создавать значительных накладных расходов.
Следует отметить, что атрибут #[no_mangle]
и extern "C"
обязательны для всех таких методов. Без них невозможно будет выполнить правильную компиляцию, совместимую с C/C++. Более того, они необходимы для следующего шага интеграции.
После написания кода для шим-методов необходимо подготовить заголовочный файл для библиотеки. Это можно сделать вручную или можно использовать библиотеку cbindgen для автоматической генерации. В случае использования cbindgen потребуется написать скрипт сборки build.rs и включить cbindgen как зависимость для сборки.
Пример скрипта сборки, который может автоматически сгенерировать заголовочный файл:
Также вы должны использовать атрибуты #[no_mangle] и extern "C"
для каждого C-совместимого атрибута. Без них библиотека может некорректно скомпилироваться, и cbindgen не запустит автоматическую генерацию заголовка.
После всех этих шагов вы можете протестировать свою библиотеку в небольшом проекте, чтобы выявить все проблемы с совместимостью или генерацией заголовков. Если возникнут проблемы во время генерации заголовков, вы можете попробовать настроить их с помощью файла cbindgen.toml (шаблон можно найти здесь: https://github.com/eqrion/cbindgen/blob/master/template.toml).
Стоит отметить проблему, которая возникла при интеграции BLAKE3: MemorySanitizer может вызывать ложные срабатывания, так как он не может определить, инициализированы ли некоторые переменные в Rust. Эта проблема была решена написанием метода с более явным определением для некоторых переменных, хотя эта реализация метода медленнее и используется только для исправления сборок MemorySanitizer.