QT程序打包并部署在docker内

最进尝试写qt的界面程序,想将qt程序打出一个独立的包,并运行在docker内,网上的教程都存在部分问题(或者是不满足我的使用场景)

参考网址

一. 安装 linuxdeployqt

1.1 下载 linuxdeployqt

linuxdeployqt 下载 , 下载的包是一个静态程序可以直接使用

1.2 安装 linuxdeployqt

即将下载的程序重命名,并放在合适的位置

mv linuxdeployqt-6-x86_64.AppImage linuxdeployqt
chmod 777 linuxdeployqt
mv linuxdeployqt /usr/local/bin

测试是否安装成功

linuxdeployqt --version

二. 使用 linuxdeployqt 找寻依赖库

运行打包指令(Test是我的qt程序,且是 release 版本的,假定我们的qt程序放在 ~/data/目录下,当前命令也在~/data/目录执行)

linuxdeployqt Test -appimage

此时的包都放在当前目录的 lib/ 目录下.

注意: 当前只是找寻了所需的Qt依赖,但是Qt环境需要的基础依赖库没有找齐,将其放在docker下仍然跑不起来

当报错 .desktop file is missing a Categories= key 时, 在当前目录下的 default.desktop 文件末尾添加

Categories=Application;

docker 打包 docker打包qt程序_docker 打包

然后重新运行

linuxdeployqt Test -appimage

三. 补齐 libqxcb.so 依赖的库

也可以在docker内直接安装 libfontconfig1 libgl1 libxcb1 这三个库来补齐,就可以省略这一步骤了.

3.1 编写脚本 lib_qt_copy.sh

这个脚本的目的是为了找寻依赖的xcb库

#!/bin/bash
if [ $# != 1 ]
then
    echo "传参数顺序: ./脚本.sh  <要发布的可执行文件文件>"
    exit 0
fi

LibDir=$PWD/xcblib
mkdir $LibDir

Target=$1

lib_array=($(ldd $Target | grep -o "/.*" | grep -o "/.*/[^[:space:]]*"))

for Variable in ${lib_array[@]}
do
    cp "$Variable" $LibDir
done

3.2 执行脚本

libqxcb.so 在 plugins/platforms/ 目录下

bash ./lib_qt_copy.sh plugins/platforms/libqxcb.so

那么 依赖的Qt库和Qt依赖的库分别放在 lib/ 和 xcblib/ 目录下,它们之间有些库是重复的,可以将它们合成一个目录.

四. 给予 docker 访问 gui 的权限.

在 /etc/profile 末尾添加

if [ "$DISPLAY" != "" ]
then
 xhost +
fi

然后在当前终端执行

source /etc/profile

此后所有的操作都需要在当前终端上执行,因为当前终端开启了x11权限.重启后就不会有这些顾虑了,因为已经应用到了全局.

4.1 进入docker终端

有两种方式,第一种就是编写 docker compose 的配置文件,第二种就是直接在 docker run 后面接参数.

两种方式使用一个就行

方式一. 使用 docker compose 进入终端

创建 docker-compose.yml 文件,并添加以下内容

注意: 我们添加了一个docker目录的映射,所以将前面打包的qt程序放在当前目录下的docker目录下,这样就不用后续拷贝到docker里面的.

version: '3.9'
name: code-develop
services:
  ubuntu:
    environment:
     - DISPLAY
    tty: true
    image: ubuntu:18.04
    profiles: ["ubuntu"]
    network_mode: host
    privileged: true
    volumes: 
     - /tmp/.X11-unix:/tmp/.X11-unix
     - ~/data:/data

如果没有 docker 镜像,记得先拉取 ubuntu:18.04 镜像

执行 docker 容器的生成

docker compose up ubuntu -d

进入 docker 容器

docker compose exec ubuntu bash

方式二. 使用 docker run 命令进入终端

执行命令

docker run -itd -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY -e GDK_SCALE -e GDK_DPI_SCALE  --name test-gui --privileged  -v ./data:/data --network host ubuntu:18.04 bash
docker exec -it test-gui bash

4.2 测试 gui 权限是否开放成功

在docker容器内运行下面指令,如果 apt 比较慢的话,可以自己手动更改镜像源(推荐华为镜像源和清华镜像源)

apt update
apt install xarclock
xarclock

如果 xarclock 运行起来的话,就说话gui权限已经开放,若报错 can't open display,则重启电脑,并重新进入docker ,看能否执行成功.

五. 运行 qt 程序

进入docker后,开始测试我们的Qt程序能否执行.

设置依赖库的环境变量和Qt调试环境变量

cd /data/
# 这一步是为了报错的时候,可以看到报错的地方
export QT_DEBUG_PLUGINS=1
# 这一步是给出依赖的库路径,请根据实际情况调整
export LD_LIBRARY_PATH=./lib/:./xcblib
./Test

如果中间报错缺少库,设置 QT_DEBUG_PLUGINS 为 1 后可以看到缺少库的名称,可以在主机中找到对应的库并拷贝到 docker 中.
也可以通过 apt-file search libxx.so 来查找属于哪个包,然后安装对应的包.



要写的东西比较多,所以有些混乱,有不同见解的地方可以沟通,我也会持续更新和改善这篇文章.