web-dev-qa-db-ja.com

標準ライブラリをC ++プログラムに静的にリンクするにはどうすればよいですか?

私はCode :: Blocks IDE(v13.12)をGNU GCCコンパイラで使用しています。

  1. プログラムに必要なランタイムライブラリの静的バージョンをリンカにリンクさせたいのですが、どうすればよいですか?
  2. 実行可能ファイルのサイズが大きくなることはすでに知っていますが、他の欠点を教えてください。
  3. Visual C++ Expressでこれを行うのはどうですか?
8
AmRCPP

まだ誰も答えを出していないので、やってみます。残念ながら、Code :: Blocks IDEであることがわからないため、私の答えは部分的なものにすぎません。

1GCCで静的にリンクされた実行可能ファイルを作成する方法

これはIDE固有ではありませんが、GCC(および他の多くのコンパイラ)一般に当てはまります。_main.cpp_に単純な「hello、world」プログラムがあると仮定します(外部依存関係はありません。標準ライブラリとランタイムライブラリ)。コンパイルして静的にリンクします。

  1. _main.cpp_を_main.o_にコンパイルします(出力ファイル名は暗黙的です):

    _$ g++ -c -Wall main.cpp
    _

    _-c_は、コンパイルステップの後で停止するようにGCCに指示します(リンカーを実行しないでください)。 _-Wall_は、ほとんどの診断メッセージをオンにします。初心者のプログラマーがそれをより頻繁に使用し、それにもっと注意を払うならば、このサイトの多くの質問は尋ねられなかっただろう。 ;-)

  2. リンク_main.o_(複数のオブジェクトファイルをリストできます)は、標準ライブラリとランタイムライブラリを静的にプルし、実行可能ファイルをファイルmainに配置します。

    _$ g++ -o main main.o -static
    _

    _-o main_スイッチを使用しないと、GCCは最終的な実行可能ファイルをあまり名前のないファイル_a.out_(かつては「アセンブリ出力」の略)に入れていたでしょう。

特に最初は、ビルドツールチェーンをよりよく理解するのに役立つため、このようなことを「手作業で」行うことを強くお勧めします。

実際のところ、上記の2つのコマンドを1つにまとめることができます。

_$ g++ -Wall -o main main.cpp -static
_

妥当なIDEには、そのようなコンパイラ/リンカフラグを指定するためのオプションが必要です。

2静的リンクの長所と短所

理由for静的リンク:

  • 互換性のあるアーキテクチャとオペレーティングシステムを備えた任意のマシンにコピーできる単一のファイルがあり、インストールされているライブラリのバージョンに関係なく、それは正常に機能します。

  • 共有ライブラリが利用できない環境でプログラムを実行できます。たとえば、静的にリンクされたCGI実行可能ファイルをchroot()刑務所に入れると、Webサーバーの攻撃対象領域を減らすのに役立つ場合があります。

  • ダイナミックリンクは必要ないので、プログラムの起動mightが速くなります。 (特に共有ライブラリが別のプロセス用にすでにロードされている場合は、逆のことが当てはまる状況があると確信しています。)

  • リンカは関数アドレスをハードコーディングできるため、関数呼び出しmightの方が高速です。

  • 共通ライブラリの複数のバージョン(LAPACKなど)がインストールされているシステムでは、静的リンクを使用すると、_LD_LIBRARY_PATH_を正しく設定することを心配せずに、特定のバージョンを常に使用できます。明らかに、これはデメリットでもあります。これは、再コンパイルせずにcannotライブラリを選択するためです。常に同じバージョンが必要な場合、そもそも複数のバージョンをインストールしたのはなぜですか?

