するために使用さ動的に対静的リンクライブラリ
-
02-07-2019 - |
質問
作成時にクラスライブラリはC++の間で選択することができますのダイナミック(.dll
, .so
)および静的(.lib
, .a
)。の違いは何ですから、時で適切な使用の?
解決
静的ライブラリは、バイナリ内のコードのサイズを増やします。それらは常にロードされ、コンパイルしたコードのバージョンが実行されるコードのバージョンです。
動的ライブラリは個別に保存およびバージョン管理されます。更新が元のバージョンとバイナリ互換であると考えられる場合、コードに同梱されていた元のものではなかった動的ライブラリのバージョンを読み込むことができます。
さらに、動的ライブラリは必ずしもロードされる必要はありません-通常、最初に呼び出されたときにロードされます-同じライブラリを使用するコンポーネント間で共有できます(複数のデータロード、1つのコードロード)。
ほとんどの場合、動的ライブラリはより優れたアプローチであると考えられていましたが、元々は大きな欠陥(google DLL地獄)がありましたが、最近のWindows OS(特にWindows XP)によってほとんど排除されました。
他のヒント
静的ライブラリとは何かを十分に説明している人もいますが、少なくともWindowsでは、静的ライブラリを使用する際の注意点をいくつか指摘したいと思います。
-
シングルトン:グローバル/静的でユニークなものが必要な場合は、静的ライブラリに配置する際に十分に注意してください。複数のDLLがその静的ライブラリに対してリンクされている場合、それぞれが独自のシングルトンのコピーを取得します。ただし、アプリケーションがカスタムDLLを持たない単一のEXEである場合、これは問題ではない可能性があります。
-
参照されていないコードの削除:静的ライブラリに対してリンクすると、DLL / EXEによって参照される静的ライブラリの部分のみがDLL / EXEにリンクされます。
たとえば、
mylib.lib
にa.obj
およびb.obj
が含まれ、DLL / EXEが参照する関数または変数のみa.obj
の場合、b.obj
全体がリンカーによって破棄されます。b.obj
にグローバル/静的オブジェクトが含まれている場合、それらのコンストラクタとデストラクタは実行されません。これらのコンストラクタ/デストラクタに副作用がある場合、それらが存在しないことに失望する可能性があります。同様に、静的ライブラリに特別なエントリポイントが含まれている場合、それらが実際に含まれていることに注意する必要があります。組み込みプログラミング(Windowsではなく、OK)でのこの例は、特定のアドレスにあるとマークされた割り込みハンドラーです。また、割り込みハンドラがエントリポイントとしてマークされ、破棄されないようにする必要があります。
別の結果として、静的ライブラリには未解決の参照のために完全に使用できないオブジェクトファイルが含まれることがありますが、それらのオブジェクトファイルから関数または変数を参照するまでリンカーエラーは発生しません。これは、ライブラリが作成されてからずっと後に発生する可能性があります。
-
デバッグシンボル:静的ライブラリごとに個別のPDBが必要な場合や、デバッグシンボルをオブジェクトファイルに配置して、PDBにロールバックできるようにする場合がありますDLL / EXE。 Visual C ++ドキュメントでは、必要なオプションについて説明しています。
-
RTTI:単一の静的ライブラリを複数のDLLにリンクすると、同じクラスの複数の
type_info
オブジェクトになる場合があります。プログラムがtype_info
を" singleton"と想定している場合データと& typeid()
またはtype_info :: before()
を使用すると、望ましくない驚くべき結果が得られる可能性があります。
libは、アプリケーションの実行可能ファイルにバンドルされているコードの単位です。
dllは、実行可能コードのスタンドアロン単位です。そのコードに呼び出しが行われた場合にのみ、プロセスにロードされます。 dllは複数のアプリケーションで使用でき、複数のプロセスにロードできますが、ハードドライブにはコードのコピーが1つしかありません。
Dll pros :複数の製品間でコードを再利用/共有するために使用できます。オンデマンドでプロセスメモリにロードし、不要なときにアンロードできます。プログラムの残りの部分から独立してアップグレードできます。
DLLの短所:dllの読み込みとコードのリベースのパフォーマンスへの影響。バージョン管理の問題(" dll hell")
Lib pros :コードは常にプロセスにロードされ、リベースされないため、パフォーマンスへの影響はありません。バージョン管理の問題はありません。
Lib cons :実行可能ファイル/プロセス" bloat&quot ;; -すべてのコードは実行可能ファイルにあり、プロセスの開始時にロードされます。再利用/共有なし-各製品には独自のコードのコピーがあります。
静的ライブラリと動的ライブラリの技術的な意味に加えて(静的ファイルはすべてを1つの大きなバイナリと動的ライブラリにバンドルし、複数の異なる実行可能ファイル間でコードを共有できる)、合法的な意味があります。
>たとえば、LGPLライセンスコードを使用していて、LGPLライブラリに対して静的にリンクする(したがって、1つの大きなバイナリを作成する)場合、コードは自動的にオープンソースになります(自由のように無料) LGPLコード。共有オブジェクトに対してリンクする場合は、LGPLライブラリ自体に対して行った改善/バグ修正のみをLGPLする必要があります。
たとえば、モバイルアプリケーションのコンパイル方法を決定する場合、これははるかに重要な問題になります(Androidでは静的と動的の選択肢がありますが、iOSではそうではありません-常に静的です)。
静的ライブラリの作成
$:~/static [32]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$:~/static [33]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H
void foo();
#endif
$:~/static [34]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$:~/static [35]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H
void foo2();
#endif
$:~/static [36]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$:~/static [37]> cat makefile
hello: hello.o libtest.a
cc -o hello hello.o -L. -ltest
hello.o: hello.c
cc -c hello.c -I`pwd`
libtest.a:foo.o foo2.o
ar cr libtest.a foo.o foo2.o
foo.o:foo.c
cc -c foo.c
foo2.o:foo.c
cc -c foo2.c
clean:
rm -f foo.o foo2.o libtest.a hello.o
$:~/static [38]>
動的ライブラリの作成
$:~/dynamic [44]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$:~/dynamic [45]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H
void foo();
#endif
$:~/dynamic [46]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$:~/dynamic [47]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H
void foo2();
#endif
$:~/dynamic [48]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$:~/dynamic [49]> cat makefile
hello:hello.o libtest.sl
cc -o hello hello.o -L`pwd` -ltest
hello.o:
cc -c -b hello.c -I`pwd`
libtest.sl:foo.o foo2.o
cc -G -b -o libtest.sl foo.o foo2.o
foo.o:foo.c
cc -c -b foo.c
foo2.o:foo.c
cc -c -b foo2.c
clean:
rm -f libtest.sl foo.o foo
2.o hello.o
$:~/dynamic [50]>
C ++プログラムは2つのフェーズで構築されます
- コンパイル-オブジェクトコード(.obj)を生成します
- リンク-実行可能コード(.exeまたは.dll)を生成します
静的ライブラリ(.lib)は.objファイルの単なるバンドルであるため、完全なプログラムではありません。プログラムを構築する第2(リンク)フェーズを経ていません。一方、DLLはexeのようなものであるため、完全なプログラムです。
静的ライブラリを構築する場合、まだリンクされていないため、静的ライブラリのコンシューマは、使用したのと同じコンパイラを使用する必要があります(g ++を使用した場合、g ++を使用する必要があります)。
静的ライブラリがクライアントにコンパイルされます。コンパイル時に.libが使用され、ライブラリの内容が消費実行可能ファイルの一部になります。
動的ライブラリは実行時にロードされ、クライアント実行可能ファイルにコンパイルされません。複数のクライアント実行可能ファイルがDLLをロードしてその機能を利用できるため、動的ライブラリはより柔軟です。これにより、クライアントコードの全体的なサイズと保守性も最小限に抑えられます。
静的ライブラリは、最終的な実行可能ファイルにリンクする必要があります。実行可能ファイルの一部になり、どこにいてもそれに従います。動的ライブラリは、実行可能ファイルが実行されるたびにロードされ、DLLファイルとして実行可能ファイルから分離されたままになります。
実行可能ファイルを再リンクすることなく(実行可能ファイルを置き換えることなく、DLLファイルを置き換えるだけで)ライブラリが提供する機能を変更できるようにする場合は、DLLを使用します。
動的ライブラリを使用する理由がない場合は常に静的ライブラリを使用します。
&quot; 共有ライブラリの書き方&quot;に関するUlrich Drepperの論文また、共有ライブラリを最大限に活用する方法、または彼が「動的共有オブジェクト」と呼んでいるものを詳述する優れたリソースです。 (DSO)。 ELF バイナリ形式の共有ライブラリに焦点を当てていますが、Windows DLLには次のような議論が適しています。まあ。
(大規模なプロジェクトで)行っているトレードオフは、最初の読み込み時間にあり、ライブラリはいつかリンクされます。行わなければならない決定は、リンクがコンパイラーが弾丸を噛んで前もって行う必要があるか、動的リンカーがロード時にそれを行うことができます。
ライブラリを複数の実行可能ファイルで共有する場合、実行可能ファイルのサイズを小さくするためにライブラリを動的にするのが理にかなっています。それ以外の場合は、必ず静的にしてください。
dllを使用することにはいくつかの欠点があります。ロードとアンロードには追加のオーバーヘッドがあります。追加の依存関係もあります。 dllを変更して、executalbesとの互換性を失わせると、機能しなくなります。一方、静的ライブラリを変更しても、古いバージョンを使用してコンパイルされた実行可能ファイルは影響を受けません。
ライブラリが静的な場合、リンク時にコードが実行可能ファイルにリンクされます。これにより、実行可能ファイルが大きくなります(動的ルートに行った場合よりも)。
ライブラリが動的な場合、リンク時に、必要なメソッドへの参照が実行可能ファイルに組み込まれます。つまり、実行可能ファイルと動的ライブラリを出荷する必要があります。また、ライブラリ内のコードへの共有アクセスが安全で、他のものよりも優先されるロードアドレスであるかどうかを考慮する必要があります。
静的ライブラリを使用できる場合は、静的ライブラリを使用します。
静的ライブラリは、コードが実行可能ファイルにコンパイルされるアプリケーションにリンクされている場合、ライブラリのオブジェクトコードを含むアーカイブです。共有ライブラリは、実行可能ファイルにコンパイルされないという点で異なります。代わりに、動的リンカーはいくつかのディレクトリを検索して必要なライブラリを探し、それをメモリにロードします。 複数の実行可能ファイルが同じ共有ライブラリを同時に使用できるため、メモリ使用量と実行可能ファイルのサイズが削減されます。ただし、実行可能ファイルとともに配布するファイルがさらにあります。ライブラリは、リンカーが見つけることができる場所にある使用システムにインストールされていることを確認する必要があります。静的リンクはこの問題を排除しますが、実行可能ファイルが大きくなります。
組み込みプロジェクトまたは専用プラットフォームの静的ライブラリで作業することが唯一の方法である場合、アプリケーションにコンパイルする手間も少なくなります。また、すべてのものを含むプロジェクトとメイクファイルがあると、人生がより楽しくなります。
私たちはプロジェクトで多くのDLL(&gt; 100)を使用しています。これらのDLLは互いに依存関係にあるため、動的リンクのセットアップを選択しました。ただし、次の欠点があります。
- 起動が遅い(&gt; 10秒) Windowsは名前の一意性に基づいてモジュールをロードするため、
- DLLをバージョン管理する必要がありました。そうしないと、記述された独自のコンポーネントは、間違ったバージョンのDLL(つまり、独自の分散セットの代わりに既にロードされているもの)を取得します
- optimizerは、DLL境界内でのみ最適化できます。たとえば、オプティマイザーは頻繁に使用されるデータとコードを隣り合わせに配置しようとしますが、これはDLLの境界を越えて機能しません
より良いセットアップは、すべてを静的ライブラリにすることです(したがって、実行可能ファイルは1つだけです)。これは、コードの重複が発生しない場合にのみ機能します。テストはこの仮定をサポートしているように見えますが、公式のMSDNの引用を見つけることができませんでした。たとえば、次のようにして1つのexeを作成します。
- exeはshared_lib1、shared_lib2を使用します
- shared_lib1はshared_lib2を使用します
- shared_lib2
shared_lib2のコードと変数は、最終的なマージされた実行可能ファイルに一度だけ存在する必要があります。誰でもこの質問をサポートできますか?
いう一般的な経験則からすると、大型のコードベース、すべての低レベルのライブラリ(例えば、UtilsまたはGuiの枠組みは、いパーティショニングにより管理しや図書館のしく静ます。動的ライブラリさんに買いものが少ない驚きを--からのインスタンスsingletonsを備えています。
また図書館は全く別に、コードベース(例えば第三者に図書館でその検討では、dll.場合には図書館はLGPLする必要がある利用のdllとにかくのライセンス条件です。