xxxxxxxxxx
cargo new rust-dylib-test --lib
cd rust-dylib-test/
在 Cargo.toml 中添加:
xxxxxxxxxx
[dependencies]
libc = "0.2.133"
[lib]
crate-type = ["cdylib"]
修改 src/lib.rs:
xxxxxxxxxx
use 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)
}
执行:
xxxxxxxxxx
cargo build
在 target/debug 可以看到动态链接库 librust_dylib_test.dylib(不同平台上前缀和扩展名可能不同)。
创建 Python 程序 test_dylib.py:
xxxxxxxxxx
#!/usr/bin/env python3
import sys
import ctypes
from 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 源代码文件和上一步编译的动态链接库,放到相同目录下,然后执行:
xxxxxxxxxx
python3 test_dylib.py