[Exchange and share] Linux下的Qt程序发布流程
Tofloor
poster avatar
redmibook
deepin
2024-02-16 00:58
Author

工具

  • patchelf
  • appimagetool
  • linuxdeployqt

其中,linuxdeployqt 需要编译,从源码中解除 glibc 的版本限制。然后,统一放到 /usr/local/bin/ 这个目录下,方便调用。

打包 AppImage 时,最好特别强调一下 wayland 库的调用及支持,当然,最重要的是把插件拷贝齐全:

linuxdeployqt ./rimetool.AppDir/usr/share/applications/newReader.desktop -appimage -extra-plugins=iconengines,platformthemes/libqgtk3.so -exclude-libs=libzstd.so

输入法动态链接库

这个文件 libfcitx5platforminputcontextplugin.so 要放到 QtQCreator 下,实现对 fcitx5 的支持。

但是,要用当前的 Qt 工具链来编译这个库,因为:这个库要与你的 Qt-App 对接,而跨版本可能会不兼容。

编译 fcitx5-qt

基础工具链

sudo apt install g++ gcc cmake extra-cmake-modules libgl1-mesa-dev

Qt环境变量

profile 中添加:

export QTDIR=$HOME/Qt/6.6.1/gcc_64
export PATH=$QTDIR/bin:$PATH
export LD_PLUGINS_PATH=$QTDIR/plugins:$LD_PLUGINS_PATH
export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
export QT_DEBUG_PLUGINS=1

记得:source ~/.profile

拉源码

i5@debian:~/文档$ git clone https://github.com/fcitx/fcitx5-qt.git
正克隆到 'fcitx5-qt'...
remote: Enumerating objects: 3191, done.
remote: Counting objects: 100% (478/478), done.
remote: Compressing objects: 100% (51/51), done.
remote: Total 3191 (delta 441), reused 431 (delta 427), pack-reused 2713
接收对象中: 100% (3191/3191), 1.08 MiB | 1.74 MiB/s, 完成.
处理 delta 中: 100% (2429/2429), 完成.
i5@debian:~/文档$

修改CmakeLists

最外层的 CMakeLists.txt :

option(ENABLE_QT4 "Enable Qt 4" Off)
option(ENABLE_QT5 "Enable Qt 5" Off)
option(ENABLE_QT6 "Enable Qt 6" On)
option(ENABLE_X11 "Enable X11 support" On)
option(BUILD_ONLY_PLUGIN "Build only plugin" On)
option(BUILD_STATIC_PLUGIN "Build plugin as static" Off)
option(WITH_FCITX_PLUGIN_NAME "Enable plugin name with fcitx" On)
option(ENABLE_QT6_WAYLAND_WORKAROUND "Enable Qt6 Wayland workaround" On)

依赖列表

  • libxkbcommon-dev
  • libvulkan-dev
  • qt6-wayland-dev

sudo apt install libxkbcommon-dev libvulkan-dev qt6-wayland-dev

编译过程纪录

i5@debian:~/文档/fcitx5-qt/build$ cmake ..
-- The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found XCB_XCB: /usr/lib/x86_64-linux-gnu/libxcb.so (found version "") 
-- Found XCB: /usr/lib/x86_64-linux-gnu/libxcb.so  found components: XCB 
-- Found XKBCommon_XKBCommon: /usr/lib/x86_64-linux-gnu/libxkbcommon.so (found version "") 
-- Found XKBCommon: /usr/lib/x86_64-linux-gnu/libxkbcommon.so (Required is at least version "0.5.0") found components: XKBCommon 
-- Found X11: /usr/include   
-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so
-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so - found
-- Looking for gethostbyname
-- Looking for gethostbyname - found
-- Looking for connect
-- Looking for connect - found
-- Looking for remove
-- Looking for remove - found
-- Looking for shmat
-- Looking for shmat - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE  
-- Performing Test HAVE_STDATOMIC
-- Performing Test HAVE_STDATOMIC - Success
-- Found WrapAtomic: TRUE  
-- Found OpenGL: /usr/lib/x86_64-linux-gnu/libOpenGL.so   
-- Found WrapOpenGL: TRUE  
-- Found XKB: /usr/lib/x86_64-linux-gnu/libxkbcommon.so (Required is at least version "0.5.0") 
-- Found WrapVulkanHeaders: /usr/include  
-- Found Wayland_Client: /usr/lib/x86_64-linux-gnu/libwayland-client.so (found version "") 
-- Found Wayland_Server: /usr/lib/x86_64-linux-gnu/libwayland-server.so (found version "") 
-- Found Wayland_Cursor: /usr/lib/x86_64-linux-gnu/libwayland-cursor.so (found version "") 
-- Found Wayland_Egl: /usr/lib/x86_64-linux-gnu/libwayland-egl.so (found version "") 
-- Found Wayland: /usr/lib/x86_64-linux-gnu/libwayland-client.so;/usr/lib/x86_64-linux-gnu/libwayland-server.so;/usr/lib/x86_64-linux-gnu/libwayland-cursor.so;/usr/lib/x86_64-linux-gnu/libwayland-egl.so (found suitable version "1.21.0", minimum required is "1.15")  
CMake Warning at /usr/share/ECM/find-modules/FindWayland.cmake:130 (message):
  Could not find wayland.xml in
