Create  Edit  Diff  FrontPage  Index  Search  Changes  History  RSS  Source  Login

RakefileFormat

3.1 はじめに

まず第一に、Rakefile 専用のフォーマットというのは存在しません。Rakefile は実行可能な Ruby のコードで構成されます。ruby スクリプトとして正当であれば、Rakefile としても正当です。

専用のフォーマットはないと説明しましたが、典型的な Ruby プログラムではあまり見かけない、ちょっと変わったイディオムを使用することがあります。Rakefile は、タスクとアクションを合わせて指定するために、その、ちょっと変わったイディオムをサポートしています。

それでは、Rakefile はどのように書くのでしょうか?

3.2 タスク

タスクは Rakefile の基本となる作業単位です。タスクは、タスク名(通常は、シンボルか文字列)、前提条件リスト(これも、シンボルか文字列)、アクション(ブロックとして与えられる)を持ちます。

単純なタスク

タスクは task メソッドを使って宣言されます。task は引数に、タスク名を一つ取ります。

task :name

前提条件付きのタスク

タスク名と => の後のリスト([ ]の中)に、どのような前提条件でも、指定することが出来ます。

task :name => [:prereq1, :prereq2]

注意!!: この構文はちょっと変わって見えますが、正当な Ruby のコードです。キーが :name 、値が前提条件([ ]の部分)の Hash を作っているだけです。要は、以下と同等です。

hash = Hash.new
hash[:name] = [:prereq1, :prereq2]
task(hash)

アクション付きのタスク

アクションは task メソッドのブロックの中に定義されます。どのような Ruby コードでもかまいません。ブロックパラメータを使って、task オブジェクトの参照を渡すこともあります。

task :name => [:prereq1, :prereq2] do |t|
  # アクション(t を利用できます。)
end

複数回の定義

タスクが2回以上定義されることがあります。その場合、定義が実行されるたびに、前提条件とアクションを、既存の定義に追加します。これは、アクションの指定と、依存関係宣言を、別の場所(おそらく別のファイル)で定義することを許可するためです。

例えば下記は、上の項(アクション付きのタスクの項)で定義されたタスクと同等のものです。

task :name
task :name => [:prereq1]
task :name => [:prereq2]
task :name do |t|
  # アクション
end

3.3 ファイルタスク

いくつかのタスクは、あるファイルから別のファイルを生成します。ファイルが既に存在すれば、そのタスクは省略されるかもしれません。ファイルタスクはファイル生成処理に使用されます。

ファイルタスクは file メソッド(task メソッドの代わり)を使用してし定義されます。なお、ファイルタスクのタスク名には、シンボルではなく文字列が使用されるのが一般的です。

以下のファイルタスクは、実行形式ファイル(prog)を生成するために、2つのオブジェクトファイル、 a.o と b.o が存在することを想定しています。このタスクでは a.o と b.o の生成については触れません。

file "prog" => ["a.o", "b.o"] do |t|
  sh "cc -o #{t.name} #{t.prerequisites.join(' ')}" 
end

3.4 ディレクトリタスク

ディレクトリの作成が必要となるケースはよくあることです。directory メソッドは、ファイルタスクに足りない、ディレクトリ作成処理を実施します。例えば、

directory "testdata/examples/doc"

と、以下は同等です。

file "testdata"              do |t| mkdir t.name end
file "testdata/examples"     do |t| mkdir t.name end
file "testdata/examples/doc" do |t| mkdir t.name end

directory メソッドには、前提条件やアクションは指定できませんが、後から追加することなら可能です。例えば以下のようにします。

directory "testdata" 
file "testdata" => ["otherdata"]
file "testdata" do
  cp Dir["standard_data/*.data"], "testdata" 
end

3.5 ルール

前提条件にファイル名が未指定の場合、Rake はルールリストから対応するタスクを探し出そうとします。

mycode.o が未定義の状態で、mycode.o タスクが実施されるとします。その場合でも rakefile には、以下のようなルールが存在します。

rule '.o' => ['.c'] do |t|
  sh "cc #{t.source} -c -o #{t.name}" 
end

上記のルールは、.o で終わるすべてのタスクに対応します。それは、前提条件に、拡張子 .c のソースファイルが存在することを指定します。mycode.c というファイルを発見すれば、mycode.c から mycode.o を生成するタスクを自動的に作り出します。

mycode.c が見つからない場合は、再帰的に、ルールに対応するタスクがないかを探そうとします。

ルールに対応するタスクが見つかった時、参照(ブロックパラメータ)に、source 属性がセットされます。これは、アクション内でで、ソースファイルを扱えるようにするためです。

