La información que indica a make cómo recompilar un sistema procede de la lectura de una base de datos llamada makefile.
MAKEFILESmake un makefileUn makefile contiene cinco clases de cosas: reglas explícitas, reglas implícitas, definiciones de variables, directivas y comentarios. Las reglas, las variables y las directivas se describen en detalle en capítulos posteriores.
objects como una lista de todos los archivos objeto (consulte Las variables simplifican los makefiles).
make haga algo especial mientras lee el makefile. Entre ellas se cuentan:
# literal, escápelo con una barra invertida (por ejemplo, \#). Los comentarios pueden aparecer en cualquier línea del makefile, aunque en ciertas situaciones reciben un tratamiento especial.
No se pueden usar comentarios dentro de referencias a variables o llamadas a funciones: cualquier aparición de # se tratará de forma literal (en lugar de como el inicio de un comentario) dentro de una referencia a variable o una llamada a función.
Los comentarios dentro de una receta se pasan a la shell, igual que cualquier otro texto de receta. La shell decide cómo interpretarlo: que sea o no un comentario depende de la shell.
Dentro de una directiva define, los comentarios no se ignoran durante la definición de la variable, sino que se conservan intactos en el valor de la variable. Cuando la variable se expande, se tratarán como comentarios de make o como texto de receta, según el contexto en el que se evalúe la variable.
Los makefiles usan una sintaxis «basada en líneas» en la que el carácter de nueva línea es especial y marca el final de una sentencia. GNU make no impone límite alguno a la longitud de la línea de una sentencia, salvo la cantidad de memoria de su computadora.
Sin embargo, resulta difícil leer líneas demasiado largas para mostrarse sin ajuste de línea o desplazamiento. Por eso, puede dar formato a sus makefiles para que sean legibles añadiendo nuevas líneas en mitad de una sentencia: esto se hace escapando las nuevas líneas internas con un carácter de barra invertida (\). Cuando necesitemos hacer la distinción, llamaremos «línea física» a una sola línea que termina en una nueva línea (esté o no escapada) y «línea lógica» a una sentencia completa que incluye todas las nuevas líneas escapadas hasta la primera nueva línea no escapada.
La forma en que se manejan las combinaciones de barra invertida y nueva línea depende de si la sentencia es una línea de receta o una línea que no es de receta. El manejo de la barra invertida y la nueva línea en una línea de receta se trata más adelante (consulte Dividir líneas de receta).
Fuera de las líneas de receta, las barras invertidas seguidas de nueva línea se convierten en un único carácter de espacio. Una vez hecho esto, todos los espacios en blanco alrededor de la barra invertida y la nueva línea se condensan en un único espacio: esto incluye todos los espacios en blanco que preceden a la barra invertida, todos los espacios en blanco al principio de la línea posterior a la barra invertida y la nueva línea, y cualquier combinación consecutiva de barra invertida y nueva línea.
Si está definido el objetivo especial .POSIX, el manejo de la barra invertida y la nueva línea se modifica ligeramente para ajustarse a POSIX.2: primero, el espacio en blanco que precede a una barra invertida no se elimina y, segundo, las barras invertidas seguidas de nueva línea consecutivas no se condensan.
Si necesita dividir una línea pero no quiere que se añada ningún espacio en blanco, puede recurrir a un truco sutil: sustituya sus pares de barra invertida y nueva línea por los tres caracteres signo de dólar, barra invertida y nueva línea:
var := one$\
word
Después de que make elimine la barra invertida y la nueva línea y condense la línea siguiente en un único espacio, esto equivale a:
var := one$ word
A continuación, make realizará la expansión de variables. La referencia a variable «$ » se refiere a una variable con el nombre de un carácter « » (espacio), que no existe y, por tanto, se expande a la cadena vacía, lo que da una asignación final equivalente a:
var := oneword
De forma predeterminada, cuando make busca el makefile, prueba los siguientes nombres, en este orden: GNUmakefile, makefile y Makefile.
Normalmente debería llamar a su makefile makefile o Makefile. (Recomendamos Makefile porque aparece de forma destacada cerca del principio de un listado de directorio, justo al lado de otros archivos importantes como README.) El primer nombre que se comprueba, GNUmakefile, no se recomienda para la mayoría de los makefiles. Debería usar este nombre si tiene un makefile específico de GNU make que no vayan a entender otras versiones de make. Los demás programas make buscan makefile y Makefile, pero no GNUmakefile.
Si make no encuentra ninguno de estos nombres, no usa ningún makefile. En tal caso, debe especificar una meta con un argumento de la orden, y make intentará averiguar cómo rehacerla usando solo sus reglas implícitas incorporadas. Consulte Uso de reglas implícitas.
Si desea usar un nombre no estándar para su makefile, puede especificar el nombre del makefile con la opción «-f» o «--file». Los argumentos «-f name» o «--file=name» indican a make que lea el archivo name como el makefile. Si usa más de una opción «-f» o «--file», puede especificar varios makefiles. Todos los makefiles se concatenan en la práctica en el orden especificado. Los nombres de makefile predeterminados GNUmakefile, makefile y Makefile no se comprueban automáticamente si especifica «-f» o «--file».
La directiva include indica a make que suspenda la lectura del makefile actual y lea uno o más makefiles antes de continuar. La directiva es una línea del makefile que tiene este aspecto:
include filenames…
filenames puede contener patrones de nombre de archivo de la shell. Si filenames está vacío, no se incluye nada y no se imprime ningún error.
Se permiten y se ignoran espacios adicionales al principio de la línea, pero el primer carácter no debe ser una tabulación (ni el valor de .RECIPEPREFIX): si la línea empieza por una tabulación, se considerará una línea de receta. Se requiere espacio en blanco entre include y los nombres de archivo, y entre los nombres de archivo; el espacio en blanco adicional se ignora ahí y al final de la directiva. Se permite un comentario que empiece por «#» al final de la línea. Si los nombres de archivo contienen referencias a variables o a funciones, estas se expanden. Consulte Cómo usar las variables.
Por ejemplo, si tiene tres archivos .mk, a.mk, b.mk y c.mk, y $(bar) se expande a bish bash, entonces la siguiente expresión
include foo *.mk $(bar)
equivale a
include foo a.mk b.mk c.mk bish bash
Cuando make procesa una directiva include, suspende la lectura del makefile que la contiene y lee de cada archivo enumerado por turno. Cuando esto termina, make reanuda la lectura del makefile en el que aparece la directiva.
Una ocasión para usar las directivas include es cuando varios programas, gestionados por makefiles individuales en distintos directorios, necesitan usar un conjunto común de definiciones de variables (consulte Asignar variables) o de reglas de patrón (consulte Definir y redefinir reglas de patrón).
Otra ocasión semejante es cuando quiere generar prerrequisitos a partir de archivos fuente de forma automática; los prerrequisitos pueden ponerse en un archivo que se incluye desde el makefile principal. Esta práctica suele ser más limpia que la de añadir de algún modo los prerrequisitos al final del makefile principal, como se ha hecho tradicionalmente con otras versiones de make. Consulte Generar prerrequisitos automáticamente.
Si el nombre especificado no empieza por una barra (ni por una letra de unidad y dos puntos cuando GNU Make se compila con soporte de rutas de MS-DOS / MS-Windows), y el archivo no se encuentra en el directorio actual, se buscan otros varios directorios. Primero se buscan los directorios que haya especificado con las opciones «-I» o «--include-dir» (consulte Resumen de opciones). Después se buscan los siguientes directorios (si existen), en este orden: prefix/include (normalmente /usr/local/include 1), /usr/gnu/include, /usr/local/include, /usr/include.
La variable .INCLUDE_DIRS contendrá la lista actual de directorios en los que make buscará los archivos incluidos. Consulte Otras variables especiales.
Puede evitar la búsqueda en estos directorios predeterminados añadiendo a la línea de órdenes la opción -I con el valor especial - (por ejemplo, -I-). Esto hará que make olvide cualquier directorio de inclusión ya establecido, incluidos los directorios predeterminados.
Si un makefile incluido no puede encontrarse en ninguno de estos directorios, no es un error fatal de inmediato; el procesamiento del makefile que contiene el include continúa. Una vez que ha terminado de leer los makefiles, make intentará rehacer cualquiera que esté desactualizado o que no exista. Consulte Cómo se rehacen los makefiles. Solo después de no haber logrado encontrar una regla para rehacer el makefile, o de haber encontrado una regla cuya receta falló, make diagnosticará el makefile que falta como un error fatal.
Si quiere que make simplemente ignore un makefile que no existe o que no puede rehacerse, sin mensaje de error, use la directiva -include en lugar de include, de este modo:
-include filenames…
Esto actúa como include en todos los aspectos, salvo que no se produce ningún error (ni siquiera una advertencia) si alguno de los filenames (o cualquier prerrequisito de alguno de los filenames) no existe o no puede rehacerse.
Por compatibilidad con algunas otras implementaciones de make, sinclude es otro nombre para -include.
MAKEFILES
Si la variable de entorno MAKEFILES está definida, make considera su valor como una lista de nombres (separados por espacio en blanco) de makefiles adicionales que deben leerse antes que los demás. Esto funciona de forma muy parecida a la directiva include: se buscan esos archivos en distintos directorios (consulte Incluir otros makefiles). Además, la meta predeterminada nunca se toma de uno de estos makefiles (ni de ningún makefile incluido por ellos) y no es un error que los archivos enumerados en MAKEFILES no se encuentren.
El principal uso de MAKEFILES es la comunicación entre invocaciones recursivas de make (consulte Uso recursivo de make). Por lo general no es deseable establecer la variable de entorno antes de una invocación de make de nivel superior, porque suele ser mejor no manipular un makefile desde fuera. No obstante, si está ejecutando make sin un makefile concreto, un makefile en MAKEFILES puede hacer cosas útiles para ayudar a que las reglas implícitas incorporadas funcionen mejor, como definir rutas de búsqueda (consulte Búsqueda de directorios para prerrequisitos).
Algunos usuarios sienten la tentación de establecer MAKEFILES en el entorno de forma automática al iniciar sesión, y de programar los makefiles para que esperen que así se haga. Es una idea muy mala, porque tales makefiles dejarán de funcionar si los ejecuta otra persona. Es mucho mejor escribir directivas include explícitas en los makefiles. Consulte Incluir otros makefiles.
A veces los makefiles pueden rehacerse a partir de otros archivos, como archivos RCS o SCCS. Si un makefile puede rehacerse a partir de otros archivos, probablemente quiera que make obtenga una versión actualizada del makefile para leerla.
Con este fin, tras leer todos los makefiles, make considerará cada uno como un objetivo meta, en el orden en que se procesaron, e intentará actualizarlo. Si las compilaciones en paralelo (consulte Ejecución en paralelo) están habilitadas, los makefiles también se reconstruirán en paralelo.
Si un makefile tiene una regla que indica cómo actualizarlo (encontrada en ese mismo makefile o en otro) o si se le aplica una regla implícita (consulte Uso de reglas implícitas), se actualizará si es necesario. Después de comprobar todos los makefiles, si alguno ha cambiado realmente, make empieza de cero y lee de nuevo todos los makefiles. (También intentará actualizar cada uno de ellos otra vez, pero normalmente esto no volverá a cambiarlos, ya que ya están actualizados.) Cada reinicio hará que se actualice la variable especial MAKE_RESTARTS (consulte Otras variables especiales).
Si sabe que uno o varios de sus makefiles no pueden rehacerse y quiere impedir que make realice una búsqueda de reglas implícitas sobre ellos, quizá por razones de eficiencia, puede usar cualquier método habitual de evitar la búsqueda de reglas implícitas. Por ejemplo, puede escribir una regla explícita con el makefile como objetivo y una receta vacía (consulte Uso de recetas vacías).
Si los makefiles especifican una regla de doble dos puntos para rehacer un archivo con una receta pero sin prerrequisitos, ese archivo se rehará siempre (consulte Reglas de doble dos puntos). En el caso de los makefiles, un makefile que tenga una regla de doble dos puntos con una receta pero sin prerrequisitos se rehará cada vez que se ejecute make y, de nuevo, después de que make empiece de cero y vuelva a leer los makefiles. Esto provocaría un bucle infinito: make rehacería constantemente el makefile y reiniciaría, sin hacer nunca nada más. Así pues, para evitarlo, make no intentará rehacer los makefiles que se especifiquen como objetivos de una regla de doble dos puntos con una receta pero sin prerrequisitos.
Los objetivos ficticios (phony) (consulte Objetivos ficticios (phony)) tienen el mismo efecto: nunca se consideran actualizados y, por tanto, un archivo incluido marcado como ficticio haría que make reiniciara de forma continua. Para evitarlo, make no intentará rehacer los makefiles marcados como ficticios.
Puede aprovechar esto para optimizar el tiempo de arranque: si sabe que no necesita que su Makefile se rehaga, puede impedir que make intente rehacerlo añadiendo cualquiera de las dos:
.PHONY: Makefile
o:
Makefile:: ;
Si no especifica ningún makefile que leer con las opciones «-f» o «--file», make probará los nombres de makefile predeterminados; consulte Qué nombre dar a su makefile. A diferencia de los makefiles solicitados explícitamente con las opciones «-f» o «--file», make no está seguro de que estos makefiles deban existir. No obstante, si un makefile predeterminado no existe pero puede crearse ejecutando reglas de make, probablemente quiera que se ejecuten las reglas para que el makefile pueda usarse.
Por lo tanto, si ninguno de los makefiles predeterminados existe, make intentará crear cada uno de ellos hasta que logre crear uno o se quede sin nombres que probar. Tenga en cuenta que no es un error que make no pueda encontrar ni crear ningún makefile; un makefile no siempre es necesario.
Cuando usa la opción «-t» o «--touch» (consulte En lugar de ejecutar las recetas), no querría usar un makefile desactualizado para decidir qué objetivos tocar. De modo que la opción «-t» no afecta a la actualización de los makefiles; estos se actualizan realmente aunque se especifique «-t». De igual modo, «-q» (o «--question») y «-n» (o «--just-print») no impiden la actualización de los makefiles, porque un makefile desactualizado daría una salida incorrecta para otros objetivos. Así, «make -f mfile -n foo» actualizará mfile, lo leerá y luego imprimirá la receta para actualizar foo y sus prerrequisitos sin ejecutarla. La receta impresa para foo será la especificada en el contenido actualizado de mfile.
Sin embargo, en ocasiones podría desear impedir la actualización incluso de los makefiles. Puede hacerlo especificando los makefiles como metas en la línea de órdenes, además de especificarlos como makefiles. Cuando el nombre del makefile se especifica explícitamente como meta, las opciones «-t» y demás sí se aplican a ellos.
Así, «make -f mfile -n mfile foo» leería el makefile mfile, imprimiría la receta necesaria para actualizarlo sin ejecutarla realmente y, a continuación, imprimiría la receta necesaria para actualizar foo sin ejecutar esta. La receta para foo será la especificada por el contenido existente de mfile.
A veces resulta útil tener un makefile que es casi igual que otro makefile. A menudo puede usar la directiva «include» para incluir uno en el otro y añadir más objetivos o definiciones de variables. Sin embargo, es inválido que dos makefiles den recetas diferentes para el mismo objetivo. Pero hay otra forma.
En el makefile que contiene (el que quiere incluir al otro) puede usar una regla de patrón que coincida con cualquier cosa para indicar que, para rehacer cualquier objetivo que no pueda construirse a partir de la información del makefile que contiene, make debería mirar en otro makefile. Para más información sobre las reglas de patrón, consulte Definir y redefinir reglas de patrón.
Por ejemplo, si tiene un makefile llamado Makefile que indica cómo crear el objetivo «foo» (y otros objetivos), puede escribir un makefile llamado GNUmakefile que contenga:
foo:
frobnicate > foo
%: force
@$(MAKE) -f Makefile $@
force: ;
Si dice «make foo», make encontrará GNUmakefile, lo leerá y verá que, para crear foo, necesita ejecutar la receta «frobnicate > foo». Si dice «make bar», make no encontrará ninguna forma de crear bar en GNUmakefile, por lo que usará la receta de la regla de patrón: «make -f Makefile bar». Si Makefile proporciona una regla para actualizar bar, make aplicará la regla. Y lo mismo para cualquier otro objetivo cuya forma de creación GNUmakefile no indique.
Esto funciona porque la regla de patrón tiene un patrón de solo «%», de modo que coincide con cualquier objetivo, sea cual sea. La regla especifica un prerrequisito force, para garantizar que la receta se ejecute aunque el archivo objetivo ya exista. Damos al objetivo force una receta vacía para impedir que make busque una regla implícita con la que construirlo; de lo contrario, aplicaría la misma regla que coincide con cualquier cosa al propio force y crearía un bucle de prerrequisitos.
make un makefile
GNU make hace su trabajo en dos fases bien diferenciadas. Durante la primera fase lee todos los makefiles, los makefiles incluidos, etc., e interioriza todas las variables y sus valores y las reglas implícitas y explícitas, y construye un grafo de dependencias de todos los objetivos y sus prerrequisitos. Durante la segunda fase, make usa estos datos interiorizados para determinar qué objetivos necesitan actualizarse y ejecuta las recetas necesarias para actualizarlos.
Es importante entender este enfoque de dos fases porque tiene un impacto directo en cómo se produce la expansión de variables y funciones; esto suele ser una fuente de cierta confusión al escribir makefiles. A continuación se presenta un resumen de las distintas construcciones que pueden encontrarse en un makefile y la fase en la que se produce la expansión de cada parte de la construcción.
Decimos que una expansión es inmediata (immediate) si se produce durante la primera fase: make expandirá esa parte de la construcción a medida que se analiza el makefile. Decimos que una expansión es diferida (deferred) si no es inmediata. La expansión de una parte de construcción diferida se retrasa hasta que se usa la expansión: ya sea cuando se hace referencia a ella en un contexto inmediato o cuando se necesita durante la segunda fase.
Puede que aún no esté familiarizado con algunas de estas construcciones. Puede consultar esta sección a medida que se vaya familiarizando con ellas en capítulos posteriores.
Las definiciones de variables se analizan de la siguiente manera:
immediate = deferred immediate ?= deferred immediate := immediate immediate ::= immediate immediate :::= immediate-with-escape immediate += deferred or immediate immediate != immediate define immediate deferred endef define immediate = deferred endef define immediate ?= deferred endef define immediate := immediate endef define immediate ::= immediate endef define immediate :::= immediate-with-escape endef define immediate += deferred or immediate endef define immediate != immediate endef
Para el operador de adición «+=», el lado derecho se considera inmediato si la variable se había establecido previamente como variable simple («:=» o «::=»), y diferido en caso contrario.
Para el operador inmediato con escape «:::=», el valor del lado derecho se expande de inmediato pero luego se escapa (es decir, todas las apariciones de $ en el resultado de la expansión se sustituyen por $$).
Para el operador de asignación de shell «!=», el lado derecho se evalúa de inmediato y se entrega a la shell. El resultado se almacena en la variable nombrada a la izquierda, y esa variable se considera una variable de expansión recursiva (y, por tanto, se reevaluará en cada referencia).
Las directivas condicionales se analizan de inmediato. Esto significa, por ejemplo, que no se pueden usar variables automáticas en directivas condicionales, ya que las variables automáticas no se establecen hasta que se invoca la receta de esa regla. Si necesita usar variables automáticas en una directiva condicional, debe trasladar la condición a la receta y usar en su lugar la sintaxis condicional de la shell.
Una regla se expande siempre de la misma manera, sea cual sea su forma:
immediate : immediate ; deferred
deferred
Es decir, las secciones de objetivo y de prerrequisito se expanden de inmediato, y la receta usada para construir el objetivo siempre se difiere. Esto es cierto para las reglas explícitas, las reglas de patrón, las reglas de sufijo, las reglas de patrón estáticas y las definiciones de prerrequisitos sencillas.
GNU make analiza los makefiles línea por línea. El análisis procede mediante los siguientes pasos:
make un makefile).
Una consecuencia importante de esto es que una macro puede expandirse a una regla entera, si ocupa una sola línea. Esto funcionará:
myrule = target : ; echo built $(myrule)
Sin embargo, esto no funcionará, porque make no vuelve a dividir las líneas después de haberlas expandido:
define myrule
target:
echo built
endef
$(myrule)
El makefile anterior da como resultado la definición de un objetivo «target» con prerrequisitos «echo» y «built», como si el makefile contuviera target: echo built, en lugar de una regla con una receta. Las nuevas líneas que todavía quedan en una línea después de completar la expansión se ignoran como espacio en blanco normal.
Para expandir correctamente una macro de varias líneas debe usar la función eval: esto hace que el analizador de make se ejecute sobre los resultados de la macro expandida (consulte La función eval).
Anteriormente aprendimos que GNU make funciona en dos fases bien diferenciadas: una fase de lectura y una fase de actualización de objetivos (consulte Cómo lee make un makefile). GNU Make también tiene la capacidad de habilitar una segunda expansión de los prerrequisitos (solo) para algunos o todos los objetivos definidos en el makefile. Para que esta segunda expansión se produzca, el objetivo especial .SECONDEXPANSION debe definirse antes de la primera lista de prerrequisitos que haga uso de esta función.
Si .SECONDEXPANSION está definido, cuando GNU make necesita comprobar los prerrequisitos de un objetivo, los prerrequisitos se expanden por segunda vez. En la mayoría de las circunstancias esta expansión secundaria no tendrá efecto, ya que todas las referencias a variables y funciones se habrán expandido durante el análisis inicial de los makefiles. Por tanto, para aprovechar la fase de expansión secundaria del analizador es necesario escapar la referencia a variable o función en el makefile. En este caso, la primera expansión se limita a quitar el escape de la referencia, pero no la expande, y la expansión se deja para la fase de expansión secundaria. Por ejemplo, considere este makefile:
.SECONDEXPANSION: ONEVAR = onefile TWOVAR = twofile myfile: $(ONEVAR) $$(TWOVAR)
Tras la primera fase de expansión, la lista de prerrequisitos del objetivo myfile será onefile y $(TWOVAR); la primera referencia a variable (no escapada) a ONEVAR se expande, mientras que a la segunda referencia a variable (escapada) simplemente se le quita el escape, sin que se reconozca como una referencia a variable. Ahora, durante la expansión secundaria, la primera palabra se expande de nuevo, pero como no contiene referencias a variables ni a funciones, conserva el valor onefile, mientras que la segunda palabra es ahora una referencia normal a la variable TWOVAR, que se expande al valor twofile. El resultado final es que hay dos prerrequisitos, onefile y twofile.
Evidentemente, este no es un caso muy interesante, ya que el mismo resultado podría haberse obtenido más fácilmente con solo hacer que ambas variables aparecieran, sin escapar, en la lista de prerrequisitos. La diferencia se hace patente si las variables se reasignan; considere este ejemplo:
.SECONDEXPANSION: AVAR = top onefile: $(AVAR) twofile: $$(AVAR) AVAR = bottom
Aquí el prerrequisito de onefile se expandirá de inmediato y se resolverá al valor top, mientras que el prerrequisito de twofile no se expandirá por completo hasta la expansión secundaria y dará un valor de bottom.
Esto es algo más emocionante, pero el verdadero poder de esta función solo se hace patente cuando se descubre que las expansiones secundarias siempre tienen lugar dentro del ámbito de las variables automáticas de ese objetivo. Esto significa que puede usar variables como $@, $*, etc. durante la segunda expansión y tendrán sus valores esperados, igual que en la receta. Lo único que tiene que hacer es diferir la expansión escapando el $. Además, la expansión secundaria se produce tanto para las reglas explícitas como para las implícitas (de patrón). Sabiendo esto, los posibles usos de esta función aumentan de forma drástica. Por ejemplo:
.SECONDEXPANSION: main_OBJS := main.o try.o test.o lib_OBJS := lib.o api.o main lib: $$($$@_OBJS)
Aquí, tras la expansión inicial, los prerrequisitos tanto del objetivo main como del lib serán $($@_OBJS). Durante la expansión secundaria, la variable $@ se establece con el nombre del objetivo, de modo que la expansión para el objetivo main dará $(main_OBJS), o sea main.o try.o test.o, mientras que la expansión secundaria para el objetivo lib dará $(lib_OBJS), o sea lib.o api.o.
También puede mezclar aquí funciones, siempre que estén correctamente escapadas:
main_SRCS := main.c try.c test.c lib_SRCS := lib.c api.c .SECONDEXPANSION: main lib: $$(patsubst %.c,%.o,$$($$@_SRCS))
Esta versión permite a los usuarios especificar archivos fuente en lugar de archivos objeto, pero da como resultado la misma lista de prerrequisitos que el ejemplo anterior.
La evaluación de las variables automáticas durante la fase de expansión secundaria, en especial la de la variable de nombre del objetivo $$@, se comporta de forma similar a la evaluación dentro de las recetas. Sin embargo, hay algunas diferencias sutiles y «casos límite» que entran en juego para los distintos tipos de definiciones de reglas que make entiende. Los detalles del uso de las distintas variables automáticas se describen a continuación.
Durante la expansión secundaria de las reglas explícitas, $$@ y $$% se evalúan, respectivamente, al nombre de archivo del objetivo y, cuando el objetivo es un miembro de un archivo de archivo (archive), al nombre del miembro objetivo. La variable $$< se evalúa al primer prerrequisito de la primera regla para este objetivo. $$^ y $$+ se evalúan a la lista de todos los prerrequisitos de las reglas que ya han aparecido para el mismo objetivo ($$+ con repeticiones y $$^ sin ellas). El siguiente ejemplo ayudará a ilustrar estos comportamientos:
.SECONDEXPANSION: foo: foo.1 bar.1 $$< $$^ $$+ # line #1 foo: foo.2 bar.2 $$< $$^ $$+ # line #2 foo: foo.3 bar.3 $$< $$^ $$+ # line #3
En la primera lista de prerrequisitos, las tres variables ($$<, $$^ y $$+) se expanden a la cadena vacía. En la segunda, tendrán los valores foo.1, foo.1 bar.1 y foo.1 bar.1 respectivamente. En la tercera tendrán los valores foo.1, foo.1 bar.1 foo.2 bar.2 y foo.1 bar.1 foo.2 bar.2 foo.1 foo.1 bar.1 foo.1 bar.1 respectivamente.
Las reglas se someten a la expansión secundaria en el orden del makefile, salvo que la regla con la receta siempre se evalúa la última.
Las variables $$? y $$* no están disponibles y se expanden a la cadena vacía.
Las reglas para la expansión secundaria de las reglas de patrón estáticas son idénticas a las de las reglas explícitas, anteriores, con una excepción: en las reglas de patrón estáticas la variable $$* se establece con la raíz (stem) del patrón. Al igual que en las reglas explícitas, $$? no está disponible y se expande a la cadena vacía.
Cuando make busca una regla implícita, sustituye la raíz (stem) y luego realiza la expansión secundaria para cada regla cuyo patrón de objetivo coincida. El valor de las variables automáticas se deriva de la misma manera que en las reglas de patrón estáticas. Como ejemplo:
.SECONDEXPANSION: foo: bar foo foz: fo%: bo% %oo: $$< $$^ $$+ $$*
Cuando se prueba la regla implícita para el objetivo foo, $$< se expande a bar, $$^ se expande a bar boo, $$+ también se expande a bar boo y $$* se expande a f.
Tenga en cuenta que el prefijo de directorio (D), tal como se describe en Algoritmo de búsqueda de reglas implícitas, se añade (tras la expansión) a todos los patrones de la lista de prerrequisitos. Como ejemplo:
.SECONDEXPANSION:
/tmp/foo.o:
%.o: $$(addsuffix /%.c,foo bar) foo.h
@echo $^
La lista de prerrequisitos impresa, tras la expansión secundaria y la reconstrucción del prefijo de directorio, será /tmp/foo/foo.c /tmp/bar/foo.c foo.h. Si no le interesa esta reconstrucción, puede usar $$* en lugar de % en la lista de prerrequisitos.