Makefileで一部だけ並列処理で実行する
Page content
	
Makefileでターゲットを呼ぶ際、全部でなく一部分だけ並列で実行したかった。
概要
Makeを並列で実行するには、-jのオプションをつけて実行する。
$ make target -j3ただ今回、targetに書いた処理のうち一部だけ並列化し、他の部分は順序通り実行してほしかった。
シェルで並列実行といえば、コマンドに&をつけてバックグラウンド実行にして、それをwaitで待つ、というのが一般的。
なので以下のように書きました。が、これだと待ってくれない。
target:
    command-parallel1 &
    command-parallel2 &
    wait
    command3
    ...
Makeで改行するとwaitは効かない
Makeは一行ごとに違うシェルで実行される。なので、上のように書くと、
- 1つめのシェルでcommand-parallel1をバックグラウンド実行
 - 2つめのシェルでcommand-parallel2をバックグラウンド実行
 - 3つめのシェルでwaitを実行するが、子プロセスがいなければ一瞬で終了する
 - command3を実行
 
となり、高い確率で、並列処理中にcommand3へ進んでしまう。
これを防ぐには、シェルを変えずにワンライナーで書けばよい。
target:
    command-parallel1 & \
    command-parallel2 & \
    wait \
    command3
    ...
並列処理で起きたエラーはスキップされる
これで部分的な並列化は実現できた。
ところが、並列処理の中でエラーが起きた際にスキップされてしまう可能性がある。
waitの仕様として、最後に終了した子プロセスの終了コードを自身の終了コードとする。なので、
target:
    command-parallel1 & \ # <- 先にエラー終了
    command-parallel2 & \ # <- 後で正常終了
    wait \ # <- 正常終了とみなす
    command3
    ...
のように、command-parallel1のエラーが無視されてしまうケースがある。
wait $(PID)でプロセスIDごとに待ってみようとしても、改行すると効かなくなるので、
    wait $(PID1) && wait $(PID2)
と、それぞれの終了ステータスを見て進むこともできない。
結局jobsオプションで解決
解決といえるか微妙だけど、targetの形を変えて、
target-parallel:
    command-parallel1
    command-parallel2
target-post:
    command3
$ make -j3 target-parallel
$ make target-postで落ち着いた。
結論としては、失敗するかもしれないような処理を並列化とwaitで雑に処理するな、ということですね。