3.6 高度なルール

ルールパターンには正規表現が使用できます。ソースファイル名を求めるのに proc 利用されることもあります。これは、複雑なルールパターンや、複雑な手順でソースファイル名を求めるのに対応するためです。

以下のルールは、上の項(ルールの項)と同等です。

rule( /\.o$/ => [
  proc {|task_name| task_name.sub(/\.[^.]+$/, '.c') }
]) do |t|
  sh "cc #{t.source} -c -o #{t.name}" 
end   

注意!! : Ruby の都合で、ルールに対する最初の引数が正規表現の場合、括弧を省略することは出来ません。

以下のルールを、Java ファイルのために利用することがあるかもしれません。

rule '.java' => [
  proc { |tn| tn.sub(/\.class$/, '.java').sub(/^classes\//, 'src/') }
] do |t|
  java_compile(t.source, t.name)  
end

注意!! : java_compile は、Java コンパイラを呼び出す命令の例えです。

3.7 ファイル読み込みの依存関係

ruby ファイル(別の rakefile も含む)でありさえすれば、require でそのファイルを読み込むことが出来ます。取り込まれたルールと宣言は、既存の定義に追加されます。

ファイルの読み込みは、タスクが評価される前に実施されるので、読み込まれるファイルは、あらかじめ準備されている必要があります。このことは、取り扱いの難しい依存ファイルを作る原因になりました。ファイルの読み込みに、準備が間に合わない状態です。

import メソッドは、すべての rakefile が読み込まれた後、rake コマンドで指定されたターゲットより先に実施されます。しかも、import メソッドに指定したファイル名にマッチするタスクがある場合は、ファイルを読み込む前に、そのタスクを実施します。このことにより、依存ファイルの生成と読み込みを、一回の rake コマンドで行うことが可能になります。

require 'rake/loaders/makefile'

file ".depends.mf" => [SRC_LIST] do |t|
  sh "makedepend -f- -- #{CFLAGS} -- #{t.prerequisites} > #{t.name}" 
end

import ".depends.mf" 

.depends.mf が存在しない場合や、ソースファイルに対して古い状態である場合は、ファイルが取り込まれる前に、新しい .depends.mf を生成します。

3.8 コメント

Ruby のコメント(# から始まる)は、どこでも使用することができます。タスクやルールにコメントを使用しても問題はありません。しかし、タスクが -T オプション(後述します)に対応することを望む場合は、desc メソッドを使用する必要があります。

desc "配布パッケージの作成" 
task :package => [ ... ] do ... end

-T(こだわり派は --task)オプションは、タスクに定義されたコメントを画面にリストアップします。desc メソッドでコメントを定義してあれば、半自動的に要約が生成されます。

traken$ rake -T
(in /home/.../rake)
rake clean            # Remove any temporary products.
rake clobber          # Remove any generated file.
rake clobber_rdoc     # Remove rdoc products
rake contrib_test     # Run tests for contrib_test
rake default          # Default Task
rake install          # Install the application
rake lines            # Count lines in the main rake file
rake rdoc             # Build the rdoc HTML Files
rake rerdoc           # Force a rebuild of the RDOC files
rake test             # Run tests
rake testall          # Run all test targets

-T オプションでは、タスクのコメントのみがリストアップされます。前提条件も合わせてリストアップしたい場合は -P(もしくは --prereqs)オプションを使用してください。

3.9 その他

do/end か { } か

Ruby のブロックは、do/end か { } のどちらかで指定されますが、rakefile でタスクやルールを指定する場合は、do/end を使用することを、強くおすすめします。rakefile で、task/file/rule メソッドを使用する場合には、括弧を省略することが多いため、{ } を使用してしまうと、期待した動作にならないことがあるからです。

例えば、プロジェクトのオブジェクトファイルのリストを返す、object_files メソッドがあるとします。そして、ルールの前提条件にその object_files メソッドが使用され、アクションの指定には { } を使用するとします。

# このようにしてはいけません!!
file "prog" => object_files {
  # ここにアクションが定義されると思いますが、うまく動いてくれません。
}

{ } は do/end より優先順位が高いため、{ } のブロックを、file メソッドのブロックではなく、object_files メソッドのブロックとして扱われてしまいます。

以下が、タスクを指定する適切な方法です。

# このようにしてください!!
file "prog" => object_files do
  # ここにアクションで、うまくいきます。。
end
Last modified:2017/08/11 00:57:03
Keyword(s):
References:[AboutRakeUserGuide] [SideMenu]