web-dev-qa-db-fra.com

Définir la variable make au moment de l'exécution de la règle

Dans mon fichier GNUake, je voudrais avoir une règle qui utilise un répertoire temporaire. Par exemple:

out.tar: TMP := $(Shell mktemp -d)
        echo hi $(TMP)/hi.txt
        tar -C $(TMP) cf $@ .
        rm -rf $(TMP)

Comme indiqué, la règle ci-dessus crée le répertoire temporaire au moment où elle est analysée. Cela signifie que, même si je ne décroche pas toujours.tar, de nombreux répertoires temporaires sont créés. Je voudrais éviter que mon/tmp soit jonché de répertoires temporaires inutilisés.

Existe-t-il un moyen de ne définir la variable que lorsque la règle est déclenchée, et non à chaque fois qu'elle est définie?

Mon idée principale est de vider mktemp et tar dans un script Shell, mais cela semble quelque peu inesthétique.

180
Emil Sit

Dans votre exemple, la variable TMP est définie (et le répertoire temporaire créé) chaque fois que les règles pour out.tar sont évaluées. Afin de créer le répertoire uniquement lorsque out.tar est effectivement déclenché, vous devez déplacer la création du répertoire dans les étapes suivantes:

out.tar : 
    $(eval TMP := $(Shell mktemp -d))
    @echo hi $(TMP)/hi.txt
    tar -C $(TMP) cf $@ .
    rm -rf $(TMP)

La fonction eval évalue une chaîne comme si elle avait été saisie manuellement dans le fichier makefile. Dans ce cas, la variable TMP est définie sur le résultat de l'appel de fonction Shell.

edit (en réponse aux commentaires):

Pour créer une variable unique, vous pouvez procéder comme suit:

out.tar : 
    $(eval $@_TMP := $(Shell mktemp -d))
    @echo hi $($@_TMP)/hi.txt
    tar -C $($@_TMP) cf $@ .
    rm -rf $($@_TMP)

Cela préfixerait le nom de la cible (out.tar, dans ce cas) à la variable, produisant une variable portant le nom out.tar_TMP. Espérons que cela suffira à prévenir les conflits.

280
e.James

Un moyen relativement simple de procéder consiste à écrire la séquence entière sous forme de script Shell.

out.tar:
   set -e ;\
   TMP=$$(mktemp -d) ;\
   echo hi $$TMP/hi.txt ;\
   tar -C $$TMP cf $@ . ;\
   rm -rf $$TMP ;\

J'ai regroupé quelques conseils connexes ici: https://stackoverflow.com/a/29085684/86967

56
nobar

Une autre possibilité consiste à utiliser des lignes distinctes pour configurer les variables Make quand une règle est déclenchée.

Par exemple, voici un fichier makefile avec deux règles. Si une règle se déclenche, elle crée un répertoire temporaire et définit TMP sur le nom du répertoire temporaire.

PHONY = ruleA ruleB display

all: ruleA

ruleA: TMP = $(Shell mktemp -d testruleA_XXXX)
ruleA: display

ruleB: TMP = $(Shell mktemp -d testruleB_XXXX)
ruleB: display

display:
    echo ${TMP}

L'exécution du code produit le résultat attendu:

$ ls
Makefile
$ make ruleB
echo testruleB_Y4Ow
testruleB_Y4Ow
$ ls
Makefile  testruleB_Y4Ow
27
user3124434