FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

DSLでビルドツールを自作する (2日目 ターゲットを作ろう)

この記事は「Qiita Advent Calendar 2019 DSLで自作ビルドツールを作ろう」の2日目の記事です。

2日目 ターゲットを作ろう

Makefileで何が必要かということを考えてみると、まずはビルド対象のターゲットが必要です。Makefileだと、以下のようなやつです。

targets: target1 target2
    echo Hello World

ターゲットを定義して、そのターゲット依存する別のターゲット、そして実行コマンドを記述するわけです。これらの情報を定義するために、DSLで以下のように記述するようにしたいです。

  • 目標とするDSLの構造
make_target :first do         # ":first" ターゲットの定義
  depends [:second, :third]   # 依存関係として:second, :thirdとして登録する
  executes "echo Hello World" # 実行コマンド
end

ターゲットを定義するために、make_targetメソッドを定義しました。make_targetの中では、以下の2つのメソッドを記述できます。

  • depends : 該当するターゲットに依存するターゲットを登録します。
  • executes : 実行するコマンドを指定します。

このメソッドを定義するために、以下のようにTargetsクラスを定義します。

class Target
  # コンストラクタ
  def initialize(name)
    @name = name
  end
  # dependsメソッド。依存関係を定義する。
  def depends(targets)
    @depends = targets
  end
  # executesメソッド。実行コマンドを定義する。
  def executes(commands)
    @commands = commands
  end
  # デバッグ用のコマンド。メンバ変数の中身を表示する。
  def show
    puts "Target Name = #{@name}, Depends = #{@depends}, Commands = #{@commands}"
  end
end

Targetsクラスを定義しました。dependsメソッド、executesメソッドは見た通りです。デバッグ用のshowメソッドと、コンストラクタとしてinitializeを定義しました。

では、このTargetクラスをインスタンス化するためにmake_targetメソッドを定義します。

def make_target (name, &block)
  target = Target.new(name)
  target.instance_eval(&block)
  target.show
end

make_targetクラスでは、ターゲットの名前とブロックを受け取り、Targetクラスをインスタンス化します。

そして、インスタンス化したtargetに対してinstance_evalを適用し、ブロックの内部のメソッドを適用します。最後に、ここではデバッグのためにshowメソッドを実行します。

これに対してテストを実行します。上記のテストを実行してみます。

make_target :first do
  depends [:second, :third]
  executes "echo Hello World"
end
ruby -Isrc/ tests/exec_test.rb
Target Name = first, Depends = [:second, :third], Commands = echo Hello World

正しく表示されていることが確認できました。

f:id:msyksphinz:20191118012638p:plain