Я хочу вызвать библиотеку C "mysql.h" на языке Rust

Я пытаюсь подключиться к mysql из кода ржавчины. Я пробовал эти шаги.

  • 1. Я написал c-код, используя
mysql.h, и команду ниже.

 $ gcc -shared mysqlrust.c -o libmysqlrust.so  $(mysql_config --cflags) $(mysql_config --libs)   $(mysql_config --cflags)
 $ cp libmysqlrust.so /usr/local/lib/rustc/i686-unknown-linux-gnu/lib/
2. Я написал код Rust, который вызывает libmysqlrust.so.

Но я не мог понять, как использовать структуру типа C "MYSQL", "MYSQL_RES", "MYSQL_ROW". Пожалуйста, покажите мне, как использовать структуру типа c из кода ржавчины.

Ответ 1

Пока еще нет возможности автоматически создавать определения типа Rust из C-структур. В этих ситуациях есть несколько способов для продолжения. Не зная API MySQL, я не могу точно сказать, что вы должны делать, но вот несколько вариантов.

1) Рассматривайте их целиком как непрозрачные указатели.

Это лучшая ситуация, в которой вы находитесь, и зависит от API-интерфейса C, который всегда принимает структуру как указатель, имеет свои собственные функции конструктора и деструктора и предоставляет функции доступа для всего, что вам нужно для доступа внутри структуры. В этих случаях вы просто определяете type MYSQL = ctypes::void и только когда-либо используете его как небезопасный указатель *MYSQL. Иногда самый простой путь - написать свои собственные C-обертки, чтобы заполнить пробелы и сделать возможным этот сценарий.

Остальные сценарии включают переопределение структуры данных Rust с той же структурой, что и структура C. Rust пытается выложить свои структуры данных таким образом, который совместим с C (хотя это не всегда удается), поэтому часто можно создать запись или перечисление Rust с размером, выравниванием и компоновкой структуры C, которую вы заботиться. Вы хотите, чтобы вы использовали типы в core::ctypes, поскольку они определены для соответствия различным общим типам C.

Обратите внимание, что модуль ctypes скоро исчезнет в пользу более полного модуля совместимости libc.

2) Определите неправильную запись Rust.

Если API предоставляет конструкторы и деструкторы, но вам по-прежнему нужен доступ к некоторым полям структуры, вы можете определить, достаточно ли структуры, чтобы добраться до полей, о которых вы заботитесь, не обращая внимания на такие вещи, как правильные размеры и выравнивание. например type MSQL = { filler1: ctypes::int, ..., connector_fd: *ctypes::char }. Вы можете прекратить определение структуры в последнем поле, о котором вы заботитесь, поскольку у вас есть функция C, чтобы выделить ее в куче с правильным размером и выравниванием. В коде Rust вы всегда ссылаетесь на него с небезопасным указателем: let mysql: *MYSQL = mysqlrust::create_mysql();

3) Определите запись ржавчины, которая является правильным размером и выравниванием, не заботясь о содержимом.

Если у вас нет функций конструктора/деструктора или вам нужно сохранить структуру в стеке, но у вас есть другие функции доступа для управления содержимым структуры, тогда вам нужно определить запись ржавчины с правильным размером и выравнивание. Для этого просто добавьте поля типа uint (который всегда имеет размер указателя) или кортежи uint, пока оба C sizeof и core::sys::size_of не согласятся на размер. Pad с u8, если размер не кратен размеру указателя. Получение правильности выравнивания является более мистическим процессом, но, используя поля uint, вы, как правило, получаете удобное выравнивание (возможно, я действительно не знаю, насколько точным является этот оператор).

Я бы рекомендовал добавить тесты для проверки работоспособности, чтобы Rust и C договорились о размере, чтобы защитить от возможного повреждения.

3) На самом деле переопределите всю структуру C.

Это довольно тяжелая ситуация для больших структур, и это возможно в теории, но я не думаю, что кто-то сделал это для структуры размером с MYSQL. Я бы избегал этого, если можно. В конце концов, для этого будет создан инструмент, основанный на clang.

Вот несколько примеров взаимодействия с C-структурами:

https://github.com/jdm/rust-socket/blob/master/socket.rs - Это переопределяет различные структуры сокетов, добавляя заполнители для полей, на которые это не заботит. Обратите внимание, что для заполнения используется u8, но я думаю, что uint с большей вероятностью создаст правильное выравнивание.

https://github.com/erickt/rust-zmq/blob/master/zmq.rs

https://github.com/pcwalton/rust-spidermonkey - Это демонстрирует взаимодействие с несколько сложным API.