mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-03 13:02:00 +00:00
62 lines
6.6 KiB
Markdown
62 lines
6.6 KiB
Markdown
# Интеграция библиотек на языке Rust в ClickHouse.
|
||
|
||
Интеграция библиотек будет описываться на основе работы проведенной для библиотеки BLAKE3.
|
||
|
||
Первым шагом интеграции является создание форка библиотеки для внесения дальнейших изменений по совместимости методов на Rust с C/C++.
|
||
|
||
В форке необходимо будет изменить конфигурацию Cargo.toml, сменив таргет на статическую библиотеку. Кроме того, необходимо добавить crate cbindgen для его дальнейшего использования при сборке.
|
||
|
||
Необходимо создать либо отредактировать сборочный скрипт build.rs, добавив в него запуск cbindgen - автогенератора заголовочных файлов .h. Пример такого запуска можно увидеть в build.rs для BLAKE3:
|
||
|
||
```
|
||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||
|
||
let package_name = env::var("CARGO_PKG_NAME").unwrap();
|
||
let output_file = ("include/".to_owned() + &format!("{}.h", package_name)).to_string();
|
||
|
||
match cbindgen::generate(&crate_dir) {
|
||
Ok(header) => {
|
||
header.write_to_file(&output_file);
|
||
}
|
||
Err(err) => {
|
||
panic!("{}", err)
|
||
}
|
||
}
|
||
```
|
||
|
||
Скрипт назначает директорию для создания залоговочного файла и в конце запускает метод генерации cbindgen.
|
||
|
||
Далее необходимо подключить библиотеку к CMake. В BLAKE3 для этого были созданы два файла - CMakeLists.txt и файл, содержащий функцию для запуска cargo build как таргета, - build_rust_lib.cmake. Последний стоит скопировать в подключаемую библиотеку и отредактировать в соотвествии с требуемыми параметрами для сборки - добавить флаги или какие-либо настройки для разных архитектур.
|
||
|
||
Завершив настройку CMake, можно приступить к созданию методов-прослоек, которые обеспечат совместимость библиотеки и остального кода ClickHouse. В частности, рассмотрим такой метод, написанный для BLAKE3:
|
||
|
||
```
|
||
#[no_mangle]
|
||
pub unsafe extern "C" fn blake3_apply_shim(
|
||
begin: *const c_char,
|
||
_size: u32,
|
||
out_char_data: *mut u8,
|
||
) -> *mut c_char {
|
||
if begin.is_null() {
|
||
let err_str = CString::new("input was a null pointer").unwrap();
|
||
return err_str.into_raw();
|
||
}
|
||
let mut hasher = Hasher::new();
|
||
let input_bytes = CStr::from_ptr(begin);
|
||
let input_res = input_bytes.to_bytes();
|
||
hasher.update(input_res);
|
||
let mut reader = hasher.finalize_xof();
|
||
reader.fill(std::slice::from_raw_parts_mut(out_char_data, OUT_LEN));
|
||
std::ptr::null_mut()
|
||
}
|
||
```
|
||
|
||
На вход метод принимает строку в C-совместимом формате, её размер и указатель, в который будет положен результат. Кроме того, для того, чтобы иметь возможность вывести ошибку, метод возвращает строку с ней как результат работы (и нулевой указатель в случае отсутствия ошибок). C-совместимые не используются в методах BLAKE3, поэтому они конвертируются посредством соотвествующих структур и методов в привычные форматы для языка Rust. Далее запускаются оригинальные методы библиотеки. Их результат следует преобразовать обратно в C-совместимые структуры, однако в данном случае удается избежать обратной конвертации, поскольку библиотека поддерживает запись напрямую по указателю *mut u8.
|
||
|
||
Кроме того, стоит отметить обязательность аттрибута #[no_mangle] и указания extern "C" для всех таких методов. Без них не удастся провести корректную совместимую с C/C++ компиляцию и автогенерацию заголовков.
|
||
|
||
После этих действий можно протестировать компиляцию и работу методов на небольшом проекте для выявляения несовместимостей и ошибок. Если возникают пробемы с генерацией заголовков, может потребоваться поработать с конфигурацией cbindgen через файл cbindgen.toml, найти который можно либо в BLAKE3, либо взяв оригинальный темплейт разработчика cbindgen: [https://github.com/eqrion/cbindgen/blob/master/template.toml](https://github.com/eqrion/cbindgen/blob/master/template.toml).
|
||
|
||
В заключение, стоит отметить пару пробелм, возникших при интеграции BLAKE3:
|
||
1) Некоторые архитектуры могут потребовать настройки компиляции в build.rs и в build_rust_lib.cmake в связи со своими особенностями.
|
||
2) MemorySanitizer плохо понимает инициализацию памяти в Rust, поэтому для избежания ложноположительных срабатываний для BLAKE3 был создан альтернативный метод, который более явно, но при этом медленнее, инициализировал память. Он компилируется только для сборки с MemorySanitizer и в релиз не попадает. Вероятно, возможны и более красивые способы решения этой проблемы, но при интеграции BLAKE3 они не были обнаружены. |