Qt プログラムのパッケージ化後のランタイム ライブラリの依存関係に関する一般的な問題の分析と解決策

目次

1. 一般的に、よくある質問は次のとおりです。

(1) Qt ライブラリのバージョン `Qt_5' が見つかりません (

(2)「」内のQtプラットフォームプラグイン「xcb」が見つかってもロードできませんでした

(3) 別の Linux システムでパッケージ化されているか、より高いバージョンの同じシステムでパッケージ化されている場合、プログラムを実行すると、セグメンテーション違反、または不正な命令 (コア ダンプ) が直接発生します。

(4) ldd アプリケーション プログラムまたはライブラリ、操作が依存するライブラリを表示すると、セグメント エラーが直接報告されます。

2. 問題を 1 つずつ分析し、解決策を考え出します。

(1) Qt ライブラリのバージョン `Qt_5' が見つかりません (

解決策は次のとおりです

(2)「」内のQtプラットフォームプラグイン「xcb」が見つかってもロードできませんでした

 (3) 別の Linux システムでパッケージ化されているか、より高いバージョンの同じシステムでパッケージ化されている場合、プログラムを実行すると、セグメンテーション違反、または不正な命令 (コア ダンプ) が直接発生します。

 (4) この問題は上記で解決されています

やっと:

オンライン コマンドを使用して QT プログラムをパッケージ化して実行すると、プログラムが実行できないことを示すプロンプトが表示されることがよくあります。

1. 一般的に、よくある質問は次のとおりです。

(1) Qt ライブラリのバージョン `Qt_5' が見つかりません (

/usr/lib/x86_64-linux-gnu/libQt5Gui.so.5: バージョン `Qt_5' が見つかりません (./実行中のプログラム名が必要です)

(2)「」内のQtプラットフォームプラグイン「xcb」が見つかってもロードできませんでした

qt.qpa.plugin: Qt プラットフォーム プラグイン「xcb」が「」に見つかりましたが、ロードできませんでした。

Qt プラットフォーム プラグインを初期化できなかったため、このアプリケーションは起動できませんでした。アプリケーションを再インストールすると、この問題が解決される可能性があります。

次のコマンドで実行します:export QT_DEBUG_PLUGINS=1。プログラムに詳細情報を出力させ、再度実行します。

 プラットフォーム ファイルの下の libqxcb.so ライブラリに依存ライブラリ libQt5XcbQpa.so.5 がないことを示すプロンプトが表示されます。

(3) 別の Linux システムでパッケージ化されているか、同じシステムでより高いバージョンでパッケージ化されている場合、プログラムを実行すると、セグメンテーション違反または不正な命令 (コア ダンプ) が直接発生ます

(4) ldd アプリケーション プログラムまたはライブラリ、操作が依存するライブラリを表示すると、セグメント エラーが直接報告されます。

2. 問題を 1 つずつ分析し、解決策を考え出します。

(1) Qt ライブラリのバージョン `Qt_5' が見つかりません (

        /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5: バージョン `Qt_5' が見つかりません (./実行中のプログラム名が必要です)

これは、プログラムの依存関係ライブラリが見つからないためです。Qt がインストールされていないベア メタル マシンでは、プログラムが依存関係ライブラリのパスを指定しない場合、デフォルトでは、/etc/ ファイルに指定された検索パスでライブラリが検索されます。 ld.so.conf ファイル。

開発環境のあるマシンで実行する場合は、以下に示すように、実行時に Qt ライブラリに移動してプログラムを検索するため、プログラムをどこから取得しても実行できます。

 新しいマシンで実行するには、Qt ライブラリがないため、プログラムの実行時にライブラリが依存する場所をパッケージ化して指定する必要があります。

問題を分析したら解決策が見えてくる

