最近看了下Rust,作为系统编程语言,真的是很复杂。我计划做一个简单的Rust模块,用于调用Dynamsoft Barcode Reader SDK,然后打包发布到https://crates.io/。
创建Rust lib工程:
cargo new dbr --lib
在lib.rs
中添加:
pub mod reader;
reader
模块对应reader.rs
文件,所以需要创建reader.h
, reader.c
:
// reader.h
typedef struct Barcode {
char* barcode_type;
char* barcode_value;
} Barcode;
typedef __int32 int32_t;
typedef void (*RustCallback)(int32_t, const char *, const char *);
int32_t register_callback(RustCallback callback);
void c_decodeFile(const char *fileName, const char *pszLicense);
// reader.c
#include "reader.h"
#include "DynamsoftBarcodeReader.h"
#include
RustCallback cb;
int32_t register_callback(RustCallback callback) {
cb = callback;
return 1;
}
void c_decodeFile(const char *fileName, const char *pszLicense)
{
void *hBarcode = DBR_CreateInstance();
if (hBarcode)
{
int ret = DBR_InitLicense(hBarcode, pszLicense);
STextResultArray *paryResult = NULL;
ret = DBR_DecodeFile(hBarcode, fileName, "");
DBR_GetAllTextResults(hBarcode, &paryResult);
int count = paryResult->nResultsCount;
printf("Barcode found: %d\n", count);
int i = 0;
for (; i < count; i++)
{
// printf("Index: %d, Barcode Type: %s, Value: %s\n", i, paryResult->ppResults[i]->pszBarcodeFormatString, paryResult->ppResults[i]->pszBarcodeText);
if (cb)
{
cb(i, paryResult->ppResults[i]->pszBarcodeFormatString, paryResult->ppResults[i]->pszBarcodeText);
}
}
DBR_FreeTextResults(&paryResult);
DBR_DestroyInstance(hBarcode);
}
}
接下来用bindgen
把reader.h
转换成reader.rs
:
cargo install bindgen
bindgen src/reader.h -o src/reader.rs
在根目录创建build.rs
用于构建工程。在构建的时候把.lib和.dll文件都拷贝到输出目录,然后把输出目录设置成库的查找路径:
extern crate cc;
extern crate bindgen;
use std::env;
use std::fs;
use std::path::Path;
fn main() {
// Get the output path
let out_dir = env::var("OUT_DIR").unwrap();
let package_offset = out_dir.find("package").unwrap_or(0);
if package_offset == 0 {
// Generates Rust FFI bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("src/reader.h")
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
bindings
.write_to_file("src/reader.rs")
.expect("Couldn't write bindings!");
}
// Build C code.
cc::Build::new()
.include("include")
.file("src/reader.c")
.compile("reader");
// Copy *.dll & .lib to the output path
let dll_src: String = String::from("./platforms/win/DynamsoftBarcodeReaderx64.dll");
let dll_dest_path = Path::new(&out_dir).join("DynamsoftBarcodeReaderx64.dll");
let _dll_result = fs::copy(dll_src, dll_dest_path);
let lib_src: String = String::from("./platforms/win/DBRx64.lib");
let lib_dest_path = Path::new(&out_dir).join("DBRx64.lib");
let _lib_result = fs::copy(lib_src, lib_dest_path);
// Link Dynamsoft Barcode Reader.
// println!("cargo:rustc-link-search={}", env!("DBR_LIB"));
println!("cargo:rustc-link-search={}", &out_dir);
println!("cargo:rustc-link-lib=DBRx64");
}
上面的代码除了库的链接,还包括C代码的编译以及.h文件到.rs文件的转换。
在Cargo.toml
中添加依赖
[build-dependencies]
cc = "1.0"
bindgen = "0.42.1"
生成reader.rs
:
cargo build
在打包前,记得把文件类型添加到Cargo.toml
中:
include = [
"**/*.lib",
"**/*.dll",
"**/*.rs",
"**/*.c",
"**/*.h",
"Cargo.toml",
]
[lib]
name = "dbr"
path = "src/lib.rs"
Crate打包:
cargo package
在https://crates.io/me生成token,通过命令行登录:
cargo login
发布Crate包:
cargo publish
这里是我制作的dbr
包:https://crates.io/crates/dbr
创建一个新的Rust工程:
cargo new test
在Cargo.toml
中添加依赖:
[dependencies]
dbr = "0.1.3"
编辑main.rs
:
extern crate dbr;
use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;
use std::env;
use dbr::reader::*;
extern "C" fn callback(index: i32, barcode_type: *const c_char, barcode_value: *const c_char) {
unsafe {
println!(
"Index {}, {}, {}",
index,
CStr::from_ptr(barcode_type).to_str().unwrap(),
CStr::from_ptr(barcode_value).to_str().unwrap()
);
}
}
fn main() {
let args: Vec = env::args().collect();
if args.len() == 1 {
println!("Please input an image file.");
return
}
println!("Hello Dynamsoft Barcode Reader!");
unsafe {
register_callback(Some(callback));
let image_file = CString::new(env::args().nth(1).expect("Missing argument")).unwrap();
let license = CString::new("t0068NQAAAFKYHV9xSZDEThUtClXNzxXH9TLSj/vYcY8mSKa0RxaGw3qNynyAMJ9Ib8UPxzFsbAMIugqPO313BvfiOdmZFTY=").unwrap();
c_decodeFile(image_file.as_ptr(), license.as_ptr());
}
println!("Bye!");
}
运行程序:
cargo run
https://github.com/dynamsoft-dbr/rust