如何在 Rust 的 FFI 中使用 C 预处理器宏?
Posted
技术标签:
【中文标题】如何在 Rust 的 FFI 中使用 C 预处理器宏?【英文标题】:How do I use C preprocessor macros with Rust's FFI? 【发布时间】:2014-02-24 11:27:28 【问题描述】:我正在编写一些代码来连接用 C 编写的现有库。在我的 Rust 代码中,我希望能够使用来自 CPP 宏的值。如果我有一个如下所示的 C include.h:
#define INIT_FLAG 0x00000001
我希望能够像这样在 Rust 中使用它:
#[link(name="mylib")]
extern
pub static init_flag: c_int = INIT_FLAG;
我查看了其他 FFI 代码并且看到了很多人
在 Rust 中复制这些值,而不是从 FFI 中获取它们。
这似乎有点脆弱,我也希望能够处理
通过 CPP 宏定义的更复杂的东西。
只有在我确定我的 Rust 文件上运行 cpp
才会起作用
CPP 宏只用于简单的事情。
【问题讨论】:
【参考方案1】:这是不可能的,我认为将来也不可能。 C 宏给它们带来了太多的问题。如果你想在你的 Rust 源代码上运行 cpp
,你可以手动完成。
如果您不想这样做,并且如果有很多常量,并且您也不想将它们的值从 C 代码复制到 Rust,您可以创建一个 C 包装器,它将为全局变量提供这些值:
#define INIT_FLAG 0x00000001
...
const int init_flag = INIT_FLAG;
你编译这个文件,从中创建一个静态库并像往常一样链接到它:
$ gcc -c init_flag.c
$ ar r libinitflag.a init_flag.o
锈源:
use std::libc;
#[link(name="initflag", kind="static")]
extern
pub static init_flag: libc::c_int;
Rust 源几乎与您尝试实现的目标相同。但是,您将需要 C 粘合对象文件。
【讨论】:
我试过这样做,使用 build.rs 和 cc::Build::new() 但它似乎不喜欢链接器的工作方式。所有 -L 和 -l 标志看起来都不错,但它在链接时对静态变量有未定义的引用。 您可能需要将代码更改为extern const int
,因为 const int
s 是私有的
@xcvr 不知道你是什么意思。在 C 中,所有项目都暴露在目标文件中,除非它们被标记为static
。 extern
只需要从 C 代码中引用 other 项,不需要“导出”任何东西,因为没有 static
所有项都被“导出”。
我的错误。这是 C++ 与 C 不同的地方之一。【参考方案2】:
这是不可能的,因为 C 宏常量在运行时不代表任何对象或实体。这是因为 cpp
预处理器甚至在编译发生之前就执行宏扩展(并处理其余指令)。考虑以下 sn-p:
#define INIT_FLAG 0x00000001
/* some code */
unsigned dummy() return INIT_FLAG;
/* some other code */
在 sn-p 上运行cpp
会产生预处理代码(所谓的编译单元,或翻译单元),所有出现的INIT_FLAG
都被替换为文字0x00000001
:
unsigned dummy() return 0x00000001;
编译单元随后被编译,生成目标文件,但现在其中没有INIT_FLAG
的踪迹。因此,在链接目标文件时不能引用INIT_FLAG
:它根本不包含这样的符号。
【讨论】:
以上是关于如何在 Rust 的 FFI 中使用 C 预处理器宏?的主要内容,如果未能解决你的问题,请参考以下文章