Makefile

2016年だけどMakefileを使ってみる

More than 1 year has passed since last update.

この資料はなに?

Makeの良さを伝えるものです

  • CとかC++の持ち物じゃない
  • 普段使うコマンドのショートカットみたいな
  • 2016年でもMakefileは便利

 2016-10-19 19.11.07.png

頑張らないでScala 〜VOYAGE GROUPにおけるアドネットワーク開発の戦略〜 // Speaker Deck


Makeってなに?Makefile???

make(メイク)は、プログラムのビルド作業を自動化するツール。コンパイル、リンク、インストール等のルールを記述したテキストファイル (makefile) に従って、これらの作業を自動的に行う。
出典:https://ja.wikipedia.org/wiki/Make

つまり、自動化のためのツール。


make が生成するのはふつう C のプログラムだが、べつに C のプログラムに限らず、Makefile に書く生成コマンドの書きように よっては、TeX のファイルだろうが、Java のプログラムだろうが 何でも make を利用して作業を軽減することができる。
出典:http://www.unixuser.org/~euske/doc/makefile/

なので、CだろうがC++だろうがScalaだろうが関係ない。


ぐぐるとこんなの出てきて難しそう...

PROGRAM = main
OBJS = main.o
CC = gcc
CFLAGS = -Wall -O2
.SUFFIXES: .c .o

.PHONY: all
all: depend $(PROGRAM)

$(PROGRAM): $(OBJS)
    $(CC) -o $(PROGRAM) $^

.c.o:
    $(CC) $(CFLAGS) -c $<

.PHONY: clean
clean:
    $(RM) $(PROGRAM) $(OBJS) depend.inc

.PHONY: depend
depend: $(OBJS:.o=.c)
    -@ $(RM) depend.inc
    -@ for i in $^; do cpp -MM $$i | sed "s/\ [_a-zA-Z0-9][_a-zA-Z0-9]*\.c//g" >> depend.inc; done

-include depend.inc

http://www.ie.u-ryukyu.ac.jp/~e085739/c.makefile.tuts.html


何が良いの?

ぼくがおもうMakeのいいところ

  • わざわざインストールしなくていい(はず)
    • デフォルトで入ってる(/usr/bin/make)
  • タブ補完が効く
  • よく使うコマンドを保存出来る
    • .bashrcにaliasはるのとは違う
    • ディレクトリ(プロジェクト)毎にコマンドを用意できるので環境は汚れない
  • よく使うコマンドを共有できる
    • 「配信サーバに対するリクエストってどうやって送ればいいですか?」に応える

サンプル

Makefileはこんな感じ。

show-ip:
        ipconfig getifaddr en0

これを使ってみる。

$ make show-ip
ipconfig getifaddr en0
192.168.0.27

これはshow-ipというタスクでipconfig getifaddr en0というコマンドを実行している。
難しいコマンドをおぼえなくていいし、Makefileの文法も簡単なので学習コストは低い。


書き方

ざっくりとはこれだけ。

<変数宣言>

<タスク名>:
  <実行したいshell>

<タスク名>:<必要ファイル名>
  <実行したいshell>

インデントはタブ文字なので注意。
ほんとは変数じゃなくてマクロと呼ばれる。


実行するシェルを標準出力に表示しない方法

実行すると実行するシェルが出力されてしまうので、鬱陶しい場合は@を先頭につける。

show-files:
        ls -lh

show-files-suppress:
        @ls -lh

実行するときは何も変わらない

$ make show-files
ls -lh
total 8
-rw-r--r--  1 petitviolet  staff    51B Oct 15 15:10 Makefile
$ make show-files-suppress
total 8
-rw-r--r--  1 petitviolet  staff    51B Oct 15 15:10 Makefile

変数宣言

Makefileの中では変数を使用することが出来る。

$ cat Makefile
MESSAGE := "HELLO"

hello:
        @echo $(MESSAGE)
$ make hello
HELLO

タスクで使用する際に上書き出来る。

$ make hello MESSAGE=こんにちは
こんにちは

タスク実行に必要なファイルを指定できる

activatorというファイルが存在していれば...みたいなタスクを定義する。

compile: activator
  @echo "Yey!"

ファイルが無いと失敗し、ファイルがあれば成功する。

$ ls
Makefile
$ make compile
make: *** No rule to make target 'activator', needed by 'compile'.  Stop.
$ touch activator
$ make compile
Yey!

順番にタスクを実行するような場合、ファイルの作成を持って成否判定を出来たりして便利!


タスクからタスクを呼ぶ

あるタスクの中から別のタスクを実行することも出来る。

task-a:
    @echo "A"
    @touch a.txt
    @make task-b

task-b: a.txt
    @echo "B"
    @touch b.txt
    @make task-c

task-c: b.txt
    @echo "C"
    @touch c.txt

clean: a.txt b.txt
    @rm a.txt b.txt c.txt
    @echo 'complete!!!'

doit:
    @make task-a
    @make clean

実行するとこんな感じになる。

$ make doit
A
B
C
complete!!!

複数行にわたるコマンドを実行したい時

一行ごとに別のshellとして実行される点に注意。

$ ls
Makefile
$ cat Makefile
make-tmp-file-home:
        @cd ~
        @touch hogehoge
$ make make-tmp-file-home
$ ls
Makefile  hogehoge

これはサブシェルの中でcdして、別のサブシェルの中でtouchしているので、カレントディレクトリでの操作となる。


&&\でつないで1つのシェルとして実行すれば良い。

$ ll $HOME | grep 'hogehoge' | wc -l
       0
$ cat Makefile
make-tmp-file-home:
        @cd ~ && \
        touch hogehoge
$ make make-tmp-file-home
$ ll $HOME | grep 'hogehoge' | wc -l
       1

シェル変数と制御文

上記の点さえ気をつければfor文も書ける。

LENGTH := 3

show-seq:
    @for i in {1..$(LENGTH)}; do \
        echo $$i; \
    done

ここでシェル変数が$$iとなっている点に注意。