Ubuntu 22.04 + Qt 6.9.3 应用程序打包与部署完整指南

1. 引言

在 Ubuntu 22.04 系统上使用 Qt 6.9.3 开发应用程序后,如何将程序打包成可独立分发的版本是一个关键步骤。本文将详细介绍一个完整的 Qt 应用程序打包解决方案,包含两个核心脚本:

  1. pack.sh - 完整的打包脚本,负责将应用程序及其所有依赖打包成可分发版本
  2. run.sh - 完整的运行脚本,确保打包后的程序能在目标环境正确运行

这两个脚本共同构成了 Qt 应用程序的完整部署方案,特别针对包含虚拟键盘等复杂依赖的应用场景。本文将提供完整的脚本代码和详细解析,帮助您理解每个步骤的作用和原理。

2. 脚本总览

本文涉及两个核心脚本,它们共同构成了 Qt 应用程序的完整打包与部署解决方案:

2.1 打包脚本 (pack.sh)

功能 :将 Qt 应用程序及其所有依赖打包成可独立分发的压缩包

主要步骤

  1. 环境清理 - 删除上次打包的残留文件
  2. 构建类型选择 - 支持 Release/Debug 版本
  3. 文件复制 - 复制可执行文件和第三方库
  4. 虚拟键盘处理 - 特殊处理 Qt 6 虚拟键盘依赖
  5. 依赖收集 - 使用 linuxdeployqt 自动收集 Qt 运行时依赖
  6. 压缩打包 - 生成版本化的压缩包

2.2 运行脚本 (run.sh)

功能 :在目标机器上正确运行打包后的应用程序

核心配置

  1. 显示环境适配 - 自动检测 DISPLAY 变量,兼容开机自启动
  2. 路径锁定 - 确保相对路径始终正确
  3. 库路径配置 - 设置 OpenVINO 和 Qt 库的搜索路径
  4. Qt 插件配置 - 配置虚拟键盘和平台插件路径
  5. 应用程序启动 - 设置调试参数并启动主程序

2.3 两个脚本的关系

  • 打包脚本 生成包含所有依赖的完整应用程序包
  • 运行脚本 确保打包后的程序能在目标环境正确运行
  • 协同工作 :打包脚本创建的压缩包解压后,直接运行 run.sh 即可启动应用程序

在 Ubuntu 22.04 系统上使用 Qt 6.9.3 开发应用程序后,如何将程序打包成可独立分发的版本是一个关键步骤。本文将详细介绍一个完整的 Qt 应用程序打包脚本,涵盖从环境清理到最终压缩打包的全过程,特别针对包含虚拟键盘等复杂依赖的应用场景。

3. 环境准备

3.1 系统要求

  • Ubuntu 22.04 LTS
  • Qt 6.9.3 (gcc_64 版本)
  • linuxdeployqt 工具
  • 基本的 shell 脚本知识

3.2 目录结构说明

在开始之前,请确保您的项目具有以下目录结构:

复制代码
项目根目录/
├── 打包脚本所在目录/
│   ├── pack.sh (打包脚本)
│   └── run.sh (运行脚本)
├── release_bin/ (Release版本可执行文件)
├── debug_bin/ (Debug版本可执行文件)
├── applib/ (第三方库文件)
└── update.sh (版本信息文件)

4. 打包脚本详解 (pack.sh)

以下是完整的打包脚本 pack.sh 内容:

bash 复制代码
#!/bin/bash

# 配置变量
APP_NAME="HA5001HM"
QMAKE_PATH="/home/wzh/Qt/6.9.3/gcc_64/bin/qmake"
QT_ROOT="/home/wzh/Qt/6.9.3/gcc_64" 
RELEASE_DIR="../release_bin"
DEBUG_DIR="../debug_bin"

echo "=========================================="
echo "          HA5001HM 打包脚本"
echo "=========================================="

