動的ライブラリと静的ライブラリを使用する場合


437

C ++でクラスライブラリを作成する場合、動的(.dll.so)および静的(.lib.a)ライブラリから選択できます。それらの違いは何ですか?いつ使用するのが適切ですか?


2
「インポートライブラリ」と呼ばれるものもあることに注意してください。stackoverflow.com/ questions / 3573475 /…
和漢短歌

回答:


299

静的ライブラリは、バイナリのコードのサイズを増やします。これらは常に読み込まれ、コンパイルしたコードのどのバージョンも実行されるコードのバージョンです。

動的ライブラリは個別に保存およびバージョン管理されます。更新が元のバージョンとバイナリ互換であると見なされた場合、コードに同梱されていた元のバージョンではないバージョンのダイナミックライブラリが読み込まれる可能性があります。

さらに、動的ライブラリは必ずしもロードされる必要はありません-通常、最初に呼び出されたときにロードされます-同じライブラリを使用するコンポーネント間で共有できます(複数のデータロード、1つのコードロード)。

ほとんどの場合、ダイナミックライブラリはより優れたアプローチであると考えられていましたが、元々は重大な欠陥(google DLL hell)がありましたが、最近のWindows OS(特にWindows XP)によってほぼ完全に排除されました。


71
Windows / Mac(パッケージマネージャーなし)では、静的ライブラリよりも動的ライブラリを使用する正当な理由はありません。Windows DLLは再配置可能ではないため、コード共有は機能しないことがよくあります(通常、各アプリは独自のバージョンのライブラリを出荷して使用します)。唯一の真の利点は、ライブラリの更新が簡単になることです。
Zifre 2009年

5
Macでは、多くのダイナミックライブラリを使用しています。たとえば、mac os xにはsqlite3が埋め込まれています。パフォーマンスを保存するためのsqlite3データベース機能を備えたプログラムを作成しました。ただし、動的リンクを使用することはめったにないため、コンパイル時間を節約し、テストをより簡単/高速にします。ただし、リリースバージョンをビルドする場合、互換性の問題が発生した場合に備えて、常に静的ライブラリを使用すると思います
ReachConnection

6
@Zifre:relocatable =別の仮想アドレスにロードできます。DLLは確かにこれをサポートしています。
dma_k

20
@dma_k:Windows DLLは異なるアドレスにロードできますが、これは、リンカーがすべてのコードをコピーしてアドレス番号を変更するためです。共有オブジェクトでは、すべてのアドレス参照が相対であるため、複数のプロセスが共有オブジェクトの同じメモリを共有できます。つまり、Windowsでは、3つのプログラムで使用される1 MBのDLL = 3 MBです。Linuxでは、3つのプログラムで使用されるA MB SO = 1 MB。
Zifre

7
WindowsとLinuxの両方に、共有ライブラリeli.thegreenplace.net/2011/08/25/ のload-timte relocationの概念があります。PositionIndependent Codeを許可した最大のものはLinuxにとって特別なものではなく、RIP相対アドレス指定が追加されましたx64命令セットを使用。WindowsとLinuxの両方でRIP相対アドレッシングを利用できるため、ライブラリを再配置するときの修正の数が減ります。
clemahieu 2013

194

静的ライブラリとは何かについては十分に説明している人もいますが、少なくとも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()する場合、望ましくない驚くべき結果が得られる可能性があります。


23
シングルトンに関する要点については、DLLが複数回ロードされる可能性があり(同じバージョンまたは複数のバージョン)、シングルトンの保証はないことを忘れないでください。
オリオンエイドリアン

参照されないコードの削除に関する追加のポイント:DLLへの呼び出しには、参照されるDLLを強制的にロードするための実際の呼び出しも必要です。それを参照として追加しても、それを参照する呼び出しを含めない場合でも、何も呼び出さない静的ライブラリがある場合と同じ結果が得られます。唯一の違いは、実際に出荷されるものです。どちらの場合も、静的コンストラクタとデストラクタは起動しません。
Orion Adrian

@ bk1eそれは起こらないはずです。.aは常に、それを使用して作成されたすべてのシンボルを含みます。それはアプリケーションに静的にリンクされている場合は、[はいのみ使用され、これらのシンボルはにリンクされます。
マイル敗走

62

libは、アプリケーション実行可能ファイル内にバンドルされているコードの単位です。

dllは、実行可能コードのスタンドアロン単位です。そのコードが呼び出されたときにのみプロセスに読み込まれます。dllは複数のアプリケーションで使用でき、複数のプロセスでロードできますが、ハードドライブにはコードのコピーが1つしかありません。

Dllプロ:複数の製品間でコードを再利用/共有するために使用できます。オンデマンドでプロセスメモリにロードし、不要なときにアンロードできます。プログラムの他の部分とは無関係にアップグレードできます。

DLLの短所:DLLの読み込みとコードのリベースのパフォーマンスへの影響。バージョン管理の問題( "dll hell")

Libプロ:コードは常にプロセスに読み込まれ、リベースされないため、パフォーマンスへの影響はありません。バージョン管理の問題はありません。

Lib cons:実行可能ファイル/プロセスの「膨張」-すべてのコードは実行可能ファイルにあり、プロセスの開始時にロードされます。再利用/共有なし-各製品には独自のコードのコピーがあります。


リベースは、ビルド時にrebase.exeを使用するか、/ BASEオプションをlink.exeに渡すことでも実行できます。これが効果的であるかどうかは、実行時に予期しないアドレス空間の競合があるかどうかによって異なります。
bk1e 2008

24

静的ライブラリと動的ライブラリの技術的な影響(静的ファイルはすべてを1つの大きなバイナリと動的ライブラリにバンドルし、複数の異なる実行可能プログラム間でコードを共有できるようにする)に加えて、法的な影響があります。

たとえば、LGPLライセンスコードを使用していて、LGPLライブラリに対して静的にリンクしている(したがって、1つの大きなバイナリを作成している)場合、コードは自動的にオープンソース(自由に自由) LGPLコードになります。共有オブジェクトに対してリンクする場合は、LGPLライブラリ自体に対して行った改善/バグ修正のみをLGPLに行う必要があります。

たとえば、モバイルアプリケーションをコンパイルする方法を決定する場合、これははるかに重要な問題になります(Androidでは静的か動的かを選択できますが、iOSでは選択できません-常に静的です)。


23

C ++プログラムは2つのフェーズで構築されます

  1. コンパイル-オブジェクトコード(.obj)を生成します
  2. リンク-実行可能コード(.exeまたは.dll)を生成します

静的ライブラリ(.lib)は.objファイルの単なるバンドルであるため、完全なプログラムではありません。プログラム構築の第2(リンク)フェーズは実行されていません。一方、DLLはexeに似ているため、完全なプログラムです。

静的ライブラリを構築する場合、まだリンクされていないため、静的ライブラリのコンシューマは、使用したのと同じコンパイラを使用する必要があります(g ++を使用する場合は、g ++を使用する必要があります)。

代わりにdllをビルドした(そしてそれを正しくビルドした)場合、どのコンパイラーを使用しているかに関係なく、すべてのコンシューマーが使用できる完全なプログラムをビルドしたことになります。ただし、コンパイラー間の互換性が必要な場合、dllからのエクスポートにはいくつかの制限があります。


1
これは私にとってニュースです。DLLを使用する場合、クロスコンパイラーにはどのような制限がありますか?同じツールチェーンを必要とせずにプログラマーをビルドさせることは、DLLにとって大きなプラスのようです
Dan

1
この回答は有益です。マイナーな警告を追加:consumers of your static library will have to use the same compiler that you used静的ライブラリがC ++ライブラリ(など)を使用する場合#include <iostream>
トゥルーアジャスター

同じコンパイラを使用しない限り、c ++ dllを使用することはできません(標準のc ++ abiがないため、シンボルはさまざまな方法で変換されます)。DLLとクライアントモジュールの両方で同じコンパイラと同じビルド設定を使用する必要があります
kcris

19

静的ライブラリを作成する

$$:~/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]>

13

静的ライブラリがクライアントにコンパイルされます。.libはコンパイル時に使用され、ライブラリの内容は使用可能な実行可能ファイルの一部になります。

動的ライブラリは実行時にロードされ、クライアント実行可能ファイルにコンパイルされません。複数のクライアント実行可能ファイルがDLLをロードしてその機能を利用できるため、動的ライブラリはより柔軟です。これにより、クライアントコードの全体的なサイズと保守性も最小限に抑えられます。


13

時間の経過に伴う変更、バージョン管理、安定性、互換性などについて慎重に検討する必要があります。

共有コードを使用する2つのアプリがある場合、相互に互換性が必要な場合に備えて、それらのアプリを強制的に一緒に変更しますか?次に、dllを使用します。すべてのexeは同じコードを使用します。

または、それらを互いに分離して、一方を変更し、もう一方を壊していないと確信できるようにしますか?次に、静的libを使用します。

DLL地獄は、おそらく静的ライブラリを使用する必要があるはずですが、代わりにdllを使用した場合で、すべてのexeがそれに対応しているわけではありません。


9

静的ライブラリを最終的な実行可能ファイルにリンクする必要があります。それは実行可能ファイルの一部になり、どこへでもそれに従います。動的ライブラリは、実行可能ファイルが実行されるたびにロードされ、DLLファイルとして実行可能ファイルから分離されたままになります。

実行可能ファイルを再リンクせずにライブラリによって提供される機能を変更できるようにする場合は、DLLを使用します(実行可能ファイルを置き換える必要なく、DLLファイルを置き換えるだけです)。

動的ライブラリを使用する理由がない限り、静的ライブラリを使用します。


他の複数のアプリケーションが同じ機能を使用する場合、DLLを使用することもできます-これにより、フットプリントを削減できます。
Tim

また、最初のコンセプトである「プラグイン」アーキテクチャを拡張して、後で追加または不明な機能を再構築または再リリースせずに許可するには、動的ライブラリを使用する必要があります。
Tim

8

Ulrich Drepperの「共有ライブラリの書き方」に関する論文は、共有ライブラリを最大限に活用する方法、または彼が「動的共有オブジェクト」(DSO)と呼ぶものを詳しく説明する優れた資料でもあります。ELFバイナリ形式の共有ライブラリに重点を置いていますが、一部の説明はWindows DLLにも適しています。



4

本当にあなたがしているトレードオフ(大きなプロジェクトで)は初期ロード時です、ライブラリはいつかリンクされるでしょう、行われなければならない決定は、コンパイラが必要とするのにリンクが長くかかるかどうかです。弾丸を噛んで前もってそれを行うか、または動的リンカーがロード時に行うことができます。


3

ライブラリを複数の実行可能ファイルで共有する場合は、動的にして実行可能ファイルのサイズを小さくすることが理にかなっています。それ以外の場合は、必ず静的にしてください。

DLLの使用にはいくつかの欠点があります。それをロードおよびアンロードするための追加のオーバーヘッドがあります。追加の依存関係もあります。dllを変更して実行可能ファイルと互換性がないようにすると、動作が停止します。一方、静的ライブラリを変更しても、古いバージョンを使用してコンパイルされた実行可能ファイルは影響を受けません。


3

ライブラリが静的な場合、リンク時にコードが実行可能ファイルにリンクされます。これにより、実行ファイルが大きくなります(動的ルートを使用した場合よりも)。

ライブラリが動的な場合、リンク時に必要なメソッドへの参照が実行可能ファイルに組み込まれます。つまり、実行可能ファイルとダイナミックライブラリを出荷する必要があります。また、ライブラリ内のコードへの共有アクセスが、他のものの中で安全な優先ロードアドレスであるかどうかも検討する必要があります。

静的ライブラリを使用できる場合は、静的ライブラリを使用してください。


3

プロジェクトでは多くのDLL(> 100)を使用しています。これらのDLLは相互に依存しているため、動的リンクの設定を選択しました。ただし、次の欠点があります。

  • 起動が遅い(> 10秒)
  • Windowsは名前の一意性に基づいてモジュールをロードするため、DLLはバージョン管理する必要がありました。独自に作成されたコンポーネントは、そうでなければ、DLLの誤ったバージョン(つまり、独自の分散セットの代わりにすでにロードされているもの)を取得します
  • オプティマイザはDLL境界内でのみ最適化できます。たとえば、オプティマイザは頻繁に使用されるデータとコードを隣り合わせに配置しようとしますが、これはDLLの境界を越えて機能しません

たぶん、より良い設定は、すべてを静的ライブラリにすることでした(したがって、実行ファイルは1つだけです)。これは、コードの重複が発生しない場合にのみ機能します。テストはこの仮定をサポートしているようですが、MSDNの公式見積もりを見つけることができませんでした。たとえば、次のようにして1つのexeを作成します。

  • exeはshared_lib1、shared_lib2を使用します
  • shared_lib1はshared_lib2を使用します
  • shared_lib2

shared_lib2のコードと変数は、マージされた最終的な実行可能ファイルに1回だけ存在する必要があります。誰でもこの質問をサポートできますか?


コードの重複を回避するために、いくつかのプリコンパイラディレクティブを何らかの方法で使用するつもりはありませんか?
ペースマン2013年

Afaiacプリコンパイルは、モジュール(exe / dll / lib)ベースでのみ機能します。プリコンパイルは主にコンパイルを高速化することを目的としていますが、コンパイル単位内に複数のインクルードが含まれることも防ぎます。ただし、この効果を実現するには、ガードを含める方が良い方法です。
gast128 2015年

2

静的ライブラリは、アプリケーションにリンクされたときにライブラリのオブジェクトコードを含むアーカイブであり、そのコードは実行可能ファイルにコンパイルされます。共有ライブラリは、実行可能ファイルにコンパイルされないという点で異なります。代わりに、動的リンカーはいくつかのディレクトリを検索して、必要なライブラリを探し、それをメモリにロードします。複数の実行可能ファイルが同じ共有ライブラリを同時に使用できるため、メモリ使用量と実行可能ファイルのサイズが削減されます。ただし、実行可能ファイルと一緒に配布するファイルが他にもあります。ライブラリがリンカが見つけられる場所のusesシステムにインストールされていることを確認する必要があります。静的リンクはこの問題を排除しますが、実行ファイルが大きくなります。


2

組み込みプロジェクトや特殊なプラットフォームの静的ライブラリでの作業が唯一の方法である場合は、多くの場合、アプリケーションにコンパイルする手間が少なくて済みます。また、すべてを含むプロジェクトとmakefileがあると、生活がより楽しくなります。


2

大きなコードベースがある場合、すべてが低レベルのライブラリ(UtilsまたはGuiフレームワークなど)の上に構築され、より管理しやすいライブラリに分割して静的ライブラリにしたいという一般的な経験則を示します。動的ライブラリは実際には何も購入せず、驚きも少​​なくなります。たとえば、シングルトンのインスタンスは1つだけです。

残りのコードベースと完全に別のライブラリ(サードパーティライブラリなど)がある場合は、それをdllにすることを検討してください。ライブラリがLGPLの場合、ライセンス条件により、とにかくDLLを使用する必要がある場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.