この記事は「Qiita Advent Calendar 2019 DSLで自作ビルドツールを作ろう」の3日目の記事です。
3日目 ターゲットを実行する
前回、ターゲットを作ったので、次はターゲットを実行するためのルールを追加します。ターゲットを実行するために、exec_target
関数を作りたいと思います。
作成したターゲットをHash関数に登録するための処理
ターゲットを指定して実行するためには、作成したターゲットを登録して、後で参照できるようにしておく必要があります。ターゲットはラベル名で識別するので、Hashを用いたテーブルを使用して、ラベル名から該当するターゲットを引き出せるようにしておきます。
グローバル領域に、@target_list
というHashマップを定義します。キーはターゲットに付けているラベル名。コンテンツはターゲットルールそのもの(Target
クラスをインスタンス化したもの)です。
src/rumy-exec.rb
def exec_target (name) if @target_list.key?(name) then target = @target_list[name] result = `#{target.commands}` puts result else puts "Error: target #{name} not found." end end
@target_list = Hash.new
make_target
実行時に、インスタンス化したターゲットを@target_list
に登録しておきます。
def make_target (name, &block) target = Target.new(name) target.instance_eval(&block) target.show @target_list[name] = target # ターゲットを@target_listに登録する。 end
ターゲットを実行する
次に、exec_target
では、同じようにラベル名を引数に指定し、ラベル名からターゲットを参照します。登録されていない(つまり作成されていない)ターゲットを参照しようとした場合はエラー、そうでない場合はターゲットから、コマンドを呼び出して実行します。
src/rumy-exec.rb
def exec_target (name) if @target_list.key?(name) then target = @target_list[name] result = `#{target.commands}` puts result else puts "Error: target #{name} not found." end end
テストを作成する
簡単なechoコマンドを呼び出すターゲットを実行する
では、実際にexec_target
を使用するテストを書いてみましょう。まずは、前回作成した:first
ターゲットを実行してみます。exec_target
の引数に:first
を渡すだけで実行できます。
tests/exec_test.rb
#!/usr/bin/ruby load "rumy-exec.rb" make_target :first do depends [:second, :third] executes "echo Hello, First Target" end exec_target :first
$ ruby ../tests/exec_test.rb [DEBUG] : Target Created = first, Depends = [:second, :third], Commands = echo Hello, First Target Hello, First Target
実行できました!ルール(Rubyのラベル)を使用して、ターゲットを実行することができました。
Cソースコードをコンパイルするターゲットを実行する
次にもう少し進んで、以下のソースコードをコンパイルするターゲットを作ってみます。
tests/simple_main.cpp
#include <stdio.h> int main () { printf("Hello rumy-make!!\n"); return 0; }
以下のように、simple_main.cpp
をコンパイルするための:compile
ターゲットを作成します。
tests/exec_test.rb
make_target :compile_c do src = "../tests/simple_main.cpp" exe = src.sub(".cpp", "") executes "gcc #{src} -o #{exe}" end exec_target :compile_c
Rubyの内部DSLを使っているわけですから、Rubyの機能をフル活用しましょう。入力ソースコードをsimple_main.cpp
とし、実行バイナリをsimple_main
としたいのですが、同じことを2回も書くのは面倒なので、Rubyの文字列に対するsub
関数を使用して、ターゲットバイナリのファイル名を作っています。そしてgccに渡す引数も#{src}
や#{exe}
を活用することで、楽に書けるように工夫をしているわけです。
実行してみると、特にエラー無くコンパイルすることができます。simple_main.cpp
から、simple_main
がコンパイルされてバイナリが作られていることを確認しましょう。
ruby ../tests/exec_test.rb [DEBUG] : Target Created = compile_c, Depends = , Commands = gcc ../tests/simple_main.cpp -o ../tests/simple_main
これを実行するためのターゲットも作りたいのですが、これは:compile
ターゲットに対する依存関係を持たせたいので、次回に持ち越しです。