2009年11月8日日曜日

【make】2 ルール(その1)

やってみると、やっぱりmakeはルールベースプログラミングでありDSLなんだなぁ、ということをあらためて感じる。


* 2 ルール
- ルールにはいくつかの種類がある。
- 'GNU make'は'make'と互換性がある。
- ルールの書き方について、'GNUM make'は'make'を進
化させて、使いやすくした部分がある。

** 2.1 明示的ルール

ターゲットは複数行にわけたり、単一行にまとめたりできる。

hoge.o piyo.o: puyo.h ponyo.h moge.h

これは、

hoge.o: puyo.h ponyo.h moge.h
piyo.o: puyo.h ponyo.h moge.h

これと等価。

hoge.o: puyo.h ponyo.h moge.h

これは、

hoge.o: puyo.h ponyo.h
hoge.o: moge.h

これと等価。

*** 2.1.1 ワイルドカード
- makeのワイルドカードは、Bournese Shellと同じ記
法。
- ワイルドカードは、makeのどの項にも使える。
- ワイルドカードの展開は、ターゲットと前提条件に
ついてはmakeが実施し、コマンドについてはシェル
が実行する。

例。
------
hoge: *.c
gcc -o $@ $^
------

- ワイルドカードは、シェルと同じように展開されて
から解釈される。なので、

*.o : piyo.h

というルールは、まだobject fileがひとつも存在し
ないディレクトリにおいては、

------
: piyo.h
------

となってしまう。

*** 2.1.2 疑似ターゲット

- 疑似ターゲット(phony target)なるものあり。
- これは、ターゲットで指定した名前のファイルは存
在しない。すなわち、そのターゲットのコマンドは
ターゲット名のファイルを生成しないようなもので
あること。

例。
------
clean:
rm -f *.o
------

- これだけだと、cleanってファイルが間違って存在し
てしまったら、'make clean'してもこの掃除処理は
実行されなくなってしまう。
- なのでこうする。

------
.PHONY: clean
clean:
rm -f *.o
------

- 応用。疑似ターゲットはmakefile内でのプロシージャ
呼び出しみたいに使える。

------
.PHONY: clean
clean: hoge
rm -f *.o

hoge:
ls -l *.o
------

- 疑似ターゲットは、エイリアス的にもつかえる。使
い勝手が向上する。

------
.PHONY: task-a
task-a: jugemujugemugokounosurikirekaijarisuigyo

jugemujugemugokounosurikirekaijarisuigyo: hoge.h piyo.h
gcc -o $@ $^
------

- よくある疑似ターゲット

| ターゲット | 意味 |
|------------+--------------------------------------------------|
| all | アプリケーションを構築するすべての作業を行う |
| install | 構築したアプリケーションをシステムに配置する |
| clean | 構築したアプリケーションを削除する |
| distclean | 配布状態に含まれていないものをすべて削除する |
| TAGS | TAGSを作成する |
| info | Texinfoのソースからinfoファイルを作成する |
| check | アプリケーションに関するすべてのテストを実施する |


*** 2.1.3 空のターゲット

- 疑似ターゲットは常に「最新ではない」と判断され
る。そのため、指定されれば常に実行される。
- なので、指定したときは常に実行される処理にはよ
い。
- 指定とは別に実行するかしないかを制御するにはどう
するか。それを制御するために、touchで時刻を更新
するファイルを利用すればよい。

- 例えば、次のようにするとhoge.cが更新されたときだ
け、piyoが実行される。

------
hoge: piyo hoge.c
gcc hoge.c -ohoge

piyo: hoge.c
size $^
touch size
------

** 2.2 変数

- 変数の基本的なかきぶりは次のとおり。

$(variable-name)

- bashでは、これはcommand substitutionだな。bash
での変数参照は、${PATH}などのcurly bracket。
bashとmake、揃えてくれればいいのに、ややこし
い。。。

*** 2.2.1 自動変数

- 自動変数は、実行ルールが決定した後に、makeが自
動的にその値を設定する。

- 自動変数の一覧

| 形式 | 意味 |
|------+------------------------------------------------------------------|
| $@ | ターゲット文字列 |
| $% | ターゲット文字列の一部。"hoge(piyo)"ならpiyo。 |
| $< | 最初の前提条件 |
| $? | 前提条件のうち、ターゲットよりも新しいもの達をスペース区切りで |
| $^ | 前提条件すべてをスペース区切りで。重複しないようにダブリを削除。 |
| $+ | 前提条件すべてをスペース区切りで。重複しないようにダブリあり。 |
| $* | ターゲット文字列の一部。通常は、suffixを削除したもの。 |

