前言
BlueZ是一个开源的蓝牙协议栈,它提供了Linux操作系统上的蓝牙支持。它包含了蓝牙协议的实现,包括L2CAP、RFCOMM、SDP、AVRCP、HID等协议,以及蓝牙核心规范的实现。BlueZ还提供了一些工具和库,以便开发者能够方便地使用蓝牙功能,例如命令行工具hcitool和hcidump,以及开发库libbluetooth和obexftp。BlueZ已经成为Linux系统上的标准蓝牙协议栈,被广泛应用于各种设备和应用中。
bluez的移植过程由于需要链接许多其他的库,而这些库有的又有各自依赖的库,所以整个项目移植下来非常繁琐,网上的教程大多都复杂且混乱,正因为踩过这些坑,本文将换一种方式一步一步教你怎么编译bluez,但是涉及的东西还是比较多,所以bluez的编译需要耐心,这不是一下子就能搞好的,跟着我的思路,耐心去做,不要碰到一点问题就放弃了,花上几个小时的时间,相信最后无论结果如何你都会收获满满。
编译环境以及源码
ubuntu版本:16.04(新建的ubuntu镜像)
交叉编译器:arm-linux-gnueabihf-gcc
所用源码:
- bluez-5.66
- dbus-1.12.20
- expat-2.5.0
- glib-2.40.0
- libffi
- libical-1.0.1
- ncurses-6.2
- readline-7.0
- zlib-1.3
- cmake-3.20.0-linux-x86_64
所有源码还有编译好的bluez我已经上传至我的gitee,可直接下载
https://gitee.com/luo-honghua/bluez5.0-porting.git
cmake下载地址
Index of /files/v3.20 (cmake.org)
PC源码编译
用ubuntu的gcc编译,为什么呢?我一开始直接用arm去交叉编译,但是总是少这少那,编译不过,一头雾水,所以先用gcc去编译,如果缺少什么,可以直接安装,做这一步主要是让你了解编译bluez的一个过程到底依赖哪些东西,gcc编译过了,那么你再用交叉编译器去编译就清楚多了。如果对自己足够自信的话也可以省去这一步。
裁剪
进入源码目录,打开终端,建一个脚本auto.sh,输入以下内容
./configure --prefix=/opt/bluez/pc_install \
--mandir=/opt/bluez/pc_install/usr/share/man \
--sysconfdir=/opt/bluez/pc_install/etc \
--localstatedir=/opt/bluez/pc_install/var \
-enable-tools -enable-test --enable-experimental --enable-maintainer-mode --disable-udev \
--enable-library --enable-shared=yes --enable-network --enable-health \
--enable-cups --enable-threads --enable-pie --enable-deprecated \
其中
- --prefix:最终目标文件生成路径
- --mandir --sysconfdir --localstatedir这几个随便写个路径,不重要,直接像我一样放到最终目标文件生成路径下
然后执行,这个时候开始报错了
这里提示少了glib,我们直接安装
sudo apt-get install libglib2.0-dev
然后重新执行脚本
可以看到glib检查已经过了,但是少了dbus,同样的,直接安装
sudo apt-get install libdbus-1-dev
再次执行
这次少了libical,安装
sudo apt-get install libical-dev
再次执行
少了readline,安装
sudo apt-get install libreadline-dev
再次执行
少了rst2man,安装
sudo apt-get install python-docutils
再次执行
可以看到,裁剪已经通过了,通过上述操作,相信你已经了解了bluez编译所依赖的库了,同样的,arm编译的时候也差不多是这些,有些可以直接安装,但是有些需要也用交叉编译的库。
编译安装
直接编译
make -j4
会报错,但是不要一看到报错就放弃,根据其报错的提示,我们直接找到报错的代码去做修改,比如这里,直接找到monitor/btmon.rst,40行的位置,根据提示,这里不能用auto。要输入具体的数值,所以这里将auto改为10
再次编译
还是报错,这里是因为,列数不匹配,要输入对应列数的数值
所以这里这样修改,再次编译
可以看到,虽然还是在报错,但是刚刚那个地方已经不报错了,接下来就是如法炮制,将其他地方都进行这样的修改
其中还会有一个这个问题
直接将下方:align: left这行删除即可
最后编译通过,进行安装
make install
最后在最终生成路径下生成这些
通过这一系列工作,bluez的pc编译就通过了,那么后续使用arm编译器编译就简单多了,为什么呢,因为使用arm编译器编译只需要将其中几个库替换为交叉编译生成的库就可以了,而且使用pc先编译还有一个好处,那就是代码无需再改了,pc可以编过,那么arm编译器也一定可以编过。
arm编译
通过上面的流程,其实我们已经知道需要哪些库的依赖了,所以我们一样按照上面的步骤来添加交叉编译的库,在编译之前,我们先建一个mypkconfig文件夹,后续将生成的pkconfig文件都复制到这个文件夹,这样后续编译一些库就不需要在裁剪的时候链接了,后面再详细解释。
可以看到,我的目录结构
- arm_install:存放交叉编译生成的bluez
- lib:存放源码交叉编译的生成的库
- pc_install:存放pc编译生成的bluez
- mypkconfig:库的环境变量
- source:源码存放目录
拥有好的编译习惯会让工作更有条理清晰
glib库编译
在进行glib编译的前还需要先编译libffi和zlib这两个库,这两个比较简单
libffi编译
直接在libffi源码目录打开终端,输入命令
./configure --prefix=/opt/bluez/lib/libffi_install --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc
其中
- --prefix:最终目标文件生成路径
- --host:编译器平台,填写你的交叉编译器
- CC:使用的c编译器,填写你的交叉编译器
后面这个就不做解释了,通过后直接编译安装
make -j4
make install
zlib编译
同样在源码目录下打开终端输入
export CC=arm-linux-gnueabihf-gcc
./configure --prefix=/opt/bluez/lib/zlib_install
make CC=arm-linux-gnueabihf-gcc -j4
make install
注意zlib不支持通过configure配置编译器,所以要手动来指定编译器。
glib编译
首先源码目录下新建一个文件glib.cache,然后输入以下内容
glib_cv_long_long_format=ll
glib_cv_stack_grows=no
glib_cv_have_strlcpy=no
glib_cv_have_qsort_r=yes
glib_cv_va_val_copy=yes
glib_cv_uscore=no
glib_cv_rtldglobal_broken=no
ac_cv_func_posix_getpwuid_r=yes
ac_cv_func_posix_getgrgid_r=yes
然后再建一个脚本文件auto.sh,输入以下内容
./configure --prefix=/opt/bluez/lib/glib_install \
CC=arm-linux-gnueabihf-gcc \
--host=arm-linux-gnueabihf \
LIBFFI_CFLAGS="-I/opt/bluez/lib/libffi_install/lib/libffi-3.0.9/include" \
LIBFFI_LIBS="-lffi -L/opt/bluez/lib/libffi_install/lib" \
ZLIB_CFLAGS="-I/opt/bluez/lib/zlib_install/include" \
ZLIB_LIBS="-lz -L/opt/bluez/lib/zlib_install/lib" \
--cache-file=glib.cache --disable-selinux --disable-xattr --disable-libelf
其中
- LIBFFI_CFLAGS:libffi头文件路径
- LIBFFI_LIBS:libffi库文件路径
- ZLIB_CFLAGS:zlib头文件路径
- ZLIB_LIBS:zlib库文件路径
如果还不清楚可以输入./configure -h查看说明
接下来直接编译,如果出现以下报错
直接编辑gdate.c这个文件,加入一行代码
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
然后重新编译安装
make -j4
make install
完成安装后,在生成目录下找到pkconfig文件,将其这个glib-2.0.pc和gthread-2.0.pc复制到上面我们新建的那个mypkconfig中,复制之前,注意先检查一下路径是否正确
DBus编译
dbus的编译需要先编译expat库
expat编译
源码目录下打开终端输入
./configure --prefix=/opt/bluez/lib/expat_install --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc --enable-shared
make -j4
make install
DBus编译
源码目录下新建脚本auto.sh,输入内容
./configure --prefix=/opt/bluez/lib/dbus_install \
--host=arm-linux-gnueabihf \
CC=arm-linux-gnueabihf-gcc \
CXX=arm-linux-gnueabihf-g++ \
--with-xml=expat --without-x \
EXPAT_LIBS="-L/opt/bluez/lib/expat_install/lib -lexpat" \
EXPAT_CFLAGS="-I/opt/bluez/lib/expat_install/include/" \
enable_selinux="no" --disable-tests
裁剪完后直接编译安装
make -j4
make install
同样的,将生成的pkconfig目录下的dbus-1.pc文件复制到mypkconfig目录下
libical编译
libical的编译有点不一样,需要使用cmake,而且对版本有要求。
cmake安装
我的免安装解压的,直接解压设置环境变量就可以直接使用
像我这里,给root用户设置环境变量,如果你是用sudo用户去编译,那就给sudo用户设置环境变量,设置环境变量这个我就不多说了,百度一查就知道了。
设置完环境变量记得source,让环境变量立即生效
完成后输入命令
cmake --version
如果显示版本是cmake version 3.20.0那就没问题
libical编译
接着回来libical源码目录下,打开终端执行下面的命令
mkdir build
cd build
export CC=arm-linux-gnueabihf-gcc;export CXX=arm-linux-gnueabihf-g++
cmake -DCMAKE_INSTALL_PREFIX=/opt/bluez/lib/libical_install -DCMAKE_BUILD_TYPE=Release -DSHARED_ONLY=yes ..
make -j4
make install
完成后同样的将生成的libical.pc复制过去
readline编译
readline的编译需要ncurses库
ncurses编译
./configure --prefix=/opt/bluez/lib/ncurses_install --host=arm-linux-gnueabihf --with-shared
make -j4
make install
安装的时候会报错
这是因为strip的时候用的是ubuntu自带的strip,而不是arm-linux-gnueabihf-strip,strip的功能你百度一下就知道是什么了,但是这个不影响,我们要的只是动态库。
readline编译
源码目录创建脚本auto.sh
./configure \
--host=arm-linux-gnueabihf \
CC=arm-linux-gnueabihf-gcc \
--prefix=/opt/bluez/lib/readline_install \
SHLIB_LIBS="-lncurses -L/opt/bluez/lib/ncurses_install/lib" \
SHLIB_CFLAGS="-I/opt/bluez/lib/ncurses_install/include" \
接着就是编译安装
make -j4
make install
要注意的是readline的生成没有pkconfig文件,所以后续编译bluez需要手动修改Makefile去指定
bluez编译
最后就是bluez的编译了,还是原来PC这份源码,先清除一下之前的裁剪配置
make distclean
然后修改auto.sh脚本内容,将编译器换成arm编译器,并且手动指定readline和ncurses的库文件路径
./configure --prefix=/opt/bluez/arm_install \
--host=arm-linux-gnueabi \
CC=arm-linux-gnueabihf-gcc \
--mandir=/opt/bluez/arm_install/usr/share/man \
--sysconfdir=/opt/bluez/arm_install/pc/etc \
--localstatedir=/opt/bluez/arm_install/var \
-enable-tools -enable-test --enable-experimental --enable-maintainer-mode --disable-udev \
--enable-library --enable-shared=yes --enable-network --enable-health \
--enable-cups --enable-threads --enable-pie --enable-deprecated \
LDFLAGS="-L/opt/bluez/lib/readline_install/lib -L/opt/bluez/lib/ncurses_install/lib" \
CFLAGS="-I/opt/bluez/lib/readline_install/include" \
打开终端先设置pkconfig环境变量
export PKG_CONFIG_PATH=/opt/bluez/mypkconfig:$PKG_CONFIG_PATH
然后在执行auto.sh进行裁剪 ,完成后先不急着编译,打开Makefile,先检查一下pkconfig是否生效,看看路径是否正确
可以看到这里dbus、glib、ical都已经是链接的我们指定的路径。
还有一个地方要注意
找到这个位置,可以看虽然已经指定了路径,但是下面LIBS那里并没有链接上readline、ncurses这两个库,所以我们手动添加上
然后编译,会报错
这里是重复定义了,我们直接打开readline.h,根据报错信息,将重复定义的函数注释掉
再次编译还是会报错
这里是类型错了,同样的,找到这个文件,进行修改
根据定义类型,可以知道,这个是有符号64位,直接将%zd改为%lld
再次编译安装直接通过
可以看到,成功生成了目标文件
至此,bluez的交叉编译完成
总结
一开始面对bluez的编译是真的头疼,因为东西太多,而且网上的教程也比较杂,搞了一两天也没什么头绪,后面换了一个思路,先编译PC版的,可以后思路一下就清晰了,然后很快arm的就编出来了。
希望我的文章对你有所帮助!