ksaitoの日記

日々試したことの覚え書き

Makefileでできること

Makefileでよく使うパターンを検証しました。

検証用のファイルは、下記の通りです。

ソースがtest1ディレクトリの*.txtでtest2ディレクトリの*.objがターゲットファイルという想定です。

できるだけ、Makefileがシンプルになるように工夫してみました。

$ tree ./test?
./test1
├── a.txt
└── b.txt
./test2
└── a.obj

0 directories, 3 files
$ 

ワイルドカード

ワイルドカードで指定したファイルに対して操作をする場合、$(wildcard)を使います。

$(wildcard 正規表現)でソースファイルのリストを作ることができます。そのリストに対して$(SRC:.txt=.obj)でソースファイルの拡張子を変更したリストを作ることができます。

$ cat Makefile
SRC=$(wildcard test1/*.txt)
OBJ=$(SRC:.txt=.obj)

all:
        @echo src=$(SRC)
        @echo obj=$(OBJ)
$ make
src=test1/a.txt test1/b.txt
obj=test1/a.obj test1/b.obj
$ 

ルールの追加

*.txtから*.objを作るためのルールを追加します。

$ cat Makefile
SRC=$(wildcard test1/*.txt)
OBJ=$(SRC:.txt=.obj)

all: $(OBJ)

%.obj: %.txt
        @echo compile src=$< obj=$@
$ make
compile src=test1/a.txt obj=test1/a.obj
compile src=test1/b.txt obj=test1/b.obj
$ 

ターゲットファイルのディレクトリを変更

ソースがtest1ディレクトリ、ターゲットがtest2ディレクトリで拡張子のルールを使う場合、下記のようにターゲットをtest1ディレクトリに作成してtest2にコピーしました。

コピー先のファイル名を$(addprefix ./test2/, $(notdir $@))でディレクトリ部分のみ変更しています。

$ cat Makefile
SRC=$(wildcard test1/*.txt)
OBJ=$(SRC:.txt=.obj)

all: $(OBJ)

%.obj: %.txt
        @echo compile src=$< obj=$@
        @echo cp -p $@ $(addprefix ./test2/, $(notdir $@))
$ make
compile src=test1/a.txt obj=test1/a.obj
cp -p test1/a.obj ./test2/a.obj
compile src=test1/b.txt obj=test1/b.obj
cp -p test1/b.obj ./test2/b.obj
$ 

仕上げ

echoを実際のコマンドに置き換えて動作をチェックします。 cleanターゲットも追加して動作を確認します。

$ cat Makefile
SRC=$(wildcard test1/*.txt)
OBJ=$(SRC:.txt=.obj)

all: $(OBJ)

%.obj: %.txt
        @echo compile src=$< obj=$@
        touch $@
        cp -p $@ $(addprefix ./test2/, $(notdir $@))

clean:
        -@rm -rf $(OBJ)
$ make -n
echo compile src=test1/a.txt obj=test1/a.obj
touch test1/a.obj
cp -p test1/a.obj ./test2/a.obj
echo compile src=test1/b.txt obj=test1/b.obj
touch test1/b.obj
cp -p test1/b.obj ./test2/b.obj
$ make 
compile src=test1/a.txt obj=test1/a.obj
touch test1/a.obj
cp -p test1/a.obj ./test2/a.obj
compile src=test1/b.txt obj=test1/b.obj
touch test1/b.obj
cp -p test1/b.obj ./test2/b.obj
$ make
make: Nothing to be done for 'all'.
$ make clean
$ make
compile src=test1/a.txt obj=test1/a.obj
touch test1/a.obj
cp -p test1/a.obj ./test2/a.obj
compile src=test1/b.txt obj=test1/b.obj
touch test1/b.obj
cp -p test1/b.obj ./test2/b.obj
$ 

本当は、ターゲットのtest2/*.objtest1/*.txtのタイムスタンプを比較して、test1/*.txtから直接test2/*.objを作りたです。