#syntex #build-tool #ffi #c

rust_c

在您的 Rust 代码中内联编写 C 代码(rust-cpp / cpp crate 的 hacky 衍生版)

2 个版本

使用旧的 Rust 2015

0.1.2 2018 年 4 月 10 日
0.1.1 2017 年 4 月 28 日
0.1.0 2017 年 4 月 24 日

#1381Rust 模式

MPL-2.0 许可证

23KB
450

rust-c

rust-cpp 版本 0.1.0 衍生而来,用于在没有完整 C++ 编译器或无需编译器的情况下。这是一个相当 hacky 的实现,旨在在 Rust 成熟到足以替换一些 C 代码之前启动一些片段。我自己无法从头开始编写这个,所以向 @mystor 致敬。有一天这个 crate 可能会消失,并融入 rust-cpp

以下注释来自 rust-cpp,对 C++ 和 cpp 进行了少量更改以适应 C 和 c,等。

rust-c 是一个构建工具和宏,它使您能够在 Rust 代码中内联编写 C 代码。

注意:此 crate 在稳定版 Rust 上工作,但它本身不是稳定的。您可以随意使用此版本,但当发布 0.2 版本时,可能会完全破坏向后兼容性。我认为这个 crate 更像一个实验,而不是一个产品。

随着工具逐渐稳定,我相信它也将稳定。具体来说,我不期望在这个模块有一个相对稳定的接口,直到我们获得一个稳定的程序宏系统。

设置

c 添加为您的项目的依赖项。它需要作为构建依赖项和普通依赖项添加,使用不同的标志。您还需要为您的项目设置一个 build.rs

[package]
# ...
build = "build.rs"

[build-dependencies]
# ...
c = { version = "0.1.0", features = ["build"] }

[dependencies]
# ...
c = { version = "0.1.0", features = ["macro"] }

然后,您还需要从您的 build.rs 调用 c 构建插件。它应该看起来像这样

extern crate c;

fn main()
{
    c::build("src/lib.rs", "crate_name", |cfg|
    {
        // cfg is a gcc::Config object. You can use it to add additional
        // configuration options to the invocation of the C compiler.
    });
}

使用

在您的 crate 中包含 cpp crate 宏

#[macro_use]
extern crate c;

然后,使用 c! 宏来定义您希望在 Rust 和 C 之间共享的代码和其他逻辑。c! 宏支持以下形式

c!
{
    // Include a C header into the C shim. Only the `#include` directive 
    // is supported in this context.
    #include <stdlib.h>
    #include "foo.h"
    
    // Write some logic directly into the shim. Either a curly-braced block or
    // string literal are supported
    raw
    {
        #define X 10
        struct Foo
        {
            uint32_t x;
        };
    }
    
    raw r#"
        #define Y 20
    "#
    
    // Define a function which can be called from rust, but is implemented in
    // C. Its name is used as the C function name, and cannot collide with
    // other C functions. The body may be defined as a curly-braced block or 
    // string literal.
    // These functions are unsafe, and can only be called from unsafe blocks.
    fn my_function(x: i32 as "int32_t", y: u64 as "uint32_t") -> f32 as "float"
    {
        return (float)(x + y);
    }
    fn my_raw_function(x: i32 as "int32_t") -> u32 as "uint32_t" r#"
        return x;
    "#
    
    // Define a struct which is shared between C and rust. In C-land its
    // name will be in the global namespace (there's only one)! In rust it will be located 
    // wherever the c! block is located
    struct MyStruct
    {
        x: i32 as "int32_t",
        y: *const i8 as "const char*",
    }
    
    // Define an enum which is shared between C and rust. In C-land it 
    // will be defined in the global namespace as an `enum` (there's only one)!. In rust,
    // it will be located wherever the c! block is located.
    enum MyEnum
    {
        A, // Known in C as `A`
        B,
        C,
        D,
    }
}

c 还提供了一个可能对互操作代码有用的头文件。该头文件包含 <stdint.h>。此头文件,rust_types.h,可以通过以下方式包含:-

c!
{
    #include "rust_types.h"
}

rust_types.h 的完整内容如下。

#ifndef _RUST_TYPES_H_
#define _RUST_TYPES_H_

#include <stdint.h>

typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef intptr_t isize;

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef uintptr_t usize;

typedef float f32;
typedef double f64;

typedef u8 bool_;

typedef uint32_t char_;

#endif

关于宏的警告

rust-cpp 无法识别和解析由宏生成的 cpp! 块中找到的信息。这些块可以正确生成 Rust 代码,但不会生成相应的 C++ 代码,这很可能会导致构建失败,出现链接错误。为了避免这种情况,请不要使用宏创建以下格式的 cpp! {} 块。

依赖关系

~0–495KB
~11K SLoC