FEATURED · 精选文章

Ubuntu下用linuxdeployqt打包Qt程序:从原理到常见坑的全流程指南

发布时间 / 2026/9/7 23:35:12
来源 / 创域科博编辑部
栏目 / 资讯中心
Ubuntu下用linuxdeployqt打包Qt程序:从原理到常见坑的全流程指南 简介面向需要在Ubuntu下将Qt程序打包并分发至无Qt环境主机的开发者这份PDF文档围绕linuxdeployqt工具系统讲解从Qt环境配置、编译linuxdeployqt源码到最终打包运行的完整流程。文档以实操方式给出~/.bashrc中PATH、LD_LIBRARY_PATH、QT_PLUGIN_PATH、QML2_IMPORT_PATH等环境变量的设置方法并针对Ubuntu 18.04等高版本系统编译源码时需注释glibc版本检查的细节做了说明。打包环节重点分析了两个高频错误patchelf工具缺失导致rpath读取失败以及libjasper.so.1缺失导致图片格式插件加载异常均给出了直接的apt安装命令和排错思路读者还可参考其中利用ldd定位缺失依赖、手动补充Qt字体、图标与QML模块的方法。资源为单个PDF文档大小约58KB篇幅精炼但覆盖关键难点已有2720人学习适合需要快速掌握linuxdeployqt打包流程的C/Qt开发者参考。1. 写在前面linuxdeployqt这把双刃剑在Ubuntu下给Qt程序打包我猜你十有八九跟linuxdeployqt较过劲。这东西本来是给Linux桌面应用做AppImage打包的但实际用起来报错能让人怀疑人生——平台插件找不到、xcb依赖缺失、ICU版本不对、qmake路径踩错……我最早接触它是在把一个Qt 5.12的串口工具发布给客户时折腾了整整两天最后总算摸透了它的脾气。这篇就专注解决一个问题在Ubuntu上怎么把别人机器上编译好的Qt程序用linuxdeployqt打包成一扔就能跑的独立可执行文件。适合刚上手Linux Qt开发、或者正被各种缺库报错折磨的兄弟参考。我会把原理、流程、常见坑一次讲清尽量让你少走弯路。先说结论linuxdeployqt本身不复杂复杂的是一堆环境依赖和Qt安装方式的坑而这些坑大多数时候是可以绕开的。2. 打包前必须搞懂的三件事2.1 linuxdeployqt到底在做什么简单来说linuxdeployqt做的事就两件一是把可执行文件依赖的Qt库比如libQt5Core.so.5、libQt5Gui.so.5复制到目标目录里二是去改写可执行文件里的库搜索路径让它在运行时能从相对路径找到这些库而不是只依赖系统的标准路径。它底层靠的是ldd扫描依赖、patchelf修改ELF的RPATH或者RUNPATH。对Qt程序来说它还会根据你源码里用过的模块去补全插件比如platforms/目录下的libqxcb.so这个特别关键——如果你遗漏了这个插件就会出现经典的could not find or load the Qt platform plugin xcb报错。理解这一点很重要因为很多排查思路都建立在这个机制上。它不是万能药只解决Qt自身依赖的问题。如果你的程序还依赖了一些别的第三方库比如OpenCV、FFmpeglinuxdeployqt默认不会帮你带除非你用额外的参数去处理。2.2 为什么选linuxdeployqt而不是其他方案打包Linux Qt程序主要有三条路一是直接编译成静态链接的Qt版本但Qt官方对静态链接的授权有限制开源版必须注意动态链接的合规性而且很多插件做静态化很麻烦二是用AppImage官方推荐的linuxdeployqt工具链也就是这里要说的方案三是自己手写shell脚本复制库修RPATH能行但极其费劲。我自己的体会是linuxdeployqt最大的优势是自动化程度高配合-appimage参数一条命令能出产物缺点是它对新版Qt和部分桌面环境的兼容性不够完美一不注意就踩坑。如果你只是要一个能跑的目录非AppImage单文件用它就够了如果你非要生成AppImage那还得额外装linuxdeploy这个辅助工具。2.3 打包环境的准备细节建议在一台比较干净的Ubuntu 18.04/20.04/22.04上做打包。为什么强调干净因为如果系统里已经装了一堆乱七八糟的Qt版本、各种LD_LIBRARY_PATHlinuxdeployqt扫描到的Qt库路径可能不是你编译时用的那套最后打包出来的程序在其他机器上跑不起来。准备阶段你得先把这几个东西装好sudo apt update sudo apt install build-essential libgl1-mesa-dev patchutils sudo apt install qt5-default # 或者你需要的Qt版本然后下载linuxdeployqt注意要选对版本。官方GitHub的Release页面提供了linuxdeployqt-continuous-x86_64.AppImage这种持续构建版直接下载加执行权限就行wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage chmod x linuxdeployqt-continuous-x86_64.AppImage下载完先确认它能跑./linuxdeployqt-continuous-x86_64.AppImage --version。如果缺FUSE跑不起来用--appimage-extract-and-run参数绕过去。这一步很多人会卡住记住了。3. 核心细节库扫描、qmake路径与插件复制3.1 qmake路径是第一个坑linuxdeployqt运行时会去调用qmake来获取Qt的安装路径、模块列表等信息。如果你的系统里有多个Qt比如Qt Creator自带的、系统装的、手动编译的linuxdeployqt很可能找错。常见报错是Could not find qmake in PATH或者打包出来到了别的机器上报Qt version mismatch。解决思路很明确把编译这个程序时用的那个qmake所在目录放到PATH最前面。比如你用的Qt 5.15.2装在/opt/Qt/5.15.2/gcc_64/bin那就export PATH/opt/Qt/5.15.2/gcc_64/bin:$PATH export LD_LIBRARY_PATH/opt/Qt/5.15.2/gcc_64/lib:$LD_LIBRARY_PATH然后先跑qmake -v确认版本再跑linuxdeployqt。这一步能解决大概一半的诡异问题。3.2 库扫描的坑与对策linuxdeployqt靠ldd扫描。但ldd有个特性它会优先读取当前环境里的LD_LIBRARY_PATH。如果你在打包时设了乱七八糟的库路径它扫到的依赖可能不是你预期的那一份。我的习惯是打包前清空LD_LIBRARY_PATH临时unset掉只保留PATH里的qmake指向。这样扫描结果最干净。另外一个注意点如果你的程序里通过dlopen动态加载了某些库比如插件系统linuxdeployqt默认扫不到。应对办法是手动把那些动态加载的so复制到打包目录的相应位置或者用unsupported-ignore-errors参数配合白名单去补。3.3 平台插件的完整复制逻辑linuxdeployqt会把Qt的插件目录整个复制到打包目录下的plugins文件夹。它是通过读取Qt安装目录里的qt_plugins路径来实现的。如果你用的是自己编译的Qt插件路径很可能不在标准位置导致复制不完整。这时你可以用-qmldir参数指定QML模块目录如果你的程序用了QML或者直接手动复制插件cp -r /opt/Qt/5.15.2/gcc_64/plugins/platforms ./打包目录/ cp -r /opt/Qt/5.15.2/gcc_64/plugins/imageformats ./打包目录/ # 其他用到的插件按需补充经验之谈platforms/libqxcb.so是重中之重缺了它几乎一定会报platform plugin xcb错误。如果出现这个报错优先检查打包目录下的plugins/platforms/里有没有这个文件。4. 实操过程一条完整的打包链路4.1 准备项目与编译咱们用一个最简单的Qt Widgets程序来演示。假设项目目录为/home/user/MyApp里面有MyApp.pro、main.cpp、mainwindow.cpp等文件。先确保用正确的qmake编译cd /home/user/MyApp mkdir build cd build qmake ../MyApp.pro make -j4编译成功后你会得到可执行文件MyApp。用ldd MyApp看一下它的依赖这里面会列出系统路径里的Qt库、X11库、xcb库等。这些信息后面排错很有用。4.2 用linuxdeployqt生成可分发目录先把可执行文件复制到一个干净的发布目录中比如/home/user/MyApp/releasemkdir -p /home/user/MyApp/release cp /home/user/MyApp/build/MyApp /home/user/MyApp/release/ cd /home/user/MyApp/release然后执行打包命令export PATH/opt/Qt/5.15.2/gcc_64/bin:$PATH unset LD_LIBRARY_PATH ../linuxdeployqt-continuous-x86_64.AppImage ./MyApp -verbose2这里的-verbose2很推荐它能打印详细的拷贝日志方便你看到底复制了哪些库、漏了哪些。命令跑完后目录下应该是这样的结构release/ ├── MyApp ├── lib/ │ ├── libQt5Core.so.5 │ ├── libQt5Gui.so.5 │ ├── libQt5Widgets.so.5 │ └── ... ├── plugins/ │ ├── platforms/ │ │ └── libqxcb.so │ ├── imageformats/ │ └── ... ├── qt.conf └── AppRun # 如果加了-appimage参数才会生成注意qt.conf这个文件它告诉Qt可执行文件去哪找插件和库。如果没有它程序会去系统的绝对路径找Qt库那就前功尽弃了。linuxdeployqt一般会自动生成你也可以手动检查里面内容通常类似[Paths] Prefix . Plugins plugins4.3 生成AppImage单文件可选如果你想要一个双击就能运行的AppImage需要再装一个辅助工具linuxdeploy。过程不复杂本质是把刚才的release目录打包进AppImage的squashfs文件系统里。不过AppImage方式对系统缺少FUSE的机器兼容性要差一些我一般更推荐直接用目录方式发布拷给别人的时候打个tar.gz就行。4.4 验证打包结果打包完成后务必在一台没有安装Qt的干净机器或容器里测试。最简单的验证方法export LD_LIBRARY_PATH./lib ./MyApp如果程序能正常弹窗说明打包成功。如果报错接下来看第5节的排查思路。5. 常见问题与排查技巧实录5.1 could not find or load the Qt platform plugin xcb这是出现频率最高的问题。原因通常有三种一是plugins/platforms/libqxcb.so不存在或没有执行权限二是libqxcb.so依赖的一些系统库缺失比如libxcb-iccc4、libxcb-image0、libxcb-keysyms1等三是xcb相关库版本不对。排查时先检查libqxcb.so在不在再用ldd看它有没有unresolved的依赖ldd ./plugins/platforms/libqxcb.so | grep not found如果有not found去系统里找对应的so装到lib/目录下或者直接把系统对应包安装上sudo apt install libxcb-xinerama0 libxcb-iccc4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev说实话这一步很多教程不会写但是实际复制libqxcb.so之前先确认这些xcb辅助库都在能省掉后面一堆麻烦。5.2 提示error while loading shared libraries: libQt5Core.so.5: cannot open shared object file这个属于最典型的RPATH/库路径问题。linuxdeployqt在可执行文件里写入了相对路径或绝对路径去指向lib/目录但如果它没写对或者程序在运行时因为某些原因覆盖了搜索路径就会找不到库。检查可执行文件的RPATHreadelf -d MyApp | grep -i rpath正常情况应该看到类似$ORIGIN/lib的条目。如果为空可以用patchelf手动加patchelf --set-rpath $ORIGIN/lib MyApp另外检查一下系统中是否装了和你打包版本冲突的Qt库特别是在用户主目录下的.qmlc缓存、.config配置里可能有旧的路径缓存。5.3 This application failed to start because it could not find or load the Qt platform plugin这个报错和第一种的区别在于即便libqxcb.so存在它仍然加载失败。通常是因为libqxcb.so依赖的libQt5XcbQpa.so.5缺失或者系统的GL库版本太低。我的经验是如果你打包用的Qt版本太新比如5.15.2以上在Ubuntu 18.04这类老系统上跑极容易遇到GL库版本对不上的问题因为Qt的xcb插件会去加载libGL。处理办法是额外拷贝一份libGL和libEGL相关的库进lib/目录cp /usr/lib/x86_64-linux-gnu/libGL.so.1 ./lib/ cp /usr/lib/x86_64-linux-gnu/libEGL.so.1 ./lib/ cp /usr/lib/x86_64-linux-gnu/libglapi.so.0 ./lib/有些家伙直接把系统的libGL目录整个拷进去虽然有点粗暴但确实能解决掉不少显示相关的问题。5.4 程序能启动但显示QXcbConnection: Could not connect to display这种问题常见于在没有图形界面的环境比如纯终端服务器里测试或者SSH远程转发X11时权限不对。属于运行环境问题而非打包问题。确认你在有真实桌面会话的机器上测试就行。5.5 打包时出现ERROR: The host system is too old for this version of Qt这个报错一般是因为linuxdeployqt检查了Qt版本和宿主系统glibc版本之间的关系认为目标系统太老。解决方法是给linuxdeployqt传参跳过检查-unsupported-allow-前缀的参数比如-unsupported-allow-new-glibc在某些版本里叫这个具体用--help看。不过注意这属于危险操作。如果目标机器glibc版本确实太低跳过检查后程序依然可能跑不起来。从源头解决还是要选择与你目标机器glibc兼容的Qt版本。5.6 打包后体积异常大又不知道怎么精简默认linuxdeployqt会把Qt库各种依赖都拷过来几MB的程序打包成一百多MB很常见。精简的话可以自己控制复制范围不直接让linuxdeployqt全量复制而是手动选择lib/和plugins/下的文件。一个比较实用的精简策略是保留core、gui、widgets、network这几个主库删掉qml相关的大块头插件只保留platforms和imageformats这两个目录其他按需补充。实测一个串口工具从160MB能精简到60MB左右当然前提是程序没用到QML。6. 文章最后的实操心得这一路踩坑踩下来我自己有个习惯固定下来了每次打包前先在打包目录里放一个run.sh脚本内容大概是#!/bin/bash # 确保Qt库路径正确 SELF_DIR$(cd $(dirname $0) pwd) export LD_LIBRARY_PATH$SELF_DIR/lib:$LD_LIBRARY_PATH export QT_PLUGIN_PATH$SELF_DIR/plugins exec $SELF_DIR/MyApp $这样即使linuxdeployqt生成的RPATH有点问题靠着这个脚本也能兜底。很多Linux用户在遇到platform plugin报错时都会习惯性地用export QT_DEBUG_PLUGINS1去调试日志会精确打出插件加载失败的原因这个参数强烈推荐——它是我排查Qt打包问题时的第一把钥匙。如果你照着上面的流程走绝大多数问题都能解决。实在不行还有个笨办法直接把整个Qt安装目录里的lib和plugins拷过去虽然大但确实什么都不会缺。个人体会是打包这件事别追求一步到位先跑通再优化体积和兼容性这才是靠谱的节奏。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