Call Stack (most recent call first):
  /usr/share/cmake-3.25/Modules/CMakeFindDependencyMacro.cmake:47 (find_package)
  /home/i5/Qt/6.6.1/gcc_64/lib/cmake/Qt6/QtPublicDependencyHelpers.cmake:36 (find_dependency)
  /home/i5/Qt/6.6.1/gcc_64/lib/cmake/Qt6WaylandClient/Qt6WaylandClientDependencies.cmake:30 (_qt_internal_find_third_party_dependencies)
  /home/i5/Qt/6.6.1/gcc_64/lib/cmake/Qt6WaylandClient/Qt6WaylandClientConfig.cmake:40 (include)
  qt6/CMakeLists.txt:5 (find_package)


CMake Warning at /usr/share/ECM/find-modules/FindWayland.cmake:130 (message):
  Could not find wayland.xml in
Call Stack (most recent call first):
  /usr/share/cmake-3.25/Modules/CMakeFindDependencyMacro.cmake:47 (find_package)
  /home/i5/Qt/6.6.1/gcc_64/lib/cmake/Qt6/QtPublicDependencyHelpers.cmake:36 (find_dependency)
  /home/i5/Qt/6.6.1/gcc_64/lib/cmake/Qt6WaylandClient/Qt6WaylandClientDependencies.cmake:30 (_qt_internal_find_third_party_dependencies)
  /home/i5/Qt/6.6.1/gcc_64/lib/cmake/Qt6WaylandClient/Qt6WaylandClientConfig.cmake:40 (include)
  qt6/CMakeLists.txt:5 (find_package)


-- Found WaylandScanner: /usr/bin/wayland-scanner  
-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY
-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY - Success
-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY
-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY - Success
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Success
-- The following OPTIONAL packages have been found:

 * Qt6CoreTools (required version >= 6.6.1)
 * Qt6Core (required version >= 6.0.0)
 * Qt6DBusTools (required version >= 6.6.1)
 * Qt6DBus (required version >= 6.0.0)
 * Qt6WidgetsTools (required version >= 6.6.1)
 * OpenGL
 * Qt6Widgets (required version >= 6.0.0)
 * XKB (required version >= 0.5.0), XKB API common to servers and clients., 
 * WrapVulkanHeaders
 * Qt6GuiTools (required version >= 6.6.1)
 * Qt6WaylandScannerTools (required version >= 6.6.1)

-- The following REQUIRED packages have been found:

 * ECM (required version >= 1.4.0)
 * XCB, X protocol C-language Binding, 
 * XKBCommon (required version >= 0.5.0), Keyboard handling library using XKB data, 
 * X11
 * Qt6 (required version >= 6.0.0)
 * Qt6Gui (required version >= 6.0.0)
 * Qt6WaylandClient (required version >= 6.0.0)
 * Qt6WaylandGlobalPrivate (required version >= 6.0.0)

