Makefileに関するあれこれ(2/2)

長いんでエントリわけてみた。
Makefileで使える関数とかまとめてみた。
これで全部じゃないかも。

subst/patsubst

文字列の置換
patsubstの方はパターン付き.

$(subst .c,.o,file1.c file2.c.c file3.h)
# -> file1.o file2.o.o file3.h
$(patsubst %.c,%.o,file1.c file2.c.c file3.h)
# -> file1.o file2.c.o file3.h

substは空白をアンダーバーに、とかそういうので使えそう。
拡張子を変える、とかならpatsubstを使おう。

strip

無駄な空白等の削除。

$(strip a b  c )				
# -> a b c

$(if...)とかと組み合わせるといいみたい。
あまり使わない気がする。というか使ったことない...。

findstring

文字列の検索

$(findstring a,a b c)
# -> a
$(findstring d,a b c)
# -> 

見つかったらその文字、見つからなかったら空欄を返すっぽい。

filter/filter-out

マッチするもの/しないものをフィルターする。

$(filter %.c %.s,file1.c file2.s file3.h)
# -> file1.c file2.s
$(filter-out %.h,file1.c file2.s file3.h)
# -> file1.c file2.s

そのまんま。
結構使えるかも。

sort

ソート

$(sort file3.c file1.c file2.c)
# -> file1.c file2.c file3.c

word/wordlist/words/firstword/lastword

リストの要素関係の関数。

# $(word n,LIST): n番目の要素。
$(word 2,file1.c file2.c file3.c)
# -> file2.c

# $(word n,m,LIST): n番目からm番目の要素(リスト)
$(wordlist 2,3,file1.c file2.c file3.c)
# -> file2.c file3.c

# $(words LIST): 要素数
$(words file1.c file2.c file3.c)
# -> 3

# $(firstword LIST): 最初の要素
$(firstword file1.c file2.c file3.c)
# -> file1.c

# $(lastword LIST): 最後の要素
$(lastword file1.c file2.c file3.c)
# -> file3.c

dir/notdir/suffix/basename/addsuffix/addprefix

ファイル名の操作とか

# ディレクトリの取得
$(dir dir/file1.ext file2.ext file3)
# -> dir ./ ./

# ファイル名(ディレクトリ以外の部分)の取得
$(notdir dir/file1.ext file2.ext file3)
# -> file1.ext file2.ext file3

# 拡張子の取得
$(suffix dir/file1.ext file2.ext file3)
# -> .ext .ext

# 拡張子を除いたもの(basenmae(1)とは挙動が違うので注意!!!
$(basename dir/file1.ext file2.ext file3)
# -> dir/file1 file2 file3

# suffix/prefixの追加
$(addsuffix .ext,file1 file2)
# -> file1.ext file2.ext
$(addprefix dir/,file1 file2)
# -> dir/file1 dir/file2

basenameの挙動にすこしハマった...。
関係としては
オリジナルパス = dir + notdir = basename + suffix
って感じ。

join

haskellでいうならzip。

$(join a b c d,1 2 3)
# -> a1 b c3 d

二つのリストを先頭から合わせていく。
片方が余った場合には変化なし。

wildcard

ワイルドカード

$(wildcard *.c)
# -> hoge.c fuga.c ...

そのまんま"*.c"でもいけないこともないのだが、wildcard使って展開した方が無難。
たしかマッチするファイルの有無で挙動が分かるはず。
"*.c"だと、マッチするファイルがない場合"*.c"と言うファイルをさすことになる。
wildcardを使うと、マッチするファイルがないときには空欄(empty)になる。

realpath/abspath

相対パス絶対パスに変換する。
realpathとabspathの違いは"./"や"../"を含まないものの処理の方法だけ...ナノカナ?

$(realpath ../hoge fuga)
# -> /someplace/hoge
$(abspath ../hoge fuga)
# -> /someplace/hoge fuga

if/or/and

条件分岐

$(if CONDITION,THEN[,ELSE])
$(or CONDITION1[,CONDITION2[,CONDITION3...]])
$(and CONDITION1[,CONDITION2[,CONDITION3...]])

うーん。ここまでMakefileをガシガシ書くことないなぁ...
まぁ、簡単なスクリプトなら書けそう。

foreach

リスト全部に処理する。

$(foreach VAR,LIST,TEXT)

と書くと、LISTの全要素分TEXTが実行されて、TEXT中の$(VAR)がLISTの各要素になる。

具体例だと

DIRS=. kazuhiki mp
files=$(foreach dir,$(DIRS),$(wildcard $(dir)/*))

とやると

DIRS=. kazuhiki mp
files=$(wildcard ./*) $(wildcard kazuhiki/*) $(wildcard mp/*)

とやったのと同じになって、カレントディレクトリとkazuhiki,mp以下のファイルを拾ってくることができる。

origin/flavor

変数の出所(!?)を調べる。

$(origin VAR)
# -> "undefined" "default" "environment" "environment override" 
# -> "file" "command line" "override" "automatic"のいずれか
$(flavor VAR)
# -> "undefined" "recursize" "simple" のいずれか

どこで宣言されたか、とかを調べるらしい。
個人的に使いそうなのは"undefined"かどうか?ぐらいな気がしないでもない...。

shell

外部プログラムを起動する

$(shell TEXT)

そのまんま。lsとか起動するとwildcard代わりになるかも。

error/warning/info

メッセージを表示する。

$(error TEXT)
$(warning TEXT)
$(info TEXT)

なんかいくつかvimでカラーリングされないのだが、これはGNU拡張だったりするのだろうか?
まぁ、いいや。どうせGNU makeしか使わないだろうし。
いっそsyntaxファイル書き換えとくといいかも...