Makefile
Makefileとは
Makefileは、複数のソースコードから構成されるプログラムをコンパイルするために、手順や関連ファイルを記述するファイルです。
makefileが存在するディレクトリ内において、makeコマンドを実行することでMakefileの記述に基づいてソースコードがコンパイルされ、実行ファイルが生成されます。
makeコマンド
makeは、依存関係のある複数のソースコードを一元的に一括してプログラムを生成するための仕組みを提供するプログラムです。
makeコマンドを実行するとMakefileが読み込まれます。Makefileファイルに記述された実行規則に従ってコンパイル処理を実行していきます。
Makefileの作り方
ルール
Makefile書式は下記の形式であり、この一節の記述を「ルール」といいます。
ターゲットは処理を行うために識別子を記述し、コマンドにはターゲットを作成するための処理内容を記述します。
コマンドは複数行を記述することも可能です。なお、コマンドの前の空白は<Tab>を指定する必要があります。
ターゲット:
コマンド
簡単な例をあげると、以下のようなMakefileを作成して「make」コマンドを実行すると、ファイルの作成を行うことができます。
all: a b
a:
touch a.txt
b:
echo message > b.txt
タスク
ターゲットとして、生成するファイルの識別子ではなく、作業を行うためのコマンド識別子を記述することができます。
実際に存在しないファイル名を指定することから「擬似ターゲット」「ダミーターゲット」と呼ばれることもあります。
「.PHONY」は,タスクターゲットを宣言するためのターゲットです。「phony」とは「偽の、まやかしの」という意味です。
タスクターゲットは「.PHONY」ターゲットを使わず作ることもできます。
ただし、タスク名と同名のファイルやディレクトリがある場合に正常処理ができない可能性がありますので、「.PHONY」は積極的に記述したほうがよいといえます。
.PHONY: タスク名
タスク名:
タスクを行うためのコマンド
下記のように記述して「make clean」コマンドを実行すると、「.o」拡張子のオブジェクトファイルが削除する削除されます。
.PHONY: clean
clean:
rm -f *.o
複数のターゲットをまとめて1つのターゲットとして扱いたい場合には、コマンド行を記述しないターゲットを定義することが可能です。
「;」は依存ターゲットとコマンド行のセパレータの意味を持っています。
下記は、「clean」と「build」を行うことを定義しています。
.PHONY: rebuild
rebuild: clean build ;
ターゲットの依存関係
ターゲットの依存関係とはターゲットを構成するために必要な部品となるターゲットを明記することです。
依存ターゲットが記述されている場合、ターゲット間の依存関係を解決して処理を行います。
また、makeコマンドはターゲットの更新日時を比較してコマンド行を実行すべきかどうかということも判断します。
ターゲット: 依存ターゲット
コマンド
コメント
Makefile内にコメントを記述する場合は、行頭に「#」を記述します。
# Hello Worldを出力する
all:
@echo Hello World!
Makefile効率化
マクロ定義
固定文字列を変数として定義し、Makefile内で変数として利用することができます。
マクロの宣言は以下の形式となります。
マクロ名 = 値
マクロの取り出し(変数の取り出し)は以下の2方法があります。
$(マクロ名)
${マクロ名}
自動変数
自動変数は、ルールが実行される際のターゲットや依存関係に基づいて値が計算・定義される変数です。
$@ | 当該ルールのターゲット名 |
$? | ターゲットより更新時刻が新しいすべての依存ターゲット名 |
$% | ターゲットがアーカイブメンバだったときのターゲットメンバ名 |
$* | サフィックスを除いたターゲット名 |
$< | 依存ターゲット名の先頭要素。 |
$^ | すべての依存ターゲット名 |
$+ | Makefileと同じ順番の依存するファイルの名前 |
サフィックスルール
サフィックスとは拡張子の意味であり、ファイルの拡張子に反応して、自動的に生成コマンドを適用するルールをサフィックスルールといいます。
例えば「.c.o: 」というターゲットは、「.o」ファイルが必要になれば、これを「.c」ファイルからつくるというルールであり、C言語では必ず「.c」から「.o」ファイルが作られるということをルール化したものです。
自動変数である「$<(先頭の依存ターゲット)」とセットで使用します。
.c.o:
$(CC) -c $<
テンプレート
CC = gcc
CFLAGS = -Wall -O2
LDFLAGS =
INCLUDES = -I/usr/local/include
LIBS = -L/usr/local/lib -lm
TARGET = prog
OBJS = file1.o file2.o
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
.PHONY: clean
clean:
-rm -f $(OBJS)
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $<