Linuxでのダイナミックライブラリの作成と更新
5977 ワード
Linuxのダイナミックライブラリ(libname.x.y.z)の作成と更新
プライマリ・プログラムとそれに依存する共有ライブラリは、異なる開発者によって開発されているためです.共有ライブラリの開発者は、バグを修正したり、機能を増やしたり、パフォーマンスを向上させたりするために、共有ライブラリのバージョンを更新し続けます.バージョンが多くなると、互換性の問題が発生する可能性があります.Windowsでは「DLL HELL」と呼ばれています.Linuxでも同様の問題が発生します.Linuxはダイナミックライブラリに対して「libname.so.x.y.z」のような命名規則を採用して互換性の問題を解決します.ここでxはプライマリ・バージョン番号、yはセカンダリ・バージョン番号、zはリリース番号を表します.約束によると、プライマリ・バージョン番号xが同じであれば互換性の問題は起こりません.つまりlibname.so.x、LinuxはSO-NAMEと呼ばれます.
プログラムは、依存する共有ライブラリの名前とマスターバージョン番号(すなわちSO-NAME)をdynamicセグメントに記録します.プログラムがロードされると、ダイナミックローダはdynamicセグメントからこれらのSONAMEを探して、適切なバージョンの依存ライブラリをロードし、互換性の問題を解決します.readelf-d programnameまたはldd programnameで表示できます.
1.共有ライブラリの作成
共有ライブラリコード:/*
* filename:hello.c
* version:1.0.0
*/
#include
void hello(void)
{
printf("HelloWorld
");
}
/*
* filename:hello.h
* version:1.0.0
*/
#ifndef HELLO_H_
#define HELLO_H_
void hello(void);
#endif
Ubuntu 15では、次のコマンドを使用してhello.cダイナミックライブラリにコンパイルし、バージョン1.0.0.注意すべきは
カンマの後ろにスペースがありません.習慣的にスペースを加えると、コンパイルエラーになることがあります.$ gcc -shared -fPIC -Wl,-soname,libhello.so.1 -o libhello.so.1.0.0 hello.c
/*
* filename:hello.c
* version:1.0.0
*/
#include
void hello(void)
{
printf("HelloWorld
");
}
/*
* filename:hello.h
* version:1.0.0
*/
#ifndef HELLO_H_
#define HELLO_H_
void hello(void);
#endif
$ gcc -shared -fPIC -Wl,-soname,libhello.so.1 -o libhello.so.1.0.0 hello.c
このときreadelfで新しく生成されたターゲットファイルを表示すると、次の図のようにSONAMEがターゲットファイルに保存されていることがわかります.
$ readelf -d libhello.so.1.0.0
Dynamic section at offset 0xf04 contains 25 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000e (SONAME) Library soname: [libhello.so.1]
......
現在のフォルダの下にあるファイルは
$ tree
.
├── hello.c
├── hello.h
└── libhello.so.1.0.0
0 directories, 3 files
共有ライブラリの作成が完了したら、他のプログラムが使用できるようにシステムにインストールする必要があります.通常は2つの方法があります
私たちがここで使っているのは方法2です.以下の結果が得られた.共有ライブラリを指すシンボルリンクが生成されていることがわかります.ダイナミックロード時(リンクではないことに注意)に頼るのがこのSONAMEです.
$ tree
.
├── hello.c
├── hello.h
├── libhello.so.1 -> libhello.so.1.0.0
└── libhello.so.1.0.0
0 directories, 4 files
2.共有ライブラリの使用
次に、作成したばかりの共有ライブラリを使用する簡単なコードを書きます.
/*
* filename:test.c
* version:1.0.0
*/
#include "hello.h"
int main(void)
{
hello();
return 0;
}
その後、リンクされたテストプログラムをコンパイルします.
$ gcc test.c -L. -lhello -o test
/usr/bin/ld: cannot find -lhello
collect2: error: ld returned 1 exit status
ここで、「-L.-lhello」は、現在のディレクトリの下でlibhello.soを検索することを示します.現在のフォルダの下にはlibhello.soが確かにありませんので、エラーが発生しました.この場合、ln-sコマンドで共有ライブラリを指すシンボルリンクを作成する必要があります.
$ ln -s libhello.so.1.0.0 libhello.so
再コンパイル(gcc test.c-L.-lhello-o test)に合格しました.このときlddコマンドで実行可能ファイルtestの依存関係を表示します.
$ ldd test
linux-gate.so.1 => (0xb7795000)
libhello.so.1 => not found
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75be000)
/lib/ld-linux.so.2 (0x80040000)
見つけられるso.1ステータスはnot foundなので、このときプログラムを実行すると必ずエラーが発生します.
$ ./test
./test: error while loading shared libraries: libhello.so.1:
cannot open shared object file: No such file or directory
動的ローダがlibhelloをどこにロードするか分からないため、実行中にエラーが発生しました.so.1.
解決策
これはテストにすぎないので、一時的な方法を使用しています.このとき、テストプログラムを実行すると、正しい結果が出力されます.
3.シミュレーションパブリッシュダイナミックライブラリ
私たちはlibhello.so.1.0.0とtest.c別のフォルダにコピーします.プログラムがダイナミックライブラリをロードするとシンボルリンクlibhelloが検索されるからです.so.1ですので「ldconfig-n.」を実行する必要があります.新しいフォルダの下にシンボルリンクを生成します.この場合、エラーが発生した場合、端末をオフにして新しい端末を再開した可能性があります.では、さっきのエクスポートLDを再実行する必要があります.LIBRARY_PATHコマンドを実行し、プログラムを実行します.
4.共有ライブラリの更新、サブバージョン番号のアップグレード
このとき、以前のディレクトリに戻ります.ダイナミックライブラリをパブリッシュするディレクトリをテストするわけではありません.次のコードを変更します.
/*
* filename:hello.c
* version:1.1.0
*/
#include
void hello(void)
{
printf("Minor Version Number was modified!
");
}
そして実行
$ gcc -shared -fPIC -Wl,-soname,libhello.so.1 -o libhello.so.1.1.0 hello.c
注意:libhello.so.1.0.0 libhelloにアップグレードしました.so.1.1.0.前にも述べたようにlibname.x,y.zでは、xは変わらず、ユーザープログラムは修正する必要はありません.つまり、ここのtestです.c変更する必要はありません.
新しく生成されたlibhelloをso.1.1.0そのシミュレーションパブリケーションディレクトリにコピーします.端末をアナログパブリケーションディレクトリに切り替えて「ldconfig-n.」を実行し、シンボルリンクを再生成する.このときのこのディレクトリのファイル構造は以下の通りである.
$ tree
.
├── libhello.so.1 -> libhello.so.1.1.0
├── libhello.so.1.0.0
├── libhello.so.1.1.0
└── test
0 directories, 4 files
プログラムを実行し、修正した結果を出力します.
5.バージョン・ライブラリのアップグレードマスター・バージョン番号の更新
もう一度c
/*
* filename:hello.c
* version:2.0.0
*/
#include
void hello(void)
{
printf("Major Version Number was modified!
");
}
共有ライブラリの再コンパイル
$ gcc -shared -fPIC -Wl,-soname,libhello.so.2 -o libhello.so.2.0.0 hello.c
そしてlibhello.so.2.0.0そのシミュレーション発行ディレクトリにコピーしldconfig-nを実行します.次に、このときのファイル構造を表示します.
$ tree
.
├── libhello.so.1 -> libhello.so.1.1.0
├── libhello.so.1.0.0
├── libhello.so.1.1.0
├── libhello.so.2 -> libhello.so.2.0.0
├── libhello.so.2.0.0
└── test
0 directories, 6 files
2つのシンボルリンクが生成されていることがわかりますが、プログラムを実行すると「Minor Version Number was modified!」と出力されます.これは、test.cを再コンパイルしていないためです.保存されているSONAMEは「libhello.so.1」であり、「libhello.so.2」ではありません.このブログでは、以下の2つのリソースを参照しています.ここで敬意を表します.