我想从Rust语言调用C库"mysql.h"

13

我正在尝试从 Rust 代码连接到 MySQL。我已经尝试了以下步骤。

  1. 我使用 mysql.h 编写了 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/
我编写了Rust代码,调用了libmysqlrust.so库。 但是我不知道如何使用C类型的结构体 "MYSQL","MYSQL_RES", "MYSQL_ROW"。 请告诉我如何在Rust代码中使用这些C类型的结构体。

2
让我们看看您编写的代码和确切的错误信息。 - mmmmmm
1
http://doc.rust-lang.org/doc/tutorial.html#passing-structures - Hans Passant
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元组的字段,直到C的sizeof和core::sys::size_of同意大小。如果大小不是指针大小的倍数,请使用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进行交互。


我在 Rust 中重新定义了这些结构体,并定义了函数。type MYSQL = ctypes::void; type MYSQL_RES = ctypes::void; type MYSQL_ROW = ctypes::void;然后我已经处理完毕。但是又出现了另一个问题。我无法将 **char 转换为 str 数组。我该如何解决?谢谢。 - Takuya Horimatsu
你需要使用不安全的代码来遍历C字符串数组并将它们转换为Rust字符串向量。类似于https://gist.github.com/1928234(未经测试)。 - brson
我明白了。 我已经成功使用了“str::from_cstr”不安全代码。 非常感谢。 :) - Takuya Horimatsu
@brson,区域里有任何更改吗? - OZ_

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接