スタティック・ライブラリとダイナミック・ライブラリの違いを含め、Linuxがどのようにライブラリを使用するかを理解することは、依存関係の問題を解決するのに役立ちます。
Linuxはある意味、相互に依存し合う静的・動的ライブラリの束です。初心者のLinuxユーザーにとって、ライブラリを扱うプロセス全体はちょっとしたミステリーかもしれません。しかし、経験豊富なユーザーにとっては、オペレーティング・システムに組み込まれた大量の共有コードは、新しいアプリケーションを書く際に有利に働きます。
このトピックに慣れるために、一般的なLinuxディストリビューションでライブラリがどのように扱われるかを示す小さな 用意しました。このハンズオン・チュートリアルをこの例に沿って進めるには、コマンドライン・エントリーを開いてください:
$ git clone https://.//_le$ cd library_sample/cc -c main.c -Wall -Werrorcc -c libmy_static_a.c -o libmy_static_a.o -Wall -Werrorcc -c libmy_static_b.c -o libmy_static_b.o -Wall -Werrorar -rsv libmy_static.a libmy_static_a.o libmy_static_b.oar: creating libmy_static.aa - libmy_static_a.oa - libmy_static_b.occ -c -fPIC libmy_shared.c -o libmy_shared.occ -shared -o libmy_shared.so libmy_shared.o$ make clean
コマンドが実行されると、これらのファイルがディレクトリに追加されるはずです:
libmy_static.alibmy_shared.so
静的リンクについて
アプリケーションがスタティック・ライブラリをリンクすると、このライブラリのコードは実行可能ファイルの一部になります。この動作はリンク処理中に一度だけ実行され、スタティック・ライブラリの拡張子は通常.aで終わります。
スタティック・ライブラリは複数のファイルから構成されますアプリケーションの例これらのターゲット・ファイルは通常ELFフォーマットで、ELFはいくつかのオペレーティング・システムと互換性のある略記法です。
fileコマンドの出力は、スタティック・ライブラリ libmy_static.a ar形式のアーカイブ・ファイル・タイプであることを示します。
$ file libmy_static.alibmy_static.a: current ar archive
ar -t を使うと、アーカイブファイルの中を見ることができます。2つの対象ファイルが表示されます:
$ ar -t libmy_static.alibmy_static_a.olibmy_static_b.o
アーカイブからファイルを抽出するには ax -x <archive-file> コマンドを使用します。提案されるファイルはELF形式のターゲットファイルです:
$ ar -x libmy_static.a$ file libmy_static_a.olibmy_static_a.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
ダイナミック・リンクについて
ダイナミックリンクとは、共有ライブラリを使用することです。共有ライブラリは通常、拡張子.soで終わります。
共有ライブラリは、Linuxシステムにおける依存関係管理の最も一般的な方法です。これらの共有ライブラリは、アプリケーションが起動する前にメモリにロードされ、複数のアプリケーションが同じライブラリを必要とする場合、そのライブラリはシステム内で一度だけロードされます。この機能により、アプリケーションのメモリ・フットプリントが削減されます。
もうひとつ注意しなければならないのは、共有ライブラリのバグが修正されると、そのライブラリを参照するすべてのアプリケーションが恩恵を受けるということです。しかしこれは、バグがまだ発見されていない場合、関連するすべてのアプリケーションがそのバグに苦しむことを意味します。
アプリケーションがあるライブラリの特定のバージョンを要求しているのに、 互換性のないバージョンの場所しか知らない場合、これは初心者にとって厄介な問題です。このシナリオでは、リンカが正しいバージョンへのパスを見つけるのを手助けしなければなりません。
これは日常的な問題ではありませんが、ダイナミック・リンクの原則を理解することは、同様の問題を解決する上で必ず役立ちます。
幸いなことに、ダイナミック・リンクの仕組みは、実際には非常にクリーンでシンプルです。
アプリケーションの起動時に必要なライブラリを確認するには、lddコマンドを使用します:
$ ldd my_applinux-vdso.so.1 (0x00007ffd)libmy_shared.so => not foundlibc.so.6 => /lib64/libc.so.6 (0xb)/lib64/ld-linux-x86-64.so.2 (0xb)
libmy_shared.soライブラリはコード・リポジトリーの一部ですが、見つかりません。これは、アプリケーションの起動時にすべての依存関係をメモリにロードする役割を担うダイナミックリンカーが、検索する標準パスの下にこのライブラリを見つけられなかったためです。
よく使用されるリポジトリの互換性のないバージョンに関連する問題は、不慣れな人にとっては非常に混乱しがちです。リンカーに正しいバージョンの場所を知らせる方法の 1 つは、環境変数 LD_LIBRARY_PATH にそのリポジトリへのパスを追加することです。この場合、正しいバージョンはこのディレクトリにあるので、環境変数にエクスポートできます:
$ LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH$ export LD_LIBRARY_PATH
これでダイナミック・リンカはライブラリを探す場所を認識し、アプリケーショ ンを実行できるようになります。もう一度 ldd を実行すると、ダイナミック・リンカがアプリケーションの依存関係を チェックし、それらをメモリにロードします。メモリ・アドレスはオブジェクト・パスの後に表示されます:
$ ldd my_applinux-vdso.so.1 (0x00007ffd)libmy_shared.so => /home/stephan/library_sample/libmy_shared.so (0xfad)libc.so.6 => /lib64/libc.so.6 (0xfad)/lib64/ld-linux-x86-64.so.2 (0xfad)
どのリンカーが呼ばれたかを調べるには、fileコマンドを使います:
$ file my_appmy_app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bc99f0fd9ee3550fa6, for GNU/Linux 3.2.0, not stripped
$ file /lib64/ld-linux-x86-64.so.2/lib64/ld-linux-x86-64.so.2: symbolic link to ld-2.31.so
lddコマンドの出力を振り返ると、各依存関係が数字で終わっていることもわかります。共有オブジェクトの一般的な命名形式は次のとおりです:
libXYZ.so.<MAJOR>.<MINOR>
$ file /lib64/libc.so.6/lib64/libc.so.6: symbolic link to libc-2.31.so
間違ったバージョンのライブラリをロードしているために起動しないアプリケーションを扱っている場合、ソフトリンクを整理したり、正しい検索パスを決定したりすることで、問題を解決できる可能性があります。
詳しくは lddのマニュアルページをご覧ください。
動的ロード
ダイナミック・ロードとは、プログラムの実行時にライブラリをロードすることです。これは特定のプログラミング手法を用いて実現されます。
動的ロードは、アプリケーションが実行時に変更可能なプラグインを使用する場合に使用されます。
詳しくは dlopenのマニュアルページを ご覧ください。
ダイナミックローダー:
Linuxでは、ほとんどの場合共有ライブラリを扱うので、アプリケーションの依存関係を検出してメモリにロードするメカニズムが必要です。
以下の順序で、これらの場所で共有ld.so 探します:
- アプリケーションの絶対パスまたは相対パスの下
$ cd library_sample/cc -c main.c -Wall -Werror
システム・ライブラリ・アーカイブ/usr/lib64にライブラリを追加するには、管理者権限が必要であることを覚えておくことが重要です。アプリケーションを実行可能にし、LD_LIBRARY_PATHを設定しないようにするには、libmy_shared.soをライブラリ・アーカイブに手動でコピーします。
unset LD_LIBRARY_PATHsudo cp libmy_shared.so /usr/lib64/
lddを実行すると、アーカイブライブラリへのパスが表示されます:
$ ldd my_applinux-vdso.so.1 (0x00007ffe82fab000)libmy_shared.so => /lib64/libmy_shared.so (0xa)libc.so.6 => /lib64/libc.so.6 (0xa)/lib64/ld-linux-x86-64.so.2 (0xa)
コンパイル時の共有ライブラリのカスタマイズ
アプリケーションに共有ライブラリを使用させたい場合は、コンパイル時に絶対パスまたは相対パスを指定します。
makefileを編集し、make -Bでプログラムを再コンパイルします。lddの出力には、 libmy_shared.so 絶対パスとともに表示されます。
これを着てください:
CFLAGS =-Wall -Werror -Wl,-rpath,$(shell pwd)
これをこう変えてください:
CFLAGS =/home/stephan/library_sample/libmy_shared.so
それから再コンパイルしてください:
出力の2行目にあるように、設定した絶対パスが使われていることを確認してください:
$ ldd my_applinux-vdso.so.1 (0x00007ffe143ed000)libmy_shared.so => /lib64/libmy_shared.so (0x00007fe0)/home/stephan/library_sample/libmy_shared.so (0x00007fe)libc.so.6 => /lib64/libc.so.6 (0x00007fe0)/lib64/ld-linux-x86-64.so.2 (0x00007fe0)
これは良い例ですが、他の人が使うためのライブラリを書いている場合はどうなるのでしょうか?新しいライブラリのパスをシステムに登録するには、/etc/ld.so.confに書き込むか、/etc/ld.so.conf.d/ディレクトリにパスを含む <library-name>.conf ファイルを作成します。その後、ldconfigコマンドを実行してld.so.cacheファイルを上書きする必要があります。特別な共有ライブラリを搭載したアプリケーションをインストールする場合、この手順は避けられないことがあります。
複数のアーキテクチャを扱う方法
一般に、アプリケーションの 32 ビット版と 64 ビット版ではライブラリが異なります。以下のリストは、異なるLinuxディストリビューションのライブラリへの標準パスを示しています:
レッドハットファミリー
- ビット:
/usr/lib - ビット:
/usr/lib64
Debian ファミリー
- ビット:
/usr/lib/i386-linux-gnu ar: creating libmy_static.a
Arch Linux ファミリー
a - libmy_static_a.oa - libmy_static_b.o
- ビット:
cc -c -fPIC libmy_shared.c -o libmy_shared.o - ビット:
cc -shared -o libmy_shared.so libmy_shared.o
これらの重要なライブラリがどこにあるかを知っていれば、ライブラリリンクの失敗という問題を過去のものにすることができます。
最初は少し戸惑うかもしれませんが、Linux ライブラリの依存性管理を理解することは、オペレーティング・システムに対するコントロールの感覚を示すことです。他のアプリケーションでこれらの手順を実行して、一般的なライブラリに慣れ親しんでから、遭遇するかもしれないライブラリの課題を解決する方法を学んでください。





