这篇文章上次修改于 225 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

在 Ubuntu 下使用 linuxdeployqt 发布 Qt 程序

前言

这里所说的 Ubuntu 其实也可以扩大到大多数 Linux 系统,Qt 程序主要指包含了 WebEngine 的程序。因为包含了 WebEngine 的程序比普通 Qt 程序依赖更多,打包更麻烦,所以会了这个另外那个也就问题不大。

开发环境

  • 操作系统:Ubuntu x64 16.04.7,linuxdeployqt 只支持在服务期内的最老的 LTS 版本,详细版本信息可在 https://wiki.ubuntu.com/Releases 查看
  • Qt 版本:5.9.7

安装 linuxdeployqt

  1. https://github.com/probonopd/linuxdeployqt/releases 下载最新发布的版本,比如现在的最新版本是:linuxdeployqt-7-x86_64.AppImage
  2. 下载完成后,将其改名为 linuxdeployqt,赋予可执行权限,然后将其移动到 /usr/local/bin 目录下以便全局使用

    sudo mv linuxdeployqt-7-x86_64.AppImage linuxdeployqt
    sudo chmod a+x linuxdeployqt
    sudo mv linuxdeployqt /usr/local/bin
    # 检查是否安装成功
    sudo linuxdelpoyqt --version
  3. 至此,linuxdeployqt 安装完成

配置 Qt 的环境变量

终端输入 gedit ~/.bashrc 命令,修改 .bashrc 文件,在文件末尾追加以下内容,其中 /opt/Qt5.9.7 是我的 Qt 安装路径,大家要用自己的路径代替

# Qt 环境变量
export PATH=/opt/Qt5.9.7/5.9.7/gcc_64/bin:$PATH
export LD_LIBRARY_PATH=/opt/Qt5.9.7/5.9.7/gcc_64/lib:$LD_LIBRARY_PATH
export QT_PLUGIN_PATH=/opt/Qt5.9.7/5.9.7/gcc_64/plugins:$QT_PLUGIN_PATH
export QML2_IMPORT_PATH=/opt/Qt5.9.7/5.9.7/gcc_64/qml:$QML2_IMPORT_PATH

最后要 source 一下使 ~/.bashrc 这个 shell 文件立即生效,而不必注销并重新登录。

source ~/.bashrc

示例程序

程序很简单,就是添加了一个 QWebEngineView,显示了百度首页:

  • mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include <QWebEngineView>
    #include <QMainWindow>
    
    namespace Ui {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
    Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
        QWebEngineView *webView;
    };
    
    #endif // MAINWINDOW_H
  • mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        webView = new QWebEngineView();
        webView->setUrl(QUrl("http://baidu.com"));
    
        ui->verticalLayout->addWidget(webView);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }

  • QtDemo.pro

    #-------------------------------------------------
    #
    # Project created by QtCreator 2020-11-04T15:27:31
    #
    #-------------------------------------------------
    
    QT       += core gui webenginewidgets
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = QtDemo
    TEMPLATE = app
    
    # The following define makes your compiler emit warnings if you use
    # any feature of Qt which has been marked as deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if you use deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    CONFIG += c++11
    
    SOURCES += \
            main.cpp \
            mainwindow.cpp
    
    HEADERS += \
            mainwindow.h
    
    FORMS += \
            mainwindow.ui
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target

编译、运行,一切正常!

打包应用程序

  • 运行 Qt 生成 Release 版本的可执行文件 QtDemo
  • 创建一个文件夹,名称最好是用可执行文件的名称,然后将 QtDemo 可执行文件复制到此文件夹下
  • 使用 linuxdeployqt 进行打包,一定要加上 -appimage 选项,命令如下:

    linuxdeployqt QtDemo -appimage

    执行上面命令出现提示信息,不用管,只是创建了一个需要你自己编辑的 desktop 文件:

    ERROR: Desktop file missing, creating a default one (you will probably want to edit it)

    对于一般的程序,到这一步,就把可执行文件的动态库等依赖文件都复制到该文件夹中了。但是我们这个 WebEngine 的程序还需要多做一步,将 /usr/lib/x86_64-linux-gnu/nss 文件夹拷贝到发布目录,否则运行的时候会报错。

编写开机脚本 runApp.sh

  • 在程序发布目录执行脚本 vi runApp.sh 创建 runApp.sh 文件
  • 写入如下内容:

    #!/bin/bash
    export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH
    export LD_LIBRARY_PATH=`pwd`/nss:$LD_LIBRARY_PATH
    export QT_PLUGIN_PATH=`pwd`/plugins:$QT_PLUGIN_PATH
    export QML2_IMPORT_PATH=`pwd`/qml:$QML2_IMPORT_PATH
    ./QtDemo
  • 添加可执行权限:chmod +x runApp.sh
  • 此时运行该脚本,则可启动程序。到这一步就可以发布了,压缩成一个压缩包发布即可

编写linux桌面图标启动(可选步骤)

修改发布目录下的 desktop 文件,并将 desktop 文件设置为可执行。可以按照 Ubuntu 官方提示修改:https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles

# --全局安装(所有用户可用),将 xxx.desktop 复制到 /usr/share/applications  
# --当前用户可用, 将 xxx.desktop 复制到 ~/.local/share/applications 目录即可
# --appName.desktop
[Desktop Entry]
Version=1.0 # app 的版本
Name=QtDemo # app 的名字
Comment= this app use for xxx # 说明信息 
Exec=/path/to/your/QtApp/QtDemo # app 的执行路径,一般用绝对路径,设置了 Path 可用相对路径,执行 shell 脚本可用 sh ./runApp.sh
Path=/working/directory/path # app 工作目录
Icon=/path/to/your/app_icon/logo.ico # icon 路径,绝对路径
Terminal=false # 是否在终端启动,效果自己试一下就知道了
StartupNotify=true # 是否使用启动通知
Type=Application
Categories=Utility;Application;

遇到的问题

  • ERROR: ldd outputLine: "libodbc.so.2 => not found"
    应用程序使用了 QxOrm,在打包时报该错误,解决办法:sudo apt-get install unixodbc-dev
  • ERROR: ldd outputLine: "libpq.so.5 => not found"
    应用程序使用了 QxOrm,在打包时报该错误,解决办法:sudo apt-get install libpq-dev

参考资料