GNU make変数の伝播についてまとめ


知りたかったこと

makeを実行するときの変数の指定の仕方は

HOGE=env make

make HOGE=arg

がある。前者はシェルによって解釈され、後者はmake自身が解釈するのだが、実行にどう違いが出るのか?

Makefile内で変数の書き方は

# exportしない
HOGE=noexp

export HOGE=exp

がある。どう違うのか?

サブディレクトリ内でmakeする書き方は

$(MAKE) -C sub

$(MAKE) -e -C sub

がある。どう違うのか?

実際には

cd subdir && $(MAKE)

という書き方もあるが、これは$(MAKE) -C subdirと同じである。

これらの違いを知りたかったので、実験してみた。

実験結果

変数定義の優先順位

環境変数<ファイル内に書いた値<makeの引数
となる。つまり、

HOGE=file

all:
    echo $(HOGE)

と書いて

HOGE=env make HOGE=arg

で実行した場合、結果はargが表示される。

HOGE=env make

で実行した場合、fileが表示される。

Makefile内のHOGE=fileを消して

HOGE=env make

で実行した場合、envが表示される。

親makeから子makeへの変数の伝播の仕方

  • 親から子へ伝わるかどうか
  • 子で定義されている変数を上書きするかどうか

を表にするとこうなる:

-eなし -eあり
make HOGE=arg 伝わる。上書きする 伝わる。上書きする
HOGE=env make 伝わる。上書きしない 伝わる。上書きする
export HOGE=file1 伝わる。上書きしない 伝わる。上書きする
HOGE=file1 伝わらない。上書きしない 伝わらない。上書きしない

まとめ

  • 変数の優先順位は、環境変数<ファイル内に書いた値<makeの引数
  • exportした場合は環境変数と同じ扱いになる。したがって子に伝播する
  • exportしない場合はシェルにおけるシェル変数と同じく、自プロセス内でのみ有効(子に伝播しない)
  • 基本的に親ファイルに書いた変数は子ファイルに書いた変数を上書きしないが、-eをつけると上書きするようになる
  • コマンドラインの引数で指定した場合(make HOGE=arg)は常に子ファイルの変数を上書きする