MY-NOTEBOOK

Friday, May 2, 2008

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

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

前提条件

  • 変換コマンドは /bin/toHtml とする( 標準入力からXMLを入れて、標準出力にHTMLが出力される )
  • xmlからhtmlに変換するときファイル名は拡張子以外は一致させる foo.xml → foo.html
  • XMLファイルはどんどん増えていく

結論だけを知りたい方はここをクリック。

もし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 その2(もっとよい方法)

※この方法は、MASA.H氏に教えていただきました。感謝します。

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)
© 2006-2012 Tomoaki Oshima