C ++でクラスライブラリを作成する場合、動的(.dll
、.so
)および静的(.lib
、.a
)ライブラリから選択できます。それらの違いは何ですか?いつ使用するのが適切ですか?
C ++でクラスライブラリを作成する場合、動的(.dll
、.so
)および静的(.lib
、.a
)ライブラリから選択できます。それらの違いは何ですか?いつ使用するのが適切ですか?
回答:
静的ライブラリは、バイナリのコードのサイズを増やします。これらは常に読み込まれ、コンパイルしたコードのどのバージョンも実行されるコードのバージョンです。
動的ライブラリは個別に保存およびバージョン管理されます。更新が元のバージョンとバイナリ互換であると見なされた場合、コードに同梱されていた元のバージョンではないバージョンのダイナミックライブラリが読み込まれる可能性があります。
さらに、動的ライブラリは必ずしもロードされる必要はありません-通常、最初に呼び出されたときにロードされます-同じライブラリを使用するコンポーネント間で共有できます(複数のデータロード、1つのコードロード)。
ほとんどの場合、ダイナミックライブラリはより優れたアプローチであると考えられていましたが、元々は重大な欠陥(google DLL hell)がありましたが、最近の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ではなく)は、特定のアドレスにあるとマークされている割り込みハンドラーです。また、割り込みハンドラがエントリポイントとしてマークされ、破棄されないようにする必要があります。
これのもう1つの結果は、静的ライブラリに未解決の参照のために完全に使用できないオブジェクトファイルが含まれている可能性があることですが、それらのオブジェクトファイルから関数または変数を参照するまで、リンカーエラーは発生しません。これは、ライブラリが作成されてからかなり後に発生する可能性があります。
デバッグシンボル:静的ライブラリごとに個別のPDBが必要な場合や、デバッグシンボルをオブジェクトファイルに配置して、DLL / EXEのPDBにロールバックする場合があります。Visual C ++のドキュメントでは、必要なオプションについて説明しています。
RTTI:type_info
単一の静的ライブラリを複数のDLLにリンクすると、同じクラスの複数のオブジェクトになる可能性があります。プログラムがそれtype_info
を「シングルトン」データであると想定し、&typeid()
またはを使用type_info::before()
する場合、望ましくない驚くべき結果が得られる可能性があります。
libは、アプリケーション実行可能ファイル内にバンドルされているコードの単位です。
dllは、実行可能コードのスタンドアロン単位です。そのコードが呼び出されたときにのみプロセスに読み込まれます。dllは複数のアプリケーションで使用でき、複数のプロセスでロードできますが、ハードドライブにはコードのコピーが1つしかありません。
Dllプロ:複数の製品間でコードを再利用/共有するために使用できます。オンデマンドでプロセスメモリにロードし、不要なときにアンロードできます。プログラムの他の部分とは無関係にアップグレードできます。
DLLの短所:DLLの読み込みとコードのリベースのパフォーマンスへの影響。バージョン管理の問題( "dll hell")
Libプロ:コードは常にプロセスに読み込まれ、リベースされないため、パフォーマンスへの影響はありません。バージョン管理の問題はありません。
Lib cons:実行可能ファイル/プロセスの「膨張」-すべてのコードは実行可能ファイルにあり、プロセスの開始時にロードされます。再利用/共有なし-各製品には独自のコードのコピーがあります。
静的ライブラリと動的ライブラリの技術的な影響(静的ファイルはすべてを1つの大きなバイナリと動的ライブラリにバンドルし、複数の異なる実行可能プログラム間でコードを共有できるようにする)に加えて、法的な影響があります。
たとえば、LGPLライセンスコードを使用していて、LGPLライブラリに対して静的にリンクしている(したがって、1つの大きなバイナリを作成している)場合、コードは自動的にオープンソース(自由に自由) LGPLコードになります。共有オブジェクトに対してリンクする場合は、LGPLライブラリ自体に対して行った改善/バグ修正のみをLGPLに行う必要があります。
たとえば、モバイルアプリケーションをコンパイルする方法を決定する場合、これははるかに重要な問題になります(Androidでは静的か動的かを選択できますが、iOSでは選択できません-常に静的です)。
C ++プログラムは2つのフェーズで構築されます
静的ライブラリ(.lib)は.objファイルの単なるバンドルであるため、完全なプログラムではありません。プログラム構築の第2(リンク)フェーズは実行されていません。一方、DLLはexeに似ているため、完全なプログラムです。
静的ライブラリを構築する場合、まだリンクされていないため、静的ライブラリのコンシューマは、使用したのと同じコンパイラを使用する必要があります(g ++を使用する場合は、g ++を使用する必要があります)。
代わりにdllをビルドした(そしてそれを正しくビルドした)場合、どのコンパイラーを使用しているかに関係なく、すべてのコンシューマーが使用できる完全なプログラムをビルドしたことになります。ただし、コンパイラー間の互換性が必要な場合、dllからのエクスポートにはいくつかの制限があります。
consumers of your static library will have to use the same compiler that you used
静的ライブラリがC ++ライブラリ(など)を使用する場合#include <iostream>
。
$$:~/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]>
時間の経過に伴う変更、バージョン管理、安定性、互換性などについて慎重に検討する必要があります。
共有コードを使用する2つのアプリがある場合、相互に互換性が必要な場合に備えて、それらのアプリを強制的に一緒に変更しますか?次に、dllを使用します。すべてのexeは同じコードを使用します。
または、それらを互いに分離して、一方を変更し、もう一方を壊していないと確信できるようにしますか?次に、静的libを使用します。
DLL地獄は、おそらく静的ライブラリを使用する必要があるはずですが、代わりにdllを使用した場合で、すべてのexeがそれに対応しているわけではありません。
静的ライブラリを最終的な実行可能ファイルにリンクする必要があります。それは実行可能ファイルの一部になり、どこへでもそれに従います。動的ライブラリは、実行可能ファイルが実行されるたびにロードされ、DLLファイルとして実行可能ファイルから分離されたままになります。
実行可能ファイルを再リンクせずにライブラリによって提供される機能を変更できるようにする場合は、DLLを使用します(実行可能ファイルを置き換える必要なく、DLLファイルを置き換えるだけです)。
動的ライブラリを使用する理由がない限り、静的ライブラリを使用します。
Ulrich Drepperの「共有ライブラリの書き方」に関する論文は、共有ライブラリを最大限に活用する方法、または彼が「動的共有オブジェクト」(DSO)と呼ぶものを詳しく説明する優れた資料でもあります。ELFバイナリ形式の共有ライブラリに重点を置いていますが、一部の説明はWindows DLLにも適しています。
このトピックの優れた議論については、Sunからのこの記事をお読みください。
これは、挿入ライブラリを挿入できることを含む、すべての利点になります。挿入の詳細については、こちらの記事を参照してください。
プロジェクトでは多くのDLL(> 100)を使用しています。これらのDLLは相互に依存しているため、動的リンクの設定を選択しました。ただし、次の欠点があります。
たぶん、より良い設定は、すべてを静的ライブラリにすることでした(したがって、実行ファイルは1つだけです)。これは、コードの重複が発生しない場合にのみ機能します。テストはこの仮定をサポートしているようですが、MSDNの公式見積もりを見つけることができませんでした。たとえば、次のようにして1つのexeを作成します。
shared_lib2のコードと変数は、マージされた最終的な実行可能ファイルに1回だけ存在する必要があります。誰でもこの質問をサポートできますか?
静的ライブラリは、アプリケーションにリンクされたときにライブラリのオブジェクトコードを含むアーカイブであり、そのコードは実行可能ファイルにコンパイルされます。共有ライブラリは、実行可能ファイルにコンパイルされないという点で異なります。代わりに、動的リンカーはいくつかのディレクトリを検索して、必要なライブラリを探し、それをメモリにロードします。複数の実行可能ファイルが同じ共有ライブラリを同時に使用できるため、メモリ使用量と実行可能ファイルのサイズが削減されます。ただし、実行可能ファイルと一緒に配布するファイルが他にもあります。ライブラリがリンカが見つけられる場所のusesシステムにインストールされていることを確認する必要があります。静的リンクはこの問題を排除しますが、実行ファイルが大きくなります。
大きなコードベースがある場合、すべてが低レベルのライブラリ(UtilsまたはGuiフレームワークなど)の上に構築され、より管理しやすいライブラリに分割して静的ライブラリにしたいという一般的な経験則を示します。動的ライブラリは実際には何も購入せず、驚きも少なくなります。たとえば、シングルトンのインスタンスは1つだけです。
残りのコードベースと完全に別のライブラリ(サードパーティライブラリなど)がある場合は、それをdllにすることを検討してください。ライブラリがLGPLの場合、ライセンス条件により、とにかくDLLを使用する必要がある場合があります。