makeがよくわからない日記

複数の*.jsを元にして、別のx.jsを作りたいとする。まあ例えば具体的には複数の*.jsをコンパイルして一つのJSファイルにするとかね。コンパイルの部分は本質ではないので「catで結合する」で代用することにしよう。

Q1

ソースコードのファイル名は未知とする。というわけでワイルドカードを使うことになるだろう。

x.js: *.js
	cat $? > x.js

いま、カレントディレクトリにa.jsとb.jsがあるとする。

$ cat > a.js
a
$ cat > b.js
b

この状態でmake x.jsすると1回目は期待通りにa.jsとb.jsを結合したx.jsが作られる。しかし、もう一度実行するとx.js自体が依存ファイルの*.jsにマッチしてしまうためエラーになる。

$ make x.js   
cat a.js b.js > x.js
$ make x.js
make: Circular x.js <- x.js dependency dropped.
make: `x.js' is up to date.

Q1: 「x.jsを依存から除外せよ」と宣言する方法はあるのか?

A1:「@n0kada: GNU makeなら deps.js: $(filter-out deps.js,$(wildcard *.js))」thanks!

Q2

やりかたがわからないので、とりあえずx.jsをカレントディレクトリではなくbuild以下に置くことにした。

build/x.js: *.js
	mkdir -p build
	cat $? > build/x.js
$ make 
mkdir -p build
cat a.js b.js > build/x.js
$ make
make: `build/x.js' is up to date.

とりあえず期待通りに動いている。a.jsやb.jsがカレントディレクトリ以外にある場合はどうか?それが同一のディレクトリにあるなら特に難しくはない。

build/x.js: src/*.js
	mkdir -p build
	cat $? > build/x.js

じゃあsrcとlibの2つのディレクトリにあったら?もちろんsrc/*.js lib/*.jsと書けばできるが「ソースファイルがあるディレクトリ」はここにかぎらず他のターゲットでも必要になるので変数にまとめたい。vpathを使えば探索するディレクトリを指定できるのだと思った。しかしうまくいかない。

SRCDIR = src lib

vpath %.js $(SRCDIR)

build/x.js: *.js
	mkdir -p build
	cat $? > build/x.js

これは*.jsを作る方法が見つからない旨のエラーになる。

$ make
make: *** No rule to make target `*.js', needed by `build/x.js'.  Stop.

仮にカレントディレクトリにc.jsを置くとcだけが対象としてコンパイルされる。

$ cat > c.js
c
$ make      
mkdir -p build
cat c.js > build/x.js

うーむ?vpathの使い方がおかしい??

しかたがないのでvpathを避けてpatsubstをしてみた。

SRCDIR = src lib

build/x.js: $(patsubst %,%/*.js,$(SRCDIR))
	mkdir -p build
	cat $? > build/x.js

これなら期待通りに動く。

$ make
mkdir -p build
cat src/a.js lib/b.js > build/x.js
$ make
make: `build/x.js' is up to date.

Q2: こんな力技に頼らない方法があるのではないか?