- 自動変数のテストmakefile

これでひととおりの挙動の確認ができる。

------
# 行頭に'#'を置くとその行はmakeのコメント行。行頭以外の置き方もあるがそれは後述。

### このプログラムの動かし方
#
# ファイルの一括削除
# make distclean
#
# 必要ファイルの作成
# make all
#
# すべてのテストを実行
# make check

### ルールの構文 (簡略版2)
# target1 target2 ... targetN : prerequiste1 prerequiste2 ... prerequisteM
# command1
# command2
# ...
# commandK

### コメントについて
# commandを書くゾーンは、行頭の'#'はmakeのコメント
# であり、それ以外はshellに渡される。それがコメント
# かどうかはshellが判断する。それ以外のゾーンでは、
# 行頭ではなくても'#'があればそれ以降はmakeのコメン
# ト。

.PHONY: all # この行はallが疑似ターゲットであることを指定している。
all: update-file1 update-file2 update-file3 hoge.c piyo.c foolib(hoge.c) foolib(piyo.c)

# phonyはまとめて指定できる。
.PHONY: check distclean update-file1 update-file2 update-file3 \
update-hoge update-piyo \
test-\# test-@ test-percent test-< test-? test-? test-^ test-+ test-*.c
# '\'でmakeの継続行になる。commandゾーンであれば
# shellにわたり、shellの継続行となる。

check: test-\# test-@ update-hoge test-percent test-< test-? test-? test-^ test-+ test-*.c

distclean:
rm -f file1 file2 file3 \
hoge.c piyo.c foolib

update-file1:
touch file1

update-file2:
touch file2

update-file3:
touch file3

update-hoge:
touch hoge.c

update-piyo:
touch piyo.c

hoge.c:
echo '#include ' > hoge.c

piyo.c:
echo '#include ' > piyo.c

# ar なarchiveについてはその構成ファイルを指定する
# ことができる。これは実戦的には.a形式のためのもの。
foolib(hoge.c): hoge.c
# $%
ar cr foolib hoge.c
## foolib(hoge.c) end
## next test maybe start

foolib(piyo.c): piyo.c
# $%
ar cr foolib piyo.c
## foolib(piyo.c) end
## next test maybe start

test-\#:
# これはmakeのコメント。commandゾーンだがshellに渡されない。
# これはmakeとしてはcommand。shellはコメントと解釈する。
## test-# end
## next test maybe start

test-@:
# ターゲット文字列(すなわちファイル名)
# $@
## test-@ end
## next test maybe start

test-percent: foolib(hoge.c) foolib(piyo.c)
## test-percent end
## next test maybe start

test-<: file1 file2 file3
# 最初の前提条件
# $<
## test-< end
## next test maybe start

test-?: update-file3 file1 file2 file3
# 前提条件のうち、ターゲットよりも新しいもの達をスペース区切りで。
# $?
touch test-\?
## test-? end
## next test maybe start

test-^: file1 file2 file3 file1
# 前提条件すべてをスペース区切りで。重複しないようにダブリを削除。
# $^
## test-^ end
## next test maybe start

test-+: file1 file2 file3 file1
# 前提条件すべてをスペース区切りで。重複しないようにダブリあり。
# $+
## test-+ end
## next test maybe start

test-*.c:
# ターゲット文字列の一部。通常は、suffixを削除したもの。
# $*
## test-*.c end
## next test maybe start
------

- 自動変数の修飾子

- ここまでのところ、makefileもソースファイルも
バイナリファイルも同一のディレクトリの同一階
層にあることを前提としている。
- しかし、makeは同一ディレクトリの中のサブディ
レクトリにあるファイルも扱える。(後で出てくる
はず)
- するとターゲットはパスを含むものもOK。
(hoge/piyo/puyo.c)など。

- この形式のターゲットのために、自動変数の修飾
子'D'と'F'がある。

例。

-------
all: dist/src/hoge.c

dist/src/hoge.c:
# target : $@
# target (directory part) : $(@D)
# target (file part) : $(@F)
-------


こつこつ。

0 件のコメント: