makefileのいろいろ

FreeBSDもZRouterもmakefileでのビルドなので、思いついたことを書き留めておきます。もちろんBSD makeの話です。

:で変数を修飾パターンに従って変更することができます。

例えばVAR=abcで${VAR:Mab}はabになりVAR=xyzだとxyzのままになります。

修飾パターンはマッチや非マッチ、置換などがあります。

```make
.if ${.TARGETS:Nall} == ""
STR="YES ALL"
.else
STR="NOT ALL"
.endif

all:
	@echo "${STR}"
	@echo "${.TARGETS:Nall}"
	@echo "${.TARGETS:Mall}"

all2:
	@echo "${STR}"
	@echo "${.TARGETS:Nall}"
	@echo "${.TARGETS:Mall}"

all3:	all
```

.TARGETSはターゲットで、:Nは:Mの反対で、マッチしたらなくなります。

実行してみます。

```
% make
YES ALL

all
```

```
% make all
YES ALL

all
```

```
% make all2
NOT ALL
all2

```

```
% make all3
NOT ALL
all3

```

all3はallを実行しているのですが、コンテキストが違う状態になります。

最初に書かれるデフォルトがallでないとまた違った動きになるので注意が必要です。

書いてから気がついたが、これでも同じです。

```make

.if ${.TARGETS} == "all"
STR="YES ALL"
.else
STR="NOT ALL"
.endif
```

こっちのほうが明示的だし、:Nとか:Mじゃないほうが良い気がします。:Nとか:Mもうまい使い方ってあるんでしょうか？

Open Watcom v2のmakefileでBSD makeでエラーが起きていました。

```make:postmake
cretype.exe : ../c/cretype.c
        $(CC) -I../../watcom/h -o $@ $<
```

$<はc.oのような暗黙(implicit)のルールでしか使えないようです。

# 並列実行

makeコマンドはjオプションで並列実行できます。

たとえばa.cとb.cからa.outを作るときにはa.cのコンパイルとb.cのコンパイルは並列してできます。またa.outはa.oとb.oができた後にリンクを実行しなければなりません。

以下のようなMakefileではいくらjオプションをつけても並列実行されません。

```makefile
test1:
        cc -c a.c
        cc -c b.c
        cc -o a.out a.o b.o
```

並列実行させるためには以下のように書きます。

```makefile
test2: a.o b.o
        cc -o a.out a.o b.o

c.o:
        cc -c $<
```

これでa.oとb.oのコンパイルは並列実行され、その後にリンクが行われます。

```
% make -j2 test2
--- a.o ---
--- b.o ---
--- a.o ---
cc  -O2 -pipe -c a.c -o a.o
--- b.o ---
cc  -O2 -pipe -c b.c -o b.o
--- test2 ---
cc -o a.out a.o b.o
```

もちろん暗黙のルールでなくそれぞれターゲットを書いても良いです。

何らかの理由で、a.o,b.oをシーケンシャルに処理したい場合は以下のような行を追加します。

```
.ORDER: a.o b.o
```

実行するとこんなです。

```
% make -j2 test2
--- a.o ---
cc  -O2 -pipe -c a.c -o a.o
--- b.o ---
cc  -O2 -pipe -c b.c -o b.o
--- test2 ---
cc -o a.out a.o b.o
```

# マクロ

FreeBSDではいろいろマクロがあり、下記だけでhello.cからプログラムが作れます。

```Makefile:Makefile
PROG=hello
MK_MAN=no

.include <bsd.prog.mk>
```

マクロのファイルは/usr/share/mkにあります。

makeすると同じディレクトリでバイナリが作れますが、bsd.obj.mkには以下のように書いてあります。

```Makefile
#
# Warn of unorthodox object directory.
#
# The following directories are tried in order for ${.OBJDIR}:
#
# 1.  ${MAKEOBJDIRPREFIX}/`pwd`
# 2.  ${MAKEOBJDIR}
# 3.  obj.${MACHINE}
# 4.  obj
# 5.  /usr/obj/`pwd`
# 6.  ${.CURDIR}
#
# If ${.OBJDIR} is constructed using canonical cases 1 or 5, or
# case 2 (using MAKEOBJDIR), don't issue a warning.  Otherwise,
# issue a warning differentiating between cases 6 and (3 or 4).
#
```

ソースのディレクトリにobjディレクトリがあれば、そこにオブジェクトが作られますが、以下を実行すると/tmpにpwdのディレクトリがなけれは同じディレクトリにオブジェが作られます。

```
% env MAKEOBJDIRPREFIX=/tmp make
```

ディレクトリを作るのは下記でできます。

```
% env MAKEOBJDIRPREFIX=/tmp make obj
```

こでれでmakeすれば/tmp/の下にオブジェクトが作られます。

オブジェクトの場所は以下の方法で確認できます。

```
% make whereobj
```

# shスクリプト

以下のようにすると、da0がある場合のみ実行されます。

```makefile
VER="10.0"

all:
        @(if [ -e /dev/da0 ]; then \
        ${MAKE} nbflash ;\
        else \
        echo "No media" ;\
        fi)

nbflash:
        sudo dd if=$(VER)/armv7.img of=/dev/da0 bs=1m conv=sync
        sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/da0 bs=1k seek=8 conv=sync
```

# Malformed conditional

定義されてないものを評価すると発生するようです。先に定義をdefined()で確認してから評価するのが良いです。