13

我正在尝试从 rust 代码连接到 mysql。我已经尝试了这些步骤。

    mysql.h1. 我用, 和下面的命令 编写了 c 代码。
    
     $ 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”的方法。请告诉我如何使用 rust 代码中的 c 类型结构。

4

1 回答 1

18

目前还没有任何方法可以从 C 结构中自动创建 Rust 类型定义。在这些情况下,有几种方法可以继续。不知道 MySQL API,我不能确切地说你应该做什么,但这里有一些选项。

1)将它们完全视为不透明的指针。

这是最好的情况,并且依赖于 C API 始终将结构作为指针,拥有自己的构造函数和析构函数,并为您需要访问结构内部的任何内容提供访问器函数。在这些情况下,您只需定义type MYSQL = ctypes::void并且仅将其用作不安全指针*MYSQL。有时最简单的方法是编写自己的 C 包装器来填补空白并使这种情况成为可能。

剩下的场景都涉及重新定义一个与 C 结构相同结构的 Rust 数据结构。Rust 尝试以与 C 兼容的方式布局其数据结构(尽管并不总是成功),因此通常可以创建具有 C 结构的大小、对齐和布局的 Rust 记录或枚举关心。您需要确保使用 中的类型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) 定义一个大小和对齐正确的 Rust 记录,而不关心内容。

如果您没有构造函数/析构函数,或者需要将结构存储在堆栈上,但是您有访问函数来操作结构的内容,那么您需要定义具有正确大小和对齐方式的 Rust 记录。为此,只需添加类型的字段uint(始终是指针大小的)或 的元组uint,直到 Csizeof和Ccore::sys::size_of都同意大小。u8如果大小不是指针大小的倍数,则用s 填充。正确对齐是一个更神秘的过程,但是通过使用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 的互操作。

于 2012-02-26T21:56:26.143 回答