装 Qt 这件事,在 Ubuntu 上可能就三行命令,但在统信 UOS 上,我前后折腾了差不多两天才把整套环境跑通——不是难,是坑藏得深。UOS 专业版的内核血统是 Debian,桌面是 DDE,包管理器还是 apt,表面上和 Debian 系一模一样,可它的软件源是自建的、包版本偏保守、部分包名直接跟上游对不上,你在网上搜到的 Ubuntu 教程十有八九会在某一步卡住。这篇就按我实际踩过的路线,把 Linux 统信 UOS 上搭建 Qt 开发环境的完整过程拆开讲:从系统体检、依赖清单,到 apt 直装 Qt5/Qt6、官方离线包落地、xcb 插件报错、中文输入法与高分屏,再到最后的依赖打包和 deb 制作。不管你是第一次在国产系统上写 Qt,还是从 Windows 迁过来想找个靠谱的落地路径,看完应该能少走不少弯路。
1. 为什么统信UOS上的Qt环境不能照搬Ubuntu那套
刚上手的时候我也是直接 Ctrl+C 了一段 Ubuntu 的安装命令,结果第一条sudo apt install qt5-default就报"无法定位软件包"。当时第一反应是软件源没更新,apt update跑了三遍还是不行,才意识到问题不在网络,而在包本身。
1.1 UOS的底层血统与软件源差异
UOS 专业版(也叫统信桌面操作系统专业版)底层基于 Debian,但具体跟哪个版本对齐,不同发行批次是有差异的,有的是 Debian 10 的底子,有的往 11 靠。这对 Qt 开发的影响主要有三点。
第一,qt5-default这个包在 Debian 10 之后的仓库里已经被移除了,上游把它拆成了qtbase5-dev、qt5-qmake、qtchooser等一组包。你在 CSDN 上刷到的老教程里那句apt install qt5-default,在 UOS 上必然失败。这不是 UOS 特意改的,是跟着上游走的。
第二,UOS 官方仓库里的 Qt 版本通常偏旧,常见的是 5.11 到 5.12 这个区间。做一般的上位机、串口工具、工控界面完全够用,但如果你要用 Qt 6 的新特性,或者项目要求 5.14/5.15,就只能走官方离线安装包这条路。
第三,很多单位的 UOS 机器是内网环境,外网访问受限,在线安装器(Qt Online Installer)跑到"正在获取组件列表"就会一直转圈。这时候离线安装包几乎是唯一解。
提示:判断能不能直接用 apt,先跑一次
apt-cache policy qtbase5-dev,看仓库里到底有没有这个包、版本号是多少,比盲目搜索快得多。
1.2 三条安装路线的取舍逻辑
我把在 UOS 上装 Qt 归纳成三条路线,各有各的适用场景,选错了会在后面反复返工。
| 路线 | 适用场景 | 优点 | 代价 |
|---|---|---|---|
| apt 直装 | 只做内网工具、版本要求不高 | 一次装全,依赖自动解决,卸载干净 | 版本偏旧,Qt6 支持视仓库而定 |
| 官方在线安装器 | 有外网、要指定版本 | 组件可选,能装 Qt Creator 和附加模块 | 内网跑不动,安装目录容易越滚越大 |
| 官方离线安装包 | 内网、要固定版本、要交付 | 完全离线,版本可控 | 包体大,组件需要提前想清楚 |
我的建议很直接:如果只是做个串口调试工具或者简单的上位机,走 apt,五分钟搞定;如果要长期维护、版本要跟团队对齐,走离线包,把安装目录放在/opt下统一管理;在线安装器基本只在你有顺畅外网、又想试新版本的时候用。
还有一点容易被忽略:Qt Creator 作为 IDE,在 UOS 上有个独立的包叫qtcreator,它跟 Qt 库本身是两回事。你完全可以用 apt 装 Qt Creator,再用离线包里的 Qt 库,二者通过 Kit 关联起来。这个组合在 UOS 上其实是最省心的。
2. 动手前的系统体检与依赖清单
我见过太多人一上来就敲安装命令,装到一半报缺库,然后开始一顿乱装,最后系统里堆了一堆半成品。花五分钟做个体检,后面能省两小时。
2.1 确认系统版本、架构与可用磁盘
先看系统身份。UOS 有多个架构版本,x86_64 是最常见的,但信创项目里 aarch64(飞腾/鲲鹏)、loongarch64(龙芯)也不少,架构对不上,安装包直接白下。
cat /etc/os-release uname -m dpkg --print-architecture/etc/os-release会告诉你发行版名称和版本号,uname -m给出内核架构(注意,内核架构和用户态架构在极少数定制机型上可能不一致,所以再补一条dpkg --print-architecture看 apt 认的架构)。
然后是磁盘。Qt 离线包安装完,加上 Qt Creator 和几个附加模块,占个 8 到 15 GB 很正常,如果勾了源码和文档,20 GB 都打不住。
df -h /opt df -h $HOME du -sh ~/.cache 2>/dev/null/opt通常挂在根分区上,$HOME可能是独立分区。我一般把 Qt 装在/opt/Qt,一来路径固定好记,二来团队里所有人的环境变量可以写成同一份脚本。如果/opt空间紧张,就装到家目录,但要记得路径里带用户名,脚本不能通用。
提示:UOS 的安装器(特别是 .run 格式的)在创建快捷方式、写
~/.local/share/applications时,如果你是用 sudo 跑的,文件属主会变成 root,之后普通用户改不了、删不掉,还会出现"菜单里有图标但点不开"的诡异现象。一定用普通用户身份运行。
2.2 软件源与apt使用注意
UOS 的 apt 源配置文件在/etc/apt/sources.list,有的版本还会在/etc/apt/sources.list.d/下放额外的源。先看看内容,确认仓库是否可达。
cat /etc/apt/sources.list ls /etc/apt/sources.list.d/ sudo apt updateapt update报错的话,常见就两种:一是源地址不通(内网没开白名单),二是 GPG 密钥过期。前者只能找运维,后者可以用sudo apt-key adv或者把密钥放到/etc/apt/trusted.gpg.d/下解决。我不建议随便往 sources.list 里加第三方源来"凑齐" Qt 的包,UOS 的库版本是有整体一致性的,混源容易把系统搞出依赖冲突,得不偿失。
另外一个小细节:UOS 默认可能开了自动锁屏和休眠,长时间编译到一半锁屏,某些显卡驱动下会导致 Qt Creator 的渲染出现花屏。在"控制中心 - 电源管理"里把自动锁屏时间调长,或者干脆关掉,编译体验会好很多。
2.3 编译工具链一次性装齐
Qt 只是框架,它底下还要靠编译器、构建工具和一堆开发头文件撑着。我习惯用一个命令把基础工具链一次装好,避免后面报错来回补。
sudo apt install -y \ build-essential \ gcc g++ make \ cmake ninja-build \ pkg-config \ git \ gdb \ ccache逐个说下为什么要它们。build-essential是元包,会带上 gcc、g++、make、libc6-dev 这些基础件,几乎是必备;cmake和ninja-build是给 CMake 工程用的,Qt 从 5.15 开始官方推荐 CMake 构建,Ninja 比 make 快一截,尤其在中大型工程上差距明显;pkg-config有些第三方库(比如 OpenCV、FFmpeg)的头文件路径要靠它来找;gdb是调试用,Qt Creator 里断点调试全靠它;ccache是编译缓存,反复重编译时能省一半以上时间,我个人强烈建议装上,配置也就是加个软链接的事。
想启用 ccache,在~/.bashrc里加一行就行:
export PATH="/usr/lib/ccache:$PATH"这样 gcc/g++ 会优先走 ccache 包装器,编译命令完全不用改。第一次编译没变化,第二次开始就能看到命中率了,用ccache -s可以查看统计。
3. 路线一:用apt把Qt5基础开发包装进系统
这条路线适合绝大多数"我就想在 UOS 上写个小工具"的场景。装完之后,系统和 Qt 库是融为一体的,升级、卸载都用 apt 管,非常干净。
3.1 核心包与可选包清单
基础开发包其实就两三个,但我一般会把常用的附加模块一起装上,省得后面缺什么补什么。
sudo apt install -y \ qtbase5-dev \ qtbase5-dev-tools \ qt5-qmake \ qtchooser \ qttools5-dev-tools \ libqt5serialport5-dev \ libqt5svg5-dev \ qtmultimedia5-dev \ qtdeclarative5-dev每个包的作用值得说清楚,不然你不知道该装哪个。qtbase5-dev是核心,包含 QtCore、QtGui、QtWidgets、QtNetwork 这些最常用的模块头文件和链接库;qtbase5-dev-tools带的是 moc、uic、rcc 这类元对象编译工具,没有它连信号槽都编译不过;qt5-qmake是 qmake 构建系统本体;qtchooser是版本选择器,后面讲多版本共存会用到。
qttools5-dev-tools里有个 Linguist 系列工具,做多语言翻译时要用;libqt5serialport5-dev是串口模块,工控和嵌入式调试场景几乎必装,这个包在 UOS 上名字和 Ubuntu 一致,可以直接装;libqt5svg5-dev处理 SVG 图标;qtmultimedia5-dev管音视频;qtdeclarative5-dev是 QML/Quick 相关。
如果你的 UOS 仓库里已经有 Qt6,也可以顺手装上,两代可以共存:
apt-cache policy qt6-base-dev sudo apt install -y qt6-base-dev qt6-tools-dev装之前用apt-cache policy确认一下有没有,没有就别硬来,报"无法定位软件包"的时候心情会不太好。
3.2 验证qmake、版本切换与qmake -query
装完别急着开 IDE,先在命令行验证。这一步能提前暴露 80% 的环境问题。
qmake -v which qmake qmake -queryqmake -v会输出类似QMake version 3.1和Using Qt version 5.12.8 in /usr/lib/x86_64-linux-gnu的信息。如果qmake命令找不到,多半是 qtchooser 没配好,或者 PATH 里没包含 Qt 的 bin 目录。
系统里同时有 Qt5 和 Qt6 的时候,qmake究竟指向哪个就要靠 qtchooser 管了:
qtchooser -list-versions export QT_SELECT=qt5 qmake -vqtchooser -list-versions会列出当前可选的版本,用QT_SELECT环境变量切换。但说实话,qtchooser 在 UOS 上偶尔会抽风,明明装了却列不出来。这种情况下我一般直接用绝对路径,最省心:
/usr/lib/qt5/bin/qmake -v /usr/lib/qt6/bin/qmake -v用绝对路径的好处是没有任何歧义,写脚本、配 IDE 都不会错。代价就是路径写死了,跨机器要改。这是个取舍,看你的场景。
编译一个最小工程验证一下,比什么都直观。建个目录,写个main.cpp:
#include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label(QStringLiteral("UOS 上的 Qt 跑起来了")); label.setAlignment(Qt::AlignCenter); label.resize(360, 120); label.show(); return app.exec(); }用 qmake 编译:
qmake -project qmake make ./项目名如果窗口弹出来了,说明库、编译器、链接器整条链路都是通的。这一步过了,后面基本就是 IDE 配置的事了。
3.3 Qt Creator 的安装与 Kit 配置
Qt Creator 在 UOS 上可以直接 apt 装:
sudo apt install -y qtcreator装完之后从启动器里能找到"Qt Creator"。第一次打开会进到"首选项 - 构建套件(Kit)"页面,这里是新手最容易懵的地方。我解释一下三个核心概念。
Qt Versions(Qt 版本):指向qmake可执行文件的路径,Qt Creator 通过它反向推导出 Qt 的头文件目录、库目录和版本号。apt 装的 Qt 一般是/usr/bin/qmake或/usr/lib/qt5/bin/qmake,点"添加"选上就行。
Compilers(编译器):C++ 编译器路径,apt 装的就是/usr/bin/g++,C 是/usr/bin/gcc。一般 Qt Creator 会自动检测到,检测不到手动加。
Kits(构建套件):把上面两者加上调试器组合起来的一套配置。名字随便起,比如"UOS-Desktop-Qt5",关键是"Qt Version"和"Compiler"两项要选对,还有"Debugger"要指向/usr/bin/gdb。
配好之后新建工程,编译运行,如果报"没有可用的构建套件",九成是 Kit 里某一项是红的。挨个看,红的那项就是问题所在。
提示:如果你用离线包装的 Qt,Kit 里的 qmake 路径要指向
~/Qt/5.14.2/gcc_64/bin/qmake这类位置,而不是/usr/bin/qmake。两套环境混用的时候,工程切换构建套件要记得同步切换,不然会出现"头文件是新的、库是旧的"这种典型链接错误。
4. 路线二:官方离线安装包落地UOS的完整流程
需要指定 Qt 版本,或者机器在内网,就走这条。流程比 apt 长,但可控性高得多。
4.1 选版本、下载与赋权
版本怎么选?我的经验是:新项目优先 5.15.x,这是 Qt5 的最后一个长期支持系列,生态最成熟,第三方库兼容性最好;如果项目要求 Qt6,那就 6.5 或更高的 LTS 版本。5.14.2 是老项目里出现频率很高的版本,很多既有代码都基于它,迁移成本低,所以也常被选。
下载下来的文件是个.run后缀的自解压安装器,名字类似qt-opensource-linux-x64-5.14.2.run。关键一步是赋可执行权限:
chmod +x qt-opensource-linux-x64-5.14.2.run ./qt-opensource-linux-x64-5.14.2.run注意前面不要加 sudo。我一开始图省事加了 sudo,装完结果 Qt Creator 的配置目录属主是 root,一打开就提示无法写入配置,改都改不动。只能把装好的目录整个删掉重来,白白浪费半小时。
还有一点,安装器是图形界面的,必须在桌面会话里跑,不能通过 SSH 无界面执行。
4.2 安装器卡住、组件勾选与离线包缺失
如果是离线安装包,安装器启动后会先让你登录 Qt 账号(新版本必须,老版本 5.14.2 可以跳过),然后进入组件选择页。这一步是整个流程里最需要动脑的地方。
安装路径:我建议/opt/Qt或者$HOME/Qt。/opt/Qt更规范,但要保证普通用户对该目录有写权限:
sudo mkdir -p /opt/Qt sudo chown $USER:$USER /opt/Qt这样安装器就能正常写入了,同时又不用 sudo 运行安装器,一举两得。
组件勾选:最少要勾这几项——
- Qt 对应版本下的
Desktop gcc 64-bit,这是 x86_64 桌面开发的核心库 Qt Creator,IDE 本体Qt Charts(做图表)、Qt Serial Port(串口)这类项目实际会用到的附加模块Sources和Debugging Tools,看个人磁盘空间,调试时能跳进 Qt 源码对排查问题帮助很大
关于卡住:离线包理论上不需要网络,但安装器启动阶段有时仍会尝试连服务器校验,内网环境下这一步会卡很久甚至超时。我的做法是先断网再启动安装器,或者在/etc/hosts里把相关域名指向 127.0.0.1,让它快速失败然后继续走离线流程。这个办法不优雅,但实测有效。
4.3 环境变量与多版本共存
装完之后,Qt 并不会自动加到 PATH 里。要在终端直接敲qmake,得配环境变量。我不建议全局改/etc/profile,那样会污染整个系统,一旦哪天想换版本就会牵一发动全身。写在~/.bashrc里更灵活:
export QTDIR=$HOME/Qt/5.14.2/gcc_64 export PATH=$QTDIR/bin:$PATH export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATHLD_LIBRARY_PATH这一条要谨慎。它会覆盖系统默认的库搜索路径,如果设得不对,可能导致系统自带的 Qt 程序(UOS 桌面本身就有不少 Qt 程序)启动异常。更安全的做法是不设LD_LIBRARY_PATH,而是在编译时通过-Wl,-rpath指定运行时库路径,或者干脆只在构建脚本里临时导出。
多版本共存的话,我习惯用 shell 函数来切换,比记住一堆路径靠谱:
qt514() { export QTDIR=$HOME/Qt/5.14.2/gcc_64 export PATH=$QTDIR/bin:$PATH qmake -v } qt65() { export QTDIR=$HOME/Qt/6.5.0/gcc_64 export PATH=$QTDIR/bin:$PATH qmake -v }写进~/.bashrc,需要哪个版本就敲哪个命令,当前在用哪个版本一目了然。这个小技巧我在好几个项目上用了,切换成本几乎为零。
5. 让程序真正跑起来:xcb、输入法、字体与高分屏
库装好了、代码编译通过了,双击运行却弹不出窗口——这是 UOS 上 Qt 新手最容易被劝退的环节。问题基本集中在四类:平台插件、输入法、字体、缩放。
5.1 "could not load the Qt platform plugin xcb" 的完整解法
这是出现频率最高的报错,完整信息通常是这样的:
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. This application failed to start because no Qt platform plugin could be initialized.很多人看到"even though it was found"就懵了,既然找到了为什么加载不了?原因是 Qt 的平台插件libqxcb.so本身依赖一批 xcb 相关的系统库,这些库缺失时,插件的动态加载就会失败,但 Qt 的错误信息不会告诉你缺了哪个库。
排查方法很直接,打开插件的调试输出:
export QT_DEBUG_PLUGINS=1 ./你的程序它会打印出加载libqxcb.so的全过程,最后几行会明确写出Cannot load library ... libxcb-xxx.so.1: cannot open shared object file,缺哪个装哪个。常见的缺失库和对应包如下:
| 报错中缺失的库 | 对应的包名 |
|---|---|
| libxcb-xinerama.so.0 | libxcb-xinerama0 |
| libxcb-icccm.so.4 | libxcb-icccm4 |
| libxcb-image.so.0 | libxcb-image0 |
| libxcb-keysyms.so.1 | libxcb-keysyms1 |
| libxcb-randr.so.0 | libxcb-randr0 |
| libxcb-render-util.so.0 | libxcb-render-util0 |
| libxcb-shape.so.0 | libxcb-shape0 |
| libxkbcommon-x11.so.0 | libxkbcommon-x11-0 |
| libxcb-xkb.so.1 | libxcb-xkb1 |
不想一个个排查的话,可以一次性把这些都装上,反正体积不大:
sudo apt install -y \ libxcb-xinerama0 libxcb-icccm4 libxcb-image0 \ libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \ libxcb-shape0 libxcb-xkb1 libxkbcommon-x11-0还有一个隐藏坑:如果QT_QPA_PLATFORM_PLUGIN_PATH这个环境变量被设成了错误的路径,或者你手动设过QT_QPA_PLATFORM,插件就可能在错误的目录里找。检查一下:
env | grep QT_如果没有特殊需求,这些变量一个都不要设,让 Qt 自动推断最省事。跑unset QT_QPA_PLATFORM_PLUGIN_PATH清掉之后往往问题就没了。
提示:如果你是在 root 用户下运行 Qt 程序,还可能碰到另一个问题——root 用户没有继承普通用户的 DISPLAY 和 XAUTHORITY 环境变量,导致连不上 X 服务器。用
sudo -E保留环境变量,或者先xhost +local:再运行,都能绕过。
5.2 中文输入法与字体
输入法问题在 UOS 上很典型:程序能跑,但输入框里打不出中文,或者输入法候选框位置跑到屏幕左上角去了。
UOS 默认用的是基于 fcitx 的输入法框架(搜狗、讯飞之类都是它的前端)。Qt5 程序要通过 fcitx 输入中文,需要libfcitx-qt5这个插件,并且环境变量要对:
export QT_IM_MODULE=fcitx export XMODIFIERS=@im=fcitx export GTK_IM_MODULE=fcitx检查插件是否存在的办法是看 Qt 的输入法插件目录:
ls /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/正常情况下应该能看到libfcitxplatforminputcontextplugin.so。如果没有,说明libfcitx-qt5相关的包没装:
sudo apt install -y fcitx-frontend-qt5如果你用的是离线包安装的 Qt,那问题会麻烦一点——那个输入法插件是针对系统 Qt 编译的,二进制层面跟离线包的 Qt 版本可能不匹配,需要自己把插件编译一份放到离线包的插件目录里。做法是拿系统的插件先试,不行再编译源码。
字体这块,UOS 自带了一套中文字体(常见的是方正系列),一般不需要额外装。但如果你的 Qt 程序在启动时显示方框或者乱码,通常是两个原因:一是源码文件的编码不是 UTF-8,二是字符串没有正确转换。Qt5 之后的默认编码已经是 UTF-8,QStringLiteral和QString::fromUtf8都能正确处理中文。老代码里那些QTextCodec::setCodecForTr的写法可以直接删掉,反而容易出问题。
判断字体是否真的生效,可以在启动时打印一下:
qDebug() << QFontDatabase().families().mid(0, 10);5.3 高分屏与显示缩放
UOS 支持在控制中心里设置缩放比例,125%、150% 很常见。Qt5 程序在非整数缩放下的表现一直是个痛点:要么模糊,要么控件重叠,要么鼠标点击位置和视觉位置错位。
Qt5 需要在程序启动前开启高 DPI 支持:
#include <QApplication> int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication app(argc, argv); // ... }这两行必须在QApplication构造之前调用,写在后面就无效了,这是个很容易忽略的顺序问题。AA_EnableHighDpiScaling让控件按缩放比例放大,AA_UseHighDpiPixmaps让图标用高清版本而不是放大后模糊。
运行时还可以用环境变量临时调:
export QT_AUTO_SCREEN_SCALE_FACTOR=1 export QT_SCALE_FACTOR=1.25QT_AUTO_SCREEN_SCALE_FACTOR=1让 Qt 跟随系统的缩放设置自动计算,QT_SCALE_FACTOR则是强制指定一个倍率。调试布局的时候我经常临时设QT_SCALE_FACTOR来模拟不同缩放下的效果,比反复改系统设置快多了。
6. 从能编译到能交付:依赖梳理与打包
自己机器上跑起来只是一半,另一半是把程序交到别人手上还能跑。UOS 上分发 Qt 程序,最容易出的问题是"我这儿好好的,同事那儿双击没反应"。
6.1 ldd 与依赖梳理
先把程序依赖了哪些库摸清楚。ldd是最直接的工具:
ldd ./你的程序 | grep "=> /"输出会列出所有运行时需要的共享库。顺序上我建议分成两类看:系统库(libc、libstdc++、libX11 这些)不用管,UOS 自带并且版本稳定;Qt 相关库(libQt5Core、libQt5Gui、libQt5Widgets 等)要重点关注,因为不同机器上的 Qt 版本可能不一样。
如果程序用了 Qt 的插件,比如platforms/libqxcb.so、imageformats/libqjpeg.so、sqldrivers/libqsqlite.so,这些是不出现在ldd输出里的,但运行时必须要。这是新手最容易漏的点——你拷了所有.so,程序还是起不来,就差在插件目录上。
6.2 打包方案:手动拷贝加rpath
linuxdeployqt是社区里流传很广的自动打包工具,思路是扫描可执行文件、把依赖库拷到一起、用patchelf改 rpath。它在 Ubuntu 上比较好用,但在 UOS 上我踩过坑:它依赖的一些工具版本对不上,而且它扫描出来的一些系统库被一起打进去后,反而在目标机器上引起冲突。
所以我的做法是半手动,逻辑清楚、出了问题也好定位。目录结构按 Qt 自己的布局来:
发布包/ ├── 你的程序 (可执行文件) ├── lib/ (Qt 的 .so 都在这里) │ ├── libQt5Core.so.5 │ ├── libQt5Gui.so.5 │ └── ... ├── plugins/ │ ├── platforms/libqxcb.so │ ├── imageformats/ │ └── ... └── 你的程序.sh (启动脚本)然后用patchelf把可执行文件的 rpath 指向lib:
patchelf --set-rpath '$ORIGIN/lib' 你的程序$ORIGIN是个特殊变量,表示可执行文件自身所在目录,这样整个包放到哪个路径下都能找到库。启动脚本里把插件路径指出来:
#!/bin/bash DIR="$(cd "$(dirname "$0")" && pwd)" export QT_QPA_PLATFORM_PLUGIN_PATH="$DIR/plugins/platforms" export QT_PLUGIN_PATH="$DIR/plugins" exec "$DIR/你的程序" "$@"这几个环境变量的含义值得记一下:QT_QPA_PLATFORM_PLUGIN_PATH只管平台插件(就是那个 xcb),QT_PLUGIN_PATH管其他所有插件(图片格式、数据库驱动等)。两个都设上最保险。
6.3 打成deb包并安装验证
裸目录分发适合临时用,正式一点还是打成 deb。deb 包本质上就是个特定结构的压缩包,手工做并不难。
先建目录骨架:
mkdir -p pkg/DEBIAN mkdir -p pkg/opt/myapp mkdir -p pkg/usr/share/applications cp -r 发布包/* pkg/opt/myapp/写控制文件pkg/DEBIAN/control:
Package: myapp Version: 1.0.0 Section: utils Priority: optional Architecture: amd64 Depends: libxcb-xinerama0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1 Maintainer: 你的名字 <you@example.com> Description: 基于 Qt 的某某工具 一句话功能说明。Architecture要跟你实际打包的平台一致,x86_64 写amd64,ARM64 写arm64。Depends里列出那些 xcb 相关的库,这样安装时 apt 会自动帮你补依赖,用户就不用自己去查缺哪个包了。
再放一个桌面入口文件pkg/usr/share/applications/myapp.desktop:
[Desktop Entry] Type=Application Name=MyApp Exec=/opt/myapp/你的程序.sh Icon=/opt/myapp/icon.png Categories=Development; Terminal=false最后打包:
dpkg-deb --build pkg myapp_1.0.0_amd64.deb验证环节不能省,一定要在一台干净的 UOS 机器上装一遍。用sudo dpkg -i装,如果报依赖问题,用sudo apt -f install补齐。装完从启动器点开,能正常出窗口、能输入中文、缩放正常,才算真的交付完成。
有个小细节:.desktop文件里的Exec用绝对路径最稳妥,如果用了启动脚本,记得给脚本加可执行权限,否则双击没反应,排查起来很浪费时间。
7. 我在UOS上踩过的具体坑与排查清单
前面讲的是"应该怎么做",这一节讲讲我实际踩到的、文档里不会写的那些坑,以及一套我常用的排查顺序。
7.1 几个印象深刻的坑
坑一:sudo 跑安装器导致后续全乱。第一次装离线包的时候我图省事sudo ./qt-opensource-linux-x64-5.14.2.run,结果 Qt Creator 的配置目录、缓存目录属主全是 root。表现是打开 Qt Creator 后任何设置都保存不了,Kit 配好重启就没了。解决方式不是改权限,而是把~/.config/QtProject和安装目录一起删掉重装。这个教训让我之后所有 GUI 安装器都坚持用普通用户跑,需要写系统目录就提前chown。
坑二:qt5-default 不存在,绕了一大圈。就是开头说的那个,一开始以为是自己源配错了,折腾半天换源、清缓存,最后才发现是包名跟着上游变了。后来我养成了一个习惯,装任何包之前先apt-cache search或者apt-cache policy确认一下,比盲目试快得多。
坑三:串口模块缺失导致链接失败。项目里用了QtSerialPort,apt 里装的是libqt5serialport5-dev,但我用的是离线包 Qt,头文件和库不在离线包里,编译直接报找不到<QtSerialPort/QSerialPort>。解决办法是在安装器里勾上 Qt Serial Port 组件,或者用系统那一份库,但要注意 ABI 匹配。离线包安装时组件一定要一次性想清楚,补装虽然可以再跑一次安装器,但会覆盖已有配置,比较烦。
坑四:输入法在 Qt6 上失效。Qt5 时代的fcitx-frontend-qt5对 Qt6 无效,Qt6 需要单独的输入法插件。如果你用 Qt6 开发,中文输入一时半会儿可能搞不定,我的临时方案是用 Qt5 做界面开发,或者给 Qt6 编译对应的 fcitx 插件。这个坑当时卡了我整整一个下午。
坑五:离线包 Qt 和系统 Qt 混用的库冲突。程序在开发机上跑得好好的,拷到测试机上启动就段错误。排查半天发现是开发机上LD_LIBRARY_PATH指向了离线包的 Qt,程序链接的是 5.14 的库,而测试机上加载到了系统的 5.12 库,ABI 不兼容直接崩。这也是我前面强调 rpath 而不是LD_LIBRARY_PATH的原因。
7.2 一张随手可查的排查表
遇到问题先别急着搜,按下面的顺序过一遍,大部分情况三轮之内就能定位。
| 现象 | 首要排查方向 | 常用命令 |
|---|---|---|
| 找不到 qmake | PATH 或 qtchooser 配置 | which qmake、qtchooser -list-versions |
| xcb 插件加载失败 | 缺 xcb 系列系统库 | QT_DEBUG_PLUGINS=1 ./程序 |
| 窗口弹出后立即退出 | 段错误或库版本冲突 | ldd ./程序、gdb ./程序 |
| 输入框打不出中文 | 输入法插件或环境变量 | echo $QT_IM_MODULE、查插件目录 |
| 中文显示成方框 | 字体缺失或编码问题 | `fc-list |
| 界面模糊或错位 | 高 DPI 未开启 | 检查AA_EnableHighDpiScaling |
| 换机器就跑不起来 | 插件未打包或 rpath 不对 | patchelf --print-rpath 程序 |
| 编译速度慢得离谱 | 没开 ccache 或并行度低 | ccache -s、make -j$(nproc) |
这张表是我压在桌面上的东西,每次换新机器搭环境都会对照着走一遍。它的价值不在于解决具体问题,而在于让你在慌乱的时候有个固定的起点,不至于东一榔头西一棒子。
最后再说一个我个人觉得挺有用的小习惯:把整套环境搭建过程写成一个 shell 脚本,从装依赖、配环境变量到创建目录,全部固化下来。UOS 的发行批次之间包名偶尔会有细微差异,但绝大部分命令是通用的,脚本跑一遍就能在新机器上复现环境,比口头跟同事说"你先装这个再装那个"高效太多。脚本里加上set -e,任何一步失败就停住,避免错误累积到最后才发现。这套东西我在三台不同配置的 UOS 机器上跑过,除了个别包名需要微调,整体非常省事。