最近拿到一个 Ubuntu 16.04 ARM 的嵌入式板子,要求能在上面跑 QML 程序。
因为通过软件仓库安装的 Qt 版本过低(5.5.1),所以要自行编译新版本的 Qt,折腾了一天踩了几个坑,记录一下。
编译 Qt
我这里选择了 Qt 5.7.1 版本,因为:
- 它是最后一个可以编译支持 XP 系统的版本,考虑到 Windows 平台可能有支持 XP 的需求。
- QtQuick.Controls2 是从 5.7 开始引入的。
安装依赖
在配置阶段就报错了,大概就是关于 Linux 显示的插件所依赖的包没有安装。
1 | apt install "^libxcb.*" libx11-xcb-dev libglu1-mesa-dev libxrender-dev |
方案来自 https://stackoverflow.com/a/39068500/22121934
编译错误
编译过程中仅有的一个错误
1 | qeglfskmsegldevice.cpp:74:82: error: invalid conversion from ‘EGLDeviceEXT {aka void*}’ to ‘EGLNativeDisplayType {aka gbm_device*}’ [-fpermissive] |
这个错误提示表明在将EGLDeviceEXT
类型转换为EGLNativeDisplayType
类型时发生了无效的转换。根据错误信息,可以看出EGLDeviceEXT
实际上是void*
类型,而EGLNativeDisplayType
是gbm_device*
类型。
查了半天在这里找到了修复补丁:https://code.qt.io/cgit/qt/qtbase.git/commit/?id=f577a01f5e8d9678d268917ca727a6e9a3e819a6
1 | EGLNativeDisplayType QEglFSKmsEglDevice::nativeDisplay() const |
配置动态库搜索路径
因为系统内已经安装了 Qt 5.5.1,我开始的想法是用第三方工具切换默认 Qt 版本,但我想错了,看我如何踩坑。。。
根据 Make qmake use qt5 by default 这里的讨论,我创建了/usr/share/qtchooser/qt571.conf
文件,并写入以下内容:
1 | /opt/Qt/5.7.1/bin |
注意文件末尾保持一个空行,否则最后的lib
就会变为li
。
然后将 qtchooser 的default.conf
软连接指向它即可。
输入qmake -v
查看,显示的确是 5.7.1 版本,看上去是成功的。
尝试运行 QML 程序,提示 QtQuick 未安装:
1 | QQmlApplicationEngine failed to load component |
但是明明在 Windows 上是可以运行的。此处又被坑了一个多小时,终于在 https://stackoverflow.com/a/30304009/22121934 这里看到了一个看似最不可能的答案,抱着试试的态度试了下,竟然不再报错了,程序能启动成功(但还有其他问题)。
原因是qtchooser
工具主要用于切换不同版本的Qt编译器和工具链,如qmake、moc等,而不会直接修改Qt库的软链接。也就是说在编译程序时用的还是 Qt 5.5.1 的工具链。
其实想想也是,如果随便修改系统默认 Qt 库的软连接,那肯定会导致其他 Qt 应用都出问题。
所以正确用法是在适当的地方设置环境变量,一般有两种选择:
- 将新版本 Qt 的 lib 目录路径加入到
LD_LIBRARY_PATH
环境变量中。 - 编译链接时设置
-Wl,-rpath
参数,将搜索路径写入ELF
文件中。
缺少字体
再次运行,报错:
1 | QFontDatabase: Cannot find font directory /opt/Qt/5.7.1/lib/fonts. |
看上去是和编译选项-system-freetype
有关:
1 | -no-freetype ........ Do not compile in Freetype2 support. |
这里有两种方式解决,一是重新编译 Qt,在编译前安装好libfontconfig
库。二是修改环境变量QT_QPA_FONTDIR
。
1 | export QT_QPA_FONTDIR=/usr/share/fonts/truetype/dejavu |
不过为了避免污染系统环境变量影响别的 Qt 程序,我选择了写在程序中:
1 |
|
软件渲染
再次运行,又报错:
1 | QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled |
这个倒好说,因为设备没有 GPU 驱动,所以 OpenGL 没法用,不得不改为软件渲染。
软件渲染需要编译安装 Qt Quick 2D Render 模块:qtdeclarative-render2d-opensource-src-5.7.1.7z
为了使用软件渲染,也要设置环境变量:
1 | qputenv("QMLSCENE_DEVICE", "softwarecontext"); |
相关阅读
qt-builder 图形化QT源码编译工具
What is the use of various Qt platform plugins?
Qt for Embedded Linux
QtQuick2DRenderer
QuickControls Versions