FPGA開発日記

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

DSLでビルドツールを自作する (15日目 環境変数・ディレクトリに依存しないビルドを実現したい)

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

15日目 環境変数ディレクトリに依存しないビルドを実現したい

ビルドツールと言えば、チームで作業しているときに自分の環境ではビルドできるのに他人の環境に持って行くとビルドできない、そんな状況ってよくありますよね。

原因は様々ですが、例えばツールのバージョンが違ったりとか、環境変数が違ったりするわけです。そんな場合は例えばPythonだとPyenvなどを使って仮想環境を作り上げ、そこでクリーンな環境を構築するわけですが、これは少しハードルが高い。もう一つの方法は、環境変数ファイルを別に用意して、ビルド時にビルドファイルと一緒に環境設定ファイルも渡すことで環境を完全に合わせる、という方法です。仮想環境ほど完璧な方法ではありませんが、ある程度は効果があるはずです。

そこで、Rumy-Makeでのビルド時に環境変数を独自に設定し、なるべく環境違いによるビルド失敗を避ける方法を考えます。

Rubyが保持している環境変数

RubyENVと呼ばれる変数に環境変数一覧を格納しているようです。ためしに、以下のコードを実行して環境変数の名前とその値を出力してみます。

#!/usr/bin/ruby

ENV.each { |k, e|
  puts "key = " + k + ", data = " + e
}
$ ./env_test.rb
key = APPDATA, data = C:\Users\msyksp\AppData\Roaming
key = BASH_ENV, data = /usr/local/lmod/lmod/init/bash
...
key = HOME, data = /home/msyksphinz
key = HOSTTYPE, data = x86_64
...
key = PERL5LIB, data = /home/msyksphinz/perl5/lib/perl5
key = PERL_LOCAL_LIB_ROOT, data = /home/msyksphinz/perl5
key = PERL_MB_OPT, data = --install_base "/home/msyksphinz/perl5"
key = PERL_MM_OPT, data = INSTALL_BASE=/home/msyksphinz/perl5

環境変数一覧が表示されました。そこで、つぎにこのハッシュリストの中身をすべて消してみます。

  • rumy-main.rb
ENV.clear

上記のクリア文をRumy-Makeの先頭に入れてビルドを実行すると、いろんなコマンドが無いと怒られてしまいました。

...
gcc: error trying to exec 'cc1': execvp: No such file or directory
gcc: error trying to exec 'cc1': execvp: No such file or directory
gcc: error trying to exec 'cc1': execvp: No such file or directory
gcc: error trying to exec 'cc1': execvp: No such file or directory
...

そこで、次に環境変数を設定するためのRumyのコマンド一覧を作成します。ビルド環境なので、基本的にPATHの追加とその他の環境変数の設定ができれば良さそうです。そこで、環境変数としてPATHを追加するためのadd_env_pathとLD_LIBRARY_PATHを設定するためのadd_env_ldpath、その他の環境変数を設定するためのadd_envを作りました。

  • src/rumy-env.rb
#!/usr/bin/ruby

# 環境変数をすべてクリアする
def clear_env
  ENV.clear
end

# 環境変数PATHを追加する
def add_env_path(env_data)
  if ENV["PATH"] == NIL then
    ENV["PATH"] = env_data
  else
    ENV["PATH"] += ":" + env_data
  end
end

# 環境変数LD_LIBRARY_PATHを追加する。
def add_env_ldpath(env_data)
  if ENV["LD_LIBRARY_PATH"] == NIL then
    ENV["LD_LIBRARY_PATH"] = env_data
  else
    ENV["LD_LIBRARY_PATH"] += ":" + env_data
  end
end

# 環境変数を追加する。
def add_env(env_name, env_data)
  ENV[env_name] = env_data
end

# 設定した環境変数を表示する
def show_env
  ENV.each{|k, e|
    puts "key = " + k + ", data = " + e
  }
end

add_env_pathadd_env_ldpathは、設定するたびに前の設定値の:を追加していきます。それ以外の環境変数については単純にハッシュに代入するだけです。

作成した関数を使用して、Swimmer-RISCVをビルドするのに必要な環境変数を設定していきます。

  • msyksphinz_env.rb
#!/usr/bin/ruby

load "rumy-env.rb"

# Clear Environment
clear_env

add_env_path "/usr/bin/"
add_env_path "/bin/"
add_env_path "/usr/local/bin/"

add_env "RUBYLIB", "/home/msyksphinz/work/rumy-make/src"

show_env

最初に環境変数をすべてクリアし、PATHの設定として/usr/bin/, /bin/, /usr/local/binを追加しました。あとは、Rumy-Makeを起動するために現状ではRUBYLIBの設定が必要なので、これも追加しておきます。

最後に、一応デバッグのためにshow_envで確認します。

作成したmsyksphinz_env.rbを、Swimmer-RISCVのビルド用のRumyファイルに追加しておけば、最初にすべての環境変数をクリアして、所望の環境変数を設定してくれます。

#!/usr/bin/ruby

load "msyksphinz_env.rb"
load "rumy-cpp.rb"

python_cflag  = `python3.6m-config --cflags`.sub("\n", "")
python_ldflag = `python3.6m-config --ldflags`.sub("\n", "")
build_date =    `date +%Y%m%d`.sub("\n", "")
...

これで、個々の環境変数に依存せずに、ビルドを行うことができます。本当は引数で指定できたりするとなお良いのですが、とりあえずここまでにしておきます。