linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)

 目录

一. 大致如下常见问题:

(1)找不到程序所依赖的Qt库 version `Qt_5' not found (required by

(2)Could not Load the Qt platform plugin "xcb" in "" even though it was found

(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentation fault,或者Illegal instruction (core dumped) 非法指令

(4)ldd 应用程序或者库,查看运行所依赖的库时,直接报段错误

二. 问题逐个分析,得出解决方法:

(1)找不到程序所依赖的Qt库 version `Qt_5' not found (required by

解决方案有如下几种

(2)Could not Load the Qt platform plugin "xcb" in "" even though it was found

 (3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentation fault,或者Illegal instruction (core dumped) 非法指令

 (4)这个问题,在上面已经解决了

最后:

用网上的命令打包QT程序运行时常遇到程序无法运行的提示:

一. 大致如下常见问题:

(1)找不到程序所依赖的Qt库 version `Qt_5' not found (required by

/usr/lib/x86_64-linux-gnu/libQt5Gui.so.5: version `Qt_5' not found (required by ./运行程序名)

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第1张图片

(2)Could not Load the Qt platform plugin "xcb" in "" even though it was found

qt.qpa.plugin: Could not Load the Qt platform plugin "xcb" in "" even though it was found.

This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第2张图片

在命令下执行:export QT_DEBUG_PLUGINS=1 ,让程序输出更多信息,再次运行linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第3张图片

 提示platforms文件下的libqxcb.so库缺少依赖库libQt5XcbQpa.so.5

(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentation fault,或者Illegal instruction (core dumped) 非法指令

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第4张图片

(4)ldd 应用程序或者库,查看运行所依赖的库时,直接报段错误

二. 问题逐个分析,得出解决方法:

(1)找不到程序所依赖的Qt库 version `Qt_5' not found (required by

        /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5: version `Qt_5' not found (required by ./运行程序名)

这个是找不到程序依赖库了,在没有安装Qt的裸机下,如果程序没有指定依赖库路径的话,默认是去 /etc/ld.so.conf 文件中指定的搜索路径寻找

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第5张图片

如果在有开发环境的机子上运行上的话,无论你把程序拿到哪个地方,都能运行,因为运行时会去Qt库里面找,如下所示

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第6张图片

 去新机子上运行,是没有Qt库的,所以需要打包指定程序运行时库依赖的位置

问题分析完了,解决方案也就出来了

解决方案有如下几种

        1.在程序编译时,先在.pro文件下指定程序运行时的库依赖路径(推荐)

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第7张图片

        2.在/etc/ld.so.conf 文件添加程序依赖路径,如下所示,不要将第一个默认的删掉或者改了,否者系统将出大问题,基本什么东西都运行不了(不推荐)

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第8张图片

 3.指定临时运行路径,只在当前窗口下有用,这个也是网上常用的方法,然后在运行程序

export LD_LIBRARY_PATH='你的库路径':$LD_LIBRARY_PATH

我比较喜欢用第一种方法,简单明了

(2)Could not Load the Qt platform plugin "xcb" in "" even though it was found

        执行:export QT_DEBUG_PLUGINS=1 , 在运行,提示找不到platforms文件下的libqxcb.so库缺少依赖库libQt5XcbQpa.so.5,如果没有这个库就链接下

        如果我们已经有这个库了,但还是提示的话,说明能找的地方都找了(指定的库位置,/etc/ld.so.conf 文件中指定的位置,临时指定的库位置等等),还是找不到。这个时候就得看一下platforms文件下的libqxcb.so库所运行时所依赖的Qt库路径在哪里

readelf -d 库名称

readelf -d 库名/程序名  可以查看默认依赖/运行库路径:Runpath

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第9张图片

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第10张图片

         可以看到,libqxcb.so库的运行依赖路径是在库所在目录的上级的上级的lib目录下目录:Library runpath: [$ORIGIN/../../lib]

         在Qt中,因为这个库libqxcb.so是Qt自带的,已经开发好的,指定的库依赖位置就是[$ORIGIN/../../lib],所以我们也能看到,在QT下安装目录下,Qt库目录lib目录就是在库libqxcb.so的上级目录的上级目录的位置

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第11张图片

         所以只要把QT库放在libqxcb.so库所在目录的上级的上级的lib目录下就可以了,也就是platforms文件夹的上一级目录的lib目录下。打包的一般目录结构都是bin目录相同目录下放lib库目录,bin目录下放程序文件,这也是很多软件发布时的标准配置。

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第12张图片

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第13张图片

 这样子就没问题啦 linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第14张图片

 (3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentation fault,或者Illegal instruction (core dumped) 非法指令

        如我将ubantu16.04下Qt打包的程序,在裸机的ubantu16.04或者18.04下运行没有,没有问题,但放到ubantu22.04下,直接报Illegal instruction (core dumped) 非法指令,

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第15张图片

或者其他linux系统下,如deepin(深度系统)下,提示段错误

这个错误我搞了半天,ldd程序,程序所有的依赖库都有,为啥还报错呢,搞不懂

想去lib目录下看下库信息,输入ls -l,结果直接报错,很多常用的linux命令在这里都报这个错linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第16张图片

         思考原因,对比了一下其他能正常运行的程序,发现lib目录下很多其他的库文件,我把那些多余的文件都删除了,结果可以输linux命令了,而且程序也能运行了,然后我在我的尝试下,发现就是这些文件搞的鬼,libbc.so.6和libpthread.so.0

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第17张图片

 然后就去查了这些库是干嘛的,一查,所有迷雾都揭开了,如下

libc.so.6是glibc的软链接

        #glibc是GNU发布的libc库,即c运行库。glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现。由于 glibc 囊括了几乎所有的 UNIX 通行的标准,可以想见其内容包罗万象。而就像其他的 UNIX 系统一样,其内含的档案群分散于系统的树状目录结构中,像一个支架一般撑起整个操作系统。在 GNU/Linux 系统中,其C函式库发展史点出了GNU/Linux 演进的几个重要里程碑,用 glibc 作为系统的C函式库,是GNU/Linux演进的一个重要里程碑。--百度百科

所以这个软链接很重要!!

        不同的linux系统下,这个libc.so.6库是不一样的,相同的系统下,也可能因为系统的升级,libc.so.6库也就行了的升级,如ubantu16.04和ubantu 22.04的libc.so.6库是不一样的。

        这也就解释了为什么在从ubantu16.04打包过来的库,在ubantu 22.04或者其他linux系统下,在这个库目录执行linux的常用命令,直接报这个Illegal instruction (core dumped) 非法指令的信息,因为本就不是这个系统的。无法识别!

        libc 和 libpthread是linux非常重要的基础库。所以在所在目录下执行命令,最先寻找的就是当前目录下的库和文件。本系统的直接跳过了,不报错误才怪!

所以把他们删掉就可以了

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第18张图片

 (4)这个问题,在上面已经解决了

        既然会出现上面这些问题,那不能避免吗,毕竟我们打包的程序,不可能只在相同版本的系统上运行,可能会拿到低或者高版本的系统,甚至其他linux系统下运行,大概率会踩雷

        要解决这个问题,就要知道出现问题的根源所在,根源就是,库的问题。库从哪里来呢?都是网上执行这个命令后打包拷过去的。所以我们先理解这个打包命令的含义:

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第19张图片

第四行那个,拷贝的命令

ldd $exe | awk '{if (match($3,"/")){ printf("%s "),$3 } }' 

        这个命令:ldd $exe 就是获取程序所依赖的库,然后通过管道|输入给awk命令处理,获取字符串中匹配有/的字符串,然后通过空格隔开,获取第三列,也就是程序所依赖库的路径

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第20张图片

         然后将所有的库全部拷贝过去,其实很多库都不需要用到,有的/lib/...开头的路径的库是不需要的,这个是linux系统自带的,全部拷过去,会拷个雷库(如libc.so.6)过去,需要拷贝的只有Qt目录下的库文件而已,所以        要对这个拷贝命令就行优化

        所依赖的QT库有一个共同点,都有Qt这两个子眼,所以在那个基础上在过滤一下就行啦

#赋值路径,准备拷贝
copyPathList=$(ldd $exe | awk  -F " " \
'
{
    if ($3 ~ "/Qt")
    { 
		 printf("%s\n"),$3
    }
}
')

最后:

写这篇博客,花了很多时间,都花这个份上了,我就把所有的打包的原创脚本代码都写出来了,想要的自己拿吧,脚本式打包,链接啥的,都给弄好了,贴心,注释都写好了,不会改的,在评论区留言吧,或者评论区交流下。对你有用的点个赞在走吧

linux下的Qt打包常见原因分析和雷区,获取一键式打包脚本(能避免各种问题)_第21张图片

一键打包代码,拿走

#!/bin/sh
exe="RFIDReaderTest" #要打包的程序名 *
#获取当前路径
currentPath=$(cd `dirname $0`; pwd)

#打包的Qt库位置 *
packDes="$currentPath/../lib" 
#程序依赖库所在位置,用于打包依赖库需要的Qt库,没有留空即可,即myLibPath=""  *
myLibPath="$currentPath/myLib"
#删除原有文件夹,新建新文件夹,存储Qt库
rm -r $packDes
mkdir $packDes

#----------获取程序所依赖的‘Qt库’路径--------------
echo "------------正在获取程序所依赖的‘Qt库’--------------"
#输出程序所依赖的Qt库
ldd $exe | awk  -F " " \
'
{
    if ($3 ~ "/Qt")
    { 
		 printf("%s\n"),$3
    }
}
'
#赋值路径,准备拷贝
copyPathList=$(ldd $exe | awk  -F " " \
'
{
    if ($3 ~ "/Qt")
    { 
		 printf("%s\n"),$3
    }
}
')

#拷贝‘Qt库’文件到打包文件夹路径中
cp $copyPathList $packDes

echo "---正在打包libQt5XcbQpa.so.*.0和libQt5DBus.so.*.0库......"

#获取依赖库中第一个库完整的路径
libPath=$(echo $copyPathList | awk -F " " '{printf("%s\n"),$1}')
#获取Qt版本号
sonPath1=$(echo $libPath | awk -F "/lib" '{printf("%s\n"),$1}')
sonPath2=$(echo $sonPath1 | awk -F "/" '{printf("%s\n"),$NF}')
sonPath3=$(echo $sonPath1 | awk -F "/$sonPath2" '{printf("%s\n"),$1}')
QtVersion=$(echo $sonPath3 | awk -F "/" '{printf("%s\n"),$NF}')
echo "当前Qt版本号为:"$QtVersion


cd $currentPath

#打包Qt插件platforms文件夹
echo "---打包Qt插件platforms文件夹......"
#分解拼接插件platforms路径
platformsPath=$(echo $libPath | awk -F "/lib/" '{printf("%s\n"),$1}')"/plugins/platforms"
echo "---platformsPath路径:"$platformsPath
#将platforms文件拷贝到程序所在路径
cp -r $platformsPath $currentPath

#分解拼接指定库路径
Qt5XcbCopyPath=$(echo $libPath | awk -F "/lib/" '{printf("%s\n"),$1}')"/lib/libQt5XcbQpa.so.$QtVersion"
Qt5DBusCopyPath=$(echo $libPath | awk -F "/lib/" '{printf("%s\n"),$1}')"/lib/libQt5DBus.so.$QtVersion"

echo "Qt5XcbCopyPath:"$Qt5XcbCopyPath
echo "Qt5DBusCopyPath:"$Qt5DBusCopyPath

#拷贝libQt5XcbQpa.so.$QtVersion和libQt5DBus.so.$QtVersion库
cp $Qt5XcbCopyPath $packDes
cp $Qt5DBusCopyPath $packDes

#软链接
echo "------- 软链接正在打包libQt5XcbQpa.so.*和libQt5DBus.so.*  --------"
cd $packDes

Qt5XcblnPath=$(echo libQt5XcbQpa.so.*.0)
Qt5DBuslnPath=$(echo libQt5DBus.so.*.0)

libName1=$(echo $QtVersion | awk -F "." '{printf("%s\n"),$1}')
libName2=$(echo $QtVersion | awk -F "." '{printf("%s\n"),$2}')

ln -s $Qt5XcblnPath  $packDes/libQt5XcbQpa.so
ln -s $Qt5XcblnPath  $packDes/libQt5XcbQpa.so.$libName1
ln -s $Qt5XcblnPath  $packDes/libQt5XcbQpa.so.$libName1.$libName2

ln -s $Qt5DBuslnPath $packDes/libQt5DBus.so
ln -s $Qt5DBuslnPath $packDes/libQt5DBus.so.$libName1
ln -s $Qt5DBuslnPath $packDes/libQt5DBus.so.$libName1.$libName2

#打包自己的库所依赖的QT库
if [ ! -d "$myLibPath" ]; then
    echo "$myLibPath no exist"
    echo "-----------'$exe'所依赖的Qt库打包完成!-----------"
    exit 1 #没有依赖自己写的库,直接结束
fi


echo "------------正在获取自己写的库所依赖的QT库--------------"
for filePath in $myLibPath/*.so
do

	echo "myLib:"$filePath
	#赋值路径,准备拷贝	
	copyPathList=$(ldd $filePath | awk -F " " \
	'
	{
	    if ($3 ~ "/Qt")
	    { 
		printf("%s\n"),$3
	    }
	}
	')
	for file in $copyPathList
	do
	    name=$(echo $file | awk -F "/lib/" '{ print $2}')
	    if [ ! -f "$packDes/$name" ];then
		echo "copy file:"$file
		#拷贝‘Qt库’文件到打包文件夹路径中
		cp $file $packDes
	    fi		    	    
	done
done 

echo "-----------所依赖的Qt库全部打包完成!-----------"

你可能感兴趣的:(qt,linux,开发语言)