FPGA開発日記

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

DSLでビルドツールを自作する (13日目 Rumyルールから外部Rumyルールを呼ぶ)

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

13日目 Rumyルールから外部Rumyルールを呼ぶ

今回実プロジェクトにRumy-Makeを適用したときに、もう一つ追加したい機能がありました。それは、外部のRumy-Makeファイルを呼び出して、ライブラリのビルドなども含めて外部ツールのビルドも行いたいということです。私の作っているRISC-Vシミュレータは外部のライブラリとしてsoftfloatを使っているので、softfloatのライブラリのビルドもRumyファイルで記述して、Swimmer-RISCVをビルドする際にこのsoftfloatのビルドも外部ライブラリのビルドとして呼び出せないか、ということを考えました。

softfloatライブラリのビルド環境をRumy-Makeに移植

まずは第一段階として、softfloatのライブラリをRumyを使ったビルド環境に置き換えます。これは簡単で、ぜ回作成したmake_libraryを使えば良いだけなのですが、一点だけ変更点は、どうもCファイルをビルドするときにg++を使用するとsoftfloatの場合は上手くリンクできないようなのです。

そこで、拡張子をみてC言語のファイルの時はccを使い、C++のファイルの時はg++を使うように実装を変k脳死ました。これでsoftfloatとSwimmer-RISCVのビルドの両方に対応できます。

def make_library(lib_name, cpp_file_list, compile_options, link_options, additional_depends = [])
...
    cc_cmd = "gcc"
    if cpp =~ /.*\.cpp$/ then
      cc_cmd = "g++"
    end
    make_target obj do
      depends [cpp]
      executes ["#{cc_cmd} #{compile_options.join(' ').to_s} -c #{cpp} -o #{obj}"]
    end
    ...

これで、softfloatもRumy-Makeでビルドできるようになりました。

  • vendor/softfloat/build-rumy/build.rb
#!/usr/bin/ruby

load "rumy-cpp.rb"
...
compile_options = compile_options + ["-DSOFTFLOAT_FAST_INT64"]
compile_options = compile_options + ["-DSOFTFLOAT_ROUND_ODD"]

# make_libarryでsoftfloatのライブラリを作成
make_library "libsoftfloat.a",
             ["../SoftFloat-3d/source/extF80M_add.c",
              "../SoftFloat-3d/source/extF80M_div.c",
              "../SoftFloat-3d/source/extF80M_eq.c",
...
              "../SoftFloat-3d/source/riscv/s_propagateNaNF64UI.c",
              "../SoftFloat-3d/source/riscv/softfloat_raiseFlags.c"],
             compile_options, [], []


if ARGV.length == 0 then
  exec_target "libsoftfloat.a"
elsif ARGV[0] == "clean" then
  clean_target "libsoftfloat.a"
elsif ARGV[0] == "draw" then
  draw_target "libsoftfloat.a"
else
  instance_eval("exec_target ARGV[0]")
end

Rumyルールで外部Rumyを呼ぶ

さて次です。Swimmer-RISCVのビルド途中にsoftfloatライブラリのビルドを呼び出すことを考えます。このために、まずはターゲットが外部ライブラリであることを意味するフラグを追加します。このために、新たにexternal_target関数を追加しました。

def external_target(lib_name, dir, depends = [])
  target = Target.new(lib_name)
  target.external(dir)
  target.depends(depends)
  $target_list[lib_name] = target
end

is_externalフラグは、このターゲットが外部Rumyルール呼び出しであることを意味します。このis_externalフラグが有効である場合、external_dirディレクトリに進んでデフォルトのビルドプロセスを動かすという仕組みにしようと思います。

そのために、exec_targetの判定オプションを以下のように追加しました。

private def do_target (name)
...
      # target_older_depends_list = target.depend_targets.each{|dep|
      skip_do_target = false
      if $target_list.key?(dep) and $target_list[dep].is_external then
        # External Target
        puts "[DEBUG] : Call External rule : " + dep
        Dir.chdir($target_list[dep].external_dir) {
...

もしis_externalが有効であれば、chdirで対象のディレクトリまで移動して同様にRumyビルドを起動します。最初は外部ライブラリのRumyファイルをその場でロードしてビルドコマンドを立ち上げようとしたのですが、よく考えるとそうするとソースファイルの位置がずれてしまいビルド対象のソースファイルを見つけることができなくなるので、やはりRumyファイルの存在するディレクトリまで移動してビルドすることにしました。それ以外のビルドは通常通りです。

このように、ビルド途中のオブジェクトファイルなどの中間ファイルをどこに置くか、というのが問題です。これは今後、環境やディレクトリに左右されないビルドの方法というものを考える中で修正していきたいと思います。

とりあえずは、外部Rumyルールの呼び出しが可能になったので、Swimmer-RISCVのビルドターゲットの中にsoftfloatのビルドルールを追加してみます。

external_target "../vendor/softfloat/build-rumy/libsoftfloat.a", "../vendor/softfloat/build-rumy/"

早速ビルドしてみましょう。

rumy 2>&1 | tee rumy.log
...
[DEBUG] : ==== Execute Target ../src/riscv_bfd_env.cpp.o ====
[DEBUG] : ==== Execute Target ../src/python3_env.cpp.o ====
[DEBUG] : Call External rule : ../vendor/softfloat/build-rumy/libsoftfloat.a
[DEBUG] : ==== Execute Target libriscv_cedar.a ====
Target Execution Skipped
Target Execution Skipped
...

うまくくビルドできたようです。これで、外部に記述しているRumyファイルを呼び出し、依存関係のライブラリをビルドできるようになりました。