2010-12-14 10 views
8

Esto es una continuación de mi pregunta anterior: SO 4403861 porque las soluciones sugeridas rompieron las dependencias, haciendo inútil el archivo MAKE. No puedo entender por qué.dependiendo de los directorios en make

estoy usando GNU Make 3.82 Tengo una regla que funciona si se ha creado el directorio obj:

objdir:=../obj 
$(objdir)/%.o: %.C 
    $(COMPILE) -MM -MT$(objdir)/$(notdir [email protected]) $< -o $(DEPDIR)/$(notdir $(basename $<).d) 
    $(COMPILE) -o $(objdir)/$(notdir [email protected]) -c $< 

Sin embargo, si el directorio obj no está allí, hacer que falle. Yo quería hacer para crear automáticamente ../obj en la demanda, por lo que añade lo que pensaba que era muy simple:

$(objdir)/%.o: %.C $(objdir) 
    $(COMPILE) -MM -MT$(objdir)/$(notdir [email protected]) $< -o $(DEPDIR)/$(notdir $(basename $<).d) 
    $(COMPILE) -o $(objdir)/$(notdir [email protected]) -c $< 

$(objdir): 
    if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi 

Cuando lo hago, hago siempre fuerza la compilación, cada vez. ¿Por qué? ¿El mkdir no debería suceder a menos que no haya directorio? ¿Por qué las dependencias son destruidas por este simple cambio?

+0

Como les comentaba en respuesta a su pregunta/comentario a mi respuesta en 4.403.861: _ "La regla dice que el archivo de objeto depende del directorio de objetos - lo que significa que si el índice de objetos ha cambiado desde el archivo de objeto fue construido por última vez (por ejemplo, porque compiló otro archivo), entonces su archivo necesita ser reconstruido.Su objetivo de compilación general depende del directorio de objetos existente; los archivos de objetos individuales no necesitan reconstrucción simplemente porque el directorio cambió. "_ –

Respuesta

2

Como ya se respondió, no se puede poner un directorio con archivos de salida como una dependencia, porque se actualiza cada vez.

Una solución (se ha dicho) es poner una -p mkdir antes de cada generación, de esta manera:

objdir:=../obj 
$(objdir)/%.o: %.C 
    @mkdir -p $(objdir) $(DEPDIR) ... 
    $(COMPILE) -MM -MT$(objdir)/$(notdir [email protected]) $< -o $(DEPDIR)/$(notdir $(basename $<).d) 
    $(COMPILE) -o $(objdir)/$(notdir [email protected]) -c $< 

Pero no amo a esta solución, ya que obliga a ejecutar una gran cantidad de procesos adicionales y mucho de veces Sin embargo, conociendo el motivo del error, hay otra manera:

exe: dirs $(OBJ) 

En el objetivo principal, el de la construcción del ejecutable, basta con insertar un objetivo directorios antes de los objetos. Dado que es golpeado con el fin:

dirs: 
    @mkdir -p $(objdir) $(DESTDIR) ... 

y esto sólo se hace una vez de todo el diseño, en lugar de una vez por archivo.

+2

Esto es una molestia poco conocida, pero no se puede usar' mkdir -p' en una marca paralela. La razón es que si las carpetas/a/b/c y/a/b/cc se están creando en paralelo hay una condición de carrera entre cuando las comprobaciones 'mkdir -p' dicen para/una existencia de directorio y luego la crea. Otro proceso (make job) puede crear el directorio en el medio la comprobación y la acción, de modo que el primer trabajo falla con EEXIST al crear el directorio. –

+1

Y las dependencias en los directorios deben ser de solo orden, como ya se mencionó. –

+0

Como se ha dicho, esta solución se rompe bajo '-j' Usted puede usar 'mkdir -p', pero tiene que obtener las dependencias correctas. Básicamente, debe hacer que todos los _objetos_ dependan del directorio. Además, para detener las recompilaciones debido a la hora del cambio del directorio, use un centinela. archivo (y una regla de patrón). Consulte a continuación (I no puede escribir la solución en este cuadro, grrrr). – bobbogo

11

Como han dicho otros, el problema es que un directorio se considera "cambiado" cada vez que se agregan o eliminan miembros del directorio, por lo que hace que su directorio de salida cambie todo el tiempo y vuelve a ejecutar todas las compilaciones de las que ha dependido en el directorio de salida.

Como alternativa a las soluciones alternativas descritas por otros, las versiones recientes de GNU make tienen soporte para "requisitos previos de solo pedido". The description of order-only prerequisites in the manual incluye un ejemplo de cómo usarlos para la creación de directorios.

+2

No creo que esto sea completamente cierto. Un directorio cambia cuando cualquiera de sus miembros se agrega, quita o renombra. (Un directorio es un archivo que contiene una asignación de nombres de archivo a archivos.) – reinierpost

+0

Lo explico aquí: http://stackoverflow.com/questions/3477418/suppress-make-rule-error-output/3554442#3554442 –

+0

reinierpost: gracias , corrigió la respuesta. – slowdog

21

También puede probar con la Orden-únicos requisitos previos link

Hay un ejemplo similar, de su pregunta, disponible.

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

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

all: $(OBJS) 

$(OBJS): | $(OBJDIR) 

$(OBJDIR): 
     mkdir $(OBJDIR) 
3

Una especie de centinela archivo va a resolver esta bastante bien. Le permite escribir una sola regla de patrón para crear todas las carpetas, no tiene ningún problema de recompilación deshonesto y es -j seguro.

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

all: ${OBJS} 

${OBJDIR}%.o : %.c ${OBJDIR}.sentinel 
    ${COMPILE.c} ${OUTPUT_OPTION} $< 

# A single pattern rule will create all appropriate folders as required 
.PRECIOUS: %/.sentinel # otherwise make (annoyingly) deletes it 
%/.sentinel: 
    mkdir -p ${@D} 
    touch [email protected] 
Cuestiones relacionadas