C言語を使うならMakeを使おうよ

次の理由からいろいろとムズムズしてしまったので、Makeについて書くことにしました。

 1. C言語 Advent Calendar 2015で2日分だけ空きがある。空きが埋まっていればめでたいし、空きがもっと多ければあきらめがつくが…^^;;;
 2. [C言語でシンプルすぎるブロック崩しを書いた](http://qiita.com/pokohide/items/a246045f3ccaf540a375)（C言語 Advent Calendar 2015 13日目）は、プログラムも記事も面白いのに、Makefileの書き方が好みではない
 3. [make触ってみた](http://qiita.com/kimikimi714/items/a9001170be25fcb72e36)（ドワンゴ Advent Calendar 2015 20日目） は参考になる情報が多い良記事だけど、結末が好みではない

なお、ここで取り上げるMakeは、GNU Makeです。Mac OS Xでコマンドラインツールをインストールしたときや、Linuxでは、makeコマンドを実行すると、GNU Makeが呼び出されるはずです。

また、以下の記述ではMakeの基本的な文法などについては説明しないので、必要に応じて「make触ってみた」記載のリンクや本記事で紹介している書籍などを参照してください。

## hello.cのコンパイル — 1つのソースファイルをコンパイル ##

たとえば、次のhello.cというC言語ソースファイルを作成し、実行することを考えます。

```hello.c
#include <stdio.h>

int main() {
    puts("hello, world!");
    return 0;
}
```

普通は次のコマンドでコンパイルし、実行可能ファイルhelloを作成することになるでしょう[^1]。

[^1]: OSやインストールされているコンパイラなど、環境に応じてコンパイルするコマンドは異なります。`cc`コマンドは多くの環境で利用可能なコンパイルコマンドです。たとえば、GCCがインストールされたLinuxでは`gcc`コマンドに、現行のMacOSXで開発環境を構築した場合には`clang`コマンドに、それぞれリンクされていることが一般的です。

```sh:
$ cc -o hello hello.c
$ ./hello
hello, world!
```

ところが、（GCCなどとともにGNU Makeがインストールされていることが前提ですが）hello.cファイルの作成以外ほかの準備をしなくても、次のコマンドでコンパイルができるのです。

```sh:
$ rm -f hello
$ make hello
cc     hello.c   -o hello
$ ./hello
hello, world!
```

`hello`の部分は、元の.cファイルの名前にあわせて記述します。

MakeはC言語のコンパイルで長年使われてきた歴史を反映し、さまざまなパターンでのコンパイルに対応しています。拡張子.cのファイルをコンパイルして拡張子を除いて同名のファイルを作成するルールが組み込まれ、`make hello`だけでコンパイルができるのも、その表れです。

### Makefileの作成 ###

#### `make hello`の`hello`を省略 ####

`make hello`と入力するのは面倒くさい、`make`だけでコンパイルしたいという場合は、Makeの設定ファイルであるMakefileをhello.cと同じディレクトリーに作成します。

```make:Makefile
hello:
```

ここで設定された`hello:`の`hello`の部分をターゲットと呼び、`make`で作成されるファイルをあらわします。Makefileに記述されたターゲットは`make`実行時に、たとえば`make hello`のような形で指定します。Makefileには複数のターゲットを指定することもできます。

Makefileで一番最初に記述されたターゲットは、`make`実行時に省略することができます。そのため、`hello:`だけをMakefileに記述した場合、`make`は`make hello`と同じ意味になります。

```sh:
$ rm -f hello
$ make
cc     hello.c   -o hello
```

#### `cc`ではなく`gcc`でコンパイル ####

Makefileの記述により、コンパイル方法の詳細を設定できます。

たとえば、コンパイル時に`cc`ではなく`gcc`を使う場合は、Makefileで変数`CC`を設定します。

```make:Makefile
CC := gcc

hello:
```

このとき、`make`を実行すると…

その前にちょっと注意。Makeは、必要最小限の作業だけを行うように設定されているため、hello.cファイルが更新されない限りhelloファイルは更新の必要がないと見なされ、再作成されません。なので、Makefileを更新して`make`を再実行する場合は、hello.cファイルを更新する（実際に更新しなくても`touch hello.c`でファイル更新日時を変更すればOK）か、helloファイルを削除するかします。

helloファイルを削除してから`make`を実行すると、次のようになります。

```sh:
$ rm -f hello
$ make
gcc     hello.c   -o hello
```

また、Makefileに次のようなcleanターゲットを追加すれば、`make clean`でhelloファイルを削除できます。

```make:Makefile
hello:

clean:
	$(RM) hello
```

`make clean`を使うことは、`rm`コマンドで誤って必要なファイルを削除してしまう危険性を減らすメリットもあります。

なお、`$(RM) hello`の前はタブ文字です。タブ文字の代わりにスペース文字を入力すると`make`が正常に動作しませんので、注意して下さい。

また、cleanターゲットの記述は、`hello:`の記述よりも後にして下さい。

#### `gcc`にオプションを付けてコンパイル ####

`gcc`にオプション`-g -Wall -Wextra`を付ける場合は、変数`CC`と`CFLAGS`を設定します。

```make:Makefile
CC := gcc
CFLAGS := -g -Wall -Wextra

hello:

clean:
	$(RM) hello
```

このとき、`make clean`と`make`を実行すると次のようになります。

```sh:
$ make clean
rm -f hello
$ make
gcc -g -Wall -Wextra    hello.c   -o hello
```

## シンプルすぎるブロック崩しのコンパイル — 複数に分割されたソースファイルをコンパイル ##

次に、[シンプルすぎるブロック崩し](http://qiita.com/pokohide/items/a246045f3ccaf540a375) のコンパイルを考えます。シンプルすぎるブロック崩しは、helloとは異なり、ソースファイルが複数に分割されています。また、ヘッダーファイルも存在します。こうした場合でも、Makeの組み込みルールを使えば、`Makefile`は簡潔に記述できます。

```make:Makefile
LDLIBS := -lncurses

block: block.o function.o

block.o function.o: function.h

clean:
	$(RM) *.o
	$(RM) block
```

Makeでは、拡張子.oのファイルから拡張子のない実行可能ファイルを作成する方法も定義されています。今回はコンパイル時にオプション`-lncurses`を付ける必要があるため、変数`LDLIBS`に設定しています。

Makeでは.oファイルから実行可能ファイルを作成する方法はあらかじめ定義されていても、どの.oファイルから実行可能ファイルを作成するのかはわからないため、`block: block.o function.o`により`block.o`と`function.o`から実行可能ファイル`block`を作成するようここで定義しています。この`block.o`と`function.o`は、`block.c`と`function.c`から必要に応じて作成されます。Makeでは、組み込みで.cファイルから.oファイルを作成するルールが設定されています。ルールが設定されている場合にファイルを必要に応じて自動作成できるのは、Makeの優れた特長です。

また、`block.o function.o: function.h`は、ヘッダーファイルを更新したあと、その変更を実行可能ファイルに反映するために必要な記述です。

この```Makefile```を作成後、次のようにコンパイルを実行できます。

```sh:
$ make
cc    -c -o block.o block.c
cc    -c -o function.o function.c
cc   block.o function.o  -lncurses -o block
```

## まとめ — Makeはそれほどむつかしくないはず ##
ここまでとりあげたMakefileはいずれも数行で終わるもので、C言語の複雑なプログラムを書くような方からすれば簡単なはずです。上記の[make触ってみた](http://qiita.com/kimikimi714/items/a9001170be25fcb72e36)で取り上げているPHP7なんかは、

 * プログラム自体が巨大かつ複雑
 * 世界中のさまざまな環境への適応を考えなければならない

といった事情があり、Makefileも複雑化し、いろいろな工夫やトリックが必要となっているいるわけです。そこまで複雑でないC言語プログラムを書くときには、ずっと単純なMakefileで十分役に立つはずです。というわけで、Makeは一度は自分で書いてほしいし、多少無理だと思っても是非使ってほしいなと思っています。特にC言語の場合ですと、先人たちの切り開いた道があちこちに残されていますので。

## お薦めの書籍 ##
Makeについてのインターネット上の情報は、[make触ってみた](http://qiita.com/kimikimi714/items/a9001170be25fcb72e36)が参考になるかと思います。ただし、Makeについてはその枯れ具合ゆえインターネット上の情報よりも書籍の方が頼りになる場面が多いかもしれません。お薦めは次の2冊です。

 * [『GNU Make』](https://www.oreilly.co.jp/books/4873112699/) GNU Makeの基礎から高度な使いこなしまで。さすがO'reilly、頼れる1冊です。
 * [『UNIXプログラミング環境』](http://www.amazon.co.jp/dp/4871483517) 第8章でC言語とパーサー（YACC）によるプログラム開発を取り上げており、その中でMakeについても詳しく解説しています。古くて難解だけど、楽しくてためになります。

## 補足 — Makeのルールを確認する ##
.cファイルや.oファイルから実行可能ファイルを作成したり、.cファイルから.oファイルを作成したりするMakeのルールを確認するためには、`make -p`コマンドを実行し、makeのデータベースを表示します。makeのデータベースにはかなり多くの内容が含まれるので、一時ファイルに保存してテキストエディターなどで開いたり、LESSなどのページャーを使うなどするとよいと思います。

たとえば、.cファイルから拡張子のない実行化のファイルを作成するルールを確認するには、`make -p`コマンドの実行結果から`%: %.c`と記載された部分を検索します。

```make:
%: %.c
#  commands to execute (built-in):
	$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
```

この定義の中で`$@`はターゲットファイル、`$^`は必須ファイル（ソース）をあらわします。たとえば`hello.c`から`hello`を作成する場合、必須ファイルは`hello.c`、ターゲットファイルは`hello`です。

次に、`LINK.c`の定義は次のようになっています。

```make:
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
```

さらに、`CC`の定義は次のようになっています。

```make:
CC = cc
```

また、`CFLAGS`、`CPPFLAGS`、`LDFLAGS`、`TARGET_ARCH`はいずれも空文字列です。

ここまでの結果をまとめると、初期状態では次のルールが設定されていることになります。

```make:
%: %.c
	cc $^   -o $@
```

そのため、`hello.c`から`hello`を作成するときには、次のコマンドが実行されます。

```sh:
cc hello.c   -o hello
```