解決策は次のとおりです

        1. プログラムをコンパイルするとき、プログラムが .pro ファイルで実行されている場合は、最初にライブラリの依存関係パスを指定します (推奨)。

        2. 以下に示すように、/etc/ld.so.conf ファイルにプログラムの依存関係パスを追加します。最初のデフォルトのパスは削除または変更しないでください。そうしないと、システムに大きな問題が発生し、基本的に何も実行できなくなります (推奨されません)

 3. 現在のウィンドウでのみ有効な一時的な実行パスを指定します。これはインターネット上で一般的に使用される方法でもあり、プログラムを実行します。

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

私はシンプルで明確な最初の方法を使用することを好みます

(2)「」内のQtプラットフォームプラグイン「xcb」が見つかってもロードできませんでした

        実行:export QT_DEBUG_PLUGINS=1、実行すると、プラットフォーム ファイルの下の libqxcb.so ライブラリが見つからず、依存ライブラリ libQt5XcbQpa.so.5 が見つからないことを示すメッセージが表示されます。そのようなライブラリがない場合は、リンクしてください

        このライブラリがすでに存在しているにもかかわらずプロンプトが表示される場合は、見つけられるすべての場所 (指定されたライブラリの場所、/etc/ld.so.conf ファイルで指定された場所、一時的に指定されたライブラリの場所、など)、まだ見つかりません。現時点では、プラットフォーム ファイル内の libqxcb.so ライブラリが実行時に依存する Qt ライブラリ パスを確認する必要があります。

readelf -d 库名称

readelf -d ライブラリ名/プログラム名は、デフォルトの依存関係/実行ライブラリのパスを表示できます: Runpath

         libqxcb.so ライブラリの実行依存関係パスは、ライブラリが配置されているディレクトリの上位レベルの lib ディレクトリの下のディレクトリであることがわかります。 Library runpath: [ $ORIGIN/../../lib]

         Qt では、このライブラリ libqxcb.so は Qt に付属し、開発されているため、指定されたライブラリの依存関係の場所は[$ORIGIN/../../lib]であるため、QT のインストール ディレクトリの下にあることもわかります。 Qtライブラリディレクトリのlibディレクトリは、ライブラリlibqxcb.soの上位ディレクトリの場所です。

         したがって、QT ライブラリを libqxcb.so ライブラリがあるディレクトリの上位 lib ディレクトリ、つまり platforms フォルダの上位ディレクトリの lib ディレクトリに置くだけです。パッケージの一般的なディレクトリ構造は、lib ライブラリ ディレクトリが bin ディレクトリと同じディレクトリに配置され、プログラム ファイルが bin ディレクトリの下に配置されるというもので、これは多くのソフトウェア リリースの標準構成でもあります。

 このままでいいよ 

 (3) 別の Linux システムでパッケージ化されているか、同じシステムでより高いバージョンでパッケージ化されている場合、プログラムを実行すると、セグメンテーション違反または不正な命令 (コア ダンプ) が直接発生ます

        例えば、Qt でパッケージ化したプログラムを ubantu16.04 配下に置くと、ベアメタル上の ubantu16.04 や 18.04 では問題なく動作しますが、ubantu22.04 配下に置くと不正な命令(コア)が発生します。ダンプされます)は直接報告されます。

または、deepin (ディープ システム) などの他の Linux システムでは、セグメント エラーが表示されます。

私は長い間このエラーに取り組んできました。ldd プログラムには、プログラムのすべての依存ライブラリがあります。なぜまだエラーが報告されるのですか?理解できません。

lib ディレクトリに移動してライブラリ情報を確認したいのですが、ls -l と入力すると、結果はエラーになります。一般的に使用される Linux コマンドの多くは、このエラーをここで報告します。

         原因を考えて、他の正常に動作するプログラムを比較したところ、libディレクトリに他にもライブラリファイルが多数存在していたので、冗長なファイルを削除したところ、Linuxコマンドも入力できるようになり、プログラムも動作するようになりました。試してみたところ、これらのファイルはゴーストである libbc.so.6 と libpthread.so.0 であることがわかりました。

 次に、これらのライブラリが何のためにあるのかを確認したところ、次のようにすべての霧が晴れました。

