環境変数の設定値とカレントディレクトリの一致をチェックする
詳細な仕様
Make 実行時に、カレントディレクトリと環境変数 MAKETOP の値を比較する。
設定内容に特定のサフィックスを付けた文字列が、カレントディレクトリと先頭一致しなければ、Make を異常終了する。
例えば、"MAKETOP=~/spikelet/make/check-env"、サフィックスを "/usr/src" とした時に、
- ~/spikelet/make/check-env/usr/src で make 実行 → 正しい
- ~/spikelet/make/check-env/usr/src/sub-dir で make 実行 → 正しい
- ~/spikelet/make/check-env/usr で make 実行 → 異常終了
となればOk。
Make 内での実現方法
以下の内容のMakefileを用意して、各ディレクトリのMakefileからincludeした。
compare_env_cwd = $(if \ $(shell pwd | grep "^`echo $$$(strip $(1)) | sed 's+/$$++'`$(strip $(2))"), ,\ $(error Env `$(strip $(1))' does't point current directory)) $(call compare_env_cwd, MAKETOP, /usr/src)
これを使う側(ソースツリー内のMakefile)では、以下のように include する:
include ../../check-env.mk
....
もしくは、他にツリー全体での共通Makefileがあるなら、そのファイル内にcompare_env_cwd(定義とcall)を書いても良い。
実行結果
テストスクリプトを https://sssvn.jp/svn/spikelet/make/check-env 以下に置いた。
実行結果は以下:
% ./do-test.sh ==== success case: cwd is $MAKETOP ==== make: Entering directory `/home/taiyo/spikelet/make/check-env/usr/src' All green make: Leaving directory `/home/taiyo/spikelet/make/check-env/usr/src' ==== success case: cwd is under $MAKETOP ==== make: Entering directory `/home/taiyo/spikelet/make/check-env/usr/src/subdir' All green make: Leaving directory `/home/taiyo/spikelet/make/check-env/usr/src/subdir' ==== FAIL case: cwd is above $MAKETOP ==== make: Entering directory `/home/taiyo/spikelet/make/check-env/usr' ../check-env.mk:6: *** Env `MAKETOP' does't point current directory. Stop. make: Leaving directory `/home/taiyo/spikelet/make/check-env/usr' ==== FAIL case: $MAKETOP is not set ==== make: Entering directory `/home/taiyo/spikelet/make/check-env/usr/src' ../../check-env.mk:6: *** Env `MAKETOP' does't point current directory. Stop. make: Leaving directory `/home/taiyo/spikelet/make/check-env/usr/src' ==== success case: cwd is under $MAKETOP/ ==== make: Entering directory `/home/taiyo/spikelet/make/check-env/usr/src/subdir' All green make: Leaving directory `/home/taiyo/spikelet/make/check-env/usr/src/subdir'
"All green" という表示がMake成功、"*** ... Stop." の表示がMakeの異常終了を示している。
たしかに、「詳細な仕様」に示したような結果になっている。
その他メモ
Conditional Parts of Makefiles
GNU Make の conditional(if, ifeq の「文」)は、あくまで文であって、関数内部では使えない。
その代わりに $(if) という関数があるので、そちらを使った。
The call Function は関数中では使えない
$(call) の引数の前後の空白は、付けたまま関数に渡される。
受け側で$(strip)をしないと、変な空白に悩むことになる。
※第一引数(関数を定義したmake変数の名前)の前後の空白は、$(call)のC側実装の内部で削除している。
function.c: func_call()
/* There is no way to define a variable with a space in the name, so strip leading and trailing whitespace as a favor to the user. */ fname = argv[0]; while (*fname != '\0' && isspace ((unsigned char)*fname)) ++fname;
存在しないmake変数への$(call)は空文字列になる
$(call)の第一引数(関数を定義したmake変数の名前)を間違えると、Warning などを出さずに、空文字列に置換される。
これは、以下の処理のせい:
function.c: func_call()
v = lookup_variable (fname, flen); if (v == 0) warn_undefined (fname, flen); if (v == 0 || *v->value == '\0') return o;
上記のように、lookup_variable に失敗した時には variable_buffer_output() を読んでいない。
参考: id:taiyo:20080402
warn_undefined() のマクロは以下のようになっている。
#define warn_undefined(n,l) do{\ if (warn_undefined_variables_flag) \ error (reading_file, \ _("warning: undefined variable `%.*s'"), \ (int)(l), (n)); \ }while(0)
warn_undefined_variables_flag は、"make --warn-undefined-variables" とするとセットされる。
つまり、--warn-undefined-variables を付けない限り、$(call) での名前間違いは警告されない。