25个版本

0.14.25 2024年6月20日
0.14.24 2024年3月16日
0.14.22 2024年2月8日
0.14.19 2023年9月14日
0.13.11 2021年11月30日

#131 in FFI

Download history 462/week @ 2024-04-24 537/week @ 2024-05-01 356/week @ 2024-05-08 388/week @ 2024-05-15 669/week @ 2024-05-22 723/week @ 2024-05-29 405/week @ 2024-06-05 421/week @ 2024-06-12 701/week @ 2024-06-19 653/week @ 2024-06-26 755/week @ 2024-07-03 395/week @ 2024-07-10 437/week @ 2024-07-17 302/week @ 2024-07-24 558/week @ 2024-07-31 390/week @ 2024-08-07

1,752 每月下载量
用于 edge-transformers

MIT 许可证

205KB
3.5K SLoC

Interoptopus 生成CPython绑定。

用法

假设您已经编写了一个包含您的FFI逻辑的crate,名为 example_library_ffi,并希望为Python 3.7+生成 CPython绑定,请按照以下说明操作。

在您的库中

Interoptopus 属性添加到您编写的库中,并定义一个库存函数,列出您希望导出的所有符号。所有支持的结构概述可以在 参考项目 中找到。

use interoptopus::{ffi_function, ffi_type, Inventory, InventoryBuilder, function};

#[ffi_type]
#[repr(C)]
pub struct Vec2 {
    pub x: f32,
    pub y: f32,
}

#[ffi_function]
#[no_mangle]
pub extern "C" fn my_function(input: Vec2) -> Vec2 {
    input
}

pub fn my_inventory() -> Inventory {
    InventoryBuilder::new()
        .register(function!(my_function))
        .inventory()
}

将这些添加到您的 Cargo.toml 中,以便可以找到属性和绑定生成器(将 ... 替换为最新版本)

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
interoptopus = "..."
interoptopus_backend_cpython = "..."

tests/bindings.rs 中创建一个单元测试,该测试在运行 cargo test 时会生成您的绑定。在实际项目中,您可能希望将此代码添加到另一个crate中

use interoptopus::util::NamespaceMappings;
use interoptopus::{Error, Interop};

#[test]
fn bindings_cpython_cffi() -> Result<(), Error> {
    use interoptopus_backend_cpython::{Config, Generator};

    let library = example_library_ffi::my_inventory();

    Generator::new(Config::default(), library)
        .write_file("bindings/python/example_library.py")?;

    Ok(())
}

现在运行 cargo test

如果有什么不清楚的地方,您可以在GitHub上的工作示例中找到。

生成输出

以下输出是此后端可能生成的。如果您想自定义某些内容,请查看 Config 结构。如果您真的不喜欢某些内容的生成方式,很容易 创建自己的

from __future__ import annotations
import ctypes
import typing

T = typing.TypeVar("T")
c_lib = None

def init_lib(path):
    """Initializes the native library. Must be called at least once before anything else."""
    global c_lib
    c_lib = ctypes.cdll.LoadLibrary(path)
    c_lib.my_function.argtypes = [Vec2]
    c_lib.my_function.restype = Vec2


def my_function(input: Vec2) -> Vec2:
    return c_lib.my_function(input)


TRUE = ctypes.c_uint8(1)
FALSE = ctypes.c_uint8(0)


class Vec2(ctypes.Structure):
    # These fields represent the underlying C data layout
    _fields_ = [
        ("x", ctypes.c_float),
        ("y", ctypes.c_float),
    ]

    def __init__(self, x: float = None, y: float = None):
        if x is not None:
            self.x = x
        if y is not None:
            self.y = y

    @property
    def x(self) -> float:
        return ctypes.Structure.__get__(self, "x")

    @x.setter
    def x(self, value: float):
        return ctypes.Structure.__set__(self, "x", value)

    @property
    def y(self) -> float:
        return ctypes.Structure.__get__(self, "y")

    @y.setter
    def y(self, value: float):
        return ctypes.Structure.__set__(self, "y", value)

依赖关系