如何在Rust的FFI中使用C预处理器宏?

时间:2014-01-31 16:55:54

标签: macros c-preprocessor ffi rust

我正在编写一些代码来连接用C编写的现有库。在我的Rust代码中,我希望能够使用来自CPP宏的值。如果我有一个C include.h,它看起来像这样:

#define INIT_FLAG 0x00000001

我希望能够像Rust一样在Rust中使用它:

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

我看过其他FFI代码,我看到很多人 在Rust中复制这些值而不是从FFI中获取它们。 这看起来有点脆弱,我也希望能够处理 通过CPP宏定义的更复杂的东西。 在我的Rust文件上运行cpp只有在我确定我的情况下才有效 CPP宏仅用于简单的事情。

2 个答案:

答案 0 :(得分:13)

这是不可能的,我认为将来不可能。 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

Rust来源:

use std::libc;

#[link(name="initflag", kind="static")]
extern {
    pub static init_flag: libc::c_int;
}

Rust源几乎与您尝试实现的完全相同。但是,您将需要C glue目标文件。

答案 1 :(得分:5)

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

#define INIT_FLAG 0x00000001

/* some code */

unsigned dummy() { return INIT_FLAG; }

/* some other code */

在代码段上运行cpp会产生预处理代码(所谓的编译单元翻译单元),其中所有代码都被替换为INIT_FLAG文字0x00000001

unsigned dummy() { return 0x00000001; }

编译单元然后被编译,产生目标文件,但现在没有INIT_FLAG的痕迹。因此,在链接目标文件时,您无法引用INIT_FLAG:它只是不包含此类符号。