# 1. 删除上次打包和linuxdeployqt生成的文件
echo ""
echo "[Step 1] 清理上次打包文件..."
rm -rf lib/ plugins/ translations/ appConfig/ "${APP_NAME}" AppRun qt.conf qml/ 2>/dev/null
echo "          清理完成"

# 2. 选择构建类型并复制exe
echo ""
echo "[Step 2] 选择构建类型"
echo "          0 - Release 版本"
echo "          1 - Debug   版本"
read -p "请输入选择 (0/1): " build_type

case $build_type in
    0)
        echo "          选择 Release 版本"
        source_dir="${RELEASE_DIR}"
        ;;
    1)
        echo "          选择 Debug 版本"
        source_dir="${DEBUG_DIR}"
        ;;
    *)
        echo "          无效选择,默认使用 Release"
        build_type="0"
        source_dir="${RELEASE_DIR}"
        ;;
esac

echo "          从 ${source_dir}/${APP_NAME} 复制到当前目录..."
cp "${source_dir}/${APP_NAME}" .
if [ $? -ne 0 ]; then
    echo "          ERROR: 复制失败!源文件: ${source_dir}/${APP_NAME}"
    exit 1
fi
echo "          复制成功"

# 3. 复制第三方库到 lib 目录...
echo ""
echo "[Step 3] 复制第三方库到 lib 目录..."
mkdir -p lib
cp -r ../applib/* lib/ 2>/dev/null || true
if [ -d "../applib" ]; then
    echo "          复制成功"
else
    echo "          警告: 没有找到 applib 目录"
    exit 1
fi

# 4. 预拷贝虚拟键盘全套QML与依赖库
echo ""
echo "[Step 4] 预拷贝虚拟键盘全套QML文件..."
if [ ! -d "${QT_ROOT}/qml/QtQuick/VirtualKeyboard" ]; then
    echo "          ERROR: 虚拟键盘源目录不存在,打包终止!"
    exit 1
fi
mkdir -p qml/QtQuick/VirtualKeyboard
cp -r "${QT_ROOT}/qml/QtQuick/VirtualKeyboard"/* qml/QtQuick/VirtualKeyboard/
if [ $? -ne 0 ] || [ ! -d "qml/QtQuick/VirtualKeyboard/Styles" ]; then
    echo "          ERROR: 虚拟键盘 QML 补全失败,打包终止!"
    exit 1
fi
echo "          虚拟键盘 QML 补全成功"

echo ""
echo "[Step 4.1] 补全虚拟键盘底层依赖库..."
cp -f "${QT_ROOT}/lib/libQt6VirtualKeyboard.so.6" lib/
cp -f "${QT_ROOT}/lib/libQt6VirtualKeyboardSettings.so.6" lib/
if [ $? -ne 0 ]; then
    echo "          ERROR: 虚拟键盘依赖库复制失败,打包终止!"
    exit 1
fi
echo "          虚拟键盘依赖库补全成功"

echo ""
echo "[Step 4.2] 补全虚拟键盘依赖附属QML模块..."
mkdir -p qml/Qt/labs/folderlistmodel
mkdir -p qml/QtQuick/Layouts
mkdir -p qml/QtQuick/Window

cp -r "${QT_ROOT}/qml/Qt/labs/folderlistmodel"/* qml/Qt/labs/folderlistmodel/
cp -r "${QT_ROOT}/qml/QtQuick/Layouts"/* qml/QtQuick/Layouts/
cp -r "${QT_ROOT}/qml/QtQuick/Window"/* qml/QtQuick/Window/
echo "          依赖QML模块补全成功"

echo ""
echo "[Step 4.3] 补全QuickLayout依赖库..."
cp -f "${QT_ROOT}/lib/libQt6QuickLayouts.so.6" lib/
if [ $? -ne 0 ]; then
    echo "          ERROR: 依赖库复制失败,打包终止!"
    exit 1
fi
echo "          依赖库补全成功"

# 5. 执行 linuxdeployqt 打包工具
echo ""
echo "[Step 5] 执行 linuxdeployqt 依赖分发..."
linuxdeployqt "${APP_NAME}" -qmake="${QMAKE_PATH}" -extra-plugins=platforminputcontexts -qmlimports="${QT_ROOT}/qml"
if [ $? -ne 0 ]; then
    echo "          ERROR: linuxdeployqt 执行失败!"
    exit 1
fi
echo "          linuxdeployqt 执行成功"

# 6. 压缩打包输出
echo ""
echo "[Step 6] 开始打包压缩..."

# 获取版本号
if [ -f "update.sh" ]; then
    source update.sh
    ver="${ver#*\"}"
    ver="${ver%\"}"
    echo "          获取版本号: ${ver}"
else
    ver="unknown"
    echo "          警告: 未找到 update.sh,版本号设为 unknown"
fi

# 压缩到上级目录
echo "          执行: tar -czvf ../update_${ver} ./*"
tar -czvf "../update_${ver}" ./*
if [ $? -ne 0 ]; then
    echo "          ERROR: 打包失败!"
    exit 1
fi
echo "          打包成功: ../update_${ver}"

# 7. 打包完成
echo ""
echo "=========================================="
echo "          打包完成!"
echo "          输出文件: ../update_${ver}"
echo "=========================================="

脚本功能详解:

  1. 配置变量:定义应用程序名称、Qt路径、构建目录等关键参数
  2. 环境清理:删除上次打包的残留文件,确保干净的打包环境
  3. 构建类型选择:支持Release和Debug版本的选择
  4. 文件复制:复制可执行文件和第三方库
  5. 虚拟键盘处理:Qt 6虚拟键盘需要特殊处理,包括QML文件、依赖库和附属模块
  6. 依赖收集:使用linuxdeployqt自动收集Qt运行时依赖
  7. 压缩打包:生成版本化的压缩包,便于分发

5. 虚拟键盘依赖处理(Qt 6 特殊处理)

为什么需要特殊处理?

在 Qt 6 中,虚拟键盘(Qt Virtual Keyboard)的依赖关系比较复杂,linuxdeployqt 无法自动收集所有必要的 QML 文件和依赖库。因此需要手动处理:

5.1 虚拟键盘 QML 文件复制

bash 复制代码
# 4. 预拷贝虚拟键盘全套QML与依赖库
echo ""
echo "[Step 4] 预拷贝虚拟键盘全套QML文件..."
if [ ! -d "${QT_ROOT}/qml/QtQuick/VirtualKeyboard" ]; then
    echo "          ERROR: 虚拟键盘源目录不存在,打包终止!"
    exit 1
fi
mkdir -p qml/QtQuick/VirtualKeyboard
cp -r "${QT_ROOT}/qml/QtQuick/VirtualKeyboard"/* qml/QtQuick/VirtualKeyboard/
if [ $? -ne 0 ] || [ ! -d "qml/QtQuick/VirtualKeyboard/Styles" ]; then
    echo "          ERROR: 虚拟键盘 QML 补全失败,打包终止!"
    exit 1
fi
echo "          虚拟键盘 QML 补全成功"

关键检查点:

  • 验证 Qt 安装目录中是否存在虚拟键盘 QML
  • 确保 Styles 目录被正确复制

5.2 虚拟键盘依赖库

bash 复制代码
echo ""
echo "[Step 4.1] 补全虚拟键盘底层依赖库..."
cp -f "${QT_ROOT}/lib/libQt6VirtualKeyboard.so.6" lib/
cp -f "${QT_ROOT}/lib/libQt6VirtualKeyboardSettings.so.6" lib/
if [ $? -ne 0 ]; then
    echo "          ERROR: 虚拟键盘依赖库复制失败,打包终止!"
    exit 1
fi
echo "          虚拟键盘依赖库补全成功"

依赖库说明:

  • libQt6VirtualKeyboard.so.6: 虚拟键盘核心库
  • libQt6VirtualKeyboardSettings.so.6: 虚拟键盘设置库

5.3 附属 QML 模块

bash 复制代码
echo ""
echo "[Step 4.2] 补全虚拟键盘依赖附属QML模块..."
mkdir -p qml/Qt/labs/folderlistmodel
mkdir -p qml/QtQuick/Layouts
mkdir -p qml/QtQuick/Window

cp -r "${QT_ROOT}/qml/Qt/labs/folderlistmodel"/* qml/Qt/labs/folderlistmodel/
cp -r "${QT_ROOT}/qml/QtQuick/Layouts"/* qml/QtQuick/Layouts/
cp -r "${QT_ROOT}/qml/QtQuick/Window"/* qml/QtQuick/Window/
echo "          依赖QML模块补全成功"

必要模块:

  • Qt/labs/folderlistmodel: 文件列表模型
  • QtQuick/Layouts: 布局组件
  • QtQuick/Window: 窗口管理

5.4 QuickLayout 依赖库

bash 复制代码
echo ""
echo "[Step 4.3] 补全QuickLayout依赖库..."
cp -f "${QT_ROOT}/lib/libQt6QuickLayouts.so.6" lib/
if [ $? -ne 0 ]; then
    echo "          ERROR: 依赖库复制失败,打包终止!"
    exit 1
fi
echo "          依赖库补全成功"

注意事项:

  • 这些步骤必须在运行 linuxdeployqt 之前完成
  • 确保所有文件路径正确,否则虚拟键盘可能无法正常工作

6. 使用 linuxdeployqt 打包

6.1 执行打包命令

bash 复制代码
# 5. 执行 linuxdeployqt 打包工具
echo ""
echo "[Step 5] 执行 linuxdeployqt 依赖分发..."
linuxdeployqt "${APP_NAME}" -qmake="${QMAKE_PATH}" -extra-plugins=platforminputcontexts -qmlimports="${QT_ROOT}/qml"
if [ $? -ne 0 ]; then
    echo "          ERROR: linuxdeployqt 执行失败!"
    exit 1
fi
echo "          linuxdeployqt 执行成功"

参数说明:

  • -qmake: 指定 qmake 路径,用于分析 Qt 依赖
  • -extra-plugins=platforminputcontexts: 包含输入法上下文插件(虚拟键盘必需)
  • -qmlimports: 指定 QML 导入路径,确保 QML 模块正确加载

6.2 linuxdeployqt 工作原理

linuxdeployqt 会自动执行以下操作:

  1. 分析依赖关系:扫描可执行文件,找出所有依赖的 Qt 库
  2. 复制 Qt 库 :将所需的 Qt 库复制到 lib/ 目录
  3. 复制插件 :将 Qt 插件复制到 plugins/ 目录
  4. 生成启动脚本 :创建 AppRun 启动脚本
  5. 创建配置文件 :生成 qt.conf 配置文件
  6. 处理 QML 导入 :复制必要的 QML 模块到 qml/ 目录

6.3 压缩打包与版本管理

6.3.1 获取版本号
bash 复制代码
# 6. 压缩打包输出
echo ""
echo "[Step 6] 开始打包压缩..."

# 获取版本号
if [ -f "update.sh" ]; then
    source update.sh
    ver="${ver#*\"}"
    ver="${ver%\"}"
    echo "          获取版本号: ${ver}"
else
    ver="unknown"
    echo "          警告: 未找到 update.sh,版本号设为 unknown"
fi

版本文件示例 (update.sh):

bash 复制代码
#!/bin/bash
ver="1.0.0"
6.3.2 创建压缩包
bash 复制代码
# 压缩到上级目录
echo "          执行: tar -czvf ../update_${ver} ./*"
tar -czvf "../update_${ver}" ./*
if [ $? -ne 0 ]; then
    echo "          ERROR: 打包失败!"
    exit 1
fi
echo "          打包成功: ../update_${ver}"

压缩包内容:

  • 可执行文件
  • 所有依赖库
  • Qt 插件
  • QML 文件
  • 配置文件
  • 启动脚本

6. 压缩打包与版本管理

6.1 获取版本号

bash 复制代码
# 6. 压缩打包输出
echo ""
echo "[Step 6] 开始打包压缩..."

# 获取版本号
if [ -f "update.sh" ]; then
    source update.sh
    ver="${ver#*\"}"
    ver="${ver%\"}"
    echo "          获取版本号: ${ver}"
else
    ver="unknown"
    echo "          警告: 未找到 update.sh,版本号设为 unknown"
fi

版本文件示例 (update.sh):

bash 复制代码
#!/bin/bash
ver="1.0.0"

6.2 创建压缩包

bash 复制代码
# 压缩到上级目录
echo "          执行: tar -czvf ../update_${ver} ./*"
tar -czvf "../update_${ver}" ./*
if [ $? -ne 0 ]; then
    echo "          ERROR: 打包失败!"
    exit 1
fi
echo "          打包成功: ../update_${ver}"

压缩包内容:

  • 可执行文件
  • 所有依赖库
  • Qt 插件
  • QML 文件
  • 配置文件

7. 运行脚本详解 (run.sh)

以下是完整的运行脚本 run.sh 内容:

bash 复制代码
#!/bin/bash
# ===================== 自动适配本地/开机图形环境 =====================
# 仅当前无DISPLAY变量时(开机自启动会话环境)自动获取,本地终端不覆盖
if [ -z "$DISPLAY" ]; then
    # 动态抓取当前登录用户的真实DISPLAY,不硬写死:0,兼容多显示器/多会话
    export DISPLAY=$(w -hs | grep "$USER" | awk '{print $2}' | head -n1)
fi

# Wayland/Xorg统一兼容Qt窗口,本地/开机都无害
export QT_QPA_PLATFORM=xcb

# ===================== 锁定脚本目录,解决相对路径失效 =====================
SCRIPT_PATH="${BASH_SOURCE[0]}"
SCRIPT_DIR=$(cd "$(dirname "$SCRIPT_PATH")" &>/dev/null && pwd)
# 强制切换到脚本所在文件夹,保证 ./AppRun / lib/plugins 能找到
cd "$SCRIPT_DIR"

# ===================== 库路径 =====================
OV_ROOT="/opt/intel/openvino_2026.2.0"
export LD_LIBRARY_PATH="${OV_ROOT}/runtime/3rdparty/tbb/lib:${OV_ROOT}/runtime/lib/intel64:$LD_LIBRARY_PATH:$SCRIPT_DIR/lib:$SCRIPT_DIR/lib/Galaxy:$SCRIPT_DIR/lib/xcblib:/usr/lib/x86_64-linux-gnu"

# ===================== Qt插件绝对路径(彻底规避相对路径问题) =====================
export QT_QPA_PLATFORM_PLUGIN_PATH="$SCRIPT_DIR/plugins/platforms"
export QT_PLUGIN_PATH="$SCRIPT_DIR/plugins"
export QML2_IMPORT_PATH="$SCRIPT_DIR/qml"
export QT_IM_MODULE=qtvirtualkeyboard

# ===================== 启动主程序 =====================
ulimit -c unlimited
./HA5001HM

脚本各部分详解:

7.1 显示环境适配

环境适配逻辑:

  • 自动检测 DISPLAY 环境变量
  • 兼容多显示器和多会话环境
  • 强制使用 XCB 平台插件确保兼容性

7.2 目录锁定与路径设置

目录锁定重要性:

  • 确保相对路径始终正确
  • 避免因工作目录变化导致的库加载失败

7.3 库路径配置

库路径优先级:

  1. OpenVINO 运行时库
  2. 应用程序自带库
  3. 系统库

7.4 Qt 插件路径配置

关键配置:

  • QT_IM_MODULE=qtvirtualkeyboard: 启用 Qt 虚拟键盘
  • 使用绝对路径避免路径解析问题

7.5 启动应用程序

启动优化:

  • ulimit -c unlimited: 允许生成 core dump 文件用于调试
  • 直接运行可执行文件

8. 常见问题与解决方案

8.1 虚拟键盘不显示

问题原因: 缺少虚拟键盘依赖库或 QML 文件

解决方案:

  1. 确保步骤 4 中的所有文件都已正确复制
  2. 检查 QT_IM_MODULE 环境变量设置
  3. 验证 QML2_IMPORT_PATH 包含正确的 QML 路径

8.2 库加载失败

问题原因: 库路径配置错误

解决方案:

  1. 使用 ldd 命令检查依赖关系
  2. 确保 LD_LIBRARY_PATH 包含所有必要路径
  3. 检查库文件权限

8.3 插件加载失败

问题原因: Qt 插件路径错误

解决方案:

  1. 验证 QT_QPA_PLATFORM_PLUGIN_PATH 指向正确的 platforms 目录
  2. 检查 plugins 目录结构是否完整

9. 打包结果验证

9.1 验证步骤

  1. 文件完整性检查:

    bash 复制代码
    tar -tzf update_1.0.0.tar.gz | head -20
  2. 依赖关系验证:

    bash 复制代码
    ldd HA5001HM | grep "not found"
  3. 运行测试:

    bash 复制代码
    ./run.sh

9.2 分发准备

  1. 将压缩包复制到目标机器
  2. 解压到任意目录
  3. 运行 run.sh 启动应用程序
  4. 确保目标机器有相同的系统架构(x86_64)

10. 总结

本文详细介绍了在 Ubuntu 22.04 上使用 Qt 6.9.3 打包应用程序的完整流程,特别针对包含虚拟键盘等复杂依赖的应用。关键要点包括:

  1. 环境清理:确保每次打包从干净状态开始
  2. 虚拟键盘处理:Qt 6 需要手动复制 QML 文件和依赖库
  3. linuxdeployqt 使用:自动化处理 Qt 依赖
  4. 运行环境配置:解决开机自启动和路径问题
  5. 错误处理:完善的错误检查和退出机制

通过这个脚本,您可以轻松地将 Qt 应用程序打包成可独立分发的版本,无需在目标机器上安装完整的 Qt 开发环境。

相关推荐
qq_401700413 小时前
Qt自定义信号槽详解:带参发射 vs sender()获取,两种多信号关联方案全掌握
java·数据库·qt
自律懒人4 小时前
AI 沙箱逃逸 4 连发:GPT-5.6 黑进 Hugging Face、Kimi K3 抄答案,5 步给本地 Agent 装围栏
ubuntu
郝学胜-神的一滴6 小时前
Qt 高级编程 042:进度条从入门到自定义美化
开发语言·c++·qt·软件开发·用户界面
AI的探索之旅6 小时前
嵌入式视觉学习路线:Qt + OpenCV + 工业相机,从零到综合项目
qt·opencv·学习
老王IT7 小时前
VMware虚拟机安装的ubuntu忘记用户密码怎么办
ubuntu
我是小灰灰吖7 小时前
Ubuntu22.04,OpenCV 4.5.5 环境搭建
linux·qt·ubuntu
集智飞行9 小时前
四种方法解决ROS2超过100个节点时的DDS瓶颈
ubuntu
数智工坊9 小时前
UECP:不确定性增强的协同感知 | 基于物理先验的BEV融合新范式
linux·ubuntu·3d·机器人
≮傷£≯√1 天前
Opencv VideoCapture
qt·opencv