本文记录如何将搜狗拼音官方 DEB 重新打包为安装到系统路径的 RPM,并在 Rocky Linux 8 的 XFCE/ETX 桌面中使用 Fcitx 4 和搜狗拼音。

这个方法几乎不需要为用户做定制,在操作系统安装好后可让用户自行使用系统fcitx机制进行切换输入法。建议IT Infra团队,在使用前先在一台 el8 测试后,确保没问题后再上量到生产环境。

这个包使用系统 Fcitx 和 Qt。程序安装到 /opt/sogoupinyin,Fcitx 插件及元数据安装到系统目录。普通用户可以执行 imsettings-switch fcitx 选择 Fcitx;新用户的 Fcitx profile 会根据系统元数据启用搜狗。已有用户如果明确关闭了搜狗,原选择会保留。

这是根据官方 DEB 制作的站点自用实验包,不是搜狗官方 RPM。本文针对 Rocky Linux 8.10、x86_64、Fcitx 4、搜狗拼音 4.2.1.145;不能直接把 EL8 RPM 用于 EL9。厂商的使用和再分发条件请按实际情况核对。

2026-11-05 补充:-5 包不宜直接部署到生产。 安装前检查发现,RPM 保留了原始 DEB 中大量所有用户可写的权限:共 2,084 个普通文件和 121 个目录带有其他用户写权限。实验机 123 安装后相应路径也保留了这些权限。下文记录的是原实验和可复现步骤;在生产使用前,应重新制作、检查权限并验证新包,而不是直接安装本文的 -5 包。检查可以使用 rpm -qp --qf '[%{FILEMODES:perms} %{FILENAMES}\n]' "$rpm_file",再按第 9 位权限是否为 w 筛选普通文件和目录。

环境和验证范围

项目 本文使用的版本或配置
官方输入包 sogoupinyin_4.2.1.145_amd64.deb
构建环境 rockylinux:8 容器,x86_64
目标系统 Rocky Linux 8.10,x86_64
输入法框架 Fcitx 4.2.9.7
系统 RPM sogoupinyin-system-4.2.1.145-5.el8.x86_64.rpm
桌面 XFCE、ETX、X11、en_US.UTF-8
程序安装路径 /opt/sogoupinyin,不可通过 --prefix 改位置
目标节点 本次实验使用 172.31.0.123

在 123 上,使用独立普通用户和临时家目录进行了 ETX 桌面测试:GTK 输入框和 XFCE Terminal 都能显示搜狗候选词并提交中文。人工输入测试使用 -4;-5 只调整了两个辅助程序的符号版本,已比对确认输入法核心文件相同,-5 已安装并通过 RPM 文件校验和动态库依赖检查。-5 尚未单独进行人工输入测试,截图、更新器等辅助功能也未逐项测试。

一、准备构建目录和官方 DEB

以下构建命令使用 Bash。本文的构建机是安装了 Podman、rpm 和 sha256sum,且可以访问所需软件仓库的 x86_64 Linux 主机。创建工作目录:

1
2
mkdir -p "$HOME/sogou-system-el8-build"
cd "$HOME/sogou-system-el8-build"

从搜狗拼音 Linux 官网获取 4.2.1.145 的 amd64 DEB,复制到工作目录并命名为 sogoupinyin-official.deb:

1
2
cp /path/to/sogoupinyin_4.2.1.145_amd64.deb ./sogoupinyin-official.deb
sha256sum sogoupinyin-official.deb

本次使用的 DEB 校验值:

1
3111af17a6abddd80b856aa9c1f579a137d69f3d735ead936ddb6e5f08b59f3b  sogoupinyin-official.deb

这是此次实验输入文件的校验值,不是由本文提供的厂商签名。若下载的版本或内容不同,不应直接套用下文 spec;需要重新检查文件结构、依赖和兼容性。

本次构建目录中共有四个输入文件:

1
2
3
4
5
sogou-system-el8-build/
├── sogoupinyin-official.deb
├── sogoupinyin-system.spec
├── sogoupinyin-enable
└── build.sh

