[记]Python使用Rust编译的DLL传递字符串
前记:
c/c艹能编译dll,现在多了选择,对 Rust;Rust编写编写dll库所需环境比c c艹确实方便许多,cargo new llib --lib即可创建一个链接库工程;
嗯,想起visual studio那些设置,还真是让人头大;
这里的记录为rust dll编写与python里字符串之间的传递处理:嗯 先放相关参考link:
#https://www.codenong.com/27127413/ #http://wiki.inford.net/Rust%E7%BC%96%E5%86%99DLL #https://www.cnblogs.com/FHC1994/p/11421229.html #https://rustcc.cn/article?id=f7505bac-1c2b-42ae-9c03-a830c6a2e6f7
其中 ,lib.rs
use std::os::raw::c_char; use std::ffi::{CStr, CString}; #[no_mangle] pub extern "C" fn print_str(s: *const c_char) { let slice = unsafe { assert!(!s.is_null()); CStr::from_ptr(s) }; let r_str = slice.to_str().unwrap(); println!("Rust side print: {:?}", r_str); } #[no_mangle] pub extern "C" fn change_str(s: *mut c_char) -> *mut c_char { let mut string = unsafe { assert!(!s.is_null()); CStr::from_ptr(s).to_string_lossy().into_owned() }; string.push_str(" World!"); println!("Rust side change: {:?}", string); let c_str_changed = CString::new(string).unwrap(); c_str_changed.into_raw() } #[no_mangle] pub extern "C" fn generate_str() -> *mut c_char { let ping = String::from("pin大g"); println!("Rust side generate: {:?}", ping); let c_str_ping = CString::new(ping).unwrap(); c_str_ping.into_raw() } #[no_mangle] pub extern "C" fn free_str(s: *mut c_char) { unsafe { if s.is_null() { return; } CString::from_raw(s) }; }
dll有三种生成标准,其调用也是操作不同
这里使用cdy的标准
需在Cargo.toml里添加相关配置
[package] name = "libtest" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] [lib] name = "testlib" #生成dll的文件名 crate-type = ["cdylib"]
然后再在项目路径执行 Cargo build --release即可生成链接库,
编译器在生成库的时候会修改函数名,为了正常调用则需要加上
from ctypes import cdll,c_char_p #by 博客园:戳人痛处 bili:崩析 lib = cdll.LoadLibrary(r"D:\pppython\python\RustByMe\LibRealse\libtest\target\release\testlib.dll") lib.print_str("hhhh".encode("utf-8")) lib.generate_str.restype = c_char_p data = lib.generate_str() print(data.decode())
py的调用则是对应rs里的函数明进行调用;
在rs里的字符串并不符合c生成dll库的接口标准,因此会涉及到字符指针的变换;
rs默认的String是一个结构体,不是单纯的字符串数组
python到dll库的调用可以参考c生成的dll库调用;
因为是字符数组,所以有一个编码成 u8的过程;
当然 读取也是一样;
需预先声明读取的数据类型然后再做处理;
运行效果如下;
中文字符也能很ok的传递并显示
->Pyo3
参考:Introduction - PyO3 user guide
pyo3是Rust对python的绑定,可以直接生成原生的python模块pyd(直接从二进制进行支持);
pip install maturin
PS D:\coded\ppyy\rspy\g1> maturin maturin 0.12.20 Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages USAGE: maturin.exe <SUBCOMMAND> OPTIONS: -h, --help Print help information -V, --version Print version information SUBCOMMANDS: build Build the crate into python packages develop Installs the crate as module in the current virtualenv help Print this message or the help of the given subcommand(s) init Create a new cargo project in an existing directory list-python Searches and lists the available python installations new Create a new cargo project publish Build and publish the crate as python packages to pypi sdist Build only a source distribution (sdist) without compiling upload Uploads python packages to pypi
编写的工程可以直接以rust源码的方式打包上传pypi,当需要使用时pip安装会自动下载源码并编译;
使用指令maturin new即可生成一个rust的pyd工程;
PS D:\coded\ppyy\rspy\g1> maturin init ? 🤷 Which kind of bindings to use? › ❯ pyo3 rust-cpython cffi bin
例程
use pyo3::prelude::*; /// Formats the sum of two numbers as string. #[pyfunction] fn sum_as_string(a: usize, b: usize) -> PyResult<String> { Ok((a + b).to_string()) } /// A Python module implemented in Rust. #[pymodule] fn g1(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; Ok(()) }
编译后的wheel
其中比较小的包是源码,比较大的包是直接编译的pyd模块;
可以通过rust的一些优化设置缩减编译pyd的体积;
使用pip就可以安装
通过py调用成功
---->
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!