理由に対して静的リンク:

  • すでに述べたように、実行可能ファイルのサイズは劇的に大きくなる可能性があります。もちろん、これはリンク先のライブラリに大きく依存します。

  • オペレーティングシステムは、共有ライブラリのテキストセクションをRAMに1回だけロードするのに十分賢い場合があります。複数のプロセスが同時にライブラリを必要とする場合、静的にリンクすることで、この利点を無効にし、システムのメモリがすぐに不足する可能性があります。

  • あなたのプログラムはもはやライブラリのアップグレードから利益を得ていません。システム管理者は、1つの共有ライブラリを(できればABI互換の)新しいリリースに置き換えるだけでなく、それを使用するeveryプログラムを再コンパイルして再インストールする必要があります。これは私の意見では最も深刻な欠点です。

    たとえば、OpenSSLライブラリについて考えてみます。 Heartbleedのバグが発見され、今年初めに修正されたとき、システム管理者はパッチを適用したバージョンのOpenSSLをインストールし、すべてのサービスを再起動して、パッチがリリースされてから1日以内に脆弱性を修正できました。つまり、サービスがOpenSSLに対して動的にリンクしている場合です。静的にリンクされているものの場合、最後のソフトウェアが修正されるまでに数週間かかり、現在まで修正されていないプロプライエタリな「オールインワン」ソフトウェアがまだ出回っていると確信しています。日。

  • ユーザーは、共有ライブラリをその場で置き換えることはできません。たとえば、torsocksスクリプト(および関連するライブラリ)を使用すると、ユーザーはネットワークシステムライブラリを(_LD_PRELOAD_を適切に設定することにより)Torネットワーク経由でトラフィックをルーティングするライブラリに置き換えることができます。そしてこれは、開発者がその可能性すら考えたことのないプログラムでも機能します。 (これが安全であり、良いアイデアが無関係な議論の対象であるかどうか。)他の一般的なユースケースは、mallocなどを特殊なバージョンに置き換えることによるアプリケーションのデバッグまたは「強化」です。

私の意見では、静的リンクの欠点は、非常に特殊な場合を除いてすべての利点を上回ります。経験則として:可能な場合は動的にリンクし、必要な場合は静的にリンクします。

補遺

Alf が指摘しているように(コメントを参照)、C++標準ライブラリを静的に選択的にリンクするが、プログラム全体を静的にリンクしない特別なGCCオプションがあります。 GCCマニュアル から:

_-static-libstdc++_

G ++プログラムを使用してC++プログラムをリンクする場合、通常はlibstdc ++に対して自動的にリンクします。 libstdc ++が共有ライブラリとして利用可能であり、_-static_オプションが使用されていない場合、これはlibstdc ++の共有バージョンに対してリンクします。通常は問題ありません。ただし、完全に静的なリンクに移動せずに、プログラムで使用されるlibstdc ++のバージョンをフリーズすると便利な場合があります。 _-static-libstdc++_オプションは、他のライブラリを静的にリンクする必要はなく、g ++ドライバーにlibstdc ++を静的にリンクするように指示します。

28
5gon12eder

Visual C++では、/ MTオプションは静的リンクを実行し、/ MDオプションは動的リンクを実行します。 ( http://msdn.Microsoft.com/en-us/library/2kzt1wy3.aspx を参照)

/ MDを使用し、Microsoftから無料で入手できるC++ランタイムを再配布することをお勧めします。 C++ランタイムがインストールされると、ランタイムを必要とするどのプログラムも引き続き機能します。使用するランタイムをコンパイラーに指示するには、適切なオプションを渡す必要があります。ここに良い説明があります / MDまたは/ MTでコンパイルする必要がありますか?

Linuxでは、静的リンクの代わりにlibstdc ++を再配布することをお勧めします。彼らのシステムlibstdc ++が機能する場合、私はユーザーにそれを使用させるでしょう。 libpthreadやlibgccなどのシステムライブラリは、システムのデフォルトを使用する必要があります。これには、配布するすべてのLinuxバージョンと互換性のあるシンボルを使用してシステム上でプログラムをコンパイルする必要があります。

Mac OS Xでは、libstdc ++へのダイナミックリンクを使用してアプリを再配布するだけです。同じOSバージョンを使用している人は誰でもあなたのプログラムを使用できるはずです。

2
Juan