1. 背景
最近在参与 USB 相关的项目,需要开发一个测试工具,用于最终产品的量产配置、测试,预计运行在 Windows 上。我从微软的网站上找到了为 USB 设备开发桌面应用的两篇文章:《为 USB 设备开发 Windows 应用程序的概述》《USB 设备的 Windows 桌面应用》,文章提到了两种实现方式,一是使用 Visual Studio 创建包含 WindUSB 的模板,基于这个模板进行开发,二是使用 WinUSB 函数访问 USB 设备,后者给的教程也是基于 WindUSB 模板创建主干应用……使用 Visual Studio 有点麻烦,想试试不用 Visual Studio 的方法。
在 crates.io 上检索 USB 时,找到了 libusb-rs,这个库实现了对 libusb 的 Rust 封装,而 libusb 是 C 语言实现的跨平台 USB 设备通用访问库。
2. 搭建开发环境
(1) Rust 开发环境
手头有搭建好的 Windows 上的 Rust 开发环境,工具链为 stable-x86_64-pc-windows-gnu,后端用的是 MinGW。
(2) 安装 pkg-config
按照 libusb-rs 的要求,需要安装 pkg-config,可以按照 Stack Overflow 上的教程进行安装:How to install pkg config in windows?
- go to http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/
- download the file pkg-config_0.26-1_win32.zip
- extract the file bin/pkg-config.exe to C:\MinGW\bin
- download the file gettext-runtime_0.18.1.1-2_win32.zip
- extract the file bin/intl.dll to C:\MinGW\bin
- go to http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28
- download the file glib_2.28.8-1_win32.zip
- extract the file bin/libglib-2.0-0.dll to C:\MinGW\bin
(3) 安装 libusb
下载 libusb 的源码,根据 README.txt 中的步骤将源码复制到对应的位置。需要特别注意一下链接库的选择,如果后续程序要静态链接 libusb,需要使用 MinGW64\static\ 下的 libusb-1.0.a,如果选择动态链接,需要使用 MinGW64\dll\ 下的 libusb-1.0.dll.a,并且后续运行编译好的二进制文件时,需要把运行时库 libusb-1.0.dll 放到可执行文件的同级目录下。后面会提到,选择哪种库可通过 pkg-config 的配置文件指定。
可按如下完整流程进行安装:
- 将 libusb 源码中 include目录下的libusb-1.0目录复制到工具链的默认头文件目录下,例如C:\MinGW\include
- 在工具链的库目录下创建 libusb-1.0目录
- 将 libusb 源码中 MinGW64目录下的static目录和dll目录复制到上一步创建的libusb-1.0目录中
a. 动态链接 libusb
在工具链的库目录新建目录 pkgconfig,例如 C:\MinGW\lib\pkgconfig ,目录中添加文件 libusb-1.0.pc:
1
2
3
4
5
6
7
8
9
10
prefix=C:\MinGW
exec_prefix=${prefix}
includedir=${prefix}/include/libusb-1.0
libdir=${exec_prefix}/lib/libusb-1.0/dll	# 动态链接库所在目录
Name: libusb
Description: libusb
Version: 1.0
Cflags: -I${includedir}
Libs: -L${libdir} -llibusb-1.0	# 使用动态链接库
设置环境变量 PKG_CONFIG_PATH,指向刚才创建的 pkgconfig 目录。
1
$env:PKG_CONFIG_PATH="C:\MinGW\lib\pkgconfig"
可以用如下命令验证下配置结果:
1
pkg-config --libs --cflags libusb-1.0
没有问题的话会输出如下信息:
-IC:/MinGW/include/libusb-1.0 -LC:/MinGW/lib/libusb-1.0/static -lusb-1.0
b. 静态链接 libusb
对之前创建的 libusb-1.0.pc 文件进行修改,将库所在的目录改为静态链接库所在的目录,将最后一行的链接库由 -llibusb-1.0 改为 -lusb-1.0:
1
2
3
4
5
6
7
8
9
10
prefix=C:\MinGW
exec_prefix=${prefix}
includedir=${prefix}/include/libusb-1.0
libdir=${exec_prefix}/lib/libusb-1.0/static	# 静态链接库所在目录
Name: libusb
Description: libusb
Version: 1.0
Cflags: -I${includedir}
Libs: -L${libdir} -lusb-1.0	# 使用静态链接库
按照同样的步骤,指定环境变量,没问题的话,验证会有如下输出:
-IC:/MinGW/include/libusb-1.0 -LC:/MinGW/lib/libusb-1.0/static -lusb-1.0
3. 运行示例程序
新建项目,例如 usb_test:
1
cargo new usb_test
在项目配置文件 Cargo.toml 中添加如下依赖:
1
libusb = "0.3.0"
在 main.rs 中创建如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
extern crate libusb;
fn main() {
    let context = libusb::Context::new().unwrap();
    for device in context.devices().unwrap().iter() {
        let device_desc = device.device_descriptor().unwrap();
        println!("Bus {:03} Device {:03} ID {:04x}:{:04x}",
            device.bus_number(),
            device.address(),
            device_desc.vendor_id(),
            device_desc.product_id());
    }
}
编译:
cargo build
运行时需要注意,如前面所说,如果选择了静态链接的方式,直接运行就可以,如果选择了动态链接 libusb 的方式,运行可执行文件前要将运行时库 libusb-1.0.dll 复制到可执行文件的同级目录下,否则会报如下错误:
error: process didn’t exit successfully:
target\debug\usb.exe(exit code: 0xc0000135, STATUS_DLL_NOT_FOUND)
例如,默认情况下,编译生成的可执行文件在 target\debug 目录内,故需将 libusb-1.0.dll 复制到 target\debug 目录下内,如果生成的是 release 版本,甚至是交叉编译版本,都需要放到对应的目录去,执行 cargo clean 后得重新拷贝,比较麻烦。
运行:
1
cargo run
