make さんが "process_begin: CreateProcess((null), , ...)" とか言って爆死する件 - それと解

こんな単純な makefile があって、コマンドプロンプト(==窓)で make したとします。

default : hina.txt

hina.txt : kana.txt
	move $< $@

kana.txt :
	echo kana > $@
c:\path\to\work>make
echo kana > kana.txt
move kana.txt hina.txt
process_begin: CreateProcess((null), move kana.txt hina.txt, ...) failed.
make (e=2): 指定されたファイルが見つかりません。
make: *** [hina.txt] Error 2

move でコケるとかどういうこちゃねん!

解決方法

失敗するコマンドに対して、makeの実行に影響を及ぼさない範囲でリダイレクト or 他のコマンドへのパイプ を混ぜましょう。何を混ぜ込むかはシーンによって異なるかと思いますが、例えば…

# コマンド結果を「じげんのはざま」へ そぉい!
hina.txt : kana.txt
	move $< $@ > nul

# 無駄に修飾してみる。無駄無駄無駄ァ!!
hina.txt : kana.txt
	move $< $@ 9>&1

# 他のコマンドへパイプ。禁煙にはパイポ
hina.txt : kana.txt
	move $< $@ | more

# [追記]ぐぐったら cmd に投げるのも良しだった
hina.txt : kana.txt
	cmd /c move $< $@
c:\path\to\work>make
echo kana > kana.txt
move kana.txt hina.txt 9>&1
        1 個のファイルを移動しました。

c:\path\to\work>dir *.txt
 ドライブ C のボリューム ラベルは Windows です
 ボリューム シリアル番号は DEAD-BEEF です

 c:\path\to\work のディレクトリ

0548/02/14  14:08                 7 hina.txt
               1 個のファイル                 7 バイト
               0 個のディレクトリ  254,571,880,448 バイトの空き領域

うむ!

現象

少なからず、私が利用ている Gow に収録されている GNU make (v3.80 or v3.81) でこの現象が発生しています。

make -d すると解るのですが、特に修飾しなくとも正常に終了するコマンドは、CreateProcess() の第1・2引数共に適切なパラメータが渡されています。 この適切なパラメータは次の2種類の傾向が見受けられます。

  1. 該当コマンドのフルパス
  2. テンポラリに生成されたバッチファイルへのフルパス。 このバッチファイルは、ルールに記述されているコマンド1行がそのまま記述されていると思われ、それを実行することによりルールの1行を実行しているものと推測される。

失敗するコマンドについては、第1引数に null が指定され(ついでに、第2引数にコマンド1行がそのまま渡され) CreateProcess() に失敗しています。 今回の "move" は内部コマンドなので、そりゃ cmd かまさないと実行できないですよねぇ…と。

じゃぁ、どう回避するかと悩んだのですが、成功するコマンド・失敗するコマンドを比較した際に「成功する方はリダイレクト付いてるね…」と気づき、適当にリダイレクトかましたら実行できるように…! リダイレクトされていると強制的に「テンポラリのバッチを実行する形式」になり、結果 move が見つかるのでコマンドが成功する形になります。 …まぁそういう事してる場合は、素直に cmd に任せた方が実装が楽だったんだろうなぁ……(ぉ



ちなみに「失敗するコマンド」とか抽象的に書いてますが、おいらは今のところ "move" しか発見できてません! :-]

…ってか、何で move は失敗するのん…… copy とか echo とかの内部コマンドは成功してるのに………





ソース嫁。

トン!

つまる所

窓使いだったら nmake でも使ってろよって話ですねハイ