1. ホーム
  2. c++

[解決済み] コンパイル・リンクはどのように行われるのですか?

2022-03-20 14:19:12

質問

コンパイルとリンクはどのように行われるのですか?

<サブ (注) これは スタックオーバーフローのC++ FAQ . もし、このような形でFAQを提供することを批判したいのであれば すべての始まりとなったmetaへの投稿 は、そのための場所でしょう。その質問に対する回答は C++チャットルーム そのため、あなたの回答は、そのアイデアを思いついた人たちに読まれる可能性が非常に高いのです)。

解決方法は?

C++プログラムのコンパイルには、3つのステップがあります。

  1. プリプロセッシング:プリプロセッサはC++のソースコード・ファイルを受け取り、そのファイルに対して #include s, #define などのプリプロセッサーディレクティブを使用します。このステップの出力は、プリプロセッサ指示子のない "pure" C++ ファイルです。

  2. コンパイル:コンパイラはプリプロセッサの出力を受け取り、そこからオブジェクトファイルを生成する。

  3. リンカ:コンパイラが生成したオブジェクトファイルをリンカが受け取り、ライブラリまたは実行可能ファイルを生成する。

プリプロセッシング

プリプロセッサーは プリプロセッサーディレクティブ のように #include#define . C++の文法にとらわれないので、使用には注意が必要です。

一度に1つのC++ソースファイルに対して動作させるためには #include ディレクティブをそれぞれのファイルの内容 (通常は単なる宣言) に置き換えたり、マクロ ( #define に応じてテキストの異なる部分を選択することができます。 #if , #ifdef#ifndef ディレクティブを使用します。

プリプロセッサは、前処理用トークンのストリームに対して動作します。マクロ置換とは、トークンを他のトークンに置き換えることである(演算子 ## 2つのトークンを合成することができます。)

この後、プリプロセッサは、上記の変換の結果得られたトークンのストリームを1つの出力として生成します。また、各行がどこから来たかをコンパイラに伝える特別なマーカーも追加され、コンパイラはそれを使って適切なエラーメッセージを生成できるようになります。

いくつかのエラーは、この段階で #if#error ディレクティブを使用します。

コンパイル

コンパイルのステップは、プリプロセッサの各出力に対して実行されます。コンパイラは、純粋なC++ソースコード(現在はプリプロセッサ指示文なし)を解析し、アセンブリコードに変換します。そして、そのコードを機械語にアセンブルし、何らかのフォーマット(ELF, COFF, a.out, ...)で実際のバイナリファイルを生成するバックエンド(ツールチェインのアセンブラ)を呼び出すのです。このオブジェクトファイルには、入力で定義されたシンボルのコンパイル済みコード(バイナリ形式)が含まれています。オブジェクト・ファイル内のシンボルは、名前で参照されます。

オブジェクトファイルは、定義されていないシンボルを参照することができます。これは、宣言を使用し、その宣言を定義していない場合です。コンパイラはこれを気にせず、ソースコードが正しい形式である限り、喜んでオブジェクトファイルを生成します。

コンパイラは通常、この時点でコンパイルを停止させることができます。これを使えば、各ソースコード・ファイルを別々にコンパイルできるので、非常に便利です。というのも、これを使うと、各ソースコードファイルを別々にコンパイルすることができるからです。 すべて を変更した場合、1つのファイルだけを変更した場合です。

生成されたオブジェクトファイルは、静的ライブラリと呼ばれる特別なアーカイブに入れることで、後々の再利用が容易になります。

この段階で、シンタックスエラーやオーバーロードの解決に失敗したエラーなど、通常のコンパイラーエラーが報告されます。

リンク

リンカーは、コンパイラーが生成したオブジェクトファイルから、最終的なコンパイル出力を生成するものである。この出力は、共有(または動的)ライブラリ(名前は似ていますが、先に述べた静的ライブラリとはあまり共通点がありません)か、実行ファイルになります。

未定義のシンボルへの参照を正しいアドレスに置き換えることで、すべてのオブジェクトファイルをリンクします。これらのシンボルはそれぞれ、他のオブジェクトファイルやライブラリで定義されていることがあります。もし、標準ライブラリ以外のライブラリで定義されている場合は、リンカにそのことを伝える必要があります。

この段階で最も多いエラーは、定義の欠落や定義の重複です。前者は、定義が存在しない(書き込まれていない)か、定義が存在するオブジェクトファイルやライブラリがリンカに渡されなかったことを意味します。後者は、同じシンボルが2つの異なるオブジェクト・ファイルやライブラリで定義されていることを意味し、明らかです。