Linuxでのダイナミックライブラリの作成と更新


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
  • -sharedは、出力結果が動的共有ライブラリ
  • であることを示す.
  • -fPICは、生成位置無関係符号
  • を示す.
  • -Wlは、後続の2つのパラメータ(sonameとlibhello.so.1)をリンクに渡すことを示す.ここのlはloveの頭文字で、小文字
  • です.
    このとき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つの方法があります
  • root権限の下で、ターゲットファイルを/libまたは/usr/libディレクトリにコピーし、ldconfigコマンドを実行してシンボルリンクを生成します.これは最も簡単な方法ですが、管理者権限
  • が必要です.
  • root以外の権限でldconfig-n shared_を実行library_directory.ここで-nは、現在のディレクトリの下にシンボルリンクを作成することを示す.もちろん、現在のディレクトリを
  • にエクスポートする必要があります.
    私たちがここで使っているのは方法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.
    解決策
  • 編集/etc/ld.so.confは、今回のテスト用ディレクトリをファイルに追加し、ldconfコマンド
  • を実行する.
  • export LD_を実行LIBRARY_PATH=.:$LD_LIBRARY_PATH、一時的な方法.

  • これはテストにすぎないので、一時的な方法を使用しています.このとき、テストプログラムを実行すると、正しい結果が出力されます.

    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つのリソースを参照しています.ここで敬意を表します.
  • プログラマーの自己修養---リンク、ライブラリ(
  • http://littlewhite.us/archives/301?utm_source=tuicool&utm_medium=referral