免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Qt 5.14.2 aarch64 静态交叉编译完整指南(从零构建嵌入式 Linux 环境)

Qt 5.14.2 aarch64 静态交叉编译完整指南(从零构建嵌入式 Linux 环境) 做嵌入式 Linux 开发的人早晚都会碰到一个问题目标板是 ARM 架构跑的是 aarch64 系统但你想在 x86 主机上把 Qt 应用编好、调好、直接扔到板子上跑。如果没有预先准备好整套交叉编译环境光靠系统自带的 Qt 和 qmake你连一个“Hello Qt”都编译不出来。这篇文章就从零开始把 Qt 5.14.2 在 aarch64 架构下的静态交叉编译完整流程拆开讲清楚。整个过程覆盖工具链选择、sysroot 整理、Qt 源码裁剪、qmake.conf 定制、configure 参数剖析、实际编译、目标板部署和常见问题排错适合有 C 基础但第一次做嵌入式 Qt 交叉编译的人。我用的场景是“无桌面 Linux framebuffer 显示”这也是大多数单板设备会遇到的典型情况。先说清楚为什么要这么折腾。Qt 5.14.2 是目前很多嵌入式 Linux 发行版里最后一代 LTS 版本而且有完整离线源码包。aarch64 则是 ARM 64 位平台的主流形态从树莓派到各种工控板的系统基本都是这个架构。静态编译听起来“笨重”但它能帮你避开目标板上 Qt 库不匹配、少文件、缺依赖这些问题一个可执行文件拷过去就能跑这在维护多台设备时特别省心。1. 项目背景与整体设计思路1.1 为什么是 Qt5.14.2 aarch64 静态编译这个“铁三角”Qt 版本很多新版本功能确实多但在嵌入式环境里稳定和可控比新功能重要得多。Qt 5.14.2 是 Qt 5 系列里口碑相当好的一个 LTS 版本它的 API 稳定性经过了大量生产项目验证而且源码包是完整开放的你可以把不需要的模块裁掉只留下核心库。这一点在交叉编译里至关重要因为你没有能力也没有精力去为每一块目标板编译全套 Qt 模块。从架构角度说aarch64 已经是现在主流 ARM 板子的默认架构跑 64 位 Linux 系统。很多老项目还在用 armv7 或者 armhf但新项目基本都往 64 位走所以现在搭建 aarch64 的构建环境正是时候。静态编译的价值在于“发布形态”。动态编译的 Qt 应用部署到目标板需要把一大堆.so拷贝过去还要保证它们之间的依赖关系、版本号、加载路径全部正确。静态编译把 Qt 核心库直接打进可执行文件里目标板上只要有一个可运行的 Linux 系统和必要的显示接口程序就能启动。对量产设备来说这等于少了一半的运维问题。1.2 静态 Qt 的适用场景与代价静态编译不是银弹我先说清楚它适合什么场景。如果你的目标板上有完整的包管理工具而且你有 root 权限可以自由安装软件那动态编译其实更方便升级 Qt 某个模块只需要替换库文件。但如果是以下几种情况静态编译就很合适目标板存储空间有限不想装一整套 Qt 运行时。设备需要交付给客户客户不希望也不方便安装一堆依赖。系统里有多个版本 Qt 应用共存动态库很容易互相干扰。你想让程序在不同硬件上尽量“一次编译、到处运行”。静态编译的代价也明显。首先是磁盘和内存占用一个静态链接 QtWidgets 的程序可能比动态链接版本大好几倍。其次是编译时间静态库每次修改 Qt 配置都要全量重编。最麻烦的一点是在目标板上运行时有字体、插件、显示后端这些运行时资源仍然依赖文件系统不是你链接成.a就自动解决的。1.3 工程化思维先规划再动手交叉编译最忌讳一上来就敲 configure。我见过很多人卡在“configure 报错不知道少了什么”这个阶段其实就是因为没先想清楚目标板到底需要什么。我建议你先回答这几个问题目标板有没有显示设备是接 HDMI 屏还是 RGB 屏是用 Linux framebuffer 还是真实 X11要不要 GPU 加速需不需要 Qt Quick 或者只用 Qt Widgets有没有网络功能需不需要数据库或 WebEngine这些答案直接决定你要裁剪哪些模块。我下面提供的方案是“最小可用集”Qtbase 核心 Widgets Linux framebuffer不启用 OpenGL、不启用 X11、不启用多媒体适合先跑通流程。如果你确实需要 Qt Quick那就要保留 declarative 模块并且要准备 OpenGL ES 的头文件和库流程会更复杂。2. 环境准备工具链与 sysroot 的选择2.1 主机环境与工具链安装验证静态 Qt 的交叉编译必须在 Linux 主机上进行Windows 和 macOS 做起来非常别扭。我建议用 Ubuntu 20.04 LTS 作为主机系统原因有两个一是它自带的交叉编译工具链版本适中二是它的 sysroot 和 glibc 版本容易匹配。Ubuntu 22.04 之后默认的 GCC 版本比较新编译 Qt 5.14.2 会遇到不少版本兼容问题不太建议新手从那里起步。安装工具链可以直接用 apt 包省去手动下载的麻烦sudo apt update sudo apt install build-essential crossbuild-essential-arm64 gcc-aarch64-linux-gnu g-aarch64-linux-gnu装完以后检查是否可用aarch64-linux-gnu-gcc --version aarch64-linux-gnu-g -dumpmachine正确输出应该是类似aarch64-linux-gnu这种东西。如果命令不存在说明 PATH 有问题或者安装没成功。我还建议安装几个辅助工具后面排查问题时会用到sudo apt install cmake ninja-build rsync file gdb-multiarchfile这个命令特别实用编译完以后扫一下可执行文件能立刻看到它是不是 ARM 架构、有没有被错误链接成 x86 格式。2.2 sysroot目标板就是最好的依赖来源交叉编译里的 sysroot 指的是“目标板根文件系统的一个镜像目录”编译器在找头文件和库时会自动到这个目录里去搜而不是搜主机上的/usr/include。这非常关键因为你主机上装的库是 x86 版的直接拿给 aarch64 编译毫无意义。sysroot 来源有两种主流方式。第一是从目标板上打包这是最直接也最可靠的办法。比如目标板跑的是 Debian 系的 aarch64 Linux你可以在板子上执行tar cf - /lib /usr/lib /usr/include 2/dev/null | gzip sysroot.tar.gz然后把压缩包传回主机解压到几个空目录里。使用这种方式时请尽量用干净的系统打完包再解压。另一种方式是用debootstrap或发行版自带的libc6-dev-arm64-cross包提供的/usr/aarch64-linux-gnu目录。apt 安装的crossbuild-essential-arm64已经带了一个基础 sysroot里面包含标准 C/C 库。如果 Qt 只用基础系统库那这个就够了。我把环境的目录结构设计如下mkdir -p ~/work/qt-cross cd ~/work/qt-cross mkdir -p sysroot sysroot/usr/include sysroot/usr/lib把所有目标板相关的库文件和头文件按原本系统的路径放进去。比如你的目标板有自定义 GPU 库板子上路径是/opt/mali/include那么你在主机上也要放在sysroot/opt/mali/include。2.3 环境变量与目录规划交叉编译会用到很多路径建议统一写进一个环境变量脚本减少出错概率。我一般这样定义export CROSS_COMPILEaarch64-linux-gnu- export SYSROOT/home/user/work/qt-cross/sysroot export TOOLCHAIN_PREFIX/usr/bin/aarch64-linux-gnu- export QT5_VERSION5.14.2 export QT_BUILD_ROOT/home/user/work/qt-cross/qt-everywhere-src-5.14.2 export QT_INSTALL_PREFIX/opt/qt5.14.2-aarch64 export PATH$QT_INSTALL_PREFIX/bin:$PATH这里最关键的是QT_INSTALL_PREFIX。按我的经验安装目录不要随手设成临时目录因为整个 Qt 静态构建树里的 qmake、prl 文件、配置信息都会记录这个路径。以后不管是交叉编译应用还是到目标板部署都绕不开它建议直接固定成一个你以后想长期使用的路径比如/opt/qt5.14.2-aarch64。3. 源码获取与子模块取舍3.1 Qt5.14.2 源码的获取渠道与校验从 Qt 官网的存档目录下载qt-everywhere-src-5.14.2.tar.xz即可。这个“everywhere”源码包包含了 Qt 几乎全部模块解压后大约 1GB 左右编译前可以慢慢裁剪。拿到源码后养成校验习惯tar -xJf qt-everywhere-src-5.14.2.tar.xz cd qt-everywhere-src-5.14.2 grep -r QT_VERSION_STR qtbase/src/corelib/global/qglobal.h | head -1输出里应该能看到5.14.2字样。源码路径后面统一叫$QT_BUILD_ROOT下面凡是涉及源码目录的地方都用这个变量代替。3.2 子模块裁剪不是越多越好qt-everywhere-src里包含几十个模块例如qtwebengine、qtdeclarative、qtmultimedia等。你如果一股脑全编等着你的就是漫无边际的依赖错误和巨大的磁盘占用。在实际嵌入式项目中很多模块一辈子都用不上。我给你的裁剪原则是必须保留qtbase它是 Qt 的心脏没有它什么都白搭。视需要保留如果你只用 Widgets可以不编 declarative如果你要用 Qt Quick那就要留着 declarative同时备好 OpenGL ES 相关依赖。直接跳过qtwebengineChromium 引擎交叉编译极其痛苦、qtvirtualkeyboard、qtlocation、qtmultimedia、qtcharts、qt3d这类大模块在嵌入式起步阶段统统不要。裁剪方式不是手动删源码目录而是通过 configure 的-skip参数来排除。我会在下一节的完整命令里把需要跳过的模块列出来。4. mkspecs 配置与 configure 参数剖析4.1 认识 qmake.conf 与 mkspecs 的机制交叉编译和普通编译最大的区别在于Qt 要通过 qmake.conf 知道“该用哪个编译器、目标平台是什么、库应该去哪找”。Qt 自带了很多现成 mkspecs 文件Qt 5.14.2 里已经有一个linux-aarch64-gnu-g默认会指向aarch64-linux-gnu-gcc和aarch64-linux-gnu-g。如果你用 Ubuntu 的交叉工具链这个 mkspec 基本能直接用。不过为了更灵活我建议新建一个自己的 mkspecs 配置方便后面调整编译选项。先看下 Qt 默认支持的内容ls $QT_BUILD_ROOT/qtbase/mkspecs/ | grep aarch64你应该能看到linux-aarch64-gnu-g这样的目录。复制一份出来自己改cp -r $QT_BUILD_ROOT/qtbase/mkspecs/linux-aarch64-gnu-g \ $QT_BUILD_ROOT/qtbase/mkspecs/linux-aarch64-static-cross-g然后编辑新目录下的qmake.conf核心配置如下。每次修改后都要确认没有拼写错误MAKEFILE_GENERATOR UNIX CONFIG incremental QMAKE_INCREMENTAL_STYLE sublib include(../common/g-base.conf) include(../common/linux.conf) include(../common/gcc-base-unix.conf) QMAKE_CC aarch64-linux-gnu-gcc QMAKE_CXX aarch64-linux-gnu-g QMAKE_LINK aarch64-linux-gnu-g QMAKE_LINK_SHLIB aarch64-linux-gnu-g QMAKE_AR aarch64-linux-gnu-ar cqs QMAKE_RANLIB aarch64-linux-gnu-ranlib QMAKE_STRIP aarch64-linux-gnu-strip QMAKE_CFLAGS_RELEASE -O2 -pipe QMAKE_CXXFLAGS_RELEASE -O2 -pipe QT_QPA_DEFAULT_PLATFORM linuxfb load(qt_config)这里的关键点是QT_QPA_DEFAULT_PLATFORM linuxfb。它的意思是编译出来的 Qt 应用默认使用 Linux framebuffer 作为图形后端。对于没有 X11、没有 Wayland 的嵌入式板子linuxfb是最简单可行的方案。4.2 configure 核心参数逐个拆解Qt 的 configure 脚本参数非常多理解它们比记住它们重要。我按作用分组说明。先说最核心的三组。-prefix指定安装路径交叉编译时这个路径必须和最终部署路径保持一致。-xplatform是交叉编译开关告诉 configure 用哪个 mkspec自然要用我们刚才新建的linux-aarch64-static-cross-g。-static表示生成静态库这一条是静态交叉编译和一般交叉编译的分水岭。然后是 Qt 的许可模式和构建模式。-opensource表示用开源许可证-confirm-license自动确认许可协议否则 configure 会停下来等人工输入。-release生成发布版包含优化信息不生成调试信息。-silent减少配置时的输出不是必须但能让你更快发现问题。第三组是依赖库相关。交叉编译时目标板上未必有齐全的开发库所以 Qt 允许把一部分常用的第三方库直接内嵌源码一起编译这就是-qt-zlib、-qt-libpng、-qt-libjpeg、-qt-freetype、-qt-harfbuzz、-qt-pcre这些参数的作用。“内嵌”的意思是编译 Qt 时直接生成对应的静态库不依赖目标板上的外部动态库。这些库在静态编译场景下非常重要能极大减少链接时的外部依赖。对应地-no-glib、-no-gstreamer、-no-pulseaudio、-no-iconv、-no-dbus、-no-ssl则把暂时用不到的依赖全部关掉免得 configure 阶段到处找库。第四组是图形相关。-no-opengl表示不启用 OpenGL因为我们走 framebuffer 显示路线不需要 GPU 加速。-no-xcb表示不启用 X11 相关的 xcb 插件-no-wayland同理。-no-cups关闭打印支持-no-avx、-no-sse2、-no-avx2是关掉 x86 特有的指令集优化因为目标板是 ARM 架构这些优化毫无意义开着还可能引发玄学问题。第五组是模块裁剪。-skip加上模块名就可以跳过对应模块。这里我把 webengine、declarative、multimedia 等全部跳过。如果你要 Qt Quick去掉-skip qtdeclarative但记得同时配置好 OpenGL ES。最后-nomake examples -nomake tests表示不编译示例和测试代码省时省力省空间。4.3 一个可直接复用的完整 configure 命令综合以上分析我在项目里实际使用的 configure 命令如下。这条命令在 Qt 5.14.2 源码根目录下的一个空 build 目录里执行不建议直接在源码目录里配置。mkdir -p $QT_BUILD_ROOT/build-static cd $QT_BUILD_ROOT/build-static ../configure \ -prefix $QT_INSTALL_PREFIX \ -xplatform linux-aarch64-static-cross-g \ -static \ -release \ -opensource \ -confirm-license \ -silent \ -qt-zlib \ -qt-libpng \ -qt-libjpeg \ -qt-freetype \ -qt-harfbuzz \ -qt-pcre \ -no-glib \ -no-gstreamer \ -no-pulseaudio \ -no-iconv \ -no-dbus \ -no-ssl \ -no-opengl \ -no-xcb \ -no-wayland \ -no-cups \ -no-avx \ -no-sse2 \ -no-avx2 \ -no-feature-vk \ -skip qtdoc \ -skip qtwebengine \ -skip qtwebglplugin \ -skip qtvirtualkeyboard \ -skip qtsensors \ -skip qtdeclarative \ -skip qtmultimedia \ -skip qtquickcontrols \ -skip qtquickcontrols2 \ -skip qtserialport \ -skip qtserialbus \ -skip qtcharts \ -skip qtlocation \ -skip qtlottie \ -nomake examples \ -nomake testsconfigure 做完后需要重点查看输出里的 Summary注意 QT_INSTALL_PREFIX、QT_SYSROOT、QMAKE_SPEC 这几项是否指向预期路径。如果QMAKE_SPEC显示的不是linux-aarch64-static-cross-g说明你-xplatform参数写错了。如果显示奇怪的主机路径就要检查环境变量是否串了。5. 编译、安装与常见失败现场5.1 开始编译之前先想清楚这几件事configure 成功后目录里已经生成了构建用的 Makefile。编译之前还有几个小细节值得确认。一是编译目录和源码目录不要弄混。我前面特意建了build-static作为构建目录这样源码目录保持干净如果中途 configure 参数改错了删掉 build 目录重新来一遍就行不用重新解压源码。二是多线程编译数。Qt 编译非常吃资源make -j后面的数字要结合主机内存来定。如果内存只有 8GB建议-j416GB 以上可以-j8。强行开太多线程轻则编译速度反而下降重则直接virtual memory exhausted: Cannot allocate memory。三是保存构建日志。强烈建议用tee把输出同时写到文件里因为编译过程中错误可能几秒钟就刷过去了make -j4 21 | tee build.log5.2 编译过程中的两个高频失败与解决我在重复实验里遇到最频繁的编译失败有两类。第一类是xxx.h: No such file or directory例如fatal error: GL/gl.h: No such file or directory出现这类错误十有八九是 configure 阶段某些-no-*参数没生效或者依赖库检查被绕过。比如你明确加-no-opengl了理论上不应该再有 GL 相关头文件需求但如果 sysroot 里恰好又有不完整的 OpenGL 头文件configure 会误判可用。解决方法是回头把config.log和config.summary翻出来看里面会明确告诉你哪些特性被检测到了。对于纯 framebuffer 场景直接删掉 sysroot 里多余的头文件或者重新 review 一下 configure 命令。第二类是链接阶段缺少各种库函数引用比如undefined reference to dlopen undefined reference to pthread_create这多半是工具链默认链接了-lpthread、-ldl但某些模块的静态链接顺序不对。解决办法是在 configure 的 CXXFLAGS 里加上export CXXFLAGS-pthread -ldl或者编译应用时在.pro文件的 QMAKE_LIBS 里手动补充。更通用的做法是在 qmake.conf 里把QMAKE_LIBS_THREAD显式设成-lpthread。5.3 安装与产物检查编译成功之后执行安装make install这一步耗时相对短主要是把编译好的库、头文件、mkspecs、qmake 工具按-prefix路径复制过去。安装完成后检查一下核心产物ls -lh $QT_INSTALL_PREFIX/lib/libQt5Core.a ls -lh $QT_INSTALL_PREFIX/lib/libQt5Widgets.a $QT_INSTALL_PREFIX/bin/qmake -query如果libQt5Core.a存在而且 qmake 输出各项路径都指向/opt/qt5.14.2-aarch64说明核心编译基本成功。这里特别提醒静态库没有安装到标准系统库目录这是预期行为。qmake 工程文件通过.prl文件记录静态链接参数只要后续一直用$QT_INSTALL_PREFIX/bin/qmake来生成 Makefile它会自动把正确路径和链接参数带上。6. 部署到目标板并跑通第一个 Qt 程序6.1 部署策略把 Qt 搬到目标板还是只带可执行文件静态编译最大的优势就是理论上你只需要把编译好的可执行文件丢到目标板上就能跑。但实际操作中还要考虑一些运行时资源比如字体文件、framebuffer 设备、脚本依赖等。如果你是按上面 configure 命令构建的静态 Qt目标板只需要保证几样东西存在内核支持 framebuffer 设备通常是/dev/fb0可执行文件有执行权限有可用的字体文件。如果目标板系统里已经有/usr/share/fonts那大概率能直接跑。如果没有就需要把一个字体文件例如 DejaVuSans.ttf复制到目标板上并设置好 Qt 的字体搜索路径。Qt 库本身完全不需要部署到目标板这是动态编译做不到的。plugins、qml、translations这些目录在静态编译场景下大多数都是空的或不必要不需要复制。6.2 交叉编译一个 Hello Widgets 应用我在~/work/qt-hello下新建一个工程mkdir -p ~/work/qt-hello cd ~/work/qt-hello在工程目录下创建hello.proQT core gui widgets TARGET hello TEMPLATE app CONFIG c11 SOURCES main.cpp创建main.cpp#include QApplication #include QLabel int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label(Hello Qt5.14.2 aarch64 static); label.resize(360, 120); label.show(); return app.exec(); }然后用刚刚交叉编译出来的 qmake 来编译这个工程$QT_INSTALL_PREFIX/bin/qmake hello.pro make编译完成后用file命令检查二进制格式file hello输出应该是这样的hello: ELF 64-bit LSB executable, ARM aarch64, dynamically linked (uses shared libs), stripped这里显示的dynamically linked不要慌。它指的是系统 C 库libc、ld-linux 等仍然动态链接但 Qt 库本身已经全部以静态库方式链入二进制文件了。完全静态化会把系统的 glibc 也静态链入能省去系统库依赖但遇到用户解析、DNS 时非常容易踩坑所以实际项目中比较少这么做。如果你想进一步压缩对目标板系统的依赖可以在hello.pro里加一行QMAKE_LFLAGS -static-libgcc -static-libstdc这样把 C 运行时也静态链进去目标板上连libstdc.so都不需要了。6.3 真机运行字体、环境变量与插件注册把编译好的hello拷贝到目标板比如通过 scp 或 U 盘。在目标板上执行chmod x hello ./hello如果一切顺利屏幕上会出现一个 360x120 的窗口显示 “Hello Qt5.14.2 aarch64 static”。实际用起来我踩过最多的坑是这几种情况。第一种是Could not load the Qt platform plugin linuxfb in even though it was found这种报错。这一般是插件路径问题。虽然 Qt 是静态编译的但 platform 插件在默认情况下未必被自动链入可执行文件。解决办法有两个在工程文件里手动引入插件或者在 main.cpp 中显式导入插件。我推荐后者#include QtPlugin Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin)如果你担心不同 Qt 5.14 之间插件名有差异可以在hello.pro里添加QTPLUGIN qlinuxfb静态编译时Qt 的构建系统会利用.prl文件把插件自动链接进来。两种方法选一种即可。第二种是只有黑屏或者花屏。先确认真机有QApplication没有报错再检查/dev/fb0是否存在。如果ls /dev/fb0不存在很可能是内核没有配置 DRM/framebuffer 驱动。此外在部分单板机上你需要提前设置好显示环境变量才能使用 HDMI 输出比如设置QT_QPA_FB_DRM1或QT_QPA_PLATFORMlinuxfb:fb/dev/fb0。第三种是运行时缺字体导致中文显示成方块或者英文变豆腐块。此时可以直接运行fc-list 2/dev/null || ls /usr/share/fonts/如果不缺字体库就把字体路径设置成 Qt 能识别的export QT_QPA_FONTDIR/usr/share/fonts/truetype/dejavu ./hello如果你不想改系统环境也可以把字体文件放到可执行文件同级的fonts目录通过-platformfontpath或修改源码里的QFontDatabase逻辑实现加载。对快速验证来说直接设置QT_QPA_FONTDIR是最省事的方法。7. 常见问题速查与排错技巧7.1 配置阶段典型报错报错信息出现原因建议处理ERROR: Unknown module(s) in QT: widgetsmkspec 或-skip裁掉了 qtbase 以外关键模块或 qmake 路径不对检查 qmake 是否来自$QT_INSTALL_PREFIX/bin确认是否完整编译了 qtbaseERROR: Cannot find the platform configuration file-xplatform给了一个不存在的 mkspec用ls $QT_BUILD_ROOT/qtbase/mkspecs确认名称是否完全一致Basic XLib functionality test failed!主机误检测到 X11 相关依赖在 configure 中补上-no-xcb并确认 sysroot 里没有多余的 X11 头文件GL/gl.h: No such file or directoryOpenGL 相关头文件缺失或未彻底关闭确认-no-opengl同时排查 sysroot 里是否存在不完整的 GLES 头文件建议先删除再重新 configure7.2 编译阶段典型报错报错信息出现原因建议处理virtual memory exhausted: Cannot allocate memorymake -j开太高降到-j2或-j4同时限制 ccache 大小undefined reference to dlopen静态链接时缺少-ldl在 qmake.conf 或.pro中补充LIBS -ldl -lpthreadcannot find -lGLESv2某些模块仍引用 OpenGL ES在 configure 时明确-no-opengl -no-glesv2或保证 sysroot 提供库文件Error: invalid option -- D工具链版本和 Qt 源码处理方式不兼容优先考虑升级工具链或改用 Qt 5.15但如果你坚持 5.14.2建议换回老版本工具链7.3 运行阶段典型报错报错信息出现原因建议处理could not find or load the Qt platform plugin linuxfb平台插件没有被静态链接进应用使用Q_IMPORT_PLUGIN(QLinuxFbIntegrationPlugin)或在.pro中指定QTPLUGIN qlinuxfbThis application failed to start because no Qt platform plugin could be initializedQT_QPA_PLATFORM设置与 mkspec 不一致设置export QT_QPA_PLATFORMlinuxfb再运行Segmentation faulttoolbox 和 sysroot 版本差异较大或 glibc 不匹配检查工具链版本与目标板系统版本如果不一致重新交叉编译显示乱码或方块缺少字体或字体路径错误设置export QT_QPA_FONTDIR/usr/share/fonts如果还不行复制一个.ttf字体到板子上并指定该目录屏幕没有画面但进程在跑framebuffer 设备不存在或权限不足检查/dev/fb0用sudo chmod 666 /dev/fb0测试确认内核 DRM 驱动已加载7.4 几个可以“偷懒”却非常有效的技巧交叉编译踩坑踩多了我最大的体会是能用脚本就不要手敲。建议把 configure 命令保存成一个build_qt.sh同时把 configure 生成的config.summary一起保留这样下次不管是换工具链还是换目标板你都有一个能对账的基准。我还建议用 ccache 来加速反复编译。静态 Qt 每次重编都耗时启用 ccache 以后即使改了 Qt 源码里的某个模块大部分编译产物也能命中缓存export PATH/usr/lib/ccache:$PATH ccache -M 5G最后是 sysroot 的版本匹配问题。我发现很多人花大量时间排错最后发现是工具链版本太新gcc 生成的目标代码和目标板 glibc 版本对不上。一个稳妥做法是在目标板系统对应的发行版容器里打包 sysroot同时让工具链版本略低于目标系统的 glibc 版本这样兼容性最好。静态交叉编译 Qt 这条路走通一次以后就不再神秘。往后你在单板机上做的任何 Qt 应用都可以复用整套流程差别无非是裁剪模块和选项多少而已。我个人建议保存好这个完整配置把它当成项目的标准构建基线。在目标板显示设备、系统库和部署形态没有大变的前提下这套环境应该够用很长一段时间直到你有充分的理由升级 Qt 版本为止。
返回列表