libusb库在嵌入式Linux平台上的移植流程

2020-10-20

关键字:libusb在嵌入式上编译


 

1、why libusb?

 

libusb是一种跨平台的用C语言实现的开源USB通信库。简单来说,任何程序员都可以借用libusb库封装出来的接口在应用层高效便捷地开发基于USB通信协议的程序。

 

如果没有libusb,开发一款使用USB协议通信的程序就必须要下探到驱动层才行。也许有人会说,既然都做到USB通信这块了,那几乎都是涉及到U口设备相关的软件开发了,这种已经在跟硬件打交道的程序员多多少少都懂点驱动开发知识的,甚至有很多这种软件的定位本身就是一个驱动程序,所以不引入libusb库而直接开发一款传统意义上的驱动程序一点问题也没有。没错,但是请你再考虑的更加深入一点:假设我们就将软件需求以传统的驱动程序形式实现出来了,它同时也运行良好,这时突然来了个需求,要求我们将这款软件兼容另外一个系统平台,那我们是不是只能将源码拷贝出一份副本并修改相关系统调用以适配那个系统,然后还要用它的SDK来重新编译生成驱动才行?如此,可以轻易预见当程序需要兼容的平台多了以后其开发与维护难度是迅速飙升的。而当我们引入了libusb库以后,这一问题就几乎不存在了,唯一可能还需要我们做的就是编译适配不同系统平台的库文件出来,但它也只需要敲几条命令重新编译而不用修改源码。这就是libusb的强大的地方,同时这也是目前市面上有很多“免驱”的U口设备的底层技术支撑,其实它们并不是免驱,只是将驱动“打包”进了它们的应用程序里了而已。

 

据libusb官网发布的信息,目前为止其所支持的系统环境有如下几种:

Linux, macOS, Windows, Windows CE, Android, OpenBSD/NetBSD, Haiku, Solaris.

本篇博文就记录一下在嵌入式Linux平台下的移植与使用方式。

 

2、如何在嵌入式平台集成libusb?

 

libusb库公开的是源码形式,自己需要哪个平台就将源码拿去用哪个平台的编译工具编译生成动静态库来引用。因此,本文所描述的内容仅适合拥有相关嵌入式Linux平台系统源码或者至少有那个平台的编译链工具的同学。

 

有了编译环境以后将源码准备好,通过源码内的 configure 生成Makefile,再编译与安装,最后拿到动静态库以后就可以去开发自己的应用了。

 

3、获取

 

libusb源码直接从官网获取最原汁原味的即可,其官网地址如下:

https://libusb.info/

官网上有其简介、帮助文档以及下载链接。

 

目前libusb的源码是托管到Github上的,其资源网址如下:

https://github.com/libusb/libusb/releases

进去后下载一个最新版本就可以了。

 

笔者这边以 1.0.23 版本作为演示,如下图所示:

 

 

 

4、编译

 

源码下载好以后将其解压至可以编译的环境,其源码结构如下图所示:

 

 

接着检查一下你的编译链工具,要求相关工具,如gcc的目录要加载进环境变量中。例如,笔者这边使用的gcc工具全称是 msdk-linux-gcc,笔者在 shell 中键入 msdk几个关键字后直接以 TAB 键就能自动补全完整的工具名。如果你那边还不可以,将编译工具目录加载进PATH中。

 

然后是生成Makefile,使用如下命令即可:

./configure --host=msdk-linux --disable-udev --prefix=/home/.../libusb_install

--host 参数的内容就是指定编译工具的前缀,笔者的gcc编译工具全称是 msdk-linux-gcc,但是在这里仅需填写 msdk-linux 就行了。

--disable-udev 则是关闭 udev 的编译,因为可能有些环境并没有安装 udev 库,关掉它可以避免编译报错,一般也不会对编出来的库有什么影响。

--prefix设置的是安装目录,如果不指定这个目录,后面在安装时默认会将库文件拷贝至 /usr/lib 目录下,一般我们可能没有权限往这个目录拷贝文件,因此直接指定一个有权限的目录会方便一点。必须要注意的是这里要填绝对路径地址。

另外,你还可以执行命令 ./configure --help 来查阅它所支持的其它配置项。

 

命令执行以后,不出意外的话很快就能看到如下形式的信息:

