makeビルドシステム

最近、raspberrypiでよく遊んでいるがc言語コンパイルがめんどくさいので
makeを使うようにしてみた。
頻繁に書くものではないため多分すぐ忘れるからメモ

makeとは

コンパイル時に依存関係の解決を半自動化するビルドシステム。
作業手順を Makefile というファイルに記述しておく
( Makefile 大文字でも makefile 小文字でもいいが、大文字の方が優先される)
たぶん大文字で書くのが普通なのかも、どっちでもいいと思うけど

文法の基本

下記のセットを「ルール」と呼ぶらしい

target : souce1 souce2 ...
[TAB] command1
[TAB] command2
 ...
  • コマンドの先頭は必ずTAB文字にすること、スペースだとエラーになる
  • 行末には必ず改行が必要なので忘れないように
  • コメントは#

変数も書くことができる
使うときは$(変数)で使える。()は{}でもよい

foo = bar
target : $(foo)     # 又は${foo} 

gccを使うときのオプションとかまとめておくと便利
自動変数もある

  • $@ : ターゲットのファイル名
  • $< : 最初のソースファイル名
  • $^ : すべてのファイル名

makeを実行するときは 「make ターゲット名」 でコマンドが実行される
ターゲット名を省略した場合、一番上のルールを実行する
一番最初にメインのコンパイルルールを書いておくと

$ make

これだけでコンパイルから依存関係とか解決してくれる

PHONYターゲット

Makefile の同一ディレクトリにターゲットと同じファイル名があると
ターゲット名を指定して実行する際にエラーが起こる
この問題を解決するため、.PHONYターゲットという機能がある

foo :
    bar

.PHONY : foo

と書くとfooという同じ名前のファイルがあってもルールが実行される
コンパイルしたファイルの実行や削除に使えるとかなんとか

コード例

main.cというファイルをビルドする場合
Makefile

# コンパイル時のオプションを記入
options = -std=c17 -Wall --pedantic-errors

# makeしたときに実行されるコマンド
# main.cというC言語ファイルがある場合
# gcc -std=c17 -Wall --pedantic-errors -o prog main.c コマンドを実行
prog : main.c 
    gcc $(options) -o $@ $<

# make runしたときに実行されるコマンド
# run: の後にprogと書くことでprogが実行されていない場合は
# progターゲットに戻って実行される
# つまり、makeを実行せずにmake runするとコンパイルと実行が同時にされる
# progを実行している場合は./progが実行される
run : prog
    ./prog

# make cleanしたときに実行されるコマンド
# 要件がないのでrm -rf ./progのみ実行される
clean :
    rm -rf ./prog

# PONYターゲットを指定することでディレクトリ内にrunファイルやcleanファイルがあっても
# Mekefile内のコマンドが優先される
.PONY : run clean