GNU/Linux >> Linux の 問題 >  >> Linux

Linuxで動的ライブラリと静的ライブラリを処理する方法

Linuxは、ある意味で、相互に依存する一連の静的ライブラリと動的ライブラリです。 Linuxベースのシステムの新規ユーザーにとって、ライブラリの処理全体は謎に包まれている可能性があります。ただし、経験を積むと、オペレーティングシステムに組み込まれている大量の共有コードは、新しいアプリケーションを作成するときに有利になる可能性があります。

このトピックに触れるのに役立つように、一般的なLinuxディストリビューションで機能する最も一般的な方法を示す小さなアプリケーション例を用意しました(これらは他のシステムではテストされていません)。サンプルアプリケーションを使用してこのハンズオンチュートリアルを実行するには、コマンドプロンプトを開き、次のように入力します。

$ git clone https://github.com/hANSIc99/library_sample
$ cd library_sample/
$ make
cc -c main.c -Wall -Werror
cc -c libmy_static_a.c -o libmy_static_a.o -Wall -Werror
cc -c libmy_static_b.c -o libmy_static_b.o -Wall -Werror
ar -rsv libmy_static.a libmy_static_a.o libmy_static_b.o
ar: creating libmy_static.a
a - libmy_static_a.o
a - libmy_static_b.o
cc -c -fPIC libmy_shared.c -o libmy_shared.o
cc -shared -o libmy_shared.so libmy_shared.o
$ make clean
rm *.o

これらのコマンドを実行した後、これらのファイルをディレクトリに追加する必要があります(lsを実行します) それらを見るために):

my_app
libmy_static.a
libmy_shared.so
静的リンクについて

アプリケーションが静的ライブラリに対してリンクすると、ライブラリのコードが結果の実行可能ファイルの一部になります。これはリンク時に1回だけ実行され、これらの静的ライブラリは通常.aで終わります。 拡張機能。

静的ライブラリは、オブジェクトファイルのアーカイブ(ar)です。オブジェクトファイルは通常、ELF形式です。 ELFは、Executable and Linkable Formatの略で、多くのオペレーティングシステムと互換性があります。

fileの出力 コマンドは、静的ライブラリlibmy_static.a arです アーカイブタイプ:

$ file libmy_static.a
libmy_static.a: current ar archive

ar -tを使用 、このアーカイブを調べることができます。 2つのオブジェクトファイルが表示されます:

$ ar -t libmy_static.a 
libmy_static_a.o
libmy_static_b.o

ar -x <archive-file>を使用して、アーカイブのファイルを抽出できます。 。抽出されたファイルは、ELF形式のオブジェクトファイルです:

$ ar -x libmy_static.a
$ file libmy_static_a.o
libmy_static_a.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
ダイナミックリンクについて

その他のLinuxリソース

  • Linuxコマンドのチートシート
  • 高度なLinuxコマンドのチートシート
  • 無料のオンラインコース:RHELの技術概要
  • Linuxネットワーキングのチートシート
  • SELinuxチートシート
  • Linuxの一般的なコマンドのチートシート
  • Linuxコンテナとは何ですか?
  • 最新のLinux記事

ダイナミックリンクとは、共有ライブラリの使用を意味します。共有ライブラリは通常、.soで終わります (「共有オブジェクト」の略)

共有ライブラリは、Linuxシステムへの依存関係を管理するための最も一般的な方法です。これらの共有リソースは、アプリケーションの起動前にメモリにロードされ、複数のプロセスが同じライブラリを必要とする場合、システムに1回だけロードされます。この機能により、アプリケーションによるメモリ使用量が節約されます。

もう1つの注意点は、共有ライブラリでバグが修正されると、このライブラリを参照するすべてのアプリケーションがそのバグから利益を得るということです。これは、バグが検出されないままの場合、参照している各アプリケーションがバグの影響を受けることも意味します(アプリケーションが影響を受ける部分を使用している場合)。

アプリケーションが特定のバージョンのライブラリを必要とする場合、初心者にとっては非常に難しい場合がありますが、リンカは互換性のないバージョンの場所しか知りません。この場合、リンカが正しいバージョンへのパスを見つけるのを支援する必要があります。

