2008-09-19 21 views
96

Je dois générer un répertoire dans mon makefile et je ne voudrais pas obtenir le "répertoire existe déjà erreur" encore et encore, même si je peux facilement ignorer il.comment empêcher "répertoire existe déjà erreur" dans un makefile lors de l'utilisation mkdir

J'utilise principalement mingw/msys, mais j'aimerais aussi que quelque chose fonctionne avec d'autres shells/systèmes.

J'ai essayé mais ça n'a pas fonctionné, des idées?

ifeq (,$(findstring $(OBJDIR),$(wildcard $(OBJDIR)))) 
-mkdir $(OBJDIR) 
endif 

Répondre

95

Sous UNIX Utilisez simplement ceci:

mkdir -p $(OBJDIR) 

L'option -p de mkdir empêche le message d'erreur si le répertoire existe.

+36

"En règle générale, respectez les options et les fonctionnalités largement supportées (généralement par Posix) de ces programmes.Par exemple, n'utilisez pas 'mkdir -p', aussi pratique que cela puisse être, car quelques systèmes ne supportent pas il ne l'est pas du tout pour les exécutions parallèles. "http://www.gnu.org/s/hello/manual/make/Utilities-in-Makefiles.html –

+5

' -p' ne fonctionne pas sur Windows, ce qui est probablement ce que la question pose. Je ne sais pas comment cela a été accepté. – Antimony

+2

Pour Windows, placez le vote suivant: https://connect.microsoft.com/PowerShell/feedback/details/1074131/mkdir-and-rm-needs-unix-like-most-pertinent-switches –

11

Si avoir le répertoire existe déjà est pas un problème pour vous, vous pouvez simplement rediriger stderr pour cette commande, se débarrasser du message d'erreur:

-mkdir $(OBJDIR) 2>/dev/null 
+0

Cela a également l'avantage de fonctionner sous Windows. N'oublie pas le '-' devant la commande donc ne fais pas de caution. –

11

l'intérieur de votre makefile:

target: 
    if test -d dir; then echo "hello world!"; else mkdir dir; fi 
65

Vous pouvez utiliser la commande test:

test -d $(OBJDIR) || mkdir $(OBJDIR) 
+7

C'est la méthode préférée si vous avez besoin que vos fichiers makefiles fonctionnent à la fois sous Windows (avec gnuwin32 et PowerShell) et sous OS compatibles POSIX. –

+6

FOURNI vous avez le paquetage gnuwin32 CoreUtils pour fournir l'utilitaire 'test'. – davenpcj

+2

Très en retard ici, mais je tiens à souligner que cette solution peut casser lors de la construction en parallèle ('make -j') en raison d'une condition de concurrence entre le moment où le répertoire est testé et sa création. Un travail peut tester qu'il n'est pas là mais avant qu'il ne le crée, un autre travail crée le répertoire. Ensuite, lorsque le premier essaie de le faire, il échouera parce que le répertoire existe déjà. La meilleure solution dans ce cas est d'utiliser les pré-requis de commande comme mentionné dans la réponse de @ TeKa (qui devrait être la réponse acceptée). – C0deH4cker

7
ifeq "$(wildcard $(MY_DIRNAME))" "" 
    -mkdir $(MY_DIRNAME) 
endif 
+0

Cela fonctionne bien pour la marque MINGW sans nécessiter d'outils supplémentaires. – davenpcj

6
$(OBJDIR): 
    mkdir [email protected] 

Ce qui fonctionne également pour plusieurs répertoires, par exemple ..

OBJDIRS := $(sort $(dir $(OBJECTS))) 

$(OBJDIRS): 
    mkdir [email protected] 

Ajout de $(OBJDIR) comme la première cible fonctionne bien.

+0

Cela fonctionne très bien, merci. –

8

Sous Windows

if not exist "$(OBJDIR)" mkdir $(OBJDIR) 

Sur Unix | Linux

