最近在Radxa ROCK 3C开发板(RK3566芯片)上开发一个需要通过USB读取HID设备的项目时,遇到了需要编译安装libusb库的需求。作为一个在嵌入式领域摸爬滚打多年的开发者,我深知libusb在USB设备通信中的重要性——它是Linux系统下最常用的USB设备访问库之一,提供了用户空间访问USB设备的统一接口。
为什么选择从源码编译而不是直接apt安装?主要原因有三:
提示:在嵌入式开发中,从源码编译第三方库是常见做法,可以更好地控制编译参数和依赖关系。
在开始编译libusb之前,需要确保开发板上已安装必要的构建工具链。以下命令会安装编译所需的基础工具:
bash复制sudo apt update
sudo apt install -y build-essential pkg-config git autoconf automake libtool
这些包的作用分别是:
在通过git克隆源码时,可能会遇到HTTP/2协议相关的网络错误。这是因为某些网络环境对HTTP/2支持不完善导致的。解决方法是将git配置为使用HTTP/1.1协议:
bash复制git config --global http.version HTTP/1.1
如果克隆过程中出现超时错误(Error 56),通常是由于网络不稳定造成的。我的经验是:
使用git克隆最新的libusb源码仓库:
bash复制git clone https://github.com/libusb/libusb.git
cd libusb
建议在稳定分支上进行开发,而不是直接使用master分支。可以查看可用的发布版本:
bash复制git tag -l
git checkout v1.0.26 # 切换到稳定版本
现代开源项目通常使用autotools构建系统,但源码仓库中一般不包含生成的Makefile文件。我们需要先运行autogen.sh脚本:
bash复制sudo ./autogen.sh
在这个过程中可能会遇到udev相关的错误:
code复制configure: error: udev support requested but libudev header not installed
这是因为libusb默认启用了udev支持(用于设备热插拔通知),但系统缺少相关开发文件。解决方法:
bash复制sudo apt install -y libudev-dev
安装完成后重新运行autogen.sh即可。
运行configure脚本进行编译配置:
bash复制./configure --prefix=/usr/local --enable-shared --disable-static
关键参数说明:
注意:在嵌入式系统中,通常建议使用共享库以节省存储空间,除非有特殊需求必须使用静态链接。
配置完成后,就可以开始编译和安装了:
bash复制sudo make -j$(nproc) # 使用所有CPU核心并行编译
sudo make install
sudo ldconfig # 更新动态链接器缓存
-j$(nproc)参数可以让make使用所有可用的CPU核心进行并行编译,显著加快编译速度。
创建一个简单的测试程序test.c,用于验证libusb是否正常工作:
c复制#include <libusb-1.0/libusb.h>
#include <stdio.h>
int main() {
libusb_context *ctx = NULL;
ssize_t cnt;
// 初始化上下文
if (libusb_init(&ctx) < 0) {
fprintf(stderr, "Failed to initialize libusb\n");
return 1;
}
// 可选:开启调试日志(级别3为详细输出)
libusb_set_debug(ctx, 3);
// 获取设备列表
libusb_device **list;
cnt = libusb_get_device_list(ctx, &list);
if (cnt < 0) {
fprintf(stderr, "Failed to get device list\n");
libusb_exit(ctx);
return 1;
}
printf("Found %zd USB devices:\n", cnt);
for (int i = 0; i < cnt; i++) {
struct libusb_device_descriptor desc;
libusb_get_device_descriptor(list[i], &desc);
printf(" Bus %03d Device %03d: ID %04x:%04x\n",
libusb_get_bus_number(list[i]),
libusb_get_device_address(list[i]),
desc.idVendor, desc.idProduct);
}
// 释放资源
libusb_free_device_list(list, 1); // 第二个参数为1表示同时关闭设备
libusb_exit(ctx);
return 0;
}
使用pkg-config自动获取正确的编译和链接参数:
bash复制gcc test.c -o test_libusb $(pkg-config --cflags --libs libusb-1.0)
./test_libusb
如果一切正常,程序会列出当前连接的所有USB设备的信息,包括总线号、设备地址和厂商/产品ID。
如果编译时出现类似"libusb.h: No such file or directory"的错误,可能是由于:
解决方法:
bash复制# 检查头文件位置
find /usr -name libusb.h
# 如果安装在非标准路径,需要显式指定
gcc test.c -o test -I/path/to/include -L/path/to/lib -lusb-1.0
如果运行时报错"error while loading shared libraries",说明动态链接器找不到库文件。解决方法:
bash复制# 检查库文件是否在标准路径
ls /usr/local/lib/libusb-1.0.so
# 如果不在标准路径,需要更新链接器缓存
sudo ldconfig
# 或者临时设置LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH
普通用户访问USB设备可能需要root权限。长期解决方案是添加udev规则:
bash复制# 创建规则文件
sudo nano /etc/udev/rules.d/99-libusb.rules
# 添加以下内容(根据实际设备修改idVendor和idProduct)
SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666"
# 重新加载udev规则
sudo udevadm control --reload-rules
sudo udevadm trigger
libusb支持同步和异步两种I/O模式。对于高性能应用,建议使用异步API:
c复制#include <libusb-1.0/libusb.h>
void callback(struct libusb_transfer *transfer) {
// 处理传输完成事件
}
void async_example(libusb_device_handle *dev_handle) {
unsigned char buffer[64];
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
libusb_fill_interrupt_transfer(
transfer, dev_handle, 0x81, // 端点地址
buffer, sizeof(buffer), callback, NULL, 0);
libusb_submit_transfer(transfer);
// 需要在事件循环中处理事件
while (1) {
libusb_handle_events(NULL);
}
}
libusb不是线程安全的,但在多线程环境中使用时可以:
c复制// 线程安全初始化
libusb_init_thread(NULL, NULL, NULL);
通过注册热插拔回调,可以实时监测USB设备的插拔事件:
c复制static int hotplug_callback(libusb_context *ctx, libusb_device *dev,
libusb_hotplug_event event, void *user_data) {
// 处理热插拔事件
return 0;
}
void register_hotplug() {
libusb_hotplug_register_callback(NULL,
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
LIBUSB_HOTPLUG_ENUMERATE, 0x1234, 0x5678, LIBUSB_HOTPLUG_MATCH_ANY,
hotplug_callback, NULL, NULL);
}
在实际项目中使用libusb时,我总结了一些实用技巧:
调试技巧:
c复制libusb_set_debug(ctx, 3);
性能优化:
跨平台考虑:
错误处理:
固件开发配合:
在Radxa ROCK 3C这类资源有限的嵌入式设备上,还需要特别注意: