makefile - para - ¿Por qué no se activan las reglas de patrón implícitas de.PHONY?
makefile linux c (3)
De esta sección del manual de make:
La búsqueda de reglas implícitas (ver Reglas implícitas) se omite para los objetivos .PHONY. Esta es la razón por la que declarar un destino como .PHONY es bueno para el rendimiento, incluso si no está preocupado por el archivo real existente.
Por lo tanto, sus objetivos implícitos nunca se buscan porque son falsos.
Puedes lograr lo que estás tratando de hacer de otra manera. Prueba esto:
SUBDIRS := all clean
.PHONY: $(SUBDIRS)
$(SUBDIRS):
echo $(MAKE) -C src $@
echo $(MAKE) -C dict $@
Tengo el siguiente makefile recursivo:
.PHONY: all clean
%.subdir:
$(MAKE) -C src $*
$(MAKE) -C dict $*
all: all.subdir
clean: clean.subdir
y funciona bien:
$ make all
make -C src all
make[1]: Entering directory `/or-1.3.6-fix/src''
make[1]: Nothing to be done for `all''.
make[1]: Leaving directory `/or-1.3.6-fix/src''
make -C dict all
make[1]: Entering directory `/or-1.3.6-fix/dict''
make[1]: Nothing to be done for `all''.
make[1]: Leaving directory `/or-1.3.6-fix/dict''
Pero sería más lógico definir las reglas de %.subdir
como falsas:
.PHONY: all clean all.subdir clean.subdir
Y ahora haz que deje de funcionar como yo quiero:
$ make all
make: Nothing to be done for `all''.
$ make -d all
...
Updating goal targets....
Considering target file `all''.
File `all'' does not exist.
Considering target file `all.subdir''.
File `all.subdir'' does not exist.
Finished prerequisites of target file `all.subdir''.
Must remake target `all.subdir''.
Successfully remade target file `all.subdir''.
Finished prerequisites of target file `all''.
Must remake target `all''.
Successfully remade target file `all''.
make: Nothing to be done for `all''.
¿Alguien puede explicarme por qué (o, mejor aún, señalarme que haga documentación)?
Que GNU haga que los objetivos requeridos declarados como .PHONY
para ser explícitos ya se ha indicado en las otras respuestas, lo que también proporcionó algún remedio a esto.
En esta respuesta adicional, me gustaría agregar un alterativo que, al probar, combina un comportamiento "falso", es decir, que los objetivos se activan cada vez, sin importar si existen archivos con el mismo nombre (se ignoran). La alternativa es la siguiente:
.PHONY: phony_explicit
phony_explicit:
%.subdir: phony_explicit
$(MAKE) -C src $*
$(MAKE) -C dict $*
Funciona bajo la premisa de que mientras que solo los objetivos explícitos se pueden establecer como .PHONY, lo que dependa de un objetivo falso explícito es, en sí mismo, heredar muchos atributos falsos (que yo sepa, todos). Un objetivo implícito, es decir, un patrón de coincidencia, como el %.subdir
anterior, es como si se agregara a .PHONY
(lo cual es imposible porque no es explícito), pero se vuelve falso a través de su prerrequisito phony_explicit
.
Se reduce a que cada regla, también implícita a través de la coincidencia de patrones, que tiene en sus requisitos un objetivo falso explícito (es decir, un objetivo que se agrega a la .PHONY
) se ejecuta a través de esta dependencia también en un estilo falso (cada vez, incondicionalmente del sistema de archivos que tiene erróneamente un archivo con un nombre coincidente).
De hecho, la documentación de GNU make menciona el target FORCE
, que en algunas versiones de GNU que no ofrecen un objetivo .PHONY
emula en parte el comportamiento de .PHONY
. La alternativa que se presenta aquí utiliza este enfoque de objetivo de FUERZA, sin embargo, debido a que se utiliza GNU make, también establece el objetivo de FORCE
como .PHONY
evitando posibles conflictos con archivos realmente existentes del mismo nombre.
Con esta solución incluso un
touch clean.subir; make clean.subdir
dará la invocación deseada de
make -C src clean
make -C dist clean
Lo que podría ser un punto pro potencial de esta alternativa es que no necesita una declaración explícita de clean.subdir
y all.subdir
, pero en realidad está usando la %.subdir
patrones implícita %.subdir
.
Tienes razón, tendría más sentido definir las reglas de subdirección como PHONY. Pero Make no tiene en cuenta las reglas implícitas para los objetivos de PHONY, por lo que tendrá que volver a escribir esa regla. Sugiero lo siguiente:
SUBDIR_TARGETS = all.subdir clean.subdir
.PHONY: all clean $(SUBDIR_TARGETS)
$(SUBDIR_TARGETS): %.subdir:
$(MAKE) -C src $*
$(MAKE) -C dict $*
all: all.subdir
clean: clean.subdir