文章目录
Qt跨平台
Qt
的跨平台为 一次编码,处处编译,这与 Java
依赖虚拟机实现的 一次编译,处处运行 是不同的。
Java跨平台实现
Java
是把针对不同平台与操作系统的跨系统核心代码抽象出来,形成单独的 JVM层(java virtual machine)
,Java
代码运行在 JVM
上,把跨平台 java语言框架问题
分解为在不同平台上设计 JVM
的问题,结构简单、逻辑清晰、易于实现 1。
为此,Java
付出了牺牲效率的代价。Java
语言需要先通过 JVM
再映射到操作系统里,最后由CPU
执行,执行过程多了一步。早期由于 Java语言
主要使用 解释性编译器
,从而导致运行效率进一步降低。但是随着 即时编译技术(JIT)
的推出,尤其是硬件计算速度的大幅提升,Java运行效率
问题基本得到解决 1。
Qt跨平台实现
Qt平台
封装了针对不同平台的类库,API
。这些都被上层做了封装,对我们开发者来说操作各种平台的接口都是一样的 1。以我最近使用的 QSerialPort
为例子,在 Qserialport.h
中可发现以下蛛丝马迹:
//line 74
#if defined(Q_OS_WIN32)
typedef void* Handle;
#else
typedef int Handle;
#endif
//line 307
#if defined(Q_OS_WIN32)
Q_PRIVATE_SLOT(d_func(), bool _q_startAsyncWrite())
#endif
//line 90
#if defined(Q_OS_WIN32)
: readChunkBuffer(QSERIALPORT_BUFFERSIZE, 0)
#endif
{
writeBufferChunkSize = QSERIALPORT_BUFFERSIZE;
readBufferChunkSize = QSERIALPORT_BUFFERSIZE;
}
//line 1253
qint64 QSerialPort::bytesToWrite() const
{
qint64 pendingBytes = QIODevice::bytesToWrite();
#if defined(Q_OS_WIN32)
pendingBytes += d_func()->writeChunkBuffer.size();
#endif
return pendingBytes;
}
可见 QSerialPort
提供的接口是使用 宏
做了跨平台处理的。
那么 Qt
为我们提供的跨平台接口有那些呢?
Qt的界面,Qt封装的一些库包,数据结构以及算法…
对于 Qt项目
中不提供跨平台的部分,则需要我们自己实现,常用的就是 宏
。
例如换行操作:
#ifdef Q_OS_WIN32
qDebug() << "Windows换行!\r\n";
#else
//假设是Linux
qDebug()<<"unWindows换行!\n ";
#endif
好了下面进入正题,Qt
- Windows
程序及Linux
程序打包发布。
Qt - Windows打包发布
最小依赖库
在 QtCore
中,当我们把构建方式选为Release
,将生成 *.exe
文件
直接打开该文件会提示 缺少xxx.dll
等错误。
我们可在 Qt
的编译器路径下搜索缺失的 dll文件
;
我的路径是 xxx\QT5.9.3\5.9.3\mingw53_32\bin
,找到后将其放到可执行文件· 同一路径
下。
下图是我复制的 dll库
,应该是 最小依赖库
了。
Windeployqt
作为懒鬼,我坚信懒是人类发展的原动力。
于是我发现了一个便捷的工具 Windeployqt
,它将帮助我们将依赖库复制到指定目录中。
例如我这在 D盘
创建了一个 UHelper文件夹
,然后将前面生成的 UHelper.exe
移动进去。
打开Qt for Desktop
;
执行 windeployqt *.exe
。
可以发现,依赖的库都复制进去了
Enigma Virtual Box 打包为可独立运行exe
我们可以将上面的 exe文件
及 dll文件
打包给别人,但是这样一点也不酷。
有没有办法直接将 exe
和 所需的dll库
都打包为一个exe
文件呢?
还真有,Enigma Virtual Box
就是一个不错的选择。
下载地址见:Enigma Virtual Box官网
ps:如果是使用 Windeployqt
添加的库,把所有添加的 dll
及文件夹都拖选添加至 Enigma Virtual Box
即可。
切记:文件夹也要,并且不要试图去改变它。
执行完成后,就生成了一个独立可执行程序。
Inno Setup 封装为安装包
下载地址见:Inno Setup官网
使用流程可参考 2 Inno setup 打包教程
生成安装程序如下:
安装完成后的文件目录如下:
有别于直接移植的是,在控制面板中是可以查找得到该程序的(即修改了注册表)。并且它给我们提供了一个卸载程序。
如何修改版本信息
到此为止我们生成的可执行文件都是没有详细信息的。
修改.pro
最简单的方法莫过于直接在 pro文件
中添加以下代码。
//版本信息
VERSION = xx.xx.xx.xx
//图标
RC_ICONS = xxxx.ico
//公司名称
QMAKE_TARGET_COMPANY = ""
//产品名称
QMAKE_TARGET_PRODUCT = ""
//文件说明
QMAKE_TARGET_DESCRIPTION = ""
//版权信息
QMAKE_TARGET_COPYRIGHT = ""
//中文(简体)
RC_LANG = 0x0004
rc资源文件
由于 rc文件
是 Windows
平台相关的东西,Qt助手
中对于 rc文件
几乎没有任何介绍 5。
使用可查看本文参考 - 传送门 。
Qt - Linux打包发布
将项目拷贝到 Ubuntu18.04
;
Qt环境
与 Windows
下的相同,均为 Qt5.9.3
;
移过去后,UI
显示有点问题,于是修改了一下 UI
;
然后用 Release
编译,即生成可执行文件 UHelper
。
由于 Ubuntu
自带了Qt库
6,我们可以直接运行:
./UHelper
程序运行效果:
若非 Ubuntu
系统则需要拷贝so库
。
拷贝依赖库
可以使用 ldd命令
查看其依赖库及路径:
ldd UHelper
//or
ldd ./UHelper
一个个复制很麻烦,为此可以借助 shell脚本
完成 so库
的复制:
#!/bin/sh
# ldd $exe (所以这里写你的可执行文件名)
exe="UHelper"
# copy 目录
des="/home/hsy/SW/Qt5.9.3/Project/UHelper_test"
# awk 匹配第三个参数“/”,排除掉没有路径的
deplist=$(ldd $exe | awk '{if (match($3,"/")){printf("%s\n"),$3}}')
# 将so库拷贝至des目录
# -L:--dereference 始终遵循源中的符号链接
# -n: --no-clobber 不要覆盖已存在的文件
cp -L -n $deplist $des
执行:
chmod 777 pack.sh
./pack.sh
复制完以后的结果如下图所示:
再编写一个可执行文件;
UHelper.sh
#!/bin/sh
appname=`basename $0 | sed s,\.sh$,,`
dirname=`dirname $0`
tmp="${dirname#?}"
if [ "${dirname%$tmp}" != "/" ]; then
dirname=$PWD/$dirname
fi
LD_LIBRARY_PATH=$dirname
export LD_LIBRARY_PATH
$dirname/$appname "$@"
注意:这里的脚本名必须和可执行文件名一致。
通过运行此脚本而不是可执行文件,可以确保动态链接程序将找到Qt库 7。
linuxdelpoyqt
linuxdeployqt
可以理解为 Windeployqt
的 Linux
版本,让你的打包如丝般顺滑。
同时,linuxdelpoyqt
是一个开源项目,下载地址见 Github-linuxdelpoyqt
下载完成后我们给它重命名为 delpoyqt
。
执行一下:
但是,我们在其他路径下调用则显得很不方便。
为此可将其移动到 /usr/local/bin
,这样在任何地方都可以使用 deployqt
。
sudo mv ./deployqt /usr/local/bin
验证:
打包:
AppImage
的文档提到,其理念是:应用程序应建立在最旧的系统上,以使它们可以在较新的系统上运行 8。
至于原因,其解释为:这样就可以排除某些 基础库
,而这些 基础库
可以在所有主要的 桌面Linux发行版
中找到,从而减少了 One app = one file
的开销 8。
显然 Linuxdeployqt
的作者是非常认同这种做法的。
probonopd :我认为应用程序开发人员只是为最新和最大的发行版进行开发而“懒惰”,并告诉用户“仅升级您的OS即可使用此应用程序” 9。
目前所支持的最新Ubuntu LTS
版本为16.04
。
安装Ubuntu16.04
镜像,记得选 arm版
并安装 Qt
、Linuxdeployqt
…
重复之前的步骤,再重新执行:
sudo deployqt Uhelper -appimage
这里提示图标的问题,可以暂时忽略。
如何设置图标,如何让软件开机自启,如何打包为 deb文件
,可参考 在Linux下使用linuxdeployqt发布Qt程序 10。