web-dev-qa-db-fra.com

Teste si un répertoire existe dans un makefile

Dans sa réponse @Grundlefleck explique comment vérifier si un répertoire existe ou non. J'en ai essayé d'utiliser ceci dans un makefile comme suit:

foo.bak: foo.bar
    echo "foo"
    if [ -d "~/Dropbox" ]; then
        echo "Dir exists"
    fi

Fonctionnement make foo.bak (étant donné que foo.bar existe) génère l'erreur suivante:

echo "foo"
foo
if [ -d "~/Dropbox" ]; then
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [foo.bak] Error 2

La solution de contournement que j'ai faite était d'avoir un script bash autonome dans lequel le test est implémenté et j'ai appelé le script à partir de makefile. Cela semble toutefois très lourd. Existe-t-il un moyen plus agréable de vérifier si un répertoire existe à l'intérieur de makefile?

51
Dror

Les commandes Make, si une commande Shell, doivent être sur une seule ligne ou sur plusieurs lignes à l'aide d'une barre oblique inverse pour l'extension de ligne. Donc, cette approche fonctionnera:

foo.bak: foo.bar
    echo "foo"
    if [ -d "~/Dropbox" ]; then echo "Dir exists"; fi

Ou

foo.bak: foo.bar
    echo "foo"
    if [ -d "~/Dropbox" ]; then \
        echo "Dir exists"; \
    fi
58
lurker

Cette approche fonctionne avec des échos minimaux:

.PHONY: all
all:
ifneq ($(wildcard ~/Dropbox/.*),)
        @echo "Found ~/Dropbox."
else
        @echo "Did not find ~/Dropbox."
endif
39
cforbish

Agit en l'absence d'un répertoire

Si vous avez seulement besoin de savoir si un répertoire n'existe pas et si vous voulez agir sur celui-ci en le créant par exemple, vous pouvez utiliser des cibles Makefile ordinaires:

directory = ~/Dropbox

all: | $(directory)
    @echo "Continuation regardless of existence of ~/Dropbox"

$(directory):
    @echo "Folder $(directory) does not exist"
    mkdir -p $@

.PHONY: all

Remarques:

  • Le | indique que make ne devrait pas se soucier de l’horodatage (c’est un order-only-prerequisite ).
  • Plutôt que d'écrire mkdir -p $@, vous pouvez écrire false pour quitter ou résoudre votre cas différemment.

Si vous devez également exécuter une série d'instructions particulière sur l'existence d'un répertoire, vous ne pouvez pas utiliser ce qui précède. En d'autres termes, cela équivaut à:

if [ ! -d "~/Dropbox" ]; then
    echo "The ~/Dropbox folder does not exist"
fi

Il n'y a pas d'instruction else.

Agir en présence d'un répertoire

Si vous voulez l'inverse de if-statement, c'est également possible:

directory = $(wildcard ~/Dropbox)

all: | $(directory)
    @echo "Continuation regardless of existence of ~/Dropbox"

$(directory):
    @echo "Folder $(directory) exists"

.PHONY: all $(directory)

Ceci est équivalent à:

if [ -d "~/Dropbox" ]; then
    echo "The ~/Dropbox folder does exist"
fi

Encore une fois, il n'y a pas d'instruction else.

Agir à la fois sur la présence et sur l'absence d'un répertoire

Cela devient un peu plus lourd, mais vous donne finalement des objectifs intéressants pour les deux cas:

directory = ~/Dropbox
dir_target = $(directory)-$(wildcard $(directory))
dir_present = $(directory)-$(directory)
dir_absent = $(directory)-

all: | $(dir_target)
    @echo "Continuation regardless of existence of ~/Dropbox"

$(dir_present):
    @echo "Folder $(directory) exists"

$(dir_absent):
    @echo "Folder $(directory) does not exist"

.PHONY: all

Ceci est équivalent à:

if [ -d "~/Dropbox" ]; then
    echo "The ~/Dropbox folder does exist"
else
    echo "The ~/Dropbox folder does not exist"
fi

Naturellement, le développement de caractère générique peut être plus lent qu'une instruction if-else. Cependant, le troisième cas est probablement assez rare et est simplement ajouté à des fins de complétude.

21
Anne van Rossum

Essaye ça:

.PHONY: all
something:
    echo "hi"
all:
    test -d "Documents" && something

Cela n'exécutera les commandes sous something que si Documents existe.

Afin de traiter le problème noté dans les commentaires, vous pouvez créer une variable comme celle-ci:

PATH_TEST = ~/SomeDirectory

test -d $(PATH_TEST) && something
10
user1508519

J'ai eu un cas où je voulais définir une variable basée sur le test si un répertoire existe ou non au plus haut niveau du Makefile où les approches décrites ci-dessus ne fonctionnent pas. J'ai trouvé ici une belle solution qui peut être utilisée comme ceci:

MY_DIRNAME=../External
ifneq "$(wildcard $(MY_DIRNAME) )" ""
  # if directory MY_DIRNAME exists:
  INCLUDES += -I../External
else
  # if it doesn't:
  INCLUDES += -I$(HOME)/Code/External
endif

Cela modifiera la variable INCLUDES en fonction du répertoire stocké dans MY_DIRNAME existe ou pas.

(Motivation: Dans mon cas, cette variable serait utilisée dans un autre Makefile inclus ultérieurement par le premier:

include $(SFRAME_DIR)/Makefile.common

Je voulais que le même Makefile travaille dans deux environnements différents de manière simple.)

9
fuenfundachtzig

Il existe une réponse très différente qui vous permet d’utiliser vos instructions if telles que vous les avez envisagées dans un shell:

.ONESHELL:
foo.bak: foo.bar
    echo "foo"
    if [ -d "~/Dropbox" ]; then
        echo "Dir exists"
    fi

Notez que la seule différence est ONESHELL cible spéciale .

1
Anne van Rossum