web-dev-qa-db-ja.com

共有オブジェクト(.so)、静的ライブラリ(.a)、およびDLL(.so)の違いは?

私はLinuxのライブラリに関していくつかの議論に関わってきたので、いくつか確認したいと思います。

アプリケーションを構築するときにライブラリを使用するには2つの方法があるということを理解しています(間違っている場合は修正してください。後で投稿を編集します)。

  1. 静的ライブラリ(.aファイル):リンク時には、ライブラリ全体のコピーが最終アプリケーションに配置されるため、ライブラリ内の関数は常に呼び出し元のアプリケーションで利用できます。
  2. 共有オブジェクト(.soファイル):リンク時に、オブジェクトは対応するヘッダー(.h)ファイルを介してそのAPIに対して検証されます。ライブラリは実際には必要とされる実行時まで使用されません。

静的ライブラリの明らかな利点は、アプリケーション全体を自己完結型にできることですが、動的ライブラリの利点は「.so」ファイルを置き換えることができることです(つまり、セキュリティのために更新する必要がある場合)。バグ)ベースアプリケーションを再コンパイルする必要なし。

共有オブジェクトとダイナミックリンクライブラリ(DLL)は、どちらも ".so"ファイルであっても区別する人もいます。 Linuxや他のPOSIX準拠のOS(MINIX、UNIX、QNXなど)でのC/C++開発に関して、共有オブジェクトとDLLの間に違いはありますか? 1つの大きな違いは(これまでのところ)共有オブジェクトは実行時に使われるだけで、DLLは最初にアプリケーション内でdlopen()呼び出しを使って開かなければならないということです。

最後に、一部の開発者は "共有アーカイブ"について言及しました。これは私の知る限りでは静的ライブラリそのものでもありますが、アプリケーションによって直接使用されることは決してありません。代わりに、他の静的ライブラリは「共有アーカイブ」とリンクして、(すべてではないが)いくつかの関数/リソースを共有アーカイブから構築中の静的ライブラリに引き込みます。

ご協力ありがとうございます。

更新


これらの用語が私に提供された文脈において、Linuxを学ばなければならなかったのはWindows開発者のチームによって使用された事実上誤った用語でした。私はそれらを修正しようとしましたが、(誤った)言語規範が行き詰まりました。

  1. 共有オブジェクト:プログラムの起動時にプログラムに自動的にリンクされ、スタンドアロンファイルとして存在するライブラリ。ライブラリはコンパイル時にリンクリストに含まれます(例:LDOPTS+=-lmylibという名前のライブラリファイルの場合はmylib.so)。 ライブラリはコンパイル時、およびアプリケーションの起動時に存在している必要があります。
  2. 静的ライブラリ:アプリケーションコードと、プログラムのビルド時にプログラムに自動的にリンクされるライブラリコードを含む単一の(より大きな)アプリケーションのビルド時に実際のプログラム自体にマージされるライブラリ、およびその両方を含む最終バイナリメインプログラムとライブラリ自体は、単一のスタンドアロンバイナリファイルとして存在します。ライブラリはコンパイル時にリンクリストに含まれます(すなわち、mylib.aという名前のライブラリファイルの場合はLDOPTS+=-lmylib)。 ライブラリはコンパイル時に存在しなければなりません。
  3. DLL:基本的に共有オブジェクトと同じですが、コンパイル時にリンクリストに含まれるのではなく、ライブラリがdlopen()/dlsym()コマンドを介してロードされるため、プログラムがコンパイルするためにライブラリが存在する必要はありません。 。 また、ライブラリはアプリケーションの起動時またはコンパイル時に存在する必要はありません。現時点ではdlopen/dlsymが必要です。電話がかけられます。
  4. 共有アーカイブ:基本的に静的ライブラリと同じですが、 "export-shared"と "-fPIC"フラグを付けてコンパイルされています。ライブラリはコンパイル時にリンクリストに含まれます(すなわち、mylibS。aという名前のライブラリファイルの場合はLDOPTS + = - lmylibS)。この2つの違いは、共有オブジェクトまたはDLLが共有アーカイブを自分自身のコードに静的にリンクし、共有オブジェクト内の機能を他のプログラムで使用できるようにする場合に、この追加フラグが必要なことです。 DLL内部で使用するのではなく、これは、誰かがあなたに静的ライブラリを提供していて、それをSOとして再パッケージ化したい場合に役立ちます。 ライブラリはコンパイル時に存在しなければなりません。