これは日常的な問題ではありませんが、ダイナミックリンクを理解することは確かにそのような問題を解決するのに役立ちます。

幸いなことに、このための仕組みは非常に簡単です。

アプリケーションの起動に必要なライブラリを検出するには、lddを使用できます。 、特定のファイルで使用される共有ライブラリを出力します:

$ ldd my_app 
        linux-vdso.so.1 (0x00007ffd1299c000)
        libmy_shared.so => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007f56b869b000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f56b8881000)

ライブラリlibmy_shared.soに注意してください はリポジトリの一部ですが、見つかりません。これは、アプリケーションを実行する前にすべての依存関係をメモリにロードするダイナミックリンカーが、検索する標準の場所でこのライブラリを見つけることができないためです。

リンカが互換性のないバージョンの一般的なライブラリ(bzip2など)を検出することに関連するエラー たとえば)は、新しいユーザーにとっては非常に混乱する可能性があります。これを回避する1つの方法は、リポジトリフォルダーを環境変数LD_LIBRARY_PATHに追加することです。 リンカに正しいバージョンを探す場所を指示します。この場合、適切なバージョンがこのフォルダーにあるため、エクスポートできます:

$ LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

これで、ダイナミックリンカはライブラリの場所を認識し、アプリケーションを実行できるようになります。 lddを再実行できます ダイナミックリンカを呼び出します。ダイナミックリンカは、アプリケーションの依存関係を検査し、それらをメモリにロードします。メモリアドレスは、オブジェクトパスの後に表示されます:

$ ldd my_app 
        linux-vdso.so.1 (0x00007ffd385f7000)
        libmy_shared.so => /home/stephan/library_sample/libmy_shared.so (0x00007f3fad401000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f3fad21d000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3fad408000)

呼び出されたリンカーを見つけるには、fileを使用できます。 :

$ file my_app 
my_app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=26c677b771122b4c99f0fd9ee001e6c743550fa6, for GNU/Linux 3.2.0, not stripped

リンカー/lib64/ld-linux-x86–64.so.2 ld-2.30.soへのシンボリックリンクです 、これは私のLinuxディストリビューションのデフォルトのリンカーです:

$ file /lib64/ld-linux-x86-64.so.2 
/lib64/ld-linux-x86-64.so.2: symbolic link to ld-2.31.so

lddの出力を振り返って 、(libmy_shared.soの横にあります)も表示されます )各依存関係が数字で終わること(例:/lib64/libc.so.6 )。共有オブジェクトの通常の命名スキームは次のとおりです。

**lib** XYZ.so **.<MAJOR>** . **<MINOR>**

私のシステムでは、libc.so.6 共有オブジェクトlibc-2.30.soへのシンボリックリンクでもあります 同じフォルダ内:

$ file /lib64/libc.so.6 
/lib64/libc.so.6: symbolic link to libc-2.31.so

ロードされたライブラリのバージョンが間違っているためにアプリケーションが起動しないという問題に直面している場合は、シンボリックリンクを調べて再配置するか、正しい検索パスを指定することで、この問題を修正できる可能性があります(「ダイナミックローダー」を参照)。 :以下のld.so ")。

詳細については、lddをご覧ください。 マニュアルページ。

動的ローディング

動的読み込みとは、ライブラリ(.soなど)を意味します ファイル)は、プログラムの実行時にロードされます。これは、特定のプログラミングスキームを使用して行われます。

動的読み込みは、実行時に変更できるプラグインをアプリケーションが使用する場合に適用されます。

dlopenを参照してください 詳細については、manページを参照してください。

ダイナミックローダー:ld.so

Linuxでは、主に共有オブジェクトを処理しているため、アプリケーションの依存関係を検出してメモリにロードするメカニズムが必要です。

ld.so これらの場所で共有オブジェクトを次の順序で検索します:

  1. アプリケーションの相対パスまたは絶対パス(-rpathでハードコードされています GCCのコンパイラオプション)
  2. 環境変数LD_LIBRARY_PATH
  3. ファイル/etc/ld.so.cache

