コンパイラとは? ソースコードからマシンコードへ
コンパイラは、あなたが書いたソースコードを、コンピュータが実行できる低レベルの形式へ、通常はプログラムの実行前に一度に翻訳するプログラムです。
C、Rust、Goのような言語でコードを書くとき、CPUはそのテキストを直接実行できません。コンパイラはソースを読み、エラーがないか検査し、マシンが実行できる実行可能ファイル (または中間形式) を生成します。コンパイルは事前に行われるため、ほとんどの誤りはプログラムが起動する前に捕捉され、生成されるバイナリは高速に動作する傾向があります。
コンパイラが実際にすること
コンパイラは段階的に動作します。ソースをトークン化し (lexing) 、構造を表す木を構築し (parsing) 、型とルールを検査し (意味解析) 、最後にターゲットコードを出力します。各段階でプログラムを拒否できるため、コンパイル段階は強力な正しさのgateでもあります。
コンパイラ vs インタプリタ
コンパイラはプログラム全体を実行前に翻訳し、自己完結したartifactを生成します。インタプリタは実行時にコードを1行ずつ読んで実行します。コンパイル言語は通常より速く動作し、インタプリタ言語は通常より速く起動し反復しやすいです。
コンパイルが生成するもの
- 特定のCPUアーキテクチャ向けのネイティブなマシンコード (例: x86-64やARM) 。
- JavaやC#が行うような、仮想マシン向けのbytecode。
- まったく別の言語。この場合ツールはしばしばトランスパイラと呼ばれます。
- 診断: 不正なbuildを早期に止めるエラーと警告。
なぜコンパイラが重要か
翻訳を超えて、コンパイラは最適化します。関数をインライン化し、デッドコードを除去し、より速く動くよう命令を並べ替えます。また言語の型システムを強制し、バグのまるごと1つのクラスを、本番のインシデントではなくコンパイル時エラーへと変えます。
簡単な例
gcc main.c -o app を実行すると main.c を読み、コンパイルし、app という実行可能ファイルを書き出します。未宣言の変数を参照すると、コンパイラは止まり、壊れたバイナリを生成する代わりにエラーを表示します。
CIにおけるコンパイラ
コンパイル段階はbuildの中で最も高コストな部分であることが多く、CPUとメモリに敏感です。大きなコンパイルは小さなrunnerでは遅く、メモリを使い切ると強制終了されることさえあります。より大きなrunner (Latchkeyが提供) はコンパイル時間を短縮し、一時的なout-of-memoryやtoolchainの不調は自動でリトライできるため、1つの不正なbuildがmergeをブロックしません。
重要なポイント
- コンパイラは、プログラムの実行前にソースコードをマシンコードや別の低レベル形式へ翻訳します。
- エラーを早期に捕捉し、速度のために出力を最適化できます。
- コンパイルはbuildの中で最も重く、CPUとメモリに制約される段階であることが多いです。