如何将 C 预处理器宏与 Rust 的 FFI 一起使用?



我正在编写一些代码,该代码插入了用C的现有库。我希望能够使用CPP宏中的值。如果我有一个c include.h,看起来像这样:

#define INIT_FLAG 0x00000001

我希望能够在这样的生锈中使用它:

#[link(name="mylib")]
extern {
    pub static init_flag: c_int = INIT_FLAG;
}

我看过其他FFI代码,我看到很多人复制这些价值在Rust中,而不是从FFI中获取它们。这似乎有点脆弱,我也想处理通过CPP宏定义的更复杂的事物。在我的生锈文件上运行cpp只有在我确定我的CPP宏仅用于简单的事物。

这是不可能的,我认为将来不会有可能。C宏带来太多问题。如果您想在生锈源上运行cpp,可以手动执行。

如果您不想这样做,并且如果有很多常数,并且您也不想将其值从C代码复制到Rust,则可以制作一个C包装器,该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 Source几乎与您尝试实现的目标相同。但是,您需要C胶对象文件。

这仅仅是不可能的,因为C宏常数在运行时不代表任何对象或实体。这是因为cpp预处理器甚至在汇编之前都执行宏观扩展(并处理其余指令)。考虑以下片段:

#define INIT_FLAG 0x00000001
/* some code */
unsigned dummy() { return INIT_FLAG; }
/* some other code */

在摘要上运行cpp产生预处理的代码(SO称为汇编单元 translation单位),该代码 ) INIT_FLAG均由文字0x00000001

unsigned dummy() { return 0x00000001; }

然后,编译单元进行编译,从而导致对象文件,但现在没有INIT_FLAG的痕迹。因此,在针对对象文件链接时,您不能参考INIT_FLAG:它根本不包含此类符号。

最新更新