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庫以及簡單的使用示例,筆者將會在另一篇博文中記述。如有需要請閱讀筆者的另一篇博文。