追加アップデート

"DLL"と "shared library"の区別は、当時私が働いていた会社の(怠惰で不正確な)口語表現(Windows開発者はLinux開発へのシフトを余儀なくされ、固まった用語)でした。上記。

さらに、「共有アーカイブ」の場合、ライブラリ名の後に続く「S」リテラルは、その会社で使用されている単なる慣例であり、一般的な業界では使用されていません。

237
DevNull

DLLと共有オブジェクトは同じことを表すのに異なる用語であると常に思っていました。WindowsではDLLと呼ばれ、UNIXシステムでは共有オブジェクトであり、一般的な用語であるダイナミックリンクライブラリと呼ばれますUNIX上で.soを開くことは 'dynamic library'の後でdlopen()と呼ばれます。

これらは実際にはアプリケーションの起動時にのみリンクされていますが、ヘッダーファイルに対する検証の概念は正しくありません。ヘッダファイルは、ライブラリを使用するコードをコンパイルするために必要なプロトタイプを定義しますが、リンク時には、リンカはライブラリ自身の内部を調べて、必要な関数が実際にあることを確認します。リンカはリンク時にどこかで関数本体を見つけなければならず、そうでなければエラーを発生させるでしょう。実行時にそれが行われるのは、プログラムがコンパイルされてからライブラリ自体が正しく変更されている可能性があるためです。これが、ABIの変更が古いバージョンに対してコンパイルされた既存のプログラムを中断させるものであるため、ABIの安定性がプラットフォームライブラリで非常に重要である理由です。

静的ライブラリは、プロジェクトのコンパイルの一部として自分で構築しているものと同じように、コンパイラから直接取り出したオブジェクトファイルの集まりです。したがって、静的ライブラリはまったく同じ方法で読み込まれ、リンカに渡されます。まったく同じ方法で落ちた。

83
Matthew Walton

A static library(.a)は、リンカによって生成された最終的な実行可能ファイルに直接リンクできるライブラリです。このライブラリに含まれているため、ライブラリをシステムに配置する必要はありません。実行可能ファイルがデプロイされます。

A 共有ライブラリ(.so)はリンクされていますが、最終的な実行可能ファイルに埋め込まれていないライブラリです。 。

A Windows上のダイナミックリンクライブラリ(.dll)はLinux上の共有ライブラリ(.so)に似ていますが、OSに関連する2つの実装にはいくつかの違いがあります(WindowsとLinux)。

A DLLでは、エクスポートと内部の2種類の関数を定義できます。エクスポートされた関数は、それらが定義されているDLL内からと同様に、他のモジュールによって呼び出されることを意図しています。内部関数は通常、それらが定義されているDLL内からのみ呼び出されることを意図しています。

Linux上のSOライブラリは、すべてのシンボルが問い合わせプロセスで使用可能であるため、エクスポート可能なシンボルを示すための特別なexportステートメントを必要としません。

168
aleroot

私はWindowsでのDLLの詳細について詳しく説明することができます。

DLLは共有オブジェクトファイルのようなものです。どちらもイメージであり、それぞれのOSのプログラムローダーによってメモリにロードする準備ができています。イメージには、リンカーとローダーが必要な関連付けを行い、コードのライブラリを使用するのに役立つさまざまなメタデータが付いています。