checking for linux/netlink.h... yes
checking poll.h usability... yes
checking poll.h presence... yes
checking for poll.h... yes
checking sys/timerfd.h usability... yes
checking sys/timerfd.h presence... yes
checking for sys/timerfd.h... yes
checking whether TFD_NONBLOCK is declared... yes
checking whether TFD_CLOEXEC is declared... yes
checking whether to use timerfd for timing... yes
checking for pipe2... yes
checking for struct timespec... yes
checking sys/time.h usability... yes
checking sys/time.h presence... yes
checking for sys/time.h... yes
checking for sigaction... yes
checking whether CC supports -std=gnu99... yes
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating libusb-1.0.pc
config.status: creating Makefile
config.status: creating libusb/Makefile
config.status: creating examples/Makefile
config.status: creating tests/Makefile
config.status: creating doc/Makefile
config.status: creating doc/doxygen.cfg
config.status: creating config.h
config.status: executing depfiles commands
config.status: executing libtool commands

这就表示配置已经成功,Makefile已经自动生成了。不放心的话可以查找一下Makefile的情况,笔者这边的Makefile查找结果如下:

$ find -type f -name Makefile
./examples/Makefile
./tests/Makefile
./Makefile
./libusb/Makefile
./doc/Makefile

 

如果您很不幸在执行这条命令的时候遇到了如下报错:

checking whether we are using the GNU C++ compiler... yes
checking whether msdk-linux-g++ accepts -g... yes
checking dependency style of msdk-linux-g++... gcc3
checking build system type... x86_64-pc-linux-gnu
checking host system type... Invalid configuration `msdk-linux': machine `msdk' not recognized
configure: error: /bin/sh ./config.sub msdk-linux failed

不用慌,这并不是什么大问题,只是libusb觉得它暂时不支持你的编译工具而已,我们只需要放过这块的条件判断即可。打开源码根目录下的 config.sub 文件,在约第 246 行的位置仿照已有的case分支添加你的编译链信息,如下图所示:

 

再次执行,就能成功的了。

 

有了Makefile就可以编译了,编译直接在源码根目录下执行以下命令:

make

稍等片刻,便可见到如下形式的打印:

core.c:2370: warning: zero-length gnu_printf format string
  CC       libusb_1_0_la-descriptor.lo
descriptor.c: In function 'libusb_get_device_descriptor':
descriptor.c:546: warning: zero-length gnu_printf format string
  CC       libusb_1_0_la-hotplug.lo
  CC       libusb_1_0_la-io.lo
io.c: In function 'disarm_timerfd':
io.c:1333: warning: zero-length gnu_printf format string
io.c: In function 'libusb_interrupt_event_handler':
io.c:1915: warning: zero-length gnu_printf format string
  CC       libusb_1_0_la-strerror.lo
  CC       libusb_1_0_la-sync.lo
  CC       os/libusb_1_0_la-poll_posix.lo
  CC       os/libusb_1_0_la-threads_posix.lo
  CC       os/libusb_1_0_la-linux_usbfs.lo
  CC       os/libusb_1_0_la-linux_netlink.lo
  CCLD     libusb-1.0.la
make[2]: Leaving directory `/home/tmp_deleteme/libusb-1.0.23/libusb'
Making all in doc
make[2]: Entering directory `/home/tmp_deleteme/libusb-1.0.23/doc'
make[2]: Nothing to be done for `all'.
make[2]: Leaving directory `/home/tmp_deleteme/libusb-1.0.23/doc'
make[2]: Entering directory `/home/tmp_deleteme/libusb-1.0.23'
make[2]: Leaving directory `/home/tmp_deleteme/libusb-1.0.23'
make[1]: Leaving directory `/home/tmp_deleteme/libusb-1.0.23'

一般来说,只要能正常结束编译命令就代表成功了。

 

同时,在 libusb/.libs/ 目录下也能见到编译生成出来的库文件,如下图所示:

 

 

最后,再执行安装命令,直接在源码根目录下执行:

make install

如果命令能不报错退出,则表示安装成功。此时去到你先前指定的安装目录,会发现多了两个目录,如下图所示:

 

这里面就放着相关头文件以及动静态库文件了。

 

如此,便完成了整个编译过程。

 

5、开发

 

在得到上一步编译生成的库文件和头文件以后即可直接拿去供自己的应用开发使用了。

 

关于应用libusb库以及简单的使用示例,笔者将会在另一篇博文中记述。如有需要请阅读笔者的另一篇博文。

 


 

posted @ 2020-10-20 20:56  大窟窿  阅读(2700)  评论(5编辑  收藏  举报