私はCMakeとNinjaを使ってC ++で書かれたテスト実行可能ファイルを構築しています。 GCC 4.8を使用しています。 Ubuntu 14を使用しています。
CMakeを実行してninjaビルドスクリプトを設定し、ninjaを実行してビルドします。 CMakeスクリプトで、ターゲット依存libcrypto.so
関係として別のopensslファイルを指定します。*.so
実行可能ファイルを実行すると、次のエラーが発生します。
共有ライブラリの読み込みエラー:libcrypto.so.1.0.0:共有オブジェクトファイルを開くことができません。そのファイルまたはディレクトリはありません。
私のlibcrypto.so
ファイルはテスト実行可能ファイルの横にあります。
-rw-r--r-- 1 robert domain users 1796847 Apr 20 15:43 libboost_wave.so
-rw-r--r-- 1 robert domain users 410916 Apr 20 15:43 libboost_wserialization.so
-rw-r--r-- 1 robert domain users 2251519 Apr 21 11:28 libcrypto.so
-rw-r--r-- 1 robert domain users 701627 Apr 20 15:43 libEGL.so
-rw-r--r-- 1 robert domain users 4255871 Apr 20 15:43 libGLES_CM.so
-rw-r--r-- 1 robert domain users 7550551 Apr 20 15:43 libGLESv2.so
-rw-r--r-- 1 robert domain users 949113 Apr 17 14:34 libsqlite.so
-rw-r--r-- 1 robert domain users 496298 Apr 21 11:28 libssl.so
-rwxr-xr-x 1 robert domain users 3099250 Apr 21 11:30 Test_UI_String*
(私が実行している実行可能ファイルはですTest_UI_String
。)
CMakeは実行可能ファイルの横に共有ライブラリを出力するように設定されています。なぜなら、Windows(私にとって開発に最も慣れている)のような他のプラットフォームでは、DLLファイルを見つけてロードするためにEXEの横にある必要があるからです。
1.0.0
なぜライブラリファイルの最後に追加されるのか混乱しています。依存関係をリンクしたときにlibcrypto.so
上記のディレクトリにある名前と同じ名前があるため、最後にバージョン番号なしでそれを見つける必要があります。
ここでの動作をよりよく理解したいのですが、主な質問は基本的に期待どおりに動作させる方法(実行ファイルと同じディレクトリにあるライブラリの依存関係を見つける)です。
答え1
リンカは、実行可能ファイル(または他の共有ライブラリ)を構築するときに名前の-l
プレフィックスとサフィックスとしてlib
使用するように要求されたライブラリを検索します。.so
たとえば、要求-lcrypto
するとlibcrypto.so
。
ライブラリが見つかると、リンカはそのライブラリからsonameというメタデータフラグメントを読み取ります。その後、sonameはビルド中の実行可能ファイルにログインし、実行時に同じライブラリを再検索するために使用される名前です。もちろん、sonameはリンク時に実際に見つけたライブラリの名前と異なる場合があります。
この機能のユースケースは、システムに互換性のない複数のライブラリバージョンを同時にインストールする機能です。一般的に使用される方法は次のとおりです。
まず、この規則がなければ何が起こるかを説明します。
開発ヘッダー(.h
ファイル)は特定のバージョンのライブラリに関連付けられ、ファイル.so
にはそのバージョンも含まれます。
/usr/include/mylibrary.h
/usr/lib/libmylibrary.so
アプリケーションはmyapp
このバージョンのライブラリに対してコンパイルされ、実行時/usr/lib/libmylibrary.so
にロードされます。
後でライブラリが新しいバージョンにアップグレードされました。.h
ファイルが.so
新しいバージョンに置き換えられます。残念ながら、新しいバージョンには互換性のないABIがあります。
これでmyapp
、実行時に競合が発生したか、未定義の動作が表示されます。なぜなら、あるABIを使用してあるバージョンに対してコンパイルしたのですが、実行時に別のバージョンをロードするためです。
どうしたの?そしてソネームルール:
ライブラリは次のようにインストールされます。
/usr/include/mylibrary.h
/usr/lib/libmylibrary.so -> libmylibrary.so.1
/usr/lib/libmylibrary.so.1
そして/usr/lib/libmylibrary.so.1
そこにsonameを挿入しましたlibmylibrary.so.1
。
myapp
ビルド時に検索するか/usr/lib/libmylibrary.so
、リンカはシンボリックリンクをたどって実際にロードします/usr/lib/libmylibrary.so.1
。また、実際にsonameがlibmylibrary.so.1
記録されますmyapp
。実行時にシンボリックリンクを迂回して直接myapp
ロードされます。/usr/lib/libmylibrary.so.1
その後、ライブラリは互換性のないABIを含む新しいバージョンにアップグレードされました。.h
ファイルが.so
新しいバージョンに置き換えられます。libmylibrary.so.2
新しいファイルが表示されます。以前のバージョンのコンテンツはlibmylibrary.so.1
変更されません。
/usr/include/mylibrary.h
/usr/lib/libmylibrary.so -> libmylibrary.so.2
/usr/lib/libmylibrary.so.1
/usr/lib/libmylibrary.so.2
これで実行されると、myapp
読み込まれ続け、libmylibrary.so.1
期待どおりに実行されます。ただし、他の新しいアプリケーションがインストールされている場合、またはmyapp
アプリケーション自体が再コンパイルされると、シンボリックリンクに従い、新しいバージョンが使用されます。
現在見ている問題は、アプリケーションをリンクしたときにリンカーがsonameを含むライブラリを見つけたことですlibcrypto.so.1.0.0
。
コピーはlibcrypto.so
soname ifを使用して作成されましたかlibcrypto.so.1.0.0
?
もう1つの可能性(ここで最も可能性が高い)は、libcrypto.so
コピーにsonameがありませんが、リンカーが実際に見つけて使用することです。システム(OpenSSL で) libcrypto.so
、名前が由来したところです。