最近、仕事で Makefile から別のビルド システムへの変換を行っています。いくつかの場所で、関数マップ、フィルター、および foreach 構成要素を使用するかなり毛むくじゃらの Make コードを見てきました。ビルド スクリプトはできるだけ宣言的であるべきだと思うので、これには驚きました。
とにかく、これは私に考えさせました: Makefile 言語 (具体的には最新の GNU make と言います) チューリングは完全ですか?
最近、仕事で Makefile から別のビルド システムへの変換を行っています。いくつかの場所で、関数マップ、フィルター、および foreach 構成要素を使用するかなり毛むくじゃらの Make コードを見てきました。ビルド スクリプトはできるだけ宣言的であるべきだと思うので、これには驚きました。
とにかく、これは私に考えさせました: Makefile 言語 (具体的には最新の GNU make と言います) チューリングは完全ですか?
はい、これを参照してください。ラムダを取得したら、そこからすべて下り坂になります。
これは盗用されたフィボナッチの例です
これは、より一般化するための基盤を構築するのに十分なはずです (私は仕事に戻らなければなりません。さもなければ、もっとプレイしたいと思います)。
dec = $(patsubst .%,%,$1)
not = $(if $1,,.)
lteq = $(if $1,$(if $(findstring $1,$2),.,),.)
gteq = $(if $2,$(if $(findstring $2,$1),.,),.)
eq = $(and $(call lteq,$1,$2),$(call gteq,$1,$2))
lt = $(and $(call lteq,$1,$2),$(call not,$(call gteq,$1,$2)))
add = $1$2
sub = $(if $(call not,$2),$1,$(call sub,$(call dec,$1),$(call dec,$2)))
mul = $(if $(call not,$2),$2,$(call add,$1,$(call mul,$1,$(call dec,$2))))
fibo = $(if $(call lt,$1,..),$1,$(call add,$(call fibo,$(call dec,$1)),$(call fibo,$(call sub,$1,..))))
fact = $(if $(call lt,$1,..),.,$(call mul,$1,$(call fact,$(call dec,$1))))
numeral = $(words $(subst .,. ,$1))
go = $(or $(info $(call numeral,$(call mul,$1,$1)) $(call numeral,$(call fibo,$1)) $(call numeral,$(call fact,$1)) ),$(call go,.$1))
_ := $(call go,)
これは、二乗、フィボナッチ数、および階乗を出力します。数値サイズには 16 ビットの制限があるようです。残念。
否定的な答えとして、GNU make は再帰を作成するいくつかのメカニズムを積極的にブロックします。
「再帰関数」の意味で再帰的ではありません: それらはそれ自体で定義することはできません:
Actually make detects the infinite loop and reports an error.
(ちなみに、それらを許可することが実際にどのように役立つかはわかりません。)
2)ルールの連鎖
次のいずれかを再帰的にすることはできません。
No single implicit rule can appear more than once in a chain. (...)
This constraint has the added benefit of preventing any infinite loop
in the search for an implicit rule chain.
(メイクファイルをデバッグしている間、これでかなりの時間を失いました - メイクファイルを維持するのを難しくする他のすべてのものに加えて.)
PS 最近のプロジェクトのために、私はGNU make 3.82 へのパッチを書きました。このパッチは、新しい-Mオプションでこの制限を取り除きます (説明を参照)。それは私にとってはうまくいきます。