- やりたいこと
- 調査の前提
- 方法1) すべての変数を環境変数として引き渡す
- 方法2) 特定の変数のみ環境変数として引き渡す
- 方法3) 特定のターゲットのサブプロセスにのみ環境変数を引き渡す
- 方法4) 特定のコマンドに対して環境変数を引き渡す
- おわりに
やりたいこと
makeで実行するコマンドに対して、つまりmakeから起動するサブプロセスに対して、Makefile内で定義した変数を環境変数として引き渡したい。 変数の引き渡しについて、makeのドキュメントにsub make(makeの再帰呼び出し)の説明があるが、実質的にはその説明内容はサブプロセスの起動にも適用できそう。
以降では、サブプロセスへの環境変数の渡し方ついて調査した結果を記しておく。
調査の前提
以下のMakefileをベースにして、必要に応じて編集して調査した。
FOO := foo BAR := bar .PHONY: test1 test1: @env | grep -E "(FOO|BAR)" || true .PHONY: test2 test2: @env | grep -E "(FOO|BAR)" || true
このMakefileの冒頭では、変数FOO
とBAR
を定義している。
そしてターゲットtest1
で、コマンドenv
を実行することにより、環境変数にFOO
とBAR
が含まれているかを確認している。
ターゲットtest2
の内容はターゲットtest1
と同じだが、環境変数のスコープを確認するために利用する。
現時点ではFOO
もBAR
も環境変数に含まれていないので、以下に示すようにmake
を実行しても何も表示されない。
$ make test1 (何も表示されない) $ make test2 (何も表示されない)
ちなみに、Makefile内のコマンドラインの末尾の|| true
は、マッチする文字列がなかった場合にgrep
がエラーを返してmake
が失敗に終わってしまうので、その対策である。
方法1) すべての変数を環境変数として引き渡す
makeのデフォルトの挙動では、Makefileで定義した変数はサブプロセスに引き渡されることはない。
しかしながらexport
という命令を利用することで、デフォルトの挙動を変更して、Makefileで定義したすべての変数を環境変数としてサブプロセスに引き渡すことができる。
Makefileは以下のようになる。
export FOO := foo BAR := bar .PHONY: test1 test1: @env | grep -E "(FOO|BAR)" || true .PHONY: test2 test2: @env | grep -E "(FOO|BAR)" || true
このMakefileを利用した実行結果は以下のようになり、環境変数FOO
とBAR
がサブプロセスであるenv
に引き渡されていることが分かる。
$ make test1 BAR=bar FOO=foo $ make test2 BAR=bar FOO=foo
なお、今回は試していないが、同様の効果を得るために.EXPORT_ALL_VARIABLES
という特別なターゲットも利用できるらしい。
これは、古いmakeを利用すると予約語export
が処理できずにエラーになるために、その回避策として利用するようである。
方法2) 特定の変数のみ環境変数として引き渡す
これはbashの環境変数のやり方に似ている。
変数定義の先頭にexport
を付与することで、Makefile中の変数を環境変数としてサブプロセスに引き渡すことができる。
Makefileは以下のようになる。
export FOO := foo BAR := bar .PHONY: test1 test1: @env | grep -E "(FOO|BAR)" || true .PHONY: test2 test2: @env | grep -E "(FOO|BAR)" || true
このMakefileでは、変数FOO
をサブプロセスに環境変数として引き渡すために、変数FOO
の定義にexport
を付与している。
一方で、変数BAR
にはexport
を付与していないので、サブプロセスの環境変数には含まれない。
このMakefileを利用した実行結果は以下のようになり、環境変数FOO
がサブプロセスであるenv
に引き渡されていることが分かる。
$ make test1 FOO=foo $ make test2 FOO=foo
方法3) 特定のターゲットのサブプロセスにのみ環境変数を引き渡す
target-specific variable(ターゲット固有の変数)を利用することで、特定のターゲットで起動されるサブプロセスに環境変数を引き渡すことができる。
Makefileは以下のようになる。
FOO := foo BAR := bar .PHONY: test1 test1: export FOO := $(FOO) test1: @env | grep -E "(FOO|BAR)" || true .PHONY: test2 test2: @env | grep -E "(FOO|BAR)" || true
このMakefileでは、ターゲットtest1
で変数FOO
をサブプロセスに環境変数として引き渡すために、次の1文を追加している。
test1: export FOO := $(FOO)
代入を省略してtest1: export FOO
とできれば楽なのだが、残念ながらMakefileの文法上それはできないようだ。
このMakefileを利用した実行結果は以下のようになり、ターゲットtest1
でのみ、環境変数FOO
がサブプロセスであるenv
に引き渡されていることが分かる。
$ make test1 FOO=foo $ make test2 (何も表示されない)
方法4) 特定のコマンドに対して環境変数を引き渡す
ターゲットの中のコマンドラインで、コマンドの先頭に引き渡す環境変数を書いておく。 このやり方はmakeとは関係がなく、bashの仕様に沿ったもの。
Makefileは以下のようになる。
FOO := foo BAR := bar .PHONY: test1 test1: @FOO=$(FOO) env | grep -E "(FOO|BAR)" || true .PHONY: test2 test2: @env | grep -E "(FOO|BAR)" || true
このMakefileを利用した実行結果は以下のようになり、コマンドラインで環境変数を指定した場合のみ、環境変数FOO
がサブプロセスであるenv
に引き渡されていることが分かる。
$ make test1 FOO=foo $ make test2 (何も表示されない)
おわりに
export
の他にも、unexport
やoverride
などの命令を利用することで、環境変数の取扱をより詳細に制御できるのではと思うが、今回はそこまでは踏み込んでいない。
差し当たって、上記の4つの方法を使えれば、今のところ個人的には問題なさそう。