DLLファイルへのリンクは、コンパイルリンク時に暗黙的に発生することも、実行時に明示的に発生することもあります。いずれにせよ、DLLは最終的にプロセスのメモリ空間にロードされ、エクスポートされたすべてのエントリポイントがアプリケーションで使用できるようになります。
実行時に明示的に使用する場合はLoadLibrary()
、およびGetProcAddress()
を使用してDLLを手動でロードし、呼び出す必要のある関数へのポインターを取得します。
プログラムのビルド時に暗黙的にリンクされている場合、プログラムで使用される各DLLエクスポートのスタブは、インポートライブラリからプログラムにリンクされ、プロセスの起動時にEXEとDLLが読み込まれると、これらのスタブが更新されます。(はい、ここでは少し以上簡略化しました...)
これらのスタブはどこかから取得する必要があり、Microsoftツールチェーンでは、インポートライブラリと呼ばれる特別な形式の.LIBファイルから取得します。必要な.LIBは通常、DLLと同時にビルドされ、DLLからエクスポートされた各関数のスタブが含まれています。
紛らわしいことに、同じライブラリの静的バージョンも.LIBファイルとして出荷されます。DLLのインポートライブラリであるLIBは、通常、一致する静的LIBよりも小さい(多くの場合、はるかに小さい)ことを除いて、それらを区別する簡単な方法はありません。
ちなみに、GCCツールチェーンを使用する場合、DLLと一致するインポートライブラリは実際には必要ありません。Windowsに移植されたバージョンのGnuリンカーは、DLLを直接理解し、必要なほとんどのスタブをその場で合成できます。
更新
すべての要点が実際にどこにあり、実際に何が起こっているのかを知ることに抵抗できない場合は、MSDNで常に役立つことがあります。Matt Pietrekの記事「 Win32PortableExecutable File Formatの詳細」は、EXEファイルの形式と、そのロードおよび実行方法の非常に完全な概要です。もともとMSDNMagazine caに掲載されて以来、.NETなどをカバーするように更新されています。2002年。
また、プログラムで使用されているDLLを正確に知る方法を知っておくと役立ちます。そのためのツールはDependencyWalker、別名depends.exeです。そのバージョンはVisualStudioに含まれていますが、最新バージョンは作成者からhttp://www.dependencywalker.com/で入手できます。リンク時に指定されたすべてのDLL(初期ロードと遅延ロードの両方)を識別でき、プログラムを実行して、実行時にロードされる追加のDLLを監視することもできます。
アップデート2
以前のテキストの一部を書き直して、読み直しの際に明確にし、MSDNとの一貫性を保つために暗黙的および明示的なリンクの用語を使用しました。
したがって、ライブラリ関数をプログラムで使用できるようにする方法は3つあります。明らかなフォローアップの質問は、「どの方法を選択するか」です。
静的リンクは、プログラム自体の大部分がリンクされる方法です。すべてのオブジェクトファイルが一覧表示され、リンカによってEXEファイルにまとめられます。その過程で、リンカは、モジュールが互いの関数を呼び出すことができるように、グローバルシンボルへの参照を修正するなどの小さな雑用を処理します。ライブラリは静的にリンクすることもできます。ライブラリを構成するオブジェクトファイルは、リンカが必要なシンボルを含むモジュールを検索する.LIBファイルにライブラリアンによってまとめられます。静的リンクの効果の1つは、プログラムによって使用されるライブラリーのモジュールのみがリンクされることです。他のモジュールは無視されます。たとえば、従来のC数学ライブラリには、多くの三角関数が含まれています。しかし、あなたがそれにリンクして使用する場合cos()
、あなたはのためのコードのコピーで終わるていないsin()
か、tan()
あなたはまた、これらの機能を呼ばない限り。豊富な機能を備えた大規模なライブラリの場合、このモジュールを選択的に含めることが重要です。組み込みシステムなどの多くのプラットフォームでは、ライブラリで使用できるコードの合計サイズは、実行可能ファイルをデバイスに格納するために使用できるスペースと比較して大きくなる可能性があります。選択的に含めることなく、これらのプラットフォーム用のプログラム構築の詳細を管理することは困難になります。
ただし、実行中のすべてのプログラムに同じライブラリのコピーがあると、通常は多くのプロセスを実行するシステムに負担がかかります。適切な種類の仮想メモリシステムを使用すると、同じコンテンツを持つメモリのページがシステムに1回だけ存在する必要がありますが、多くのプロセスで使用できます。これにより、コードを含むページが、実行中の他の多くのプロセスの一部のページと同一になる可能性が高くなるという利点が生まれます。ただし、プログラムがランタイムライブラリに静的にリンクしている場合、それぞれに異なる場所にあるプロセスメモリマップに配置された関数の異なる組み合わせがあり、それ自体がすべてであるプログラムでない限り、共有可能なコードページは多くありません。プロセス以上で実行します。したがって、DLLのアイデアには、もう1つの大きな利点があります。
ライブラリのDLLには、そのすべての機能が含まれており、クライアントプログラムですぐに使用できます。多くのプログラムがそのDLLをロードする場合、それらはすべてそのコードページを共有できます。誰もが勝ちます。(まあ、DLLを新しいバージョンで更新するまでは、それはこの話の一部ではありません。物語のその側のGoogle DLL地獄。)
したがって、新しいプロジェクトを計画するときに最初に行うべき大きな選択は、動的リンケージと静的リンケージの間です。静的リンケージを使用すると、インストールするファイルが少なくなり、使用するDLLをサードパーティが更新する必要がなくなります。ただし、プログラムはより大きく、Windowsエコシステムの市民としてはそれほど優れていません。ダイナミックリンケージを使用すると、インストールするファイルが増え、使用するDLLをサードパーティが更新する際に問題が発生する可能性がありますが、通常はシステム上の他のプロセスに慣れています。
DLLの大きな利点は、メインプログラムを再コンパイルしたり、再リンクしたりすることなく、ロードして使用できることです。これにより、サードパーティのライブラリプロバイダー(MicrosoftやCランタイムなど)がライブラリのバグを修正して配布できるようになります。エンドユーザーが更新されたDLLをインストールすると、そのDLLを使用するすべてのプログラムでそのバグ修正のメリットをすぐに得ることができます。(それが物事を壊さない限り。DLL地獄を参照してください。)
もう1つの利点は、暗黙的ロードと明示的ロードの違いにあります。明示的なロードという余分な労力を費やすと、プログラムが作成および公開されたときにDLLが存在していなかった可能性があります。これにより、たとえばプラグインを検出してロードできる拡張メカニズムが可能になります。
lib /list xxx.lib
とlink /dump /linkermember xxx.lib
。このStackOverflowの質問を参照してください。