システムライブラリアーカイブ/usr/lib64にライブラリを追加することに注意してください。 管理者権限が必要です。 libmy_shared.soをコピーできます ライブラリアーカイブに手動で移動し、LD_LIBRARY_PATHを設定せずにアプリケーションを動作させます :

unset LD_LIBRARY_PATH
sudo cp libmy_shared.so /usr/lib64/

lddを実行するとき 、ライブラリアーカイブへのパスが表示されるのを確認できます:

$ ldd my_app 
        linux-vdso.so.1 (0x00007ffe82fab000)
        libmy_shared.so => /lib64/libmy_shared.so (0x00007f0a963e0000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f0a96216000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0a96401000)
コンパイル時に共有ライブラリをカスタマイズします

アプリケーションで共有ライブラリを使用する場合は、コンパイル時に絶対パスまたは相対パスを指定できます。

makefileを変更し(10行目)、make -Bを呼び出してプログラムを再コンパイルします。 。次に、lddの出力 libmy_shared.soを表示します 絶対パスとともにリストされます。

これを変更します:

CFLAGS =-Wall -Werror -Wl,-rpath,$(shell pwd) 

これには(必ずユーザー名を編集してください):

CFLAGS =/home/stephan/library_sample/libmy_shared.so 

次に再コンパイルします:

$ make

設定した絶対パスを使用していることを確認します。これは、出力の2行目に表示されます。

$ ldd my_app
    linux-vdso.so.1 (0x00007ffe143ed000)
        libmy_shared.so => /lib64/libmy_shared.so (0x00007fe50926d000)
        /home/stephan/library_sample/libmy_shared.so (0x00007fe509268000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fe50909e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe50928e000)

これは良い例ですが、他の人が使用できるライブラリを作成している場合、これはどのように機能しますか?新しいライブラリの場所は、/etc/ld.so.confに書き込むことで登録できます。 または<library-name>.confを作成します /etc/ld.so.conf.d/の下の場所を含むファイル 。その後、ldconfig ld.so.cacheを書き換えるには実行する必要があります ファイル。この手順は、特別な共有ライブラリを提供するプログラムをインストールした後に必要になる場合があります。

ld.soをご覧ください 詳細については、マニュアルページをご覧ください。

複数のアーキテクチャを処理する方法

通常、32ビットバージョンと64ビットバージョンのアプリケーションには異なるライブラリがあります。次のリストは、さまざまなLinuxディストリビューションの標準的な場所を示しています。

RedHatファミリー

  • 32ビット:/usr/lib
  • 64ビット:/usr/lib64

Debianファミリー

  • 32ビット:/usr/lib/i386-linux-gnu
  • 64ビット:/usr/lib/x86_64-linux-gnu

ArchLinuxファミリー

  • 32ビット:/usr/lib32
  • 64ビット:/usr/lib64

FreeBSD (Linuxディストリビューションではなく技術)

  • 32ビット:/usr/lib32
  • 64ビット:/usr/lib

これらの主要なライブラリを探す場所を知っていると、壊れたライブラリリンクが過去の問題になる可能性があります。

最初は混乱するかもしれませんが、Linuxライブラリの依存関係管理を理解することは、オペレーティングシステムを制御していると感じる方法です。他のアプリケーションでこれらの手順を実行して、一般的なライブラリに精通し、途中で発生する可能性のあるライブラリの課題を修正する方法を引き続き学習してください。


Linux
  1. Linuxで静的IPアドレスを設定してネットワークを構成する方法

  2. Ansibleの静的および動的ホストインベントリを管理する方法

  3. Linuxで静的IPアドレスを設定してルーティングテーブルを変更する方法

  1. Linuxでサービスを管理および一覧表示する方法

  2. LinuxにAnsibleをインストールしてテストする方法

  3. LinuxでFlatpakをインストールして使用する方法

  1. LinuxとWindowsをデュアルブートする方法

  2. ArchLinuxで静的および動的IPアドレスを構成する方法

  3. Linux 開発用のヘッダーとライブラリを設定する方法