C++のコンパイルとリンクの仕組みを初心者向けに解説
生徒
「C++で作ったプログラムを実行するには何をするんですか?」
先生
「C++では、まずコンパイルをしてソースコードを機械語に変換し、次にリンクをして一つの実行ファイルにまとめます。」
生徒
「コンパイルとリンクの違いがよくわかりません…。」
先生
「簡単にいうと、コンパイルはレシピを翻訳して調理手順に変える作業、リンクは別々の材料を一つの完成料理にまとめる作業です。」
1. コンパイルとは?
C++のソースコード(.cppファイル)は、人間が読める言葉で書かれています。コンパイルとは、このコードをコンピュータが理解できる機械語(オブジェクトファイル)に変換する作業です。例えると、英語のレシピを日本語に翻訳するような作業です。
// コマンド例(GCC)
g++ -c src/main.cpp -o build/main.o
このコマンドでは、main.cppをコンパイルしてmain.oというオブジェクトファイルを作成しています。-cオプションが「コンパイルのみ」を意味します。
2. リンクとは?
リンクは、複数のオブジェクトファイルやライブラリを組み合わせて一つの実行可能ファイルにまとめる作業です。例えば、src/main.oとsrc/greeting.oを一つにしてbuild/my_programという実行ファイルを作る作業です。
// コマンド例(GCC)
g++ build/main.o build/greeting.o -o build/my_program
この作業がないと、コンパイルしただけではプログラムを実行できません。リンクは「完成品を作る最後の工程」と考えるとわかりやすいです。
3. コンパイルとリンクの流れ
一般的なC++プロジェクトでは、次のような流れになります:
- srcにある.cppファイルをコンパイルしてオブジェクトファイル(.o)を作る
- includeフォルダのヘッダファイル(.h/.hpp)を参照しながら、必要な関数やクラスの情報を取り込む
- 複数のオブジェクトファイルをリンクして、最終的な実行ファイルをbuildフォルダに作成する
// 全体の流れ(GCCの場合)
g++ -c src/main.cpp -o build/main.o
g++ -c src/greeting.cpp -o build/greeting.o
g++ build/main.o build/greeting.o -o build/my_program
これでbuild/my_programを実行すれば、プログラムが動作します。
4. ヘッダファイルとリンクの関係
ヘッダファイル(.h/.hpp)は、関数やクラスの宣言だけを書きます。実体は.cppに書かれているので、コンパイル時に「宣言を知る」ために必要です。リンク時に実体が結合され、最終的な実行ファイルが生成されます。
// include/greeting.hpp
#ifndef GREETING_HPP
#define GREETING_HPP
void sayHello();
#endif
// src/greeting.cpp
#include <iostream>
#include "greeting.hpp"
void sayHello() {
std::cout << "Hello World!" << std::endl;
}
このように、ヘッダファイルは「約束事」、cppファイルは「実際の処理」というイメージです。
5. MakefileやCMakeで自動化
大きなプロジェクトでは、手動でコンパイル・リンクを行うのは大変です。MakefileやCMakeを使うと、自動的に依存関係を解析してコンパイル・リンクを実行してくれます。これにより、初心者でも効率的にC++開発ができます。
# Makefile例
all: my_program
my_program: main.o greeting.o
g++ main.o greeting.o -o my_program
main.o: src/main.cpp
g++ -c src/main.cpp -o main.o
greeting.o: src/greeting.cpp
g++ -c src/greeting.cpp -o greeting.o