Qt程序自依赖AppImage打包教材1/4(以TheNewPlayerFree为例)
Tofloor
poster avatar
已退deepin
deepin
2020-07-11 16:54
Author
本帖最后由 user0001 于 2020-7-12 06:26 编辑

1/4
https://bbs.deepin.org/post/196995

2/4
https://bbs.deepin.org/post/196996

3/4
https://bbs.deepin.org/post/196998

4/4 (end)
https://bbs.deepin.org/post/196999

自依赖是商业软件打包的常用方式,意思就是把当前的运行环境需要的文件,包括动态库,第三方依赖一起打包进AppImage,这样的AppImage的兼容性最高,不依赖于任何额外的包。下面我们就TheNewPlayerFree为例来讲解如何进行商业级别的软件打包。

1. 安装路径规划
假设thenewplayerfree最终安装到/usr/local/thenewplayerfree下面,我们规划路径如下:
注意,我们的打包方法不会用任何绝对路径,也就是说把thenewplayerfree搬迁到任何地方都是可以正常运行,例如/opt/apps/thenewplayerfree

usr/local/thenewplayerfree   <-- 最终的运行位置(对于AppImage而言这个/是虚拟的,犹如docker里面的根目录)
usr/local/thenewplayerfree/bin <-- 二进制文件和启动脚本
为什么不直接启动应用而要用脚本?https://bbs.deepin.org/user/223313
社区商店打包我的程序的时候犯了一个错误,就是去掉了我的脚本。用脚本的原因是要在真正启动thenewplayerfree之前,将运行的环境虚拟为本安装包自带的动态库和依赖库!这样可以带来更好的兼容性,无论以后这个AppImage安装在何种Linux平台,都不会报依赖问题。
这个技巧在以后打包其它软件的时候一样重要。



usr/local/thenewplayerfree/bin/thenewplayerfree  <-- 二进制文件
usr/local/thenewplayerfree/bin/thenewplayerfree.sh  <-- 启动脚本,用来设置运行的虚拟环境


usr/local/thenewplayerfree/lib/   <--所有的第三方依赖

usr/local/thenewplayerfree/plugins <-- Qt的平台插件

usr/local/thenewplayerfree/share/images <-- 程序图标
usr/local/thenewplayerfree/share/languages <-- 语言
usr/local/thenewplayerfree/etc/qt.conf          <-- Qt程序的环境配置

usr/share/pixmaps/thenewplayerfree.png  <--图标
usr/share/applications/thenewplayerfree.desktop  <--桌面文件

2. 开始制作AppImage

创建打包需要的目录结构,对于AppImage,打包的顶层目录需要以AppDir结尾
mkdir -p thenewplayer.AppDir/usr/local/thenewplayerfree/bin
mkdir -p thenewplayer.AppDir/usr/local/thenewplayerfree/etc

mkdir -p thenewplayer.AppDir/usr/local/thenewplayerfree/share

mkdir -p thenewplayer.AppDir/usr/local/thenewplayerfree/share/images

mkdir -p thenewplayer.AppDir/usr/local/thenewplayerfree/share/languages

mkdir -p thenewplayer.AppDir/usr/share/pixmaps

mkdir -p thenewplayer.AppDir/usr/share/applications


准备文件
cp thenewplayerfree thenewplayer.AppDir/usr/local/thenewplayerfree/bin/
构造启动脚本thenewplayerfree.sh
vim thenewplayer.AppDir/usr/local/thenewplayerfree/bin/thenewplayerfree.sh
内容如下:

#!/bin/sh

realpath="`realpath $0`"  #获取当年启动脚本的真实位置
appname="`basename $realpath | cut -d. -f1`" #获取应用的名字,其实就是得到thenewplayerfree

#获取当年启动脚本的目录所在位置,因为AppImage执行的时候路径是动态的,所以需要知道位置在哪里
dirname="`dirname $realpath`"
cd $dirname
dirname="`pwd`"
cd -

#获取Qt程序的依赖库位置, 注意我们要用绝对路径。
libpath="$dirname/../lib"
cd $libpath
libpath="`pwd`"
cd -

#设置依赖库,当年Qt程序可以通过qt.conf配置,所以可以不用设置lib
#export LD_LIBRARY_PATH=$libpathLD_LIBRARY_PATH

#获取Qt平台插件位置,注意我们要用绝对路径。
pluginpath="$dirname/../plugins"
cd $pluginpath
pluginpath="`pwd`"
cd -

#设置Qt平台插件环境变量
export QT_QPA_PLATFORM_PLUGIN_PATH=$pluginpath:$QT_QPA_PLATFORM_PLUGIN_PATH

#是否开启调试
#export QT_DEBUG_PLUGINS=1

#获取虚拟的根目录位置
rootdir=$dirname/../../../..
cd $rootdir
rootdir="`pwd`"
cd -

#设置Qt的兼容性选项和额外的环境变量,请参考AppImage官网技术手册
export GDK_PIXBUF_MODULEDIR="${rootdir}/usr/lib/gdk-pixbuf-2.0/loaders"
export GDK_PIXBUF_MODULE_FILE="${rootdir}/usr/lib/gdk-pixbuf-2.0/loaders.cache"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATHGDK_PIXBUF_MODULEDIR"
export GTK_PATH="$rootdir/usr/lib/gtk-2.0"
export GTK_IM_MODULE_FILE="$rootdir/usr/lib/gtk-2.0GTK_PATH"
export PANGO_LIBDIR="$rootdir/usr/lib"

#用exec启动一个程序意味着系统自动将当前的脚本终结并转换到执行的 程序
#$@的意思是是来自于脚本的所有命令后参数
exec "$dirname/$appname" "$@"


待续...

Reply Favorite View the author
All Replies
avatar
神末shenmo
deepin
Spark-App
Q&A Team
2020-07-11 17:02
#1
Reply View the author
avatar
jianguo922
deepin
2020-07-11 23:12
#2
感谢分享!
Reply View the author
avatar
忘记、过去
deepin
2020-07-12 02:28
#3

学到了,谢谢大佬指点......

一开始打包的1.6.6-6~1.6.6-9几个版本我都是拆deb包重新打包的,这几个都没有丢掉启动脚本......就是把脚本写死成绝对路径了,不能挪走......
后来1.6.6-10的版本偷了一次懒,直接用了打包好的AppImage,通过a2d工具套娃了一下,生成了简单的deb包就上架了。
我一直以为appimage不需要这些就能直接运行的......这次算是学到了。
Reply View the author