Home About
Make , Bash , Ubuntu

Makefileの中でワイルドカードを使ってファイルを指定する方法

カレントディレクトリに複数のXMLファイル (*.xml) があり、これをHTMLに変換したい。 このときMakeを使って、更新されたファイルだけ変換するようにしたいがどうすればいいか。

前提条件

もしXMLファイル数が変化しないならば...

もしXMLファイル数が変化しないならば、 Makefile に以下のように記述しておけばよい。
(変換対象となるファイルは foo1.xml foo2.xml foo3.xml)

.SUFFIXES:
.SUFFIXES: .xml .html
.xml.html :
	cat $< | /bin/toHtml > $@

all: foo1.html foo2.html foo3.html

しかし、foo4.xml,foo5.xml,hoge1.xml といった具合にどんどん変換対象ファイルが増える場合、 ファイル名/ファイル数が変化するたびに、Makefile を書き換えるのは面倒な上、間違いが起きる。

ファイル数が変化しても、対応できるMakefileを書くにはどうしたらいいか?

ファイル数が変化しても対応できるMakefile その1

これよりもっとよい方法は その2 を参照のこと。

ファイル名/ファイル数が変化しても対応できるように、 Makefile中に カレントディレクトリにある 全部のxmlファイルを列挙して make を実行する シェルスクリプトを書いてしまいます。

.SUFFIXES:
.SUFFIXES: .xml .html
.xml.html :
	cat $< | /bin/toHtml > $@

.PHONY: all
all: 
	for xmlf in *.xml ; do  htmlf=$${xmlf%.*}.html; $(MAKE) $$htmlf ; done

.PHONY: clean
clean:
	$(RM) *.html

Makefile中にシェルスクリプトを書くのをさけたい場合は、 その2 の方法を使います。

Makefile中のシェルスクリプト記述の注意点

シェルスクリプトをMakefileに直接書く場合は、

  1. 一行で書く
  2. $はエスケープするため$$ のように重ねて書く必要がある

ファイル数が変化しても対応できるMakefile その2

Makefile だけで解決する方法がありました。

.SUFFIXES:
.SUFFIXES: .xml .html
.xml.html :
	cat $< | /bin/toHtml > $@

xmlfiles:=$(wildcard *.xml)
htmlfiles=$(xmlfiles:.xml=.html)

.PHONY: all
all: $(htmlfiles)

.PHONY: clean
clean:
	$(RM) $(htmlfiles)

ポイントは以下の2つです。

ポイント1) カレントディレクトリのxmlの拡張子をもつファイルだけ集める

xmlfiles:=$(wildcard *.xml)

これでカレントディレクトリにあるxmlファイルを$(xmlfiles)に代入することができます。

ポイント2) xmlの拡張子をまとめてhtmlに変換する

makeでは最終的に生成したファイル名を指定しなければならないため、 xmlの拡張子を持つファイル名を得ただけでは、問題は半分しか解決していません。

たとえば、 foo-1.xml foo-2.xml がカレントディレクトリにあるならば、 ここで実際に得たい文字列は、 foo-1.html foo-2.html になります。
ポイント1)により既に、$(xmlfiles)= foo-1.xml foo-2.xml は得ているため、 あとはこのxmlの部分をhtmlに変えるために以下の記述をします。

htmlfiles=$(xmlfiles:.xml=.html)

以上です。