-- Configuring done
-- Generating done
-- Build files have been written to: /home/i5/文档/fcitx5-qt/build
i5@debian:~/文档/fcitx5-qt/build$ make
[  4%] Automatic MOC for target Fcitx5Qt6DBusAddons
[  4%] Built target Fcitx5Qt6DBusAddons_autogen
[  9%] Building CXX object qt6/dbusaddons/CMakeFiles/Fcitx5Qt6DBusAddons.dir/Fcitx5Qt6DBusAddons_autogen/mocs_compilation.cpp.o
[ 13%] Building CXX object qt6/dbusaddons/CMakeFiles/Fcitx5Qt6DBusAddons.dir/fcitxqtwatcher.cpp.o
[ 18%] Building CXX object qt6/dbusaddons/CMakeFiles/Fcitx5Qt6DBusAddons.dir/fcitxqtdbustypes.cpp.o
[ 22%] Building CXX object qt6/dbusaddons/CMakeFiles/Fcitx5Qt6DBusAddons.dir/fcitxqtinputcontextproxy.cpp.o
[ 27%] Building CXX object qt6/dbusaddons/CMakeFiles/Fcitx5Qt6DBusAddons.dir/fcitxqtinputcontextproxyimpl.cpp.o
[ 31%] Building CXX object qt6/dbusaddons/CMakeFiles/Fcitx5Qt6DBusAddons.dir/fcitxqtinputmethodproxy.cpp.o
[ 36%] Building CXX object qt6/dbusaddons/CMakeFiles/Fcitx5Qt6DBusAddons.dir/fcitxqtcontrollerproxy.cpp.o
[ 36%] Built target Fcitx5Qt6DBusAddons
[ 40%] Automatic MOC for target fcitx5platforminputcontextplugin-qt6
[ 40%] Built target fcitx5platforminputcontextplugin-qt6_autogen
[ 45%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/fcitx5platforminputcontextplugin-qt6_autogen/mocs_compilation.cpp.o
[ 50%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/fcitx4watcher.cpp.o
[ 54%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/fcitx4inputcontextproxy.cpp.o
[ 59%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/fcitx4inputcontextproxyimpl.cpp.o
[ 63%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/fcitx4inputmethodproxy.cpp.o
[ 68%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/hybridinputcontext.cpp.o
[ 72%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/qfcitxplatforminputcontext.cpp.o
[ 77%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/fcitxcandidatewindow.cpp.o
[ 81%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/fcitxtheme.cpp.o
[ 86%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/font.cpp.o
[ 90%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/qtkey.cpp.o
[ 95%] Building CXX object qt6/platforminputcontext/CMakeFiles/fcitx5platforminputcontextplugin-qt6.dir/main.cpp.o
[100%] Linking CXX shared module libfcitx5platforminputcontextplugin.so
[100%] Built target fcitx5platforminputcontextplugin-qt6
i5@debian:~/文档/fcitx5-qt/build$
  • 终产物

/home/i5/文档/fcitx5-qt/build/qt6/platforminputcontext/libfcitx5platforminputcontextplugin.so

另一种选择

打包所有依赖,临时赋予环境变量给 App-Bin 可能是另一种选择。

setup.sh

这个脚本,是执行程序的脚本,它被桌面快捷方式文件调用:

#!/bin/bash
export LD_LIBRARY_PATH=/opt/rimetools/Q-t/lib:/opt/rimetools/Q-t/plugins
QT_QPA_PLATFORM=xcb /opt/rimetools/newReader

显然,QT_QPA_PLATFORM=xcb 是为了避坑 wayland ,在这里也可以不添加它。
export LD_LIBRARY_PATH=/opt/rimetools/Q-t/lib:/opt/rimetools/Q-t/plugins 则是临时环境变量,供程序寻址。

newReader.desktop

这里显示了调用关系,而且指定了图标目录,程序类别。

[Desktop Entry]
X-VERSION=1.0
Type=Application
Name=newReader
Exec=/opt/rimetools/setup.sh
Icon=/opt/rimetools/executive/rimetool.ico
Comment=InputMethod tools
Terminal=false
Categories=System;Utility;

安装与卸载

注意,这里使用了 Dash ,因为现在很多发行版默认使用它取代 Bash,语法细节有所区别。

  • install.sh
#!/bin/dash

WBCHR_PIDS=$(pgrep newReader)

string="${WBCHR_PIDS}"

echo $WBCHR_PIDS

if [ ${string}"abc" = "abc" ]
then
  echo "newReader 没有活动的进程"
else
  echo "检测到 newReader 正在运行,即将杀掉!"
  kill $WBCHR_PIDS
fi

if [ -d /opt/rimetools ];then
  echo "rimetools 文件夹存在,将会删了它!"
  sudo rm -rf /opt/rimetools
fi

sudo cp -rf rimetools /opt
sudo cp -rf /opt/rimetools/executive/newReader.desktop /usr/share/applications
sudo chmod a+x /usr/share/applications/newReader.desktop
sudo chmod a+x /opt/rimetools/newReader
sudo chmod 777 /opt/rimetools/setup.sh
sudo chmod 777 /opt/rimetools -R
sudo ln -sf /usr/lib/x86_64-linux-gnu/libGL.so.1 /usr/lib/libGL.so

echo "安置成功!"
  • remove.sh
#!/bin/dash

WBCHR_PIDS=$(pgrep newReader)

string="${WBCHR_PIDS}"

echo $WBCHR_PIDS

if [ ${string}"abc" = "abc" ]
then
  echo "newReader 没有活动的进程"
else
  echo "检测到 newReader 正在运行,即将杀掉!"
  kill $WBCHR_PIDS
fi

if [ -d /opt/rimetools ]
then
  echo "rimetools 文件夹存在,将会删了它!"
  sudo sudo rm -rf /opt/rimetools
fi

if [ -f /usr/share/applications/newReader.desktop ]
then
  echo "newReader 快捷方式存在,将会删了它!"
  sudo sudo rm -rf /usr/share/applications/newReader.desktop
fi

总之,在 Linux 下,搞应用程序发布,这可能是最简洁的方式了。

Reply Favorite View the author
All Replies

No replies yet