Touch ファイル
2007年4月26日
makeを使用してビルドを実行する場合、出力ファイルと入力ファイルの変更日を比較して作業が必要かどうかを判断します。コンパイルなど(a.out は foo.c に依存)の場合うまく機能しますが、場合によっては出力がわかりにくいことがあります。
1つの例として、テストの実行があります。そこでの出力とは?出力の1つはテストレポートです。テストレポートのターゲットはその後、レポートファイルの日付を、実行ファイルとテストデータファイルの日付と比較できます。そうすることで、何か変更があった場合にのみテストを実行できます。
ほとんどの場合、出力ファイルには有益な情報が含まれます。ただし、ターゲットを実行する必要があるかどうかを判断する場合、実際に出力ファイルの内容ではなく、日付のみが重要になります。その結果、makeスクリプトの一般的な慣用句は、タイムマーカーとしてのみ使用される空ファイルです。私はこれを「タッチファイル」と呼んでいます。これは通常Unixのtouchコマンドでのみ操作され、ファイルの変更時刻を更新するためです。
タッチファイルは、複数のファイルの範囲で日付を比較する場合に役立ちます。出力がファイル全体にわたるツリーである場合、更新時間を調べてツリー全体をナビゲートするよりも、タッチファイルを更新する方が迅速になります。
タッチファイルはmakeでは一般的で自然な慣用句ですが、antではそれほど一般的ではありません。ただし、依然として役立つことがよくあります。これは、この数日間hibernateのHQL DomainSpecificLanguageがどのように実装されているかを調べているときに特に私を悩ませました。HQLの中心には、3つの文法ファイルによって定義された文法を持つAntlrパーサのトリオがあります。これらの文法ファイルのいずれかが変更されると、パーサソースコードを再生成する必要があります。
これのantソースを以下に示します。
<target name="init.antlr"
depends="init"
description="Check ANTLR dependencies.">
<uptodate property="antlr.isUpToDate"
targetfile="${dir.out.antlr-package}/.antlr_run">
<srcfiles dir="${dir.grammar}" includes="*.g"/>
</uptodate>
</target>
<target name="antlr"
depends="init.antlr"
unless="antlr.isUpToDate"
description="Generate ANTLR parsers.">
<taskdef name="antlrtask"
classname="org.apache.tools.ant.taskdefs.optional.ANTLR">
<classpath>
<fileset dir="${dir.lib}">
<include name="ant-antlr-*.jar"/>
<include name="antlr-*.jar"/>
</fileset>
</classpath>
</taskdef>
<mkdir dir="${dir.out.antlr-package}" />
<antlrtask target="${dir.grammar}/hql.g"
outputdirectory="${dir.out.antlr-package}" />
<antlrtask target="${dir.grammar}/hql-sql.g"
outputdirectory="${dir.out.antlr-package}" />
<antlrtask target="${dir.grammar}/sql-gen.g"
outputdirectory="${dir.out.antlr-package}" />
<touch file="${dir.out.antlr-package}/.antlr_run"/>
</target>
init.antlrタスクは、特定の.antlr_runファイルに基づいてantlr.isUpToDateプロパティを設定することに注意してください。このプロパティがtrueの場合、メインのantlrタスクは実行されません。antlrタスクの最後に、空の.antlr.runファイルがタッチされます。
hibernateのメインビルド内では、これが使用されるタスクです。結果として、パーサソースファイルは必要に応じてのみ生成されます。本当にファイルを強制的に再生成したい場合は、別のターゲットがあります。
<target name="antlr.regen"
depends="init,cleanantlr,antlr"
description="Regenerate all ANTLR generated code." />
<target name="cleanantlr"
depends="init"
description="Clean up the generated ANTLR parsers.">
<delete dir="${dir.out.antlr-package}"/>
</target>
このターゲットは、cleanAntlrタスクへの依存関係を記述することでその目標を達成することに注意してください。init.antlrへの依存関係はすでにantlrタスクにあるため、依存関係は示されません。