Windows DLLにはエクスポートテーブルがあります。エクスポートは、名前でもテーブル位置(数値)でもかまいません。後者の方法は「オールドスクール」と見なされ、はるかに脆弱です。DLLを再構築してテーブル内の関数の位置を変更すると、障害が発生する可能性があります。名前で。それで、問題としてそれを忘れてください、しかしあなたがサードパーティベンダーのlibsのような「恐竜」コードで作業するならば、それがそこにあることにちょうど注意してください。

Windows DLLは、EXE(実行可能アプリケーション)の場合と同じように、コンパイルとリンクによって構築されますが、DLLが使用されるのと同じように、SOは独立していないことを意味します。動的ロードまたはリンク時バインディングによるアプリケーション(SOへの参照はアプリケーションバイナリのメタデータに埋め込まれ、OSプログラムローダーは参照されたSOを自動的にロードします)。 SOが他のSOを参照できるように、DLLは他のDLLを参照できます。

Windowsでは、DLLは特定のエントリポイントのみを利用可能にします。これらは「輸出」と呼ばれます。開発者は特別なコンパイラキーワードを使用してシンボルを(他のリンカやダイナミックローダに対して)外部から見えるようにすることも、リンク時にDLL自体が作成されています。現代の慣習は、シンボル名をエクスポートするためにキーワードで関数定義を装飾することです。現在のコンパイル単位の外側のDLLからインポートされるシンボルとしてそのシンボルを宣言するキーワードを持つヘッダファイルを作成することも可能です。詳細については、キーワード__declspec(dllexport)および__declspec(dllimport)を調べてください。

DLLの興味深い機能の1つは、標準の「ロード時/アンロード時」のハンドラー関数を宣言できることです。 DLLがロードまたはアンロードされるときはいつでも、DLLは場合によっては初期化またはクリーンアップを実行できます。これは、デバイスドライバや共有オブジェクトインタフェースなどのオブジェクト指向のリソースマネージャとしてDLLを持つようにうまくマッピングされています。

開発者が既に作成されたDLLを使用したい場合、彼女はDLLの作成時にDLL開発者によって作成された "export library"(* .LIB)を参照するか、明示的にDLL実行時に、LoadLibrary()およびGetProcAddress()メカニズムを介して名前でエントリポイントアドレスを要求します。ほとんどの場合、LIBファイル(単にDLLのエクスポートされたエントリポイントのリンカメタデータを含む)に対してリンクすることは、DLLが使用される方法です。動的ロードは通常、プログラムビヘイビアー(アドオンまたは後で定義された機能へのアクセス、別名「プラグイン」)に「多態性」または「ランタイム構成可能性」を実装するために予約されています。

Windowsのやり方は時々混乱を招くことがあります。システムは.LIB拡張子を使用して、通常の静的ライブラリ(POSIX * .aファイルなどのアーカイブ)と、リンク時にアプリケーションをDLLにバインドするために必要な "エクスポートスタブ"ライブラリの両方を参照します。そのため、*。LIBファイルに同じ名前の* .DLLファイルがあるかどうかを常に確認する必要があります。そうでなければ、*。LIBファイルが静的ライブラリアーカイブであり、DLLのバインディングメタデータをエクスポートしていない可能性が高いです。

29
JoGusto

静的ファイルはリンク時にアプリケーションにコピーされ、共有ファイルはリンク時に検証され、実行時にロードされるという点で正しいのです。

アプリケーションが実行時にアプリケーションに代わって実行したい場合は、dlopen呼び出しは共有オブジェクトだけではありません。それ以外の場合は、アプリケーションの起動時に共有オブジェクトが自動的にロードされます。 DLLSと.soは同じものです。 dlopenは、プロセスにさらにきめ細かい動的ロード機能を追加するために存在します。 DLLを開く/使用するためにdlopenを使用する必要はありません。これはアプリケーションの起動時にも発生します。

4
rapadura