この記事は「Qiita Advent Calendar 2019 DSLで自作ビルドツールを作ろう」の15日目の記事です。
15日目 環境変数・ディレクトリに依存しないビルドを実現したい
ビルドツールと言えば、チームで作業しているときに自分の環境ではビルドできるのに他人の環境に持って行くとビルドできない、そんな状況ってよくありますよね。
原因は様々ですが、例えばツールのバージョンが違ったりとか、環境変数が違ったりするわけです。そんな場合は例えばPythonだとPyenvなどを使って仮想環境を作り上げ、そこでクリーンな環境を構築するわけですが、これは少しハードルが高い。もう一つの方法は、環境変数ファイルを別に用意して、ビルド時にビルドファイルと一緒に環境設定ファイルも渡すことで環境を完全に合わせる、という方法です。仮想環境ほど完璧な方法ではありませんが、ある程度は効果があるはずです。
そこで、Rumy-Makeでのビルド時に環境変数を独自に設定し、なるべく環境違いによるビルド失敗を避ける方法を考えます。
Rubyが保持している環境変数
RubyはENV
と呼ばれる変数に環境変数一覧を格納しているようです。ためしに、以下のコードを実行して環境変数の名前とその値を出力してみます。
#!/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_path
とadd_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", "") ...
これで、個々の環境変数に依存せずに、ビルドを行うことができます。本当は引数で指定できたりするとなお良いのですが、とりあえずここまでにしておきます。