2010-08-13 4 views
39

Dernièrement au travail, j'ai fait de la traduction de Makefiles vers un système de construction alternatif. J'ai vu un peu de code Makey dans certains endroits en utilisant la carte fonctionnelle, le filtre et les constructions foreach. Cela m'a surpris car je pense que les scripts de construction devraient être aussi déclaratifs que possible.Est-ce que les fichiers makefiles Turing sont complets?

Quoi qu'il en soit, cela m'a fait penser: est le langage Makefile (disons que la dernière version de GNU est spécifique) Turing complète?

+1

Sans votre description, je vous demanderais si vous résolviez un pari :) –

+0

C'est sous Unix, il a une syntaxe velue, et il est étonnamment puissant. La plupart des choses comme ça sont Turing-complètes. Je n'ai pas été surpris il y a vingt ans quand quelqu'un m'a montré une machine vi macro Turing. –

+3

Vous pouvez débourser à tout ce que vous aimez, y compris une machine de Turing, pendant la construction des cordes. Techniquement, vous avez perdu à ce stade. (Nous avons des appels Perl dans nos Makefiles. –

Répondre

40

Oui, voir this. Une fois que vous avez lambda, tout est descendu de là.

Voici un exemple

plagiarized Fibonacci

Cela devrait être suffisant pour construire une base pour plus de généralité (je dois retourner au travail, ou je jouerais plus.)

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,) 

Ceci imprime des carrés, des nombres de fibonacci et des factoriels. Il semble y avoir une limite de 16 bits sur la taille des nombres. Bummer.

+1

Une fois que vous avez lambda, alors je suppose que vous pouvez créer un combinateur Y qui vous donne la récursivité. Comme vous le dites, tout en descendant de là. –

+9

C'est génial. Et effrayant. Généralement effrayant. –

+0

@Jorg Oleg est un gars génial mais effrayant. Généralement effrayant. Lire les autres choses qu'il a. – deinst

6

Pour une réponse négative: GNU make bloque activement certains mécanismes pour créer une récursivité:

1) Recursively expanded variables

ne sont pas récursive dans le sens « de fonction récursive »: ils ne peuvent pas être définis en termes d'eux-mêmes:

Actually make detects the infinite loop and reports an error. 

(je ne vois pas comment leur permettant pourraient être utiles dans la pratique, par la voie.)

2) Rule chaining

ne peut pas être récursive, soit:

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. 

(je perdu tout à fait beaucoup de temps au cours de cette mise au point pendant mes Makefile - en plus de toutes les autres choses qui rendent difficile à makefiles maintenir.)

PS pour un projet récent, j'ai écrit a patch to GNU make 3.82 qui supprime cette limitation avec une nouvelle option -M (voir discussion). Ça fonctionne bien pour moi.

+0

Ceci est intéressant, mais je serais très surpris si make pouvait toujours détecter des macros récursives en présence de quelque chose comme $ (eval). –

Questions connexes