libc.so.6 は glibc へのソフトリンクです

        #glibc は GNU が公開した libc ライブラリ、つまり C ランタイム ライブラリです。glibc は Linux システムの最下位 API であり、他のほとんどすべてのランタイム ライブラリは glibc に依存します。Linux オペレーティング システムによって提供されるシステム サービスをカプセル化することに加えて、glibc 自体も他の多くの必要な機能サービスの実現を提供します。glibc には一般的な UNIX 標準がほぼすべて含まれているため、その内容はすべてを網羅していると想像できます。また、他の UNIX システムと同様に、含まれるファイル グループはシステムのツリー状のディレクトリ構造に分散され、ブラケットのようにオペレーティング システム全体をサポートします。GNU/Linux システムでは、その C 関数ライブラリの開発履歴は、GNU/Linux の進化におけるいくつかの重要なマイルストーンを示しています。システムの C 関数ライブラリとして glibc を使用することは、GNU/Linux の進化における重要なマイルストーンです。--百度百科事典

したがって、このソフトリンクは非常に重要です。

        Linux システムが異なると、libc.so.6 ライブラリは異なります。同じシステムでも、ubantu16.04 や ubantu 22.04 などのシステム アップグレードにより、libc.so.6 ライブラリもアップグレードされる可能性があります。図書館は違います。

これは、ubantu 22.04 またはその他の Linux システムで ubantu16.04 からパッケージ化されたライブラリが、このライブラリ ディレクトリで Linux の一般的なコマンドを実行し、この不正な命令 (コア ダンプされた)不正な命令        の情報を直接報告する理由も説明します。システム。認識できない!

        libc と libpthread は Linux の非常に重要な基本ライブラリです。したがって、コマンドが配置されているディレクトリでコマンドを実行する場合、最初に探すのは現在のディレクトリ内のライブラリとファイルです。このシステムは直接スキップしました。エラーを報告しないのは奇妙です!

だからそれらを削除してください

 (4) この問題は上記で解決されています

        上記の問題が発生するため、回避することはできますか? 結局のところ、パッケージ化したプログラムは、同じバージョンのシステム上でのみ実行できるわけではなく、システムの下位または上位のバージョンを取得したり、他の Linux システム上で実行したりすることもあります。私のものを踏んでください

        この問題を解決するには、問題の根本原因、つまりライブラリの問題を知る必要があります。図書館はどこから来たのですか? このコマンドをオンラインで実行すると、これらはすべてパッケージ化され、コピーされます。そこで、まずこのパッケージ化コマンドの意味を理解しましょう。

4行目のコピーコマンドです。

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

        このコマンド: ldd $exeは、プログラムが依存するライブラリを取得し、それをパイプライン経由で awk コマンドに入力します|文字列内の / に一致する文字列を取得し、それらをスペースで区切って 3 番目の文字列を取得します。列 (プログラム) 依存ライブラリへのパス

         次に、過去のすべてのライブラリをコピーします。実際、多くのライブラリは使用する必要がありません。/lib/... で始まるパスを持つ一部のライブラリは必要ありません。これは Linux システムに付属しているものです。以前は、ライブラリ(libc.so.6 など)は Qt ディレクトリ内のライブラリ ファイルのみをコピーする必要があったため、コピー コマンドを最適化する必要があります

        彼らが依存する QT ライブラリには 1 つの共通点があります。それらはすべて Qt の 2 つのサブアイを持っているため、それに基づいてフィルタリングしても大丈夫です。

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

やっと:

このブログを書くのにとても時間がかかりましたが、これがすべてです。パッケージ化されたオリジナルのスクリプト コードはすべて私が書きました。スクリプト スタイルのパッケージ化、リンクなど、必要なものを選択してください。まあ、気をつけて、メモはすべてですコメント欄にメッセージを残すか、コメント欄でご連絡ください。役に立ったら高評価してください、行きましょう

.pro ファイルは、プログラムの実行時に検索されるライブラリ パスを最初に指定します。

 ワンクリック プログラムに必要な QT ライブラリ パッケージ化シェル スクリプト:

#!/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库全部打包完成!-----------"

おすすめ

転載: blog.csdn.net/qq_44667165/article/details/129145426