概要
うまいやり方ないなと思っていたら、思いついたので備忘録として残す。
環境
- GNU Make 4.2.1
Tips
Makefileで作業ディレクトリを使う
なぜやるか
- 作業ディレクトリが固定の場合、並列でmakeをすると悲しいことになる
- 作業ディレクトリ内のファイルが処理中に書き換えられる
やり方
やり方は色々あるが、作ることよりも失敗したときに如何に消すかが問題となる。
解説は後にして、次のように書くと良い。
test-mktemp:
$(eval WORK_DIR := $(shell mktemp -d abcde-XXX))
bash -c "while test -d /proc/$$PPID; do sleep 0.5; done; rm -fR $(WORK_DIR)" &
...好きな処理...
例) echo "hello" > $(WORK_DIR)/hello.txt
解説
- 続く行で作業ディレクトリのパスを知りたいので eval で一時ディレクトリのパス名を控える
- makeのプロセスが死ぬまで待って、死んだら作業ディレクトリを削除するコードをバックグラウンドで動かすコードを仕込みます
- makefile では子プロセスでコマンドが実行されるので、makeのプロセスは
$PPID
で取得します。- shell では
trap "rm -fR 作業ディレクトリ" EXIT
で終了時にファイル削除ができるが、trap
を仕込んでも実行されるのは子プロセス側なので、次の行で有効にはならない
- shell では
- makefile では子プロセスでコマンドが実行されるので、makeのプロセスは
検証用コード
成功時と失敗による中断時の双方で動作することを確認するため、終了コードを引数で受け取れるようにする。
EXIT_CODE ?= 0
test-mktemp:
$(eval WORK_DIR := $(shell mktemp -d abcde-XXX))
bash -c "while test -d /proc/$$PPID; do sleep 0.5; done; rm -fR $(WORK_DIR)" &
sleep 3
echo "hello" > $(WORK_DIR)/hello.txt
cat $(WORK_DIR)/hello.txt
exit $(EXIT_CODE)
以下の通り、 exit した後で、ディレクトリが消え ls: cannot access
と表示される(期待通りの動作)。
$ make test-mktemp EXIT_CODE=0 & timeout 5 bash -c "while true; do ls -1d abcde-*; sleep 1; done"
[1] 49784
bash -c "while test -d /proc/$PPID; do sleep 0.5; done; rm -fR abcde-O2i" &
sleep 3
abcde-O2i
abcde-O2i
abcde-O2i
echo "hello" > abcde-O2i/hello.txt
cat abcde-O2i/hello.txt
hello
exit 0
# timeout 3 bash -c "while true; do ls -ld abcde-O2i; sleep 1; done"
abcde-O2i
ls: cannot access 'abcde-*': No such file or directory
[1]+ Done make test-mktemp EXIT_CODE=0
$ make test-mktemp EXIT_CODE=1 & timeout 5 bash -c "while true; do ls -1d abcde-*; sleep 1; done"
[1] 49831
bash -c "while test -d /proc/$PPID; do sleep 0.5; done; rm -fR abcde-zh2" &
sleep 3
abcde-zh2
abcde-zh2
abcde-zh2
echo "hello" > abcde-zh2/hello.txt
cat abcde-zh2/hello.txt
hello
exit 1
make: *** [Makefile:46: test-mktemp] Error 1
abcde-zh2
ls: cannot access 'abcde-*': No such file or directory
[1]+ Exit 2 make test-mktemp EXIT_CODE=1