if [ ! -d "$(OBJDIR)" ]; then mkdir $(OBJDIR); fi 
+0

Celui-ci pour Windows. – checksum

+0

'/ bin/sh: 1: Erreur de syntaxe: fin du fichier inattendu (attendant" alors ") ' – wotanii

+0

La première version est pour Windows, la deuxième option fonctionne sous Linux comme @checksum dit –

18

Voici une astuce que j'utilise avec GNU make pour créer des répertoires de sortie de compilateur. Tout d'abord définir cette règle:

%/.d: 
      mkdir -p $(@D) 
      touch [email protected] 

ensuite faire tous les fichiers qui vont dans le répertoire en fonction du fichier .d dans ce répertoire:

obj/%.o: %.c obj/.d 
    $(CC) $(CFLAGS) -c -o [email protected] $< 

utilisation Note de < $ au lieu de $ ^.

éviter Enfin, les fichiers .d d'être automatiquement supprimés:

.PRECIOUS: %/.d 

sauter le fichier .d et dépendant directement du répertoire, ne fonctionnera pas, comme le temps de modification du répertoire est mis à jour chaque fois qu'un fichier est écrit dans ce répertoire, ce qui forcerait la reconstruction à chaque invocation de make.

+1

Ah, merci, j'essayais pour obtenir quelque chose comme ça au travail. Je ne veux pas "tester -d foo || mkdir foo" sur plusieurs objectifs, car ensuite utiliser "make -j2" les testera en même temps, les deux tests donnant faux, et ensuite deux processus vont essayer de mkdir, le le dernier d'entre eux échoue. – unhammer

109

En regardant the official make documentation, voici une bonne façon de le faire:

OBJDIR := objdir 
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o) 

$(OBJDIR)/%.o : %.c 
    $(COMPILE.c) $(OUTPUT_OPTION) $< 

all: $(OBJS) 

$(OBJS): | $(OBJDIR) 

$(OBJDIR): 
    mkdir -p $(OBJDIR) 

Vous devriez voir ici l'utilisation du | opérateur de tuyauterie, définissant une commande uniquement prérequis. Cela signifie que la cible $(OBJDIR) doit être existante (au lieu de plus récente) afin de créer la cible actuelle.

Notez que j'ai utilisé mkdir -p. Le drapeau -p a été ajouté par rapport à l'exemple des documents. Voir les autres réponses pour une autre alternative.

+3

Ceci est certainement le moyen officiel de ce problème. – lcltj

+0

@CraigMcQueen: Je voulais vraiment dire que _ "la cible' $ (OBJDIR) 'devrait être ** existante **" _. Faites des vérifications pour la présence de fichiers (et les horodatages) pour décider si vous avez besoin de construire la cible. Donc ici, si '$ (OBJDIR)' est absent, il le construira, de sorte qu'il soit ** existant ** afin de construire la cible courante '$ (OBJS)', qui sera créée à l'intérieur. – ofavre

+0

Bien sûr, vous avez raison. Mes excuses. –

3

Il fonctionne sous mingw32/msys/Cygwin/linux

ifeq "$(wildcard .dep)" "" 
-include $(shell mkdir .dep) $(wildcard .dep/*) 
endif 
0

Un peu plus simple que la réponse de Lars:

something_needs_directory_xxx : xxx/.. 

et règle générique:

%/.. : ;@mkdir -p $(@D) 

Non tactile fichiers à nettoyer ou à faire .PRECIOUS :-)

Si vous voulez voir un autre petit truc gmake générique, ou si vous êtes intéressé par un make non récursif avec un échafaudage minimal, vous pouvez consulter Two more cheap gmake tricks et les autres articles liés à ce blog.

0

Si vous ignorez explicitement le code de retour et de vidage du flux d'erreur alors votre make ignorer l'erreur si elle se produit:

mkdir 2>/dev/null || true 

Cela ne devrait pas causer un danger pour la course dans une marque parallèle - mais je n » t testé pour être sûr.