如何在Windows上製做一個包含.lib和.dll的Rust Crate包

最近看了下Rust,做爲系統編程語言,真的是很複雜。我計劃作一個簡單的Rust模塊,用於調用Dynamsoft Barcode Reader SDK,而後打包發佈到https://crates.io/git

製做發佈Rust Crate包

建立Rust lib工程:github

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 <stdio.h>

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);
    }
}

接下來用bindgenreader.h轉換成reader.rsui

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文件的轉換。code

Cargo.toml中添加依賴orm

[build-dependencies]
cc = "1.0"
bindgen = "0.42.1"

生成reader.rs:blog

cargo build

在打包前,記得把文件類型添加到Cargo.toml中:token

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 <token>

發佈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<String> = 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 <image file>

源碼

https://github.com/dynamsoft-dbr/rust

相關文章
相關標籤/搜索