プログラムをコンパイルしprog
、ソースからビルドされて にインストールされている OpenSSL の 1.0.2 ベータ版にリンクしようとしています/usr/local/ssl-1.0.2
。0.9.8 を使用している古いシステムでは、これはそれほど問題なく動作します。1.0.1 がインストールされている最近のシステムでは、これにはもう少し作業が必要です。なぜなのか疑問に思います。
1) Ubuntu 10.04、OpenSSL 0.9.8 の場合:
1.0.2 に対してコンパイルおよびリンクするために私が実行する手順は次のとおりです。
$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto
=> 0.9.8 ファイルのみが表示されるので、1.0.2 ファイルへのパスを追加します...
$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto
=>
libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
libcrypto.so.0.9.8 (libc6, hwcap: 0x0008000000008000) => /lib/i686/cmov/libcrypto.so.0.9.8
libcrypto.so.0.9.8 (libc6, hwcap: 0x0004000000000000) => /lib/i586/libcrypto.so.0.9.8
libcrypto.so.0.9.8 (libc6, hwcap: 0x0002000000000000) => /lib/i486/libcrypto.so.0.9.8
libcrypto.so.0.9.8 (libc6) => /lib/libcrypto.so.0.9.8
libcrypto.so.0.9.8 (libc6) => /usr/lib/libcrypto.so.0.9.8
libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so
そしてコンパイルできるようになりますprog
...
$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog
=>
libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0x0083b000)
...そして、1.0.2 に対して正しくリンクされています。
2) Debian Wheezy、OpenSSL 1.0.1 の場合:
同じ手順で、異なる結果が得られます。
$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto
=>
libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0
同様に、1.0.2 へのパスを追加します...
$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto
=>
libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0
libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so
次にコンパイルしてみます...
$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog
=>
libcrypto.so.1.0.0 => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 (0xb7591000)
しかし、ここでは 1.0.2 に対してリンクされていません。コンパイル時のライブラリ パスは正しいですが ( で指定されていますが-L
、gcc
で使用される一部の関数は 1.0.2 に固有であるため、それ以外の場合は失敗しますprog
)、実行時のライブラリ パスは正しくありません。
3) Wheezyで動作させる方法
ランニングの有無ldconfig /usr/local/ssl-1.0.2/lib
:
$ gcc -o prog ... -Wl,--rpath=/usr/local/ssl-1.0.2/lib -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog
=>
libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0xb7592000)
または、export LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib
を実行する前にを実行しますgcc
。
知りたいこと
mr.spuratic の提案に従ってを使用するとLD_DEBUG=libs ./prog
、 でパスが検索されていることがわかりました/etc/ld.so.cache
。そのファイルを開くと、 .so が検索される順序が の出力に対応していることがわかりましたldconfig -p
。
実際の質問は次のとおりです。
- なぜ 1.0.2 ファイルは 1) では ldconfig のリストの先頭に来るのに、2) では来ないのでしょうか? まったくのランダムでしょうか? 1.0.1 ファイルと 1.0.2 ファイルが同じサフィックス ("1.0.0") を持っているために混乱しているのでしょうか?
あるいは、言い換えれば、
- 3) で追加されたフラグが 1) では必要ないのはなぜですか?
答え1
デフォルト以外のパッケージに対してコンパイル/リンクするときには、次の 3 つの点に注意する必要があります。
- ヘッダー(通常は
CFLAGS
) - コンパイル時のライブラリパス(通常は
LDFLAGS
) - ランタイムライブラリパス(rpath
LDFLAGS
、、LD_RUN_PATH
または経由)LD_LIBRARY_PATH
ld.so.conf
それが何であるかを述べていないprog
ので、その構成がどの程度適切に動作するかはわかりません (または autoconf を使用しているかどうか?)。最初の 2 つの手順のみを確実に実行するものを多数見てきました。
リンク段階ではライブラリ パスの順序が重要になります。GNU ツールチェーン (gcc と binutils) を使用している場合は、次の設定をCFLAGS
前configure
(または直接Makefile
) に設定することで、何が起こっているかを確認できるでしょう。
export CFLAGS="-Wl,-t"
これにより、-t
トレース オプションがリンカーに渡されます。make中に簡潔な "CC" 行と "LD" 行のみが出力される場合は、make コマンドにV=1
または を追加する必要がある可能性があります。VERBOSE=1
実行時に、ld.so
注意深く設定することで何が試みられるかを見ることができますLD_DEBUG
。例えば、
LD_DEBUG=libs ./myprog
(または詳細についてはfiles
または の値を試してください)symbols
ビルド時に 3 つのパラメータすべてを正しく指定するには、次のようにします。
export CFLAGS="-I/usr/local/ssl-1.0.2/include"
export LDFLAGS="-L/usr/local/ssl-1.0.2/lib -R/usr/local/ssl-1.0.2/lib"
その後、再構成/再コンパイルします。
--openssldir
より一般的な方法ではなくを使用しています--prefix
(後者をお勧めします。また、make install_sw
デフォルトのインストールで提供される 1000 個ほどのマニュアル ページとシンボリック リンクが必要ない場合は も使用してください)。これが問題の一部である可能性があります。何らかの理由で、表示されている .so ライブラリにはld.so
バージョン サフィックスがないことがわかっています (例.so.1.0.2
)。適切な " " によって、(メイン の のターゲットを介して)make install
それが設定されているはずです。link-shared
Makefile
この-R
オプションは、特定のOpenSSLライブラリの実行可能出力にRPATHを埋め込むようにリンカーに指示します。これにより、ランタイムリンカー()が通常提供するデフォルトに依存する必要がなくなりますld.so
。既存のバイナリを変更するには、chrpath
その代わり。
これは、ほぼエクスポートと同じですLD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib
。RPATH と関連する RUNPATH の詳細については、次を参照してください。http://blog.tremily.us/posts/rpath/
最後の手段として、OpenSSL を「shared」なしまたは「noshared」でビルドすることもできます。これにより、この問題のない静的ライブラリが提供されます (ただし、ELF .so 内での使用など、PIC/PIE の問題が発生するなど、他の問題が発生する可能性があります)。
更新された詳細に基づくと、問題は 1.0.1 と 1.0.2beta の両方が .so バージョン サフィックス (SONAME) を 1.0.0 に設定していることにあると思います。0.9.8 のみを搭載した最初のシステムでは、これによって問題は発生しません。1.0.1 と 1.0.2 の両方が 1.0.0 としてバージョン設定された 2 番目のシステムでは、順序に基づいて「最初に一致したものが優先されます」ld.so.{conf,d}
。ld
コンパイル時のリンカーは実行時のリンカーとは異なるプログラムでありld.so
、異なる動作をする可能性があります (通常、ご覧のとおり、シンボル エラーまたはそれ以上の結果になります)。
$ cd /usr/local/src/openssl/openssl/1.0.2beta1
$ readelf -a libssl.so | grep SONAME
0x0000000e (SONAME) Library soname: [libssl.so.1.0.0]
$ cat verchk.c
int main(int argc, char *argv[]) {
printf("build: %s\n",OPENSSL_VERSION_TEXT);
printf("run : %s\n",SSLeay_version(SSLEAY_VERSION));
return 0;
}
$ gcc -Wall -I/usr/local/src/openssl/openssl-1.0.2-beta1/include \
-Wl,-rpath /usr/local/src/openssl/openssl-1.0.2-beta1/ \
-o verchk /usr/local/src/openssl/openssl-1.0.2-beta1/libcrypto.so verchk.c
$ ./verchk
build: OpenSSL 1.0.2-beta1 24 Feb 2014
run : OpenSSL 1.0.2-beta1 24 Feb 2014
$ grep SHLIB_M...R= Makefile
SHLIB_MAJOR=1
SHLIB_MINOR=0.0
アップデート
OpenSSL-1.1 では API レベルの変更がいくつか行われたため、上記のコードは v1.1 ヘッダーおよび古いライブラリ () ではコンパイルできませんundefined reference to `OpenSSL_version'
。
SSLeay_version()
は非推奨となり、( に応じてOPENSSL_API_COMPAT
)#define
適切な API 関数 に -dされる可能性がありますOpenSSL_version()
。
答え2
新しいライブラリのパスは、 内のファイルの 1 つにありますか/etc/ld.so.conf.d
? 次に実行します:-
#ldconfig -v
キャッシュを再構築します。素早く実行すれば、出力される長いリストの中に新しいライブラリが表示されるはずです(または、grep
またはにパイプしますless
)。
おそらく、パスは最初のサーバーにはすでに存在していたが、2 番目のサーバーには存在していなかったのでしょうか?