niños - ¿Para qué son las reglas de dos puntos en un Makefile?
uso de los dos puntos (4)
Cada :: regla se procesa de forma independiente, por lo que puede ser más simple. Por ejemplo, la regla única:
libxxx.a : sub1.o sub2.o
ar rv libxxx.a sub1.o
ar rv libxxx.a sub2.o
Puede ser reemplazado por dos reglas más simples:
libxxx.a :: sub1.o
ar rv libxxx.a sub1.o
libxxx.a :: sub2.o
ar rv libxxx.a sub2.o
Las utilidades como AutoMake tienen un tiempo más fácil para escupir muchas reglas simples que algunas complejas.
Se publicó una gran respuesta con más ejemplos, luego se eliminó y luego se encontró aquí:
Gracias a RK Owen por escribirlo, y a Edward Minnix por encontrarlo nuevamente.
La sección 4.13 del manual GNU Make describe las llamadas reglas de dos puntos:
Las reglas de dos puntos son reglas escritas con ''::'' en lugar de '':'' después de los nombres de destino. Se manejan de manera diferente a las reglas ordinarias cuando el mismo objetivo aparece en más de una regla.
Cuando aparece un objetivo en varias reglas, todas las reglas deben ser del mismo tipo: todas ordinarias o todas de dos puntos dobles. Si son de dos puntos, cada uno de ellos es independiente de los otros. Los comandos de cada regla de dos puntos dobles se ejecutan si el objetivo es anterior a los requisitos previos de esa regla. Si no hay requisitos previos para esa regla, sus comandos siempre se ejecutan (incluso si el objetivo ya existe). Esto puede resultar en ejecutar ninguna, ninguna o todas las reglas de dos puntos dobles.
Las reglas de dos puntos con el mismo objetivo son, de hecho, completamente separadas unas de otras. Cada regla de dos puntos dobles se procesa individualmente, al igual que las reglas con diferentes objetivos se procesan.
Las reglas de dos puntos para un objetivo se ejecutan en el orden en que aparecen en el archivo make. Sin embargo, los casos en que las reglas de dos puntos realmente tienen sentido son aquellos en los que el orden de ejecución de los comandos no importaría.
Las reglas de dos puntos son un tanto oscuras y no son muy útiles a menudo; proporcionan un mecanismo para los casos en que el método utilizado para actualizar un objetivo difiere según los archivos de requisitos previos que causaron la actualización, y estos casos son raros.
Cada regla de dos puntos dobles debe especificar comandos; si no lo hace, se utilizará una regla implícita si se aplica. Consulte la sección Uso de reglas implícitas.
Creo un poco el significado de cada oración de esta sección individualmente, pero todavía no me queda claro para qué sirven las reglas de los dos puntos. En cuanto a que es raro, todavía no he visto ningún proyecto de código abierto cuyo Makefile no haya comenzado
all::
Por lo tanto: ¿Cuál es el propósito de las reglas de dos puntos en Makefiles?
Hay 3 situaciones donde el doble colon es útil:
- Alternar entre las reglas de compilación basadas en qué requisito previo es más nuevo que el destino. El siguiente ejemplo está basado en el "Ejemplo 19-3. Reglas de dos puntos dobles" de http://books.gigatux.nl/mirror/cinanutshell/0596006977/cinanut-CHP-19-SECT-3.html
Ejemplo de archivo .c:
c@desk:~/test/circle$ cat circle.c
#include <stdio.h>
int main (void)
{
printf("Example./n");
return 0;
}
Makefile utilizado:
c@desk:~/test/circle$ cat Makefile
# A makefile for "circle" to demonstrate double-colon rules.
CC = gcc
RM = rm -f
CFLAGS = -Wall -std=c99
DBGFLAGS = -ggdb -pg
DEBUGFILE = ./debug
SRC = circle.c
circle :: $(SRC)
$(CC) $(CFLAGS) -o $@ -lm $^
circle :: $(DEBUGFILE)
$(CC) $(CFLAGS) $(DBGFLAGS) -o $@ -lm $(SRC)
.PHONY : clean
clean :
$(RM) circle
Salir:
c@desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
make: *** No rule to make target ''debug'', needed by ''circle''. Stop.
c@desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
c@desk:~/test/circle$ vim circle.c
c@desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
c@desk:~/test/circle$ vim debug
c@desk:~/test/circle$ make circle
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
- Haz una regla de patrón terminal.
El siguiente ejemplo explica esta situación: el archivo a.config se obtiene de a.cfg, que a su vez se obtiene de a.cfg1 (a.cfg es el archivo intermedio).
c@desk:~/test/circle1$ ls
a.cfg1 log.txt Makefile
c@desk:~/test/circle1$ cat Makefile
CP=/bin/cp
%.config:: %.cfg
@echo "$@ from $<"
@$(CP) $< $@
%.cfg: %.cfg1
@echo "$@ from $<"
@$(CP) $< $@
clean:
-$(RM) *.config
Resultado (como la regla% .config es terminal, make inhibe la creación del archivo intermedio a.cfg de a.cfg1):
c@desk:~/test/circle1$ make a.conf
make: *** No rule to make target ''a.conf''. Stop.
Sin los dos puntos dobles para el% .config, el resultado es:
c@desk:~/test/circle1$ make a.config
a.cfg from a.cfg1
a.config from a.cfg
rm a.cfg
- Haga una regla que se ejecute siempre (útil para reglas limpias). La regla no debe tener prerrequisitos!
c @ desk: ~ / test / circle3 $ cat Makefile
CP=/bin/cp
a.config::
@echo "Always" >> $@
a.config::
@echo "Always!" >> $@
clean:
-$(RM) *.config
Salir:
c@desk:~/test/circle3$ make a.config
c@desk:~/test/circle3$ cat a.config
Always
Always!
c@desk:~/test/circle3$ make a.config
c@desk:~/test/circle3$ cat a.config
Always
Always!
Always
Always!
Son útiles para makefiles no recursivos y objetivos como clean
. Es decir, un archivo .mk individual puede agregar sus propios comandos al objetivo clean
ya definido en otro lugar.
Documentation da una respuesta:
Las reglas de dos puntos son un tanto oscuras y no son muy útiles a menudo; proporcionan un mecanismo para los casos en que el método utilizado para actualizar un objetivo difiere según los archivos de requisitos previos que causaron la actualización, y estos casos son raros.
Tal como dice la documentación, las reglas de dos puntos raramente son muy útiles. Son una forma agradable y pequeña de no nombrar los objetivos individuales de un objetivo falso compuesto (como todos: :), pero no es realmente necesario en este rol. Solo puedo dar un ejemplo artificial cuando sea necesario:
Supongamos que tiene un archivo de registro L que está concatenado a partir de varios otros archivos de registro L1, L2, ... Usted formula una serie de reglas de dos puntos dobles como:
L :: L1
cat $< >> $@ && rm $<
L :: L2
cat $< >> $@ && rm $<
Hoy en día en GNU make, por supuesto, usaría $^
para este tipo de magia, pero aparece como una característica inspirada en la pestaña de características de GNU make.