【问题标题】:How do I use C preprocessor macros with Rust's FFI?如何在 Rust 的 FFI 中使用 C 预处理器宏?
【发布时间】: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 宏只用于简单的事情。

【问题讨论】:

    标签: macros c-preprocessor ffi rust


    【解决方案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 ints 是私有的
    • @xcvr 不知道你是什么意思。在 C 中,所有项目都暴露在目标文件中,除非它们被标记为staticextern 只需要从 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:它根本不包含这样的符号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-10
      • 2020-02-09
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      相关资源
      最近更新 更多