YOSHINO日記

プログラミングに関すること

Rake入門

taskの依存関係を理解する

最初のサンプルなので、順を追って説明していきます。

①単純なtask

task :default => :daily_report

desc "1日のトレーニング内容を記録する"
task :daily_report do
  puts "レポートを作成しました。"
end

task :default => :daily_reportにより、rakeコマンドを簡潔に実行できる。

$ rake
#=> レポートを作成しました。

・descに記述したものは以下のコマンドで見ることが出来る。

$ rake -T
#=> rake daily_report  # 1日のトレーニング内容を記録する

②依存関係を記述する

task :default => :daily_report

desc "1日のトレーニング内容を記録する"
task :daily_report => [:run,:swim] do
  puts "レポートを作成しました。"
end

desc "1日のswim量を報告します"
task :swim do
  puts "今日あなたは2キロ泳ぎました"
end

desc "1日のrun量を報告します"
task :run do
  puts "今日はあなたは4キロ走りました"
end

task :daily_report => [:run,:swim] doの部分でtaskdaily_reportの依存関係を記述できます。

$ rake
#=> 今日はあなたは4キロ走りました
#=> 今日あなたは2キロ泳ぎました
#=> レポートを作成しました。

task :daily_report => [:swim,:run] doとすると実行順序が変わることがわかります。

$ rake
#=> 今日あなたは2キロ泳ぎました
#=> 今日はあなたは4キロ走りました
#=> レポートを作成しました。

・依存関係をクリアしないとrakeは失敗します。 以下のようにdaily_reportの依存関係の1つであるswimをコメントアウトしてrakeを実行します。

task :default => :daily_report

desc "1日のトレーニング内容を記録する"
task :daily_report => [:swim,:run] do
  puts "レポートを作成しました。"
end

#desc "1日のswim量を報告します"
#task :swim do
#  puts "今日あなたは2キロ泳ぎました"
#end

desc "1日のrun量を報告します"
task :run do
  puts "今日はあなたは4キロ走りました"
end
$ rake
#=> rake aborted!
#=> Don't know how to build task 'swim' (see --tasks)

ファイルタスク:差分ビルドの実現

Rake

タスクではなく、あえてファイルタスクを用いる理由、それは差分ビルドの実現にある。 タスクとして定義された場合、そのタスクは必ず実行される。もっと言えば、いまそれをする必要が無くとも、定義されている以上実施してしまう。しかし、ファイルタスクの場合、必要なときだけタスクを実施するのである。具体的には、定義されたファイルを作ろうとする際、まず目的ファイルが作成済みかどうかを調べる。作成済みであれば、続けて依存先のファイルの更新日時を調べ、それが目的ファイルよりも新しくなっている場合のみ、変更があったと見なしてビルド作業を実施するのだ。これは大変な時間の節約になる。

例えば、同一フォルダ内に以下のようなファイルが3つある場合を想定します。

$ ls
#=> Rakefile  report.txt  run.txt  swim.txt
$ cat run.txt
#=> run: 12キロ
$ cat swim.txt
#=> swim: 5キロ
$ cat report.txt
#=> swim: 5キロ
#=> run: 12キロ
task :default => :report

desc "ファイルに記録します"
task :report => "report.txt"
file "report.txt" => ["swim.txt","run.txt"] do
  puts "ファイルを記録します"
  swim = File.read("swim.txt")
  run = File.read("run.txt")
  report = swim + run
  File.open("report.txt","w") do |file|
    file.puts(report)
  end
end

ポイントはfile "report.txt" => ["swim.txt","run.txt"] doで、report.txtswim.txtrun.txtに依存していることです。 このような関係にある時、swim.txtrun.txtに変更が加わらなければ、file'report.txt'が更新されることはありません。

$ rake

なにも実行されません。

$ echo "swim: 20キロ" > swim.txt
$ rake
#=>  ファイルを記録します

今度はfile'report.txt'が更新されていることがわかります。

$ cat report.txt
#=> swim: 20キロ
#=> run: 12キロ

C言語コンパイル

基本的なことだけ

CC = "gcc"

task :default => "hello"

file "hello" => ["hello.o"] do
    sh "#{CC} -o hello hello.o"
end

file "hello.o" => "hello.c" do
    sh "#{CC} -c hello.c"
end

task :clean do
    sh "rm -rf hello *.o"
end

・依存関係を辿って行くと、hello=>hello.o=>hello.c

gcc -c hello.c hello.oが作成される コンパイルのみ行う(オブジェクトファイルを生成する).

gcc -o hello hello.o hello.oをhelloにリンクする

・コマンドを実行するときは、

$./hello

・rakeを2度実行しても何も起こらない

・hello.cを変更すれば、gcc -c hello.cgcc -o hello hello.oの両方が実行される。

・hello.oを変更すればgcc -o hello hello.oだけ実行される。

f:id:taiki44no:20171101215944p:plain

参照

rake 公式 C言語のビルドでほのぼのrakeでmakeするよ るびくる&RBのRubyプログラミング大作戦! ファイルを扱う作業をRakeで便利にしよう!(パート1:概要編) パーフェクト Ruby [Ruby][rake]Rakefileでgccコンパイルしてみる コンパイラ(gccコマンド)の使い方