この記事は「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ファイルを呼び出し、依存関係のライブラリをビルドできるようになりました。