先说结论:这问题十有八九不是搜狗输入法坏了,也不是 Qt 装错了,而是 Qt6 自带的插件目录里根本没有加载 fcitx 输入法框架的 Qt 模块。你把QT_IM_MODULE=fcitx设得再勤快,插件文件不落地,Qt6 应用死活都弹不出中文候选框。这篇文章记录的就是一套在麒麟 V10 系统下,安装 Qt 6.7.3 并编译 fcitx 输入法插件,最终在 Qt6 应用里正常打出中文的完整流程。配置思路对海光 amd64、兆芯 amd64、华为 arm64 这类国产硬件平台同样适用,命令基本通用。
1. 先把问题根因掰开:Qt6 为什么突然不认输入法了
很多人在麒麟 V10 上用 Qt5 的时候,中文输入法一直好好的,但换上官方 Qt6 之后就变成只能打英文。这不是你操作问题,而是 Qt5 和 Qt6 在输入法接入机制上本来就不一样。
1.1 Linux 输入法是怎么跟 Qt 打交道的
Linux 桌面里的输入法框架,比如 fcitx、ibus、搜狗输入法,和应用程序之间不是直接对话的。它们通过一套协议做桥接,早期的 XIM 协议,后来的 GTK_IM_MODULE、QT_IM_MODULE 环境变量,本质上都是告诉应用程序“你该去找哪个输入法框架要中文候选词”。
对 Qt 程序来说,它在启动时会根据QT_IM_MODULE这个环境变量,去 Qt 自己的插件目录platforminputcontexts/下面找对应的插件文件,然后加载它。比如变量值等于fcitx,Qt 就会去找libfcitxplatforminputcontextplugin.so这个动态库,找到了才能和输入法框架建立双向通道,键盘事件才能被转换成中文候选词。
打个比方,Qt 应用就像一台电脑,输入法是显示器,而那个插件就是显卡驱动。操作系统装好了,Windows 认识,但如果你把一张 NBA 显卡插上去,没有对应驱动,显示器当然不亮。Qt6 的问题就是官方给的那套“驱动”里,缺失了 fcitx 这一张。
1.2 搜狗输入法在麒麟系统上通常挂在 fcitx4 下
麒麟 V10 官方源里的搜狗输入法,几乎都是基于 fcitx 4.x 框架的。新版 fcitx5 虽然也能用,但搜狗 Linux 版并不直接等于 fcitx5。我们这边遇到的大部分麒麟机器,默认搜索狗都是和 fcitx4 绑定在一起的。
所以当你给 Qt6 程序设置QT_IM_MODULE=fcitx时,Qt 要的不是 fcitx5 的新版接口,而是那个能对接 fcitx4 的 Qt 输入上下文插件。这一点很关键,因为它直接决定了你该去编译哪个源码包。用错了工程,编译出来的插件对不上号,照样没用。
不少人在这一步踩坑,跑去下载 fcitx5 的 Qt 插件在 fcitx4 环境下强行加载,结果 fcitx 进程里根本没有对应的上下文,Qt 程序照样无法输入中文。
1.3 Qt 官方安装包默认不带 fcitx 插件
Qt 官方提供的 Linux 离线安装包或在线安装包,里面 Qt 6.7.3 确实自带了一堆 QPA 平台插件,也带了 ibus 的输入上下文插件,但唯独没有带 fcitx 的插件。如果你打开装好的 Qt 目录看一眼:
ls /opt/Qt/6.7.3/gcc_64/plugins/platforminputcontexts/大概率看到的就是libibusplatforminputcontextplugin.so这类文件,根本没有libfcitxplatforminputcontextplugin.so。于是环境变量QT_IM_MODULE=fcitx就成了空气,Qt 只能默默回退到默认的 xcb 输入上下文,最终表现就是中英文切换无效。
所以问题的核心不是“Qt6 安装失败”,而是“Qt6 缺少 fcitx 的桥接插件”。解决方案也很明确,手动编译一个 fcitx 的 Qt6 插件,扔到 Qt6 的插件目录里。
2. 动手前先检查环境和依赖,顺便把 Qt 6.7.3 装上
编译插件这件事本身不算难,但环境不对,后面会反复报错,而且错得莫名其妙。我习惯先花十分钟把环境弄清,别急着 clone 源码开编。
2.1 三步确认系统版本、CPU 架构和输入法框架
首先确认操作系统版本,麒麟 V10 有桌面版和服务器版,包管理器也有所不同,有的是 yum,有的是 dnf,还有基于 apt 的版本。知道自己是什么包管理系统,才知道后面装依赖用什么命令:
cat /etc/os-release然后确认 CPU 架构。这一步对国产平台尤其重要,因为你在 x86 机器上编出来的插件不能直接拿到 ARM 机器上用,反过来也一样:
uname -mx86_64 对应海光、兆芯这一类 amd64 平台,aarch64 对应华为 arm64 平台。接下来的命令整体是一致的,只是编译产物不能在两种架构间混用。
最后确认当前输入法框架用的到底是 fcitx4 还是 fcitx5。可以直接看输入法进程和相关进程名,也可以执行:
fcitx-diagnose如果系统里装的是 fcitx4,这个命令会输出 fcitx 4.x 的版本信息。搜狗输入法界面能正常弹候选词,但 Qt6 应用里弹不出来,基本确定就是走 fcitx4 通道。
2.2 安装编译工具链和 fcitx 开发头文件
编译 fcitx 的 Qt 插件需要三样东西:C++ 编译器、CMake 构建工具、fcitx 的开发头文件。麒麟的软件源里一般都有,只是名字可能叫fcitx-devel也可能叫fcitx-libs-dev,我建议先搜一下确认:
yum search fcitx | grep dev或者,如果系统走的是 apt:
apt-cache search fcitx | grep dev基本编译工具链可以直接装:
sudo yum install -y gcc gcc-c++ make cmake extra-cmake-modules sudo yum install -y fcitx-devel fcitx-libs-devel如果你用的是 apt 系,那么:
sudo apt install -y gcc g++ make cmake extra-cmake-modules sudo apt install -y fcitx-libs-devextra-cmake-modules是很多 Qt 周边工程构建时要用到的 CMake 模块集合,装上能省不少麻烦。另外你要确保系统里有 X11 相关开发库,比如 libxkbcommon-x11,漏了最后链接阶段会报找不到符号。
2.3 部署 Qt 6.7.3
如果你还没装 Qt 6.7.3,这里简单交代一下部署思路。官方在线安装器适合有图形界面操作的环境,但在服务器或离线环境里更省事的做法是直接下载离线安装包,解压到一个固定目录,比如/opt/Qt/。
解压完成后,先确认 qmake 的版本是不是 6.7.3:
/opt/Qt/6.7.3/gcc_64/bin/qmake -query QT_VERSION把 Qt 的 bin 目录加进 PATH,后面编译插件和测试程序都用得上:
export PATH=/opt/Qt/6.7.3/gcc_64/bin:$PATH再确认一下这个 Qt6 的插件目录在哪。不同安装方式目录不一样,有的是gcc_64/plugins,有的打包名会带target_qt之类。这一步要记好,待会儿编译出来的插件要放进去:
/opt/Qt/6.7.3/gcc_64/bin/qtpaths6 --plugin-dir或者直接看:
ls -d /opt/Qt/6.7.3/gcc_64/plugins/platforminputcontexts/注意一点:如果之前机器上已经装了某个 Linux 发行版自带的 Qt6,那这儿的路径可能就不是/opt/Qt,而是/usr/lib/x86_64-linux-gnu/qt6/plugins/这种系统路径。到底往哪拷贝,取决于你打算让哪个 Qt 实例生效。
3. 核心环节:编译 fcitx 的 Qt 6 输入法插件
这一步是整个问题解决的关键,也是最容易出幺蛾子的地方。说难也不难,但源码选错、CMake 参数不对、插件放错目录,任何一个环节出问题都会导致前功尽弃。
3.1 选择正确的源码工程
前面说过,搜狗输入法在麒麟上通常走的是 fcitx4,所以我们要编译的是 fcitx 官方推出的 Qt 输入法插件工程,这个工程在社区里通常叫 fcitx-qt5,也就是给 Qt 程序用的 fcitx 模块。这里有个容易误解的地方:工程名叫 fcitx-qt5,但 Qt6 出来后,社区做了适配,完全可以通过修改构建配置让它对着 Qt6 编译。
如果你系统里用的是 fcitx5,那应该改用 fcitx5-qt 这个工程,里面的 Qt6 支持更完善。为了对症,我这里主要讲针对 fcitx4 和搜狗输入法的编译路线,fcitx5 的情况我在后面单独说。
拉取源码的方式不需要纠结,直接去 fcitx 在代码托管平台上维护的头文件工程里拉最新版即可:
git clone https://github.com/fcitx/fcitx-qt5.git cd fcitx-qt5/拉下来的源码目录结构大概是src/、src/platforminputcontext/这样的布局,核心插件源码就在src/platforminputcontext/下。
3.2 CMake 配置:指定 Qt6 的路径强制编译
原版 fcitx-qt5 默认用 CMake 找 Qt5,如果你直接cmake ..,它十有八九会找到系统自带的 Qt5 然后编译出 Qt5 版本插件,这个插件放进 Qt6 目录是加载不起来的。
所以我们要在 CMake 阶段显式指向 Qt 6.7.3 的 CMake 配置文件路径。Qt 6 安装好之后,在/opt/Qt/6.7.3/gcc_64/lib/cmake/下面是有一整套 Qt6 的 CMake 模块的,我们只要让 CMake 优先看到这个路径就行:
mkdir build && cd build/ cmake .. \ -DCMAKE_PREFIX_PATH=/opt/Qt/6.7.3/gcc_64/lib/cmake \ -DQt6_DIR=/opt/Qt/6.7.3/gcc_64/lib/cmake/Qt6 \ -DCMAKE_INSTALL_PREFIX=/usr如果你的 fcitx-qt5 源码版本太老,CMakeLists 里压根没有 Qt6 的检索逻辑,那就需要先做一点小改动。最省事的办法是把 CMakeLists.txt 里find_package(Qt5 ...)改成find_package(Qt6 ...),同时把项目里引用 Qt5 模块主题的地方统一改到 Qt6。命令行里也可以强制指定:
cmake .. -DQt6_DIR=/opt/Qt/6.7.3/gcc_64/lib/cmake/Qt6但这只对已经支持 Qt6 检索的版本有效。老版本源码就需要你动一下 CMakeLists,或者直接找社区里已经适配过 Qt6 的分支工程来用。
3.3 编译输出文件名与目录定位
配置通过之后,直接开编:
make -j$(nproc)编译完成后,在src/platforminputcontext/下会生成.so动态插件文件。这里文件名很关键,应该是类似于libfcitxplatforminputcontextplugin.so的文件。确认生成位置:
find . -name "*fcitx*platforminputcontext*.so"如果你编出来的是一个带 debug 后缀或者版本号后缀的文件,Qt 在按插件名加载时可能认不出来,最好把名字规范成libfcitxplatforminputcontextplugin.so这种形式。
3.4 把插件拷进 Qt 6.7.3 的插件目录
拿到.so文件后,把它复制到 Qt 的 platforminputcontexts 目录下,这是整篇文章最不能搞错的一步:
sudo cp ./src/platforminputcontext/libfcitxplatforminputcontextplugin.so \ /opt/Qt/6.7.3/gcc_64/plugins/platforminputcontexts/复制完建议立刻验证一下文件格式和依赖库,特别是架构对不上会直接加载失败:
file /opt/Qt/6.7.3/gcc_64/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.sofile输出里应该能看到x86-64或aarch64,这个必须和当前系统架构一致。如果是 x86 机器,却看到 ARM 的架构标识,那就说明你编的是交叉编译产物或者干脆拷错了文件。
如果你用的是麒麟自带的系统 Qt6,路径可能是这样的:
sudo cp libfcitxplatforminputcontextplugin.so /usr/lib/aarch64-linux-gnu/qt6/plugins/platforminputcontexts/判断依据其实就一条,哪个 Qt6 实际在用,就放到哪个目录。搞不清楚的话,在 Qt 程序运行前设置QT_PLUGIN_PATH指定到 Qt 目录,然后用插件拷贝路径和QT_PLUGIN_PATH保持一致。
3.5 如果你实际用的是 fcitx5
假如排查之后发现麒麟系统上运行的其实是 fcitx5,而不是 fcitx4,那编译工程要换成 fcitx5-qt。步骤类似,但 CMake 参数更清晰,因为它原生就支持 Qt6:
git clone https://github.com/fcitx/fcitx5-qt.git cd fcitx5-qt/ mkdir build && cd build/ cmake .. -DENABLE_QT6=ON \ -DQt6_DIR=/opt/Qt/6.7.3/gcc_64/lib/cmake/Qt6 make -j$(nproc)编译出的插件名称同样是libfcitxplatforminputcontextplugin.so,拷贝位置也一样。区别在于它依赖的是 fcitx5 的运行库,所以系统里必须真的在跑 fcitx5,否则加载了也找不到输入法进程。
4. 配置环境变量,让 Qt6 应用真正加载 fcitx 插件
插件文件放到位只完成了一半。Qt6 应用启动时到底去不去加载这个插件,还要看QT_IM_MODULE等一系列环境变量。
4.1 全局统一设置三件套环境变量
不管是什么 Linux 桌面,要正常使用 fcitx 输入法体系,通常需要配置三个环境变量。它们各自负责不同的作用域:
| 环境变量 | 内容 | 作用对象 |
|---|---|---|
QT_IM_MODULE | fcitx | Qt 程序选择输入上下文插件 |
GTK_IM_MODULE | fcitx | GTK 程序选择输入法模块 |
XMODIFIERS | @im=fcitx | X11 程序通过 XIM 协议调用输入法 |
其中最关键的是QT_IM_MODULE,它的值必须和插件加载机制匹配,Qt 才会去platforminputcontexts/下找fcitx对应的那个.so文件。建议把配置写进全局环境文件,避免每次开终端都要手打:
sudo tee /etc/environment <<'EOF' QT_IM_MODULE=fcitx GTK_IM_MODULE=fcitx XMODIFIERS=@im=fcitx EOF改完之后,注销当前用户重新登录,让桌面环境重新读取环境变量。仅仅开一个新终端有时候不够,因为桌面的会话管理器在启动时就已经把旧环境广播给所有应用了。
4.2 用调试日志确认插件真实加载
环境变量配好之后,别急着开输入法,先用 Qt 自带的调试开关看一眼插件到底有没有加载成功。Qt 有专门的运行时环境变量,打开后会在标准输出打印插件加载过程,这个办法非常直观:
export QT_DEBUG_PLUGINS=1 your_qt6_application重点看标准输出里有没有这么一行:
QFactoryLoader::QFactoryLoader() checking "/opt/Qt/6.7.3/gcc_64/plugins/platforminputcontexts" ... Loaded platform input context plugin "fcitx"如果看到Loaded ... "fcitx",说明 Qt 已经找到了插件并识别出输入上下文。如果看到Failed to load ... "fcitx",那就得回到 3.4 那一步,检查插件文件是否存在、架构是否正确、属性依赖有没有缺失。
这招在排查“明明设置了变量但没反应”这类问题时特别管用。很多用户走到这步直接怀疑搜狗坏了,其实用QT_DEBUG_PLUGINS=1一跑,立刻就知道是插件没加载,而不是输入法框架的问题。
4.3 实测中文输入
插件被加载不代表一定就能出中文,还要确认 fcitx 进程本身在运行,搜狗输入法已经启用。终端里检查:
ps -ef | grep fcitx再打开任意一个 Qt6 程序,拉一个文本输入框,按 Ctrl+Space 或者直接在 Qt 程序里切换到中文输入法,看能不能弹出搜狗候选词窗口。
如果你手上没有 Qt6 写的现有应用,可以用 Qt 自带的文本示例测试。Qt 6.7.3 安装包里带了 examples,或者自己写一个几十行的小窗口程序,放一个 QLineEdit,什么都不用做,启动起来直接输入就行。这是最干净的验证环境,没有桌面环境之外的其他干扰因素。
5. 常见问题速查:我这台机器到底卡在哪一步
下面把我在麒麟 V10、海光/兆芯/华为平台上实际踩过的坑,按“现象 -> 原因 -> 处理”的逻辑整理成一张表,方便你拿着现象直接对号入座。
| 现象 | 大概率原因 | 处理办法 |
|---|---|---|
设了QT_IM_MODULE=fcitx但 Qt6 程序还是英文输入 | 插件文件没放进 Qt6 插件目录 | 按第 3.4 节路径拷贝,然后用QT_DEBUG_PLUGINS=1验证 |
日志提示Failed to load "fcitx" | 插件架构不对或缺失动态库依赖 | file查看架构,ldd查看依赖,确认和系统匹配 |
| Qt6 Ctrl+Space 不弹出候选词,但系统其他应用正常 | fcitx 进程没有启动或搜狗输入法坏了 | 先重新启动 fcitx,再看搜狗状态 |
| 插件编译时 CMake 找不到 Qt6 | 没有指定 Qt6_DIR / CMAKE_PREFIX_PATH | 显式传给 CMake 对应路径,必要时修改 CMakeLists 的 Qt 版本检索 |
编译报extra-cmake-modules相关错误 | 缺少 ECM 模块 | 安装 extra-cmake-modules |
| 从 x86 上直接拷贝 plugin 到 ARM 机器 | 编译产物不跨架构 | 在目标平台上重新编译,或者用相同架构的容器编译 |
| 用老版 fcitx-qt5 源码编译 Qt6 时报一堆 Qt5 API 错误 | 源码没有适配 Qt6 | 找社区适配分支,或更换 fcitx5-qt 配合 fcitx5 |
| Qt 插件目录没有写权限 | 目录属主为 root | sudo 拷贝,或将该目录属主改为当前用户 |
程序启动后中英文切换没反应,但终端里fcitx正常 | Qt 程序可能走了 GTK 环境或配置文件被覆盖 | 检查.desktop启动器里的环境变量优先级,最好纳入/etc/profile.d/ |
这里面最容易被忽略的是最后一个。有些 Qt6 桌面应用是通过.desktop文件启动的,如果这里面单独设置了 Environment 字段,可能覆盖/etc/environment里的全局值,导致QT_IM_MODULE被改写成别的内容。遇到这种拆包该怎么办,去它的启动器脚本里搜一遍QT_IM_MODULE,有就删掉或者改成fcitx。
另外还有个小经验:如果系统里同时装了 Qt5 和 Qt6,不要图省事把 Qt5 版插件拷到 Qt6 目录。两个版本的 QPA 接口差异不小,Qt5 插件在 Qt6 下即使侥幸加载了,也可能在输入时直接段错误。宁可多编译几分钟,也不要偷懒混用。
6. 不同国产平台上的编译注意事项
海光、兆芯都是 x86_64 架构,编译流程完全一样,编出来的插件可以直接在当前机器上用。但华为 arm64 平台就不一样了,命令相同,架构不同,最关键的点是必须在目标设备上编译,或者使用相同架构的编译环境。
6.1 海光和兆芯:x86_64 的一次编译
海光和兆芯的 CPU 架构本质都是 x86_64,所以在一个源上编译出来的插件,理论上可以拷贝到另一台相同架构的机器上使用。实际部署时需要注意 Qt 安装路径尽量保持一致,否则插件文件拷过去了,但/opt/Qt/6.7.3/...的路径对不上,还是会加载失败。
最好是每台机器都独立执行一遍编译,这样插件依赖的 Qt 版本、编译器 ABI 都严格对齐,省去后续排查的麻烦。
6.2 华为 arm64:一定要在目标架构上编译
华为 arm64 平台上,Qt 6 的目录名可能不是gcc_64,有的版本的 Qt 打包目录会变成arm64或者aarch64。执行ls /opt/Qt/6.7.3/的时候不要想当然,看一眼实际目录名,后续所有命令都基于真实路径来写。
编译时务必在 arm64 机器上直接执行。如果你手头只有 x86 的开发机,理论上可以用交叉编译工具链,但 Qt 插件这种强耦合 QPA 接口的工程,交叉编译时经常出现头文件不一致、rcc 资源编译器版本错乱的问题,为了省这点编译时间,后面可能花几小时来排查,很不划算。
建议做法是在一台同架构的华为 arm64 机器上,或者在该架构的容器里完成编译,再把插件拷贝到场。神奇的是,ARM 上的环境变量、配置方式、插件名字和 x86 完全一样,只是文件格式和动态库依赖不同。
6.3 Qt 版本不一致导致的 ABI 兼容问题
插件的 ABI 和 Qt 版本是强绑定的。你按 Qt 6.7.3 编译出来的插件,放进 Qt 6.2 的目录里,大概率加载失败,甚至可能让应用启动崩溃。如果系统里既装了 6.2 又装了 6.7,一定要严格核对实际运行的那个 Qt 程序用的是哪一套库。
有一个简单的验证方法,直接用 ldd 看插件链接到哪个 Qt 库:
ldd /opt/Qt/6.7.3/gcc_64/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.so输出里如果链接到了/opt/Qt/6.7.3/gcc_64/lib/libQt6XcbQpa.so.6,说明插件确实是以 6.7.3 为目标编译的。如果你发现程序实际用的是另一个 Qt 路径,那又要重新来一遍。
7. 最后再分享一个排查技巧,能省大半天时间
踩这个坑的人,十有八九都在反复重启输入法和 Qt 程序,但很少会去开 Qt 的插件调试日志。其实 Qt 在这块做得很好了,QT_DEBUG_PLUGINS=1这一行,比任何排查工具都直接。
我的习惯是,一旦 Qt6 应用出现输入法症状,第一时间设置这几个变量:
export QT_DEBUG_PLUGINS=1 export QT_QPA_PLATFORM=xcb export QT_LOGGING_RULES="*.debug=false;qt.qpa.*=true"然后启动程序,看输出。如果 Qt 压根没去platforminputcontexts目录找插件,那就是路径配置问题,可能是你的程序用了另一个 Qt,也可能QT_PLUGIN_PATH被别的东西覆盖了。如果 Qt 去了目录但找不到文件,那就回到文件名和拷贝路径上检查。如果 Qt 找到了文件但加载失败,多半是架构不对或者动态库缺失,跑一下ldd就知道缺谁。
这套排查逻辑不依赖 fcitx 本身,也不依赖搜狗输入法版本,只针对 Qt 和插件之间的关系。而且它的输出结果非常明确,不会给你一堆模棱两可的提示。我在多台海光、兆芯、华为 arm64 平台上试过,只要插件加载成功,输入法问题九成都能解决。
整个过程听起来步骤多,但拆透了就是两件事:编译一个对得上 fcitx4 的 Qt6 插件,再让它被正确的 Qt 实例加载。插件落地、环境变量指对、日志确认加载,这三步走完,麒麟 V10 上 Qt6 打中文这种折磨人的问题,基本就能收工了。