Rakefileの勘所
あー、毎回watchコマンドとかbuildコマンドとかを打ち込むのはやだなー、ビルドスクリプト書きたいなー、Makefileで十分かCakefileにするかRakefileにするか、よっしゃRakefileにしよう、あれーどういうふうに書けばいいんだっけかなー
と、プロジェクトを作る度に思っている気がするので、自分用のメモをまとめることにします。
Rakeについて
Rakeは、RoRでヘビーに使われていることで一斉を風靡したMakeみたいなビルドツールです。元々、Jim Weirich氏が作成したサードパーティのユーティリティだったのですが、Ruby 1.9から標準ライブラリに組み込まれたようです*1。
Rakeの勘所
使い方を一からステップアップで書くのは面倒なので、サンプルとして修論のTeXをコンパイルする時に使ったコードをそのまま載せることにし、その後でポイントを列挙することにします。
# -*- coding: utf-8 -*- ### 各種設定 # 拡張子を除いたターゲットファイル名(texとbibは同名に) TARGET = "thesis" # TeX関係の実行ファイルが入っているディレクトリ TEX_BIN = "/Applications/UpTeX.app/teTeX/bin" # 使用するTeXプログラムとオプション TEX = "#{TEX_BIN}/platex --file-line-error" # 使用するBibTeXプログラムとオプション BIBTEX = "#{TEX_BIN}/jbibtex" # dviをpdfに変換するプログラムとオプション DISTILLER = "#{TEX_BIN}/dvipdfmx" ### タスク定義 def compile_tex sh "#{TEX} #{TARGET}.tex" end def compile_bibtex sh "#{BIBTEX} #{TARGET}" end def join_exts(filename, exts) exts.map { |x| "#{filename}.#{x}" } end task :default => :compile desc "一式をコンパイルしてPDFを生成。" task :compile => "#{TARGET}.pdf" do # force=trueなら強制的に一式をコンパイル if ENV['force'] == 'true' compile_tex compile_bibtex compile_tex end end file "#{TARGET}.pdf" => "#{TARGET}.dvi" do |t| sh "#{DISTILLER} #{t.prerequisites[0]}" end file "#{TARGET}.dvi" => join_exts(TARGET, ["tex", "bbl"]) do compile_tex end file "#{TARGET}.aux" => "#{TARGET}.tex" do # auxファイルが無いなら一度texファイルをコンパイル compile_tex end file "#{TARGET}.bbl" => join_exts(TARGET, ["aux", "bib"]) do compile_bibtex # 次にTARGET.dviディレクティブへ戻るが、 # 戻った時点でTARGET.dviが存在するので処理が終わってしまう。 # TeXではaux更新後にもう一度コンパイルする必要があるので代わりにここで行う。 compile_tex end require 'rake/clean' # pdfファイルは残す CLEAN.include join_exts(TARGET, [ "aux", "lof", "log", "lot", "out", "toc", "dvi", "bbl", "blg" ]) CLOBBER.include "#{TARGET}.pdf"
以下、ポイントを挙げていきます。
DSL
Rakeといえば言語内DSLですね。よく使われるメソッドとしてはtask, desc, file, shなどがあります。
- グローバルに使える関数
- 必要に応じてrequireするモジュール
- ドキュメントの「サブライブラリ」の項で列挙されているモジュール
- サンプルではrake/cleanを使ってます。
オプション
サンプルでは、:compileタスクで、ENV[‘force’]を参照していますが、
$ rake compile force=true
のように、タスク名の後に、key-valueの形でオプションを書くと、ENVに格納される仕組みになっています。コマンドオプションのようにフラグだけというのは出来ません*6。
ブロックの引数
taskやfileのブロックの引数には、Rake::Taskクラスのインスタンスが渡されます。
このRake::Taskクラスですが、ドキュメントには書かれていないのですが、プロパティとして、依存しているファイルのリストを持っています。それが、t.prerequisites
です。他にもソースコードを見ると、色々値を取れることが分かります。
ブロックの手抜きはダメ
一度はやりそうなので書いておきますが、ブロックをdo-endではなく{}で書くと爆発します。
task :default => “hoge” { do_something } # 爆発 task :default => “hoge” do do_something # :-) end
引数末尾のハッシュは括弧が省略できるのですが、括弧ブロックを使うのはエラーになります。