< 返回版块

洋芋 发表于 2020-10-22 21:31

Tags:rust, ffi

在上一篇中,我们整体介绍了 cbindgen 工具。本文将会示例如何使用 cbindgen 为我们之前写的 Rust 示例库 生成头文件。主要内容包括:

  • 生成的头文件和之前的对比
  • 为 C API 增加枚举类型,并生成头文件

使用 cbindgen.toml

我们知道可以通过 cbindgen.toml 这个配置文件,给 cbindgen 工具配置各种行为参数来生成头文件。示例库提供了 C API,那我们首先在示例库的根目录下创建一个 cbindgen.toml ,并且试试只配置以下一行内容:

language = "C"

然后执行以下命令:

cbindgen --config cbindgen.toml --crate example_03 --output example_03_header.h

我们可以看到,在根目录下生成了一个 example_03_header.h 的头文件。跟我们之前手动编写的头文件进行对比:

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

多了以上这几行 #include 文件,这是 cbindgen 工具的默认行为,它会默认导入这些 C/C++ 标准库。 我们如果不需要导入这些库时,可以通过增加以下配置内容:

no_includes = true

再执行生成命令后,这时我们可以看到这个头文件和我们之前手动编写的基本一样。

这时,如果我们想要在导出的头文件中类型统一加个前缀,比如:capi_,可以在 cbindgen.toml 增加以下配置:

[export]
prefix = "capi_"

增加枚举类型

为了演示 cbindgen 工具对 enum 枚举类型的支持,我们为示例增加个枚举类型,代码如下:

#[repr(C)]
#[derive(Debug)]
pub enum gender {
    BOY,
    GIRL,
}

同时,相应地修改函数中的一些代码:

#[no_mangle]
pub extern "C" fn student_alice() -> *mut student {
    let mut init_char_array: [c_char; 20] = [0; 20];
    for (dest, src) in init_char_array.iter_mut().zip(b"Alice\0".iter()) {
        *dest = *src as _;
    }
    let scores = [92.5, 87.5, 90.0];
    let alice = student {
        num: 1 as c_int,
        total: 280,
        name: init_char_array,
        scores,
        gender: gender::GIRL,
    };
    Box::into_raw(Box::new(alice))
}

这时,通过 cbindgen 工具生成头文件,我们可以看出新的头文件能正确地包含我们新增的枚举类型:

typedef enum {
  BOY,
  GIRL,
} capi_gender;

对于枚举类型中的变体,如果我们希望更符合 C 的风格,可以在 cbindgen.toml 中配置以下内容:

[enum]
rename_variants = "SnakeCase"

这个规则是针对枚举类型的变体进行重命名,主要的值包括(引用自 cbindgen 的文档):

# possible values (that actually do something):
# * "CamelCase": MyVariant => myVariant
# * "SnakeCase": MyVariant => my_variant
# * "ScreamingSnakeCase": MyVariant => MY_VARIANT
# * "QualifiedScreamingSnakeCase": MyVariant => ENUM_NAME_MY_VARIANT
# * "LowerCase": MyVariant => myvariant
# * "UpperCase": MyVariant => MYVARIANT
# * "None": apply no renaming

执行 cbindgen 后,可以看到头文件枚举部分的定义变为:

typedef enum {
  boy,
  girl,
} capi_gender;

小结

综上所述,我们演示了对于之前的 Rust 示例库,如何通过配置 cbindgen.toml 使用 cbindgen 生成头文件。

完整示例代码在 Github:https://github.com/lesterli/rust-practice/tree/master/ffi/example_03

hyper 的C API 也是通过 cbinggen 来生成头文件的,有兴趣的可以通过此链接围观。

评论区

写评论

还没有评论

1 共 0 条评论, 1 页