gccとは
コードのコンパイルは通常、複数の様々な処理を踏まないとできません。それを一括でやってくれるのがgccコンパイラです。
ここでは、CとC++のコンパイル機能に絞って記載します。
入力されたファイルは以下の4つの処理(のいずれか、または全部)をされて、実行できる形にコンパイルされます。この一連の処理をまとめて、言語システムと言います。
- プリプロセス
- コンパイル
- アセンブル
- リンク
CとC++によってgccを呼び出すコマンドが異なリます。
gcc # Cのファイル
g++ # C++のファイル
拡張子について
gccはファイルの拡張子を読み取り、どの処理を実施するか判断します。
拡張子 | ファイル形式 | 実行される処理 |
---|---|---|
.c | C言語ソース | プリプロセッサ、コンパイラ、アセンブラ |
.C | C++言語ソース | プリプロセッサ、コンパイラ、アセンブラ |
.cc | C++言語ソース | プリプロセッサ、コンパイラ、アセンブラ |
.cxx | C++言語ソース | プリプロセッサ、コンパイラ、アセンブラ |
.m | Objective-C言語ソース | プリプロセッサ、コンパイラ、アセンブラ |
.i | プリプロセッサ済みC言語ソース | コンパイラ、アセンブラ |
.ii | プリプロセッサ済みC++言語ソース | コンパイラ、アセンブラ |
.s | アセンブリ言語ソース | アセンブラ |
.S | アセンブリ言語ソース | プリプロセッサ、アセンブラ |
.h | プリプロセッサファイル | 通常はコマンドラインには現れません |
.o | オブジェクトファイル | リンカ |
.a | アーカイブファイル | リンカ |
詳細 (処理名 処理を停止されるオプション名)
-
プリプロセッサ(プリコンパイラ)
-E
- コンパイラの前処理、テキストファイルの追加や変換などの処理。#で始まるディレクティブに従って元のCプログラムを別のCプログラムに改変します。拡張子は**.i**
-
コンパイラ
-S
- コンピュータが解釈・実行できるアセンブリ言語の形式に一括して変換。テキストファイル**.iアセンブリ言語プログラムからなるテキストファイル.s**に翻訳。
-
アセンブラ
-c
- アセンブリ言語で記述されたテキストファイルを、マシン語命令に翻訳し、それをリロケータブルオブジェクトプログラムと呼ばれる形にパッケージ化し、その結果をオブジェクトファイルに格納する。ここでプログラムはテキストファイル(人間が読める形式)からコンピュータが直接解釈・実行できるバイナリファイルになる。拡張子は**.o**
-
リンカ(リンケージエディタ)
- 機械語(マシン語)で記述されたプログラム(オブジェクトコード)を連結、編集して実行可能ファイルを作成。hello.cというprintfを呼ぶプログラムの場合は、標準Cライブラリのprintf.oというオブジェクトファイルを結合し、hello.oに結合する。
図はCSAPP1章より
gccオプション
gccのオプションは分割して書く必要あがあります。ひとつの-
に対して、ひとつのオプションが割り振られています。
gccは複雑な処理を行っているため、オプションの数も多いです。ここでは初心者の私が使ったことのあるものや、重要だと思ったものを取り上げます。
全体的なオプション
-c
ソースファイルをコンパイルまたはアセンブルしますが、リンクはしません。処理されたファイルは、オブジェクトファイルとして出力されます。
デフォルトの設定ではソースファイルのオブジェクトファイル名の拡張子を.o
に置き換えて作成されます。
$ gcc -c test.c
=> test.o
$ gcc -c test1.c test2.c
=> test1.o test2.o
# test1.c test2.cがディレクトリ内にあるときワイルドカードも使える
$ gcc -c *.c
=> test1.o test2.o
$ gcc test1.c test2.c
=> clang: error: linker command failed with exit code 1 (use -v to see invocation)
=> 2つのコードに対してリンカの処理はできないためエラー
-o [file]
作成されるファイルの種類に関係なく、与えられた[file]という出力先に出力します。出力先がない場合は生成されます。
-cオプションを使用せず、-oオプションで名前を指定しない限り、cファイルだとa.out
が出力されます。
$ gcc -o test test.c
=> test
$ gcc test.c -o test
=> test
$ gcc test1.c test2.c -o test
=> clang: error: cannot specify -o when generating multiple output files
=> 2つのどっちにtestという出力をすればいいのか分からないからエラー
警告オプション
警告は、本質的に間違いであるわけではありませんが、危険な構造を報告したり、エラーがあるかもしれないような部分を示唆する診断メッセージです。以下のオプションは、GNU CCが生成する警告の量と種類を制御します。
-
-w
全ての警告メッセージを抑制します。 -
-Wall
一部のユーザーが簡単に回避できる(または警告を回避するように変更できる)構文に関するすべての警告が有効になります。 -
-Wextra
-Wallが含まない警告が有効になります。 -
-Weverything
全ての警告オプションを有効にします。 -
-Werror
すべての警告をエラーにします。
# こんな感じに足していきます。
gcc -Wall -Wextra -Werror test.c
プリプロセッサオプション
Cプリプロセッサを制御します。各Cソースファイルは、実際にコンパイルする前にCプリプロセッサにかけられます。
-include [file]
[file]を、通常の入力ファイルが処理される前に処理します。結果的に[file]に含まれる内容は、一番最初にコンパイルされます。
$ gcc main.c -include sum.c
=> a.out
=> main.cの冒頭で #include "sum.c"を行ったのと同じ実行ファイルになります。
リンカオプション
コンパイラがオブジェクトファイルを実行可能な出力ファイルにリンクするときに機能します。
リンカーは、ライブラリーのディレクトリーの標準リストと-L
で指定されたディレクトリを検索します。
-c
オプションが使用されているときは実行されません。
-l[library]
リンク時にlib[library].aという名前の静的ライブラリ、通常lib[library].soという名前を持つ共有ライブラリを検索します。
こちらのオプションはlのあとにスペースを開けない記述方法が推奨されています。
ディレクトリオプション
ヘッダーファイル、ライブラリー、およびコンパイラーの一部を検索するディレクトリーを指定します。
-I [dir]
ヘッダーファイルを検索するディレクトリのリストにディレクトリ[dir]を追加します。
-L [dir]
ディレクトリ[dir]をリンカオプションの-l
による検索が行なわれるディレクトリのリストに加えます。
最適化を制御するオプション
さまざまな種類の最適化を制御します。最適化のレベルが数字で表されています。
詳しくはこちらのリンクが丁寧に解説してくれています。
GCCの最適化 - Gentoo Wiki
-
-O0
最適化しない。これがデフォルトです。 -
-O1
,-O2
,-O3
の順に最適化が強く設定されますが、順にコンパイル速度が犠牲になります。 -
-Ofast
速さを重視した最適化をします。標準準拠しない最適化も行われます。 -
-Os
サイズを優先した最適化をします。
# 他のオプションと同様に記述します。
gcc -O3 test.c
参考
公式ドキュメント
公式ドキュメントの日本語訳。内容が古いので注意が必要ですが、ざっくり読むのに良かったです。
-l
オプションについては、なかなか理解を助ける記事がなかったですがこちらで触れられていました。
警告オプションは、以下がわかりやすかったです。
CSAPP1章