html tool

2020年6月29日星期一

rust dll



所有 Rust 示例,都将使用 cargo 和libc 箱子。 每个示例的Cargo.toml,都包含以下样板:

[dependencies]
libc = "*"

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

crate-type = ["cdylib"]会创建一个动态链接的库。 可查看 Cargo 文档的动态或静态库,了解更多信息.


让我们开始一些更复杂的东西,接受字符串参数。在 Rust 中,字符串由一组u8切片组成,并保证是有效的 UTF-8,允许NUL字节,在字符串内部。在 C 中,字符串只是指向一个char的指针,用一个NUL字节作为终止 (带整数值0) 。需要做一些转换工作,才能在处理好这两种表达。

extern crate libc;

use libc::{c_char, uint32_t};
use std::ffi::CStr;
use std::str;

#[no_mangle]
pub extern fn how_many_characters(s: *const c_char) -> uint32_t {
    let c_str = unsafe {
        assert!(!s.is_null());

        CStr::from_ptr(s)
    };

    let r_str = c_str.to_str().unwrap();
    r_str.chars().count() as uint32_t
}

获取一个 Rust 字符串切片 (&str) 需要几个步骤:

  1. 我们必须确保 C 指针不是NULL,因为 Rust 引用不能NULL。(会在 C 语言调用该函数,对应的,在 C 中,字符串只是指向一个char的指针,所以,该 Rust 函数的字符串参数,会迎来一个 C 指针。)

  2. 使用std::ffi::CStr包装指针。CStr将根据终止的NUL,计算字符串的长度。这需要一个unsafe区块,因为我们将解引用一个原始指针,Rust 编译器无法验证该指针,满足所有安全保证,因此程序员必须这样做。(unsafe的作用,不是说有多么特殊,只是为了让人们更快,且更好地注意到,存在安全隐患的代码。)

  3. 确保 C 字符串是有效的 UTF-8 ,并将其转换为 Rust 字符串切片。

  4. 使用字符串切片。

Python

#!/usr/bin/env python3
# coding: utf-8

import sys, ctypes
from ctypes import c_uint32, c_char_p

prefix = {'win32': ''}.get(sys.platform, 'lib')
extension = {'darwin': '.dylib', 'win32': '.dll'}.get(sys.platform, '.so')
lib = ctypes.cdll.LoadLibrary(prefix + "string_arguments" + extension)

lib.how_many_characters.argtypes = (c_char_p,)
lib.how_many_characters.restype = c_uint32

print(lib.how_many_characters("göes to élevên".encode('utf-8')))

Python 字符串,必须编码为 UTF-8,才能通过 FFI 边界.




没有评论:

发表评论