コンパイルとリンクのプロセスはどのように機能しますか?
(注:これは、StackOverflowのC ++ FAQへのエントリを意味します。このフォームでFAQを提供するというアイデアを批評したい場合は、これをすべて開始したメタへの投稿がそのための場所になります。その質問は、FAQのアイデアが最初に始まったC ++チャットルームで監視されているため、アイデアを思いついた人があなたの答えを読む可能性が非常に高くなります。)
C ++プログラムのコンパイルには、次の3つのステップが含まれます。
前処理:プリプロセッサはC ++ソースコードファイルを受け取り、#include
s、#define
s、およびその他のプリプロセッサディレクティブを処理します。このステップの出力は、プリプロセッサディレクティブのない「純粋な」C ++ファイルです。
コンパイル:コンパイラはプリプロセッサの出力を受け取り、そこからオブジェクトファイルを生成します。
リンク:リンカは、コンパイラによって生成されたオブジェクトファイルを取得し、ライブラリまたは実行可能ファイルのいずれかを生成します。
プリプロセッサは、およびのようなプリプロセッサディレクティブを処理します。これはC ++の構文に依存しないため、注意して使用する必要があります。#include
#define
#include
ディレクティブをそれぞれのファイルのコンテンツ(通常は単なる宣言)に置き換え、マクロ(#define
)を置き換え#if
、#ifdef
および#ifndef
ディレクティブに応じてテキストの異なる部分を選択することにより、一度に1つのC ++ソースファイルで機能します。
プリプロセッサは、前処理トークンのストリームで機能します。マクロ置換は、トークンを他のトークンに置き換えることとして定義され##
ます(オペレーターは、意味がある場合に2つのトークンをマージできるようにします)。
このすべての後、プリプロセッサは、上記の変換の結果として生じるトークンのストリームである単一の出力を生成します。また、各行がどこから来たのかをコンパイラーに通知するいくつかの特別なマーカーを追加して、それらを使用して適切なエラーメッセージを生成できるようにします。
#if
および#error
ディレクティブを巧妙に使用すると、この段階でいくつかのエラーが発生する可能性があります。
コンパイルステップは、プリプロセッサの各出力で実行されます。コンパイラは、純粋なC ++ソースコード(現在はプリプロセッサディレクティブなし)を解析し、それをアセンブリコードに変換します。次に、基盤となるバックエンド(ツールチェーンのアセンブラー)を呼び出して、そのコードをマシンコードにアセンブルし、実際のバイナリファイルを何らかの形式(ELF、COFF、a.out、...)で生成します。このオブジェクトファイルには、入力で定義されたシンボルのコンパイル済みコード(バイナリ形式)が含まれています。オブジェクトファイル内のシンボルは名前で参照されます。
オブジェクトファイルは、定義されていないシンボルを参照できます。これは、宣言を使用し、その定義を提供しない場合に当てはまります。コンパイラはこれを気にせず、ソースコードが整形式である限り、オブジェクトファイルを問題なく生成します。
コンパイラーでは通常、この時点でコンパイルを停止できます。これを使用すると、各ソースコードファイルを個別にコンパイルできるため、これは非常に便利です。これが提供する利点は、1つのファイルのみを変更する場合に、すべてを再コンパイルする必要がないことです。
生成されたオブジェクトファイルは、後で簡単に再利用できるように、静的ライブラリと呼ばれる特別なアーカイブに入れることができます。
構文エラーや失敗したオーバーロード解決エラーなどの「通常の」コンパイラエラーが報告されるのは、この段階です。
リンカは、コンパイラが生成したオブジェクトファイルから最終的なコンパイル出力を生成するものです。この出力は、共有(または動的)ライブラリ(名前は似ていますが、前述の静的ライブラリとの共通点はあまりありません)または実行可能ファイルのいずれかです。
未定義のシンボルへの参照を正しいアドレスに置き換えることにより、すべてのオブジェクトファイルをリンクします。これらの各シンボルは、他のオブジェクトファイルまたはライブラリで定義できます。標準ライブラリ以外のライブラリで定義されている場合は、リンカに通知する必要があります。
この段階で最も一般的なエラーは、定義の欠落または定義の重複です。前者は、定義が存在しない(つまり、定義が書き込まれていない)か、定義が存在するオブジェクトファイルまたはライブラリがリンカーに渡されなかったことを意味します。後者は明らかです。同じシンボルが2つの異なるオブジェクトファイルまたはライブラリで定義されています。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加