2008-09-19 12 views
96

Necesito generar un directorio en mi archivo MAKE y me gustaría no obtener el "directorio ya existe error" una y otra vez, aunque puedo ignorar fácilmente eso.cómo evitar que "el directorio ya exista error" en un archivo MAKEIR

Utilizo principalmente mingw/msys pero me gustaría algo que funcione también en otros shells/sistemas.

Intenté esto pero no funcionó, ¿alguna idea?

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

Respuesta

95

En UNIX Sólo tiene que usar esto:

mkdir -p $(OBJDIR) 

La opción -p de mkdir evita el mensaje de error si el directorio existe.

+36

"En general, se adhieren a las opciones soportadas ampliamente (por lo general POSIX-especificado) y características de estos programas. Por ejemplo, no utilice 'mkdir -p', conveniente, ya que puede ser, porque algunos sistemas no son compatibles en absoluto y con los demás, no es seguro para la ejecución en paralelo. "http://www.gnu.org/s/hello/manual/make/Utilities-in-Makefiles.html –

+5

' -p' no funciona en Windows, que es presumiblemente de lo que se pregunta la pregunta. No estoy seguro de cómo alguna vez fue aceptado. – Antimony

+2

Para Windows, a votar esto: https://connect.microsoft.com/PowerShell/feedback/details/1074131/mkdir-and-rm-needs-unix-like-most-pertinent-switches –

11

Si tener el directorio ya existe, no es un problema para usted, usted podría redirigir stderr para ese comando, deshacerse del mensaje de error:

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

Esto tiene la ventaja de funcionar también en Windows. No olvides el '-' delante del comando, así que make no suelta. –

11

Dentro de su makefile:

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

Puede utilizar el comando de prueba:

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

Esta es la forma preferida si necesita que sus makefiles funcionen tanto en Windows (con gnuwin32 y PowerShell) como en sistemas operativos que cumplen con POSIX. –

+6

SIEMPRE tiene el paquete gnuwin32 CoreUtils para proporcionar la utilidad 'prueba'. – davenpcj

+2

Demasiado tarde aquí, pero me gustaría señalar que esta solución puede romperse cuando se construye en paralelo ('make -j') debido a una condición de carrera entre el momento en que se prueba el directorio y se crea. Un trabajo puede probar que no está allí, pero antes de crearlo, otro trabajo crea el directorio. Luego, cuando el primero intente hacerlo, fallará porque el directorio ya existe. La mejor solución en este caso es utilizar solo los requisitos previos como se menciona en la respuesta de @TeKa (que debería ser la respuesta aceptada). – C0deH4cker

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

Esto funciona bien para la marca mingw sin necesidad de herramientas adicionales. – davenpcj

6
$(OBJDIR): 
    mkdir [email protected] 

que también funciona para múltiples directorios, por ejemplo ..

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

$(OBJDIRS): 
    mkdir [email protected] 

Agregando $(OBJDIR) como el primer objetivo funciona bien.

+0

Esto funciona muy bien, gracias. –

8

En Windows

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

En Unix | Linux

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

Este para Windows. – checksum

+0

'/ bin/sh: 1: Error de sintaxis: final del archivo inesperado (esperando" entonces ") ' – wotanii

+0

La primera versión es para Windows, la segunda opción funciona en Linux como @checksum dijo –

18

Aquí es un truco que utilizo con GNU que para la creación de directorios compilador de salida. En primer lugar definir esta regla:

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

luego hacer todos los archivos que van en el directorio depende del archivo .d en ese directorio:

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

Nota uso de $ < en lugar de $ ^.

Finalmente evitar que los archivos .d se eliminen automáticamente:

.PRECIOUS: %/.d 

Saltarse el archivo .d, y dependiendo directamente en el directorio, no va a funcionar, como el tiempo de modificación de directorio se actualiza cada vez que un archivo está escrito en ese directorio, lo que forzaría la reconstrucción en cada invocación de make.

+1

Ah, gracias, estaba intentando para hacer que algo como esto funcione No quiero "probar -d foo || mkdir foo" en varios objetivos, ya que al usar "make -j2" los probaré al mismo tiempo, ambas pruebas darán falso, y luego dos procesos intentarán mkdir, el el último de ellos falló. – unhammer

109

Mirando a the official make documentation, aquí es una buena manera de hacerlo:

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) 

debería ver aquí el uso del | operador de tubería, que define un requisito previo solo de orden. Lo que significa que el objetivo debe ser $(OBJDIR) existentes (en lugar de más reciente) con el fin de construir el destino actual.

Tenga en cuenta que he usado mkdir -p. Se agregó la bandera -p en comparación con el ejemplo de los documentos. Vea otras respuestas para otra alternativa.

+3

Esta es definitivamente la forma oficial de este problema. – lcltj

+0

@CraigMcQueen: realmente quise decir _ "el objetivo' $ (OBJDIR) 'debe ser ** existente **" _. Realice comprobaciones de presencia de archivos (y marcas de tiempo) para decidir si es necesario construir el objetivo. Por lo tanto aquí, si '$ (OBJDIR)' está ausente lo construirá, de modo que sea ** existente ** para construir el objetivo actual '$ (OBJS)', que se creará dentro. – ofavre

+0

Claro, tienes razón. Mis disculpas. –

3

Funciona bajo mingw32/MSYS/cygwin/Linux

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

Un poco más simple que Lars respuesta:

something_needs_directory_xxx : xxx/.. 

y regla genérica:

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

Sin táctil archivos para limpiar o hacer .PRECIOUS :-)

Si usted quiere ver otro pequeño truco gmake genérico, o si está interesado en el maquillaje no recursiva con andamios mínimos, es posible que el cuidado de revisar Two more cheap gmake tricks y los otros puestos relacionados con maquillaje en ese blog.

0

Si ignora explícitamente el código de retorno y volcar el flujo de error entonces su marca ignorará el error si se produce:

mkdir 2>/dev/null || true 

Esto no debería causar un peligro para la raza en una marca paralela - pero no he t probado para estar seguro.

Cuestiones relacionadas