xxxxxxxxxxcargo new rust-dylib-test --libcd rust-dylib-test/在 Cargo.toml 中添加:
xxxxxxxxxx[dependencies]libc = "0.2.133"
[lib]crate-type = ["cdylib"]修改 src/lib.rs:
xxxxxxxxxxuse std::collections::HashMap;use std::ffi::CStr;
pub struct ZipCodeDatabase { population: HashMap<String, u32>,}
impl ZipCodeDatabase { fn new() -> ZipCodeDatabase { ZipCodeDatabase { population: HashMap::new(), } }
fn populate(&mut self) { for i in 0..100_000 { let zip = format!("{:05}", i); self.population.insert(zip, i); } }
fn population_of(&self, zip: &str) -> u32 { self.population.get(zip).cloned().unwrap_or(0) }}
pub extern "C" fn zip_code_database_new() -> *mut ZipCodeDatabase { Box::into_raw(Box::new(ZipCodeDatabase::new()))}
pub extern "C" fn zip_code_database_free(ptr: *mut ZipCodeDatabase) { if ptr.is_null() { return; } unsafe { Box::from_raw(ptr); }}
pub extern "C" fn zip_code_database_populate(ptr: *mut ZipCodeDatabase) { let database = unsafe { assert!(!ptr.is_null()); &mut *ptr }; database.populate();}
pub extern "C" fn zip_code_database_population_of( ptr: *const ZipCodeDatabase, zip: *const libc::c_char,) -> u32 { let database = unsafe { assert!(!ptr.is_null()); &*ptr }; let zip = unsafe { assert!(!zip.is_null()); CStr::from_ptr(zip) }; let zip_str = zip.to_str().unwrap(); database.population_of(zip_str)}执行:
xxxxxxxxxxcargo build在 target/debug 可以看到动态链接库 librust_dylib_test.dylib(不同平台上前缀和扩展名可能不同)。
创建 Python 程序 test_dylib.py:
xxxxxxxxxx#!/usr/bin/env python3
import sysimport ctypesfrom ctypes import c_char_p, c_uint32, Structure, POINTER
class ZipCodeDatabaseS(Structure): pass
prefix = {'win32': ''}.get(sys.platform, 'lib')extension = {'darwin': '.dylib', 'win32': '.dll'}.get(sys.platform, '.so')# 注意:动态链接库的名字lib = ctypes.cdll.LoadLibrary(prefix + "rust_dylib_test" + extension)
lib.zip_code_database_new.restype = POINTER(ZipCodeDatabaseS)
lib.zip_code_database_free.argtypes = (POINTER(ZipCodeDatabaseS),)
lib.zip_code_database_populate.argtypes = (POINTER(ZipCodeDatabaseS),)
lib.zip_code_database_population_of.argtypes = (POINTER(ZipCodeDatabaseS), c_char_p)lib.zip_code_database_population_of.restype = c_uint32
class ZipCodeDatabase: def __init__(self): self.obj = lib.zip_code_database_new()
def __enter__(self): return self
def __exit__(self, exc_type, exc_value, traceback): lib.zip_code_database_free(self.obj)
def populate(self): lib.zip_code_database_populate(self.obj)
def population_of(self, zip_): return lib.zip_code_database_population_of(self.obj, zip_.encode('utf-8'))
with ZipCodeDatabase() as database: database.populate() pop1 = database.population_of("90210") pop2 = database.population_of("20500") print(pop1 - pop2)将 Python 源代码文件和上一步编译的动态链接库,放到相同目录下,然后执行:
xxxxxxxxxxpython3 test_dylib.py