概要
- makeはタイムスタンプを見てファイルの更新管理をしている
-
(依存物のタイムスタンプ) > (生成物のタイムスタンプ)
⇒ 更新
-
- タイムスタンプの精度は意外と荒い
- 実行速度がタイムスタンプの精度に勝つと
(ソース(更新前)のタイムスタンプ) == (ソース(更新後)のタイムスタンプ)
になってしまうことがある - そうなると更新の必要性判定がうまく動いてくれず、更新がうまくいかなくなる
- だからシェルやニンジャパワー1でファイルの書き換えとビルドを行うなら、ファイルの上書きとビルドをする時とかは気を付けよう
問題
Q ①のような状況で ②を実行したとき、 ファイル dst
には何が書かれている?
(脳内bashで実行してみよう)
①
$ ls
Makefile dst src
$ cat Makefile
dst:src
cat src > dst
init:
> dst
②
make init
echo "foo" >src
make dst
A fooが書かれてる
本当に?
筆者が使っているサーバで試したところ、以下のような結果となった
$ make init ;echo "foo" >src;make dst
> dst
cat src > dst
$ make init ;echo "foo" >src;make dst
> dst
make: `dst' は更新済みです
なぜか実行毎にdstが更新されたり更新済みだったりした
何が起こった?
シェルの実行速度がタイムスタンプの精度を上回った結果、
srcが前回から変更されてない→dstも更新する必要なしと判断された
makeはファイルのタイムスタンプを見て更新の不要必要を判断している
つまり、
(srcのタイムスタンプ) > (dstのタイムスタンプ)
なら
『srcのほうがdstより新しい→最後にmakeしてからsrcが更新された→再ビルドが必要』となる
問題の例だと
1. make init
で dst更新
2. echo "foo" >src
でsrc更新
3. make dst
で (srcのタイムスタンプ) > (dstのタイムスタンプ)
なら dst更新
という流れになる
しかし、1と2がタイムスタンプの精度より高速に終わると
`(srcのタイムスタンプ) == (dstのタイムスタンプ)
という状況が成立し、
3でdstの更新が行われなくなる
現に3で更新に失敗した際、タイムスタンプは以下のようになっていた
dstとsrcのタイムスタンプが同じである
$ ls --full-time src dst
-rw-rw-r-- 1 fuyutsubaki fuyutsubaki 0 2018-06-26 12:31:16.196755342 +0900 dst
-rw-rw-r-- 1 fuyutsubaki fuyutsubaki 4 2018-06-26 12:31:16.196755342 +0900 src
対策
- ファイルの上書きが発生する処理を避ける
- ニンジャパワー2を手に入れてもむやみやたらに使わない