下面给出后三个文件的完整内容。

二、编写 RPM spec

在构建工作目录创建 sogoupinyin-system.spec:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
cat > sogoupinyin-system.spec <<'SOGOU_SPEC_EOF'
Name:           sogoupinyin-system
Version:        4.2.1.145
Release:        5%{?dist}
Summary:        Sogou Pinyin for the system Fcitx 4 installation
License:        Proprietary
URL:            https://pinyin.sogou.com/linux/
Source0:        sogoupinyin-official.deb
Source1:        sogoupinyin-enable
BuildArch:      x86_64
BuildRequires:  binutils, tar, xz, patchelf
Requires:       fcitx >= 4.2.9, fcitx-data, fcitx-libs
Requires:       fcitx-gtk2, fcitx-gtk3, fcitx-qt5
Requires:       libX11, libXtst, qt5-qtbase-gui, qt5-qtdeclarative, qt5-qtsvg
Requires:       fontconfig, glibc-langpack-en
Requires:       libcurl, libpng12, openal-soft, openblas
Requires:       python3-dbus
Conflicts:      sogoupinyin-local
AutoReqProv:    no
%global debug_package %{nil}
%global __os_install_post %{nil}

%description
Experimental system-path repackaging of the vendor DEB for Rocky Linux 8.
Install the vendor application under /opt/sogoupinyin and register its main
Fcitx addon under system Fcitx paths. Use the distribution's Qt and common
libraries, retain the vendor gsettings Qt library, and omit two incompatible
optional Fcitx addons. New profiles enable Sogou while explicit existing user
choices are preserved. The optional sogoupinyin-enable command lets an
existing user enable Sogou in their own running Fcitx session.

%prep
%setup -q -c -T
mkdir payload
ar p %{SOURCE0} data.tar.xz | tar -xJ -C payload

%build

%install
mkdir -p "%{buildroot}/opt" "%{buildroot}%{_libdir}/fcitx" \
    "%{buildroot}%{_datadir}/fcitx/addon" \
    "%{buildroot}%{_datadir}/fcitx/inputmethod" \
    "%{buildroot}%{_datadir}/fcitx/imicon" \
    "%{buildroot}%{_datadir}/applications" \
    "%{buildroot}%{_datadir}/icons" "%{buildroot}%{_bindir}"

cp -a payload/opt/sogoupinyin "%{buildroot}/opt/"
# The vendor Qt build fails with an unresolved qt_version_tag on Rocky 8.
# Use the distribution's Qt and retain the vendor's gsettings bridge.
cp -a payload/opt/sogoupinyin/files/lib/qt5/lib/libgsettings-qt.so.1 \
    "%{buildroot}/opt/sogoupinyin/files/lib/"
rm -rf "%{buildroot}/opt/sogoupinyin/files/lib/qt5"
rm -f "%{buildroot}/opt/sogoupinyin/files/bin/qt.conf" \
    "%{buildroot}/opt/sogoupinyin/files/lib/libcurl.so.4" \
    "%{buildroot}/opt/sogoupinyin/files/lib/libpng12.so.0" \
    "%{buildroot}/opt/sogoupinyin/files/lib/libFcitxQt5DBusAddons.so.1" \
    "%{buildroot}/opt/sogoupinyin/files/lib/libopenal.so.1" \
    "%{buildroot}/opt/sogoupinyin/files/lib/libopenblas.so.0"
