$(OBJ:.o=.c)
のようにかくと,$(OBJ)の中のサフィックス“.o”を“.c”に置き換えられる.
パターン一致(%)を使うと次のような凝ったこともできる(gmake拡張機能).
FILES = a.o b.o c.o OBJS = $(FILES:%=lib/%) SRCS = $(OBJS:obj/%.o=src/%.c)
マクロTARGET = a b cに対して,
a,b,cの後ろに.cを追加して,
a.c,b.c,c.cにするには
$(TARGET:=.c)とすればよい.
TARGET = a b c
echo:
@echo $(TARGET:=.c)
文字列の末尾(または空白の直前)でしか置換が起こらない. これはおそらくサフィックス部分を置換することを想定しているために,このような仕様になっているのではないかと思う.
| Makefile |
|---|
# Makefile
SRCS = abcx xabc xabcx
OBJS = $(SRCS:abc=ABC)
echo:
@echo $(OBJS)
|
| 実行結果 | 説明 |
|---|---|
$ make abcx xABC xabcx |
xabcだけが置き換わって,
abcxやxabcxは置き換えの対象にならない.
|
実はmakeでも演算(文字列連結演算)ができたりする.
OBJS = a.o b.o c.o OBJS += d.o e.o f.o
シェルスクリプトのように値を前に差し込むこともできるが,その場合“:=”演算子を使う必要がある.
OBJ = a.o b.o c.o OBJ := 1.o 2.o 3.o $(OBJS)
makeのマクロ展開方法には,再起展開マクロ(=)と単純展開マクロ(:=)があり, 単純展開マクロは,makeの処理がその行に達した時点の右辺のマクロ値を使用し, 再起展開マクロは,makeがMakefileを末尾まで処理し終わって, すべてのマクロの最終的な値が決定した後に後退しながらマクロ定義を完成させるようになっている (したがって,再起展開マクロが無限ループするような定義を含んでいるとエラーになる).
これを考慮すると, 次の記述は予想とは違う動きになるかもしれないことが理解できると思う.
BASEDIR = /usr/ccs INCLUDE = $(BASEDIR)/includes BASEDIR = /usr/local LIB = $(BASEDIR)/lib
Makefileは記述順に対する依存はめったにない. ただし,依存記述行にマクロをかいた場合については時系列を意識しなければならない.
INCFILES = sub1.o: sub1.c $(INCFILES) INCFILES = sub2.h sub2.o: sub2.c $(INCFILES) INCFILES = sub3.o: sub3.c $(INCFILES)
これは,マクロの再帰的定義とは異なり,時系列に依存する. すなわち,2番目だけsub2.o: sub2.c sub2.hとなり, 1番目と3番目は$(INCFILES)は空になる(依存関係記述行に書くときは単純代入になるため).
$そのものをあらわしたいときは$$とする.
$FOOとかくと,$(F)OOと解釈される.
CC = cc ”と書くと,ccの前後の空白は無視されるのに,
“CC = cc #commentのように書くと,“cc ”と空白が入る仕様になっている.
通常はこの違いは気にならないとは思うが,まれに非常にトリッキーな現象が起こることがあるので,
いちおう頭に入れておこう.
nmakeでは${TARGET}はダメらしい.
なので,$(TARGET)の方が互換性が高くてよいかもしれない.
makeによると${TARGET}の方がお勧めっぽく書いてあるんだけども….
| 定義済みマクロ | 用途 |
|---|---|
| CC | |
| CFLAGS | |
| CPPFLAGS | Cプリプロセッサのオプション |
| AS | |
| ASFLAGS | |
| YACC | |
| YFLAGS | |
| LEX | |
| LFLAGS | |
| FC | Fortranコンパイラ |
| LINT | |
| LINTFLAGS | |
| CO | RCSのco(チェックアウト)コマンド |
| RM | rm(remove ファイル削除)コマンド |
| 動的マクロ | 機能 |
|---|---|
$@ |
|
$< |
|
$* |
|
| 動的マクロ(gmake拡張機能) | |
$^ |
依存ファイルのファイル名.
$<の違いは依存ファイルが複数個書かれている場合の動作.
$<だと最初のファイル名になるが,
$^だと,すべての依存ファイルを並べたものに置き換わる.
|
$+ |
依存ファイルのファイル名.
$^との違いは,依存ファイル群の中に同じファイル名が複数回現れる場合の動作.
$^は重複をとりのぞくが,
$+は重複をそのまま残す仕様になっている(どういうときに役立つのか理解できないけど…).
|
$? |
$^のうち,ターゲットより新しいもののを抽出したものになる.
|
さらにDとFを組み合わせてディレクトリおよびファイル名を取り出すことができる.
例えば,$(@D)とすると,ターゲットファイルのディレクトリ名,
$(@F)とすると,ターゲットファイルのパスを除いたファイル名部分が取り出せる.
現在定義されているルールを表示させるには“make -p”とすればよい.
Makefileが存在しているディレクトリで“make -p”とすると,
Makefileで定義されているルール+デフォルト ルールが表示されるので,
純粋に初期状態で登録されているデフォルト ルールだけを参照したい場合には
Makefileのないディレクトリで実行するか,
“make -p -f nothing”のように存在しないファイル名を指定して実行すればよい.