# Ubuntu's Qt exports C++ ABI symbols with a Qt_5 version tag;
# Rocky's system Qt uses the libstdc++ versions. Remove only those tags.
for file in \
    "%{buildroot}/opt/sogoupinyin/files/bin/sogoupinyin-configtool" \
    "%{buildroot}/opt/sogoupinyin/files/bin/sogoupinyin-screenshot" \
    "%{buildroot}/opt/sogoupinyin/files/bin/sogoupinyin-service" \
    "%{buildroot}/opt/sogoupinyin/files/bin/sogoupinyin-specialsymbol" \
    "%{buildroot}/opt/sogoupinyin/files/bin/sogoupinyin-updater" \
    "%{buildroot}/opt/sogoupinyin/files/bin/sogoupinyin-watchdog" \
    "%{buildroot}/opt/sogoupinyin/files/lib/libSogouIme.so" \
    "%{buildroot}/opt/sogoupinyin/files/lib/libSogouShell.so"; do
    patchelf --clear-symbol-version __cxa_throw_bad_array_new_length "$file"
    patchelf --clear-symbol-version _ZSt24__throw_out_of_range_fmtPKcz "$file"
done
for file in \
    "%{buildroot}/opt/sogoupinyin/files/bin/sogoupinyin-specialsymbol" \
    "%{buildroot}/opt/sogoupinyin/files/bin/sogoupinyin-updater"; do
    patchelf --clear-symbol-version _ZSt25__throw_bad_function_callv "$file"
done
# These two ancillary plugins are not needed for pinyin and one fails the
# Fcitx 4 ABI check on Rocky 8; install only the primary input method plugin.
cp -a payload/usr/lib/x86_64-linux-gnu/fcitx/fcitx-sogoupinyin.so \
    "%{buildroot}%{_libdir}/fcitx/"
cp -a payload/usr/share/fcitx/addon/fcitx-sogoupinyin.conf \
    "%{buildroot}%{_datadir}/fcitx/addon/"
cp -a payload/usr/share/fcitx/inputmethod/sogoupinyin.conf \
    "%{buildroot}%{_datadir}/fcitx/inputmethod/"
# Fcitx 4 enables a priority-0 engine for a new profile regardless of locale.
# An existing profile's explicit sogoupinyin:False still takes precedence.
grep -qx 'Priority=10' \
    "%{buildroot}%{_datadir}/fcitx/inputmethod/sogoupinyin.conf"
sed -i 's/^Priority=10$/Priority=0/' \
    "%{buildroot}%{_datadir}/fcitx/inputmethod/sogoupinyin.conf"
cp -a payload/usr/share/fcitx/imicon/sogoupinyin.png \
    "%{buildroot}%{_datadir}/fcitx/imicon/"
cp -a payload/usr/share/applications/sogoupinyin-*.desktop \
    "%{buildroot}%{_datadir}/applications/"
cp -a payload/usr/share/icons/. "%{buildroot}%{_datadir}/icons/"
install -m 0755 %{SOURCE1} "%{buildroot}%{_bindir}/sogoupinyin-enable"

%files
%defattr(-,root,root,-)
/opt/sogoupinyin
%{_bindir}/sogoupinyin-enable
%{_libdir}/fcitx/fcitx-sogoupinyin*.so
%{_datadir}/fcitx/addon/fcitx-sogoupinyin*.conf
%{_datadir}/fcitx/inputmethod/sogoupinyin.conf
%{_datadir}/fcitx/imicon/sogoupinyin.png
%{_datadir}/applications/sogoupinyin-*.desktop
%{_datadir}/icons/bloom/apps/*/fcitx-sogoupinyin.svg
%{_datadir}/icons/hicolor/*/apps/fcitx-sogoupinyin.png
SOGOU_SPEC_EOF

spec 做了哪些事情

  1. 用 ar 和 tar 从 DEB 的 data.tar.xz 解出 payload;不需要在构建机安装 DEB。
  2. 将 payload/opt/sogoupinyin 复制到 RPM 的构建目录,安装时对应 /opt/sogoupinyin。
  3. 移除包内自带的 Qt 和几份通用库,改用 Rocky 的系统库;保留搜狗所需的 libgsettings-qt.so.1。直接使用原厂自带 Qt 时,实验中遇到了 qt_version_tag 符号错误。
  4. 使用 patchelf --clear-symbol-version 调整若干现成 ELF 文件中的 C++ 符号版本引用。此操作不涉及搜狗源码编译;符号调整后仍需在目标系统检查动态链接和实际功能。
  5. 安装主插件 fcitx-sogoupinyin.so 及其 Fcitx 注册文件。fcitx-sogoupinyinhxm 在实验中出现 Fcitx ABI 错误;fcitx-sogoupinyinhxm 和 fcitx-sogoupinyinhdm 都未纳入 RPM。spec 的描述将两者概括为不兼容,但本次明确观察到 ABI 错误的是前者;两者相关的附加功能没有逐项验证。
  6. 将输入法元数据中的 Priority=10 改为 Priority=0。在本次 Fcitx 4 测试中,新用户生成 profile 时会启用搜狗;已有 profile 中的 sogoupinyin:False 继续保留。
  7. 安装下文的 sogoupinyin-enable,供已有用户按需启用搜狗。

spec 中的 %{buildroot} 是 RPM 的临时构建根目录。其中的删除操作不会直接删除构建机或目标机现有的系统库。

此 spec 使用 AutoReqProv: no,运行依赖由 Requires 手工声明;还将 %__os_install_post 设为空,因此 RPM 默认的部分构建后处理不会执行。包已经在本文目标环境检查过,但手工依赖未必覆盖其他精简系统上的所有需要;迁移时应重新检查。RPM 还声明与 sogoupinyin-local 冲突,不能不检查就将两者同时安装。

三、编写已有用户的启用命令

创建 sogoupinyin-enable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
cat > sogoupinyin-enable <<'SOGOU_ENABLE_EOF'
#!/usr/bin/python3
"""Enable Sogou in the current user's running Fcitx 4 session. https://icinfra.cn """
import os
import re
import subprocess
import sys
import time

try:
    import dbus
except ImportError:
    sys.exit('sogoupinyin-enable: python3-dbus is required.')

display = os.environ.get('DISPLAY', '')
match = re.search(r':(\d+)(?:\.\d+)?$', display)
if not match:
    sys.exit('sogoupinyin-enable: run this in the desktop session on the Fcitx host.')

address = ''
deadline = time.monotonic() + 8
while time.monotonic() < deadline:
    try:
        addon = subprocess.check_output(
            ['/usr/bin/fcitx-remote', '-m', 'sogoupinyin'],
            stderr=subprocess.DEVNULL, universal_newlines=True, timeout=3).strip()
        address = subprocess.check_output(
            ['/usr/bin/fcitx-remote', '-a'],
            stderr=subprocess.DEVNULL, universal_newlines=True, timeout=3).strip()
        if addon == 'fcitx-sogoupinyin' and address:
            break
    except (OSError, subprocess.SubprocessError):
        pass
    time.sleep(0.25)
else:
    sys.exit('sogoupinyin-enable: Fcitx or the Sogou addon is not available on this display.')

try:
    bus = dbus.bus.BusConnection(address)
    proxy = bus.get_object('org.fcitx.Fcitx-' + match.group(1), '/inputmethod')
    properties = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties')
    interface = 'org.fcitx.Fcitx.InputMethod'
    items = list(properties.Get(interface, 'IMList'))
    indices = [i for i, row in enumerate(items) if str(row[1]) == 'sogoupinyin']
    if len(indices) != 1:
        sys.exit('sogoupinyin-enable: expected one Sogou input method, found {}.'.format(len(indices)))
    index = indices[0]
    if bool(items[index][3]):
        print('Sogou is already enabled for this user.')
        sys.exit(0)
    row = items[index]
    items[index] = dbus.Struct((row[0], row[1], row[2], dbus.Boolean(True)), signature='sssb')
    properties.Set(interface, 'IMList', dbus.Array(items, signature='(sssb)'))
    result = list(properties.Get(interface, 'IMList'))
    enabled = [row for row in result if str(row[1]) == 'sogoupinyin' and bool(row[3])]
    if len(enabled) != 1:
        sys.exit('sogoupinyin-enable: Fcitx did not confirm that Sogou was enabled.')
    print('Sogou is enabled for this user.')
except dbus.DBusException as exc:
    sys.exit('sogoupinyin-enable: Fcitx D-Bus request failed: {}'.format(exc))
SOGOU_ENABLE_EOF
chmod 755 sogoupinyin-enable

脚本需要 python3-dbus,该依赖已写入 spec。它连接当前显示对应的 Fcitx D-Bus 服务,读取输入法列表,仅在需要时启用 sogoupinyin,并核对结果。脚本应由用户在运行 Fcitx 的桌面节点、对应桌面的终端中执行。

它不会在构建或安装 RPM 时自动修改所有用户的 profile。用户运行后,由 Fcitx 管理并保存个人选择。家目录若通过 NFS 共享,这项个人配置会随家目录被其他节点上的 Fcitx 读取。

四、编写构建脚本

创建 build.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat > build.sh <<'SOGOU_BUILD_EOF'
#!/usr/bin/env bash
# Run in an isolated Rocky Linux 8 container with /work mounted from the host. https://icinfra.cn
set -euo pipefail
dnf install -y epel-release
dnf install -y rpm-build binutils tar xz patchelf
top=/work/rpmbuild
mkdir -p "$top"/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
cp /work/sogoupinyin-official.deb "$top/SOURCES/"
cp /work/sogoupinyin-enable "$top/SOURCES/"
cp /work/sogoupinyin-system.spec "$top/SPECS/"
rpmbuild -bb --define "_topdir $top" "$top/SPECS/sogoupinyin-system.spec"
find "$top/RPMS" -name 'sogoupinyin-system-*.rpm' -print
SOGOU_BUILD_EOF
chmod 755 build.sh

构建脚本假定工作目录挂载到容器的 /work。它在容器内安装构建工具,在 /work/rpmbuild 创建 RPM 工作目录,并运行 rpmbuild -bb。构建依赖需要容器能够访问 Rocky Linux 8 和 EPEL 8 软件仓库。

五、在隔离容器中构建 RPM

在包含四个输入文件的工作目录执行:

1
2
3
4
podman run --rm --network=host \
  -v "$PWD:/work:Z" \
  docker.io/library/rockylinux:8 \
  /bin/bash /work/build.sh

:Z 用于 SELinux 环境中的私有卷标记;请只对这个构建工作目录使用。无 SELinux 的环境可按实际容器配置调整。若使用内部镜像或软件仓库,确保它们提供兼容的 Rocky Linux 8 构建环境及 patchelf。

构建完成后,RPM 位于:

1
rpmbuild/RPMS/x86_64/sogoupinyin-system-4.2.1.145-5.el8.x86_64.rpm

查看包信息、依赖、文件列表和校验值:

1
2
3
4
5
6
rpm_file="$PWD/rpmbuild/RPMS/x86_64/sogoupinyin-system-4.2.1.145-5.el8.x86_64.rpm"

rpm -qpi "$rpm_file"
rpm -qpR "$rpm_file"
rpm -qpl "$rpm_file"
sha256sum "$rpm_file"

123 上保留的本次构建产物 SHA-256 为:

1
85734508362e7ea253fdc98d49af74c6b2dcfeb00b0374a686f485d08f536496  sogoupinyin-system-4.2.1.145-5.el8.x86_64.rpm

这是那一份产物的身份校验值。重新构建时,工具版本、构建时间和 RPM 元数据可能不同,不能仅凭新包的 SHA-256 与它不同,就认定输入文件或包内容有误。应保存每次构建输入、日志和产物校验值。

为复核本文步骤,我们使用同一份 DEB、spec 和脚本,在 172.31.0.244 的 Rocky Linux 8 容器中重新构建成功。新 RPM 的整体 SHA-256 不同;逐项对比两个 RPM 的 2,267 条文件记录(含目录)后,内容摘要一致。这次复跑没有将新包安装到目标节点。

六、将 RPM 安装到目标桌面节点

1. 检查系统和已有软件

在目标节点执行:

1
2
3
4
cat /etc/os-release
uname -m
rpm -qa | grep -E '^sogoupinyin-(local|site|system)' || true
rpm -q fcitx fcitx-libs fcitx-data fcitx-gtk2 fcitx-gtk3 fcitx-qt5 imsettings

本文 RPM 面向 EL8 x86_64,需要 Fcitx 4 及相应的 GTK、Qt 模块。若已有 sogoupinyin-local,先确认旧包的用途和依赖,再规划迁移;本 RPM 的 Conflicts 会阻止二者直接共存。其他旧的用户级配置也可能影响最终加载路径,见后文排查。

目标系统需要能从配置好的软件仓库获取 RPM 声明的依赖。123 使用 Rocky Linux 8 的 BaseOS、AppStream、Extras 和 EPEL 仓库。检查已启用的仓库:

1
dnf repolist --enabled

在使用 Rocky 官方仓库、尚未启用 EPEL 的环境中,可以按站点策略安装 epel-release:

1
sudo dnf install -y epel-release

如果站点使用内部镜像,应使用管理员提供的等价仓库。不要在依赖缺失时强制忽略依赖安装。

2. 安装前检查文件和潜在冲突

在目标机器的 Bash 中指定实际包路径,并查看包中的路径、权限、依赖及脚本:

1
2
3
4
5
6
7
8
9
PKG=/tmp/sogoupinyin-system-4.2.1.145-5.el8.x86_64.rpm

rpm -qpl "$PKG" | less
rpm -qp --qf '[%{FILEMODES:perms} %{FILEUSERNAME}:%{FILEGROUPNAME} %{FILENAMES}\n]' "$PKG" | less
rpm -qpR "$PKG"
rpm -qp --conflicts "$PKG"
rpm -qp --scripts "$PKG"
rpm -qp --triggers "$PKG"
rpm -qp --filetriggers "$PKG"

清单本身不能判断目标机器是否已有同名文件。下列检查逐项列出已存在的非普通目录路径及其 RPM 归属;检查需要在实际目标机上执行。两个都是普通目录的情况会略过,已有目录的权限和所有者仍应根据需要单独检查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(
  set -o pipefail
  if ! rpm -qpi "$PKG" >/dev/null 2>&1; then
    printf 'Cannot read RPM: %s\n' "$PKG" >&2
    exit 1
  fi
  rpm -qp --qf '[%{FILEMODES:perms}\t%{FILENAMES}\n]' "$PKG" |
  {
    count=0
    while IFS=$'\t' read -r mode path; do
      if [[ -e "$path" || -L "$path" ]]; then
        if [[ $mode == d* && -d "$path" && ! -L "$path" ]]; then
          continue
        fi
        if owner=$(rpm -qf -- "$path" 2>/dev/null); then
          :
        else
          owner='not owned by RPM'
        fi
        printf '\nExisting: %s\n  RPM mode: %s\n  Owner: %s\n' \
          "$path" "$mode" "$owner"
        ls -ld -- "$path"
        count=$((count + 1))
      fi
    done
    printf '\nExisting non-directory entries: %s\n' "$count"
  }
)

not owned by RPM 并不表示可以覆盖:它可能是管理员手动创建或其他工具安装的文件。输出为零也不是完整安全保证,还应检查父目录中的符号链接、安装脚本,以及 DNF 计划安装的依赖包。

1
2
sudo dnf install --assumeno "$PKG"
sudo rpm -Uvh --test "$PKG"

前者预览 DNF 依赖计划并自动拒绝确认;后者测试 RPM 事务,但不会自动下载缺少的依赖。对于未被 RPM 管理的现有文件,rpm --test 可能通过,实际安装仍会替换文件:我们在一次性隔离容器中用本包复现了这种情况。因此应结合上面的路径扫描,而不是只依赖 --test。

3. 安装本地 RPM

将 RPM 复制到目标节点,例如 /tmp/,然后执行:

1
2
3
4
sudo dnf install -y \
  imsettings \
  google-noto-sans-cjk-ttc-fonts \
  /tmp/sogoupinyin-system-4.2.1.145-5.el8.x86_64.rpm

imsettings 提供用户选择输入法的命令;这个工具未列入搜狗 RPM 的 Requires,所以部署时显式安装。中文字体用于显示候选词和已输入的汉字,上面使用的是 123 已安装的 Noto CJK 字体包;如果站点已经提供其他合适的中文字体,可按实际情况选择。桌面环境本身仍需提前安装。

本次实验包未签名。如果目标环境要求本地 RPM 签名,应按站点流程签名并验证,再进行部署。

此包使用系统固定路径,不是可重定位的 /tools/OSS 站点包;不使用 rpm --prefix 改安装路径。若此前已安装相同版本的包,安装命令提示 already installed 并不代表重新安装或替换了包内容。

4. 检查包和系统文件

1
2
3
4
5
6
7
rpm -q sogoupinyin-system
rpm -V sogoupinyin-system
rpm -ql sogoupinyin-system | grep -E \
  '^/opt/sogoupinyin|^/usr/lib64/fcitx|^/usr/share/fcitx|^/usr/bin/sogoupinyin-enable'

grep '^Priority=' /usr/share/fcitx/inputmethod/sogoupinyin.conf
fc-list :lang=zh family | head

rpm -V 没有输出表示所检查的已安装包文件与 RPM 数据库记录一致;它不代表输入功能已经通过测试。正常情况下,最后一条命令显示 Priority=0。

核心路径如下:

路径 用途
/opt/sogoupinyin/ 搜狗程序和所需文件
/usr/lib64/fcitx/fcitx-sogoupinyin.so Fcitx 4 主插件
/usr/share/fcitx/addon/fcitx-sogoupinyin.conf 插件注册信息
/usr/share/fcitx/inputmethod/sogoupinyin.conf 输入法注册及默认优先级
/usr/bin/sogoupinyin-enable 已有用户按需启用搜狗

七、准备 ETX/XFCE 桌面启动环境

用户选择 Fcitx 和桌面应用继承输入法变量是两件事。imsettings-switch fcitx 可以保存用户选择,但无法回头修改已经运行的 xfce4-session、终端 server 或其他应用的环境。

先检查实际使用的 ETX Profile Xstart:有些 Profile 通过 env -i 直接启动 xfce4-session,这可能绕过系统通常的 X11 输入法初始化流程。在本文的 Fcitx 专用 Profile 中,需要在启动 XFCE 之前设置:

1
2
3
4
LANG=en_US.UTF-8
GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx

例如,本次使用的 ETX 环境可按以下形式配置 Xstart。@@ 是这里的 ETX Xstart 转义写法;进入桌面后应确认进程实际看到的是单个 @。如果直接在普通 shell 运行,不应把 @@ 原样当作 XMODIFIERS 的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

exec /usr/bin/env -i \
    "PATH=${PATH:-/usr/bin:/bin}" \
    "XAUTHORITY=${XAUTHORITY:-}" \
    "DISPLAY=${DISPLAY:-}" \
    "HOME=${HOME:-}" \
    "LOGNAME=${LOGNAME:-${USER:-}}" \
    "USER=${USER:-}" \
    LANG=en_US.UTF-8 \
    GTK_IM_MODULE=fcitx \
    QT_IM_MODULE=fcitx \
    XMODIFIERS=@@im=fcitx \
    /usr/bin/xfce4-session

这是 Fcitx 专用 Profile 的示例,不应直接覆盖已有的 sudo、D-Bus 或身份切换启动链;应结合站点现有 Xstart 调整并验证。这个例子会为该 Profile 中的应用固定设置 Fcitx 变量;如需同一 Profile 自由切换 IBus/Fcitx,需要另行设计和验证按用户选择初始化环境的启动链。

在 123 上,系统自带 /etc/xdg/autostart/imsettings-start.desktop,执行 imsettings-switch -n -q -x,用于读取用户选择并启动输入法。XFCE 自动启动项可能被用户配置或站点策略覆盖。软件安装、变量设置和输入法进程是不同环节,应在新建会话中分别核对。

八、普通用户选择并验证搜狗

在目标节点的 XFCE 桌面打开终端,先进入 Bash(以下命令按 Bash 编写),执行:

1
imsettings-switch fcitx

结束当前 ETX Session,重新创建一个会话。关闭客户端窗口可能只是断开连接,不能代替终止并新建会话。

在新桌面的终端检查:

1
2
3
4
5
printf 'DISPLAY=%s\nLANG=%s\nGTK_IM_MODULE=%s\nQT_IM_MODULE=%s\nXMODIFIERS=%s\n' \
  "$DISPLAY" "$LANG" "$GTK_IM_MODULE" "$QT_IM_MODULE" "$XMODIFIERS"

fcitx-remote -m sogoupinyin
grep '^EnabledIMList=' "$HOME/.config/fcitx/profile"

预期输入法变量为 fcitx、fcitx 和 @im=fcitx;fcitx-remote -m sogoupinyin 应显示:

1
fcitx-sogoupinyin

该输出说明当前 Fcitx 会话发现了插件,不等于已经完成中文输入验证。对于新的用户配置,EnabledIMList 中应包含 sogoupinyin:True。然后在终端或编辑器输入区切换到搜狗,输入拼音、选择候选词,确认中文正常提交和显示。

Fcitx profile 尚未创建或保存时,上面的 grep 可能找不到文件;需要结合当前会话的 Fcitx 状态和实际输入结果检查。

如果已有 profile 明确包含 sogoupinyin:False,系统包会保留这个选择。用户确认需要启用时,在运行 Fcitx 的同一个桌面节点和会话执行:

1
sogoupinyin-enable

如果程序提示找不到 Fcitx 或搜狗插件,先确认 DISPLAY、Fcitx 进程及 fcitx-remote -m sogoupinyin;不要在 SSH 到其他节点的 shell 中把该结果当作桌面节点的状态。

九、已有家目录和常见问题

已有用户仍在使用旧的 /tools 搜狗

系统插件安装成功,不代表已有桌面一定加载它。旧用户可能有 ~/.config/fcitx/ 插件链接、个人自动启动项,或由包装脚本启动的 Fcitx。检查当前显示对应的进程、启动环境和加载路径:

1
2
3
4
5
6
7
8
9
10
11
12
for pid in $(pgrep -u "$(id -u)" -x fcitx); do
  echo "Fcitx PID=$pid"
  tr '\0' '\n' < "/proc/$pid/environ" |
    grep -E '^(DISPLAY|FCITXDIR)=' || true
  grep -E 'fcitx-sogoupinyin\.so' "/proc/$pid/maps" |
    awk '{print $NF}' | sort -u || true
done

ls -l "$HOME/.config/fcitx/addon" \
      "$HOME/.config/fcitx/inputmethod" \
      "$HOME/.config/fcitx/lib" \
      "$HOME/.config/autostart" 2>/dev/null

确认 DISPLAY 对应当前桌面,再判断实际加载的插件。家目录通过 NFS 共享时,这些文件也可能影响其他节点;迁移前应记录和备份现状,不要直接删除。

imsettings-switch 已执行,但新桌面没有输入法

检查桌面启动时的三个输入法变量、当前用户的 imsettings 选择、D-Bus 会话、Fcitx 是否启动,以及 XFCE 自动启动项是否被覆盖。env -i 启动的桌面尤其要检查 ETX 的实际 Xstart 日志。不要仅凭终端里手动 export 成功,就推断已经启动的 XFCE 和其他应用获得了同样的环境。

Fcitx 能发现搜狗,但应用仍不能输入

插件注册、候选词显示、选词提交和中文显示需要分别验证。检查 locale、实际应用进程继承的输入法变量和应用使用的输入法接口;远端 SSH/XIM 的情况还需要按具体应用单独测试。本文验证的是 123 的本地桌面应用,不推断所有远端应用都兼容。

参考资料