Idioma: 日本語 | Español | Français | Português | 中文 | English
Anterior | Siguiente | Índice | Original en inglés (gnu.org)

6 Cómo usar las variables

Una variable es un nombre definido en un makefile que representa una cadena de texto, llamada el valor (value) de la variable. Estos valores se sustituyen, mediante una petición explícita, en los objetivos, los prerrequisitos (prerequisite), las recetas (recipe) y otras partes del makefile. (En algunas otras versiones de make, las variables se denominan macros.)

Las variables y las funciones, en todas las partes de un makefile, se expanden cuando se leen, salvo en las recetas, en los lados derechos de las definiciones de variables que usan ‘=’ y en los cuerpos de las definiciones de variables que usan la directiva define. El valor al que se expande una variable es el de su definición más reciente en el momento de la expansión. En otras palabras, las variables tienen ámbito dinámico.

Las variables pueden representar listas de nombres de archivo, opciones que pasar a los compiladores, programas que ejecutar, directorios donde buscar los archivos fuente, directorios donde escribir la salida o cualquier otra cosa que se le ocurra.

Un nombre de variable puede ser cualquier secuencia de caracteres que no contenga ‘:’, ‘#’, ‘=’ ni espacios en blanco. No obstante, los nombres de variable que contienen caracteres distintos de letras, números y guiones bajos deben tratarse con cuidado, ya que en algunos shells no pueden pasarse a través del entorno a un sub-make (véase Comunicar variables a un sub-make). Los nombres de variable que empiezan por ‘.’ seguido de una letra mayúscula podrían adquirir un significado especial en futuras versiones de make.

Los nombres de variable distinguen mayúsculas de minúsculas. Los nombres ‘foo’, ‘FOO’ y ‘Foo’ se refieren todos a variables distintas.

Es tradicional usar letras mayúsculas en los nombres de variable, pero recomendamos usar minúsculas para los nombres de variable que sirven a propósitos internos del makefile, y reservar las mayúsculas para los parámetros que controlan las reglas implícitas o para los parámetros que el usuario debería redefinir con opciones de la orden (véase Anular variables).

Unas pocas variables tienen nombres formados por un único carácter de puntuación o por solo unos pocos caracteres. Son las variables automáticas (automatic variable), y tienen usos especializados concretos. Véase Variables automáticas.

6.1 Conceptos básicos de las referencias a variables

Para sustituir el valor de una variable, escriba un signo de dólar seguido del nombre de la variable entre paréntesis o entre llaves: tanto ‘$(foo)’ como ‘${foo}’ son referencias válidas a la variable foo. Este significado especial de ‘$’ es la razón por la que debe escribir ‘$$’ para obtener el efecto de un único signo de dólar en un nombre de archivo o en una receta.

Las referencias a variables pueden usarse en cualquier contexto: objetivos, prerrequisitos, recetas, la mayoría de las directivas y los valores de variables nuevas. He aquí un ejemplo de un caso habitual, en el que una variable contiene los nombres de todos los archivos objeto de un programa:

objects = program.o foo.o utils.o
program : $(objects)
        cc -o program $(objects)

$(objects) : defs.h

Las referencias a variables funcionan por sustitución textual estricta. Así, la regla

foo = c
prog.o : prog.$(foo)
        $(foo)$(foo) -$(foo) prog.$(foo)

podría usarse para compilar un programa en C prog.c. Como los espacios delante del valor de la variable se ignoran en las asignaciones de variables, el valor de foo es exactamente ‘c’. (¡No escriba realmente sus makefiles de esta manera!)

Un signo de dólar seguido de un carácter que no sea otro signo de dólar, un paréntesis de apertura o una llave de apertura trata ese único carácter como el nombre de la variable. Así, podría referenciar la variable x con ‘$x’. Sin embargo, esta práctica puede dar lugar a confusión (por ejemplo, ‘$foo’ se refiere a la variable f seguida de la cadena oo), por lo que recomendamos usar paréntesis o llaves alrededor de todas las variables, incluso de las de una sola letra, salvo que omitirlos suponga una mejora significativa de la legibilidad. Un lugar donde la legibilidad suele mejorar es en las variables automáticas (véase Variables automáticas).

6.2 Los dos tipos (flavors) de variables

En GNU make hay distintas maneras en que una variable puede obtener un valor; las llamamos los tipos (flavors) de variables. Los tipos se distinguen por cómo manejan los valores que se les asignan en el makefile y por cómo se gestionan esos valores cuando la variable se usa y se expande más adelante.

6.2.1 Asignación de variables de expansión recursiva

El primer tipo de variable es la variable de expansión recursiva (recursively expanded). Las variables de esta clase se definen mediante líneas que usan ‘=’ (véase Establecer variables) o mediante la directiva define (véase Definir variables de varias líneas). El valor que se especifica se instala literalmente; si contiene referencias a otras variables, esas referencias se expanden cada vez que esta variable se sustituye (en el transcurso de la expansión de alguna otra cadena). Cuando esto ocurre, se denomina expansión recursiva (recursive expansion).

Por ejemplo,

foo = $(bar)
bar = $(ugh)
ugh = Huh?

all:;echo $(foo)

imprimirá ‘Huh?’: ‘$(foo)’ se expande a ‘$(bar)’, que se expande a ‘$(ugh)’, que finalmente se expande a ‘Huh?’.

Este tipo de variable es el único que admiten la mayoría de las otras versiones de make. Tiene sus ventajas y sus desventajas. Una ventaja (la mayoría así lo diría) es la siguiente:

CFLAGS = $(include_dirs) -O
include_dirs = -Ifoo -Ibar

hará lo que se pretendía: cuando ‘CFLAGS’ se expanda en una receta, se expandirá a ‘-Ifoo -Ibar -O’. Una gran desventaja es que no puede añadir algo al final de una variable, como en

CFLAGS = $(CFLAGS) -O

porque provocaría un bucle infinito en la expansión de la variable. (En realidad make detecta el bucle infinito e informa de un error.)

Otra desventaja es que cualquier función (véase Funciones para transformar texto) referenciada en la definición se ejecutará cada vez que la variable se expanda. Esto hace que make se ejecute más lento; peor aún, hace que las funciones wildcard y shell den resultados impredecibles, porque no se puede controlar con facilidad cuándo se llaman, ni siquiera cuántas veces.

6.2.2 Asignación de variables de expansión simple

Para evitar los problemas e inconvenientes de las variables de expansión recursiva, existe otro tipo: las variables de expansión simple.

Las variables de expansión simple (simply expanded variable) se definen mediante líneas que usan ‘:=’ o ‘::=’ (véase Establecer variables). Ambas formas son equivalentes en GNU make; sin embargo, el estándar POSIX solo describe la forma ‘::=’ (la compatibilidad con ‘::=’ se añade al estándar POSIX en POSIX Issue 8).

El valor de una variable de expansión simple se examina una sola vez, expandiendo cualquier referencia a otras variables y funciones, en el momento en que la variable se define. Una vez completada esa expansión, el valor de la variable no se vuelve a expandir: cuando la variable se usa, el valor se copia literalmente como su expansión. Si el valor contenía referencias a variables, el resultado de la expansión contendrá sus valores tal como estaban en el momento en que se definió esta variable. Por tanto,

x := foo
y := $(x) bar
x := later

es equivalente a

y := foo bar
x := later

He aquí un ejemplo algo más complicado, que ilustra el uso de ‘:=’ junto con la función shell. (Véase La función shell.) Este ejemplo también muestra el uso de la variable MAKELEVEL, que cambia al pasar de un nivel a otro. (Véase Comunicar variables a un sub-make para más información sobre MAKELEVEL.)

ifeq (0,${MAKELEVEL})
whoami    := $(shell whoami)
host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
endif

Una ventaja de este uso de ‘:=’ es que una receta típica de «descender a un directorio» queda entonces así:

${subdirs}:
        ${MAKE} -C $@ all

Las variables de expansión simple, en general, hacen que la programación complicada de makefiles sea más predecible, porque funcionan como las variables de la mayoría de los lenguajes de programación. Permiten redefinir una variable usando su propio valor (o su valor procesado de algún modo por una de las funciones de expansión) y usar las funciones de expansión de manera mucho más eficiente (véase Funciones para transformar texto).

También puede usarlas para introducir espacios en blanco iniciales controlados en los valores de las variables. Los caracteres de espacio en blanco iniciales se descartan de la entrada antes de la sustitución de las referencias a variables y de las llamadas a funciones; esto significa que puede incluir espacios iniciales en el valor de una variable protegiéndolos con referencias a variables, así:

nullstring :=
space := $(nullstring) # end of the line

Aquí el valor de la variable space es exactamente un espacio. El comentario ‘# end of the line’ se incluye aquí solo para mayor claridad. Como los caracteres de espacio finales no se eliminan de los valores de las variables, un simple espacio al final de la línea tendría el mismo efecto (pero sería bastante difícil de leer). Si pone espacios en blanco al final del valor de una variable, conviene poner un comentario como ese al final de la línea para dejar clara su intención. A la inversa, si no quiere ningún carácter de espacio en blanco al final del valor de su variable, debe recordar no poner un comentario cualquiera al final de la línea después de algún espacio en blanco, como en este caso:

dir := /foo/bar    # directory to put the frobs in

Aquí el valor de la variable dir es ‘/foo/bar    ’ (con cuatro espacios finales), lo que probablemente no era la intención. (¡Imagine algo como ‘$(dir)/file’ con esta definición!)

6.2.3 Asignación de variables de expansión inmediata

Otra forma de asignación permite la expansión inmediata, pero, a diferencia de la asignación simple, la variable resultante es recursiva: se volverá a expandir en cada uso. Para evitar resultados inesperados, después de expandir el valor de forma inmediata se entrecomilla automáticamente: todas las apariciones de $ en el valor tras la expansión se convierten en $$. Este tipo de asignación usa el operador ‘:::=’. Por ejemplo,

var = first
OUT :::= $(var)
var = second

hace que la variable OUT contenga el texto ‘first’, mientras que aquí:

var = one$$two
OUT :::= $(var)
var = three$$four

hace que la variable OUT contenga el texto ‘one$$two’. El valor se expande cuando se asigna la variable, de modo que el resultado es la expansión del primer valor de var, ‘one$two’; luego el valor se vuelve a escapar antes de completar la asignación, lo que da el resultado final ‘one$$two’.

A partir de ahí, la variable OUT se considera una variable recursiva, por lo que se volverá a expandir cuando se use.

Esto parece funcionalmente equivalente a los operadores ‘:=’ / ‘::=’, pero hay algunas diferencias:

En primer lugar, tras la asignación la variable es una variable recursiva normal; cuando le añade algo con ‘+=’, el valor del lado derecho no se expande de inmediato. Si prefiere que el operador ‘+=’ expanda el lado derecho de inmediato, debería usar en su lugar la asignación ‘:=’ / ‘::=’.

En segundo lugar, estas variables son ligeramente menos eficientes que las variables de expansión simple, ya que necesitan volver a expandirse cuando se usan, en lugar de simplemente copiarse. No obstante, como todas las referencias a variables están escapadas, esta expansión simplemente desescapa el valor; no expandirá ninguna variable ni ejecutará ninguna función.

He aquí otro ejemplo:

var = one$$two
OUT :::= $(var)
OUT += $(var)
var = three$$four

Después de esto, el valor de OUT es el texto ‘one$$two $(var)’. Cuando esta variable se usa, se expande y el resultado es ‘one$two three$four’.

Este estilo de asignación es equivalente al operador ‘:=’ del make tradicional de BSD; como puede ver, funciona de manera ligeramente distinta al operador ‘:=’ de GNU make. El operador :::= se añade a la especificación POSIX en el Issue 8 para proporcionar portabilidad.

6.2.4 Asignación condicional de variables

Hay otro operador de asignación para variables, ‘?=’. Se denomina operador de asignación condicional de variables, porque solo tiene efecto si la variable aún no está definida. Esta instrucción:

FOO ?= bar

es exactamente equivalente a esta (véase La función origin):

ifeq ($(origin FOO), undefined)
  FOO = bar
endif

Tenga en cuenta que una variable establecida con un valor vacío sigue estando definida, de modo que ‘?=’ no la establecerá.

6.3 Funciones avanzadas para referenciar variables

Esta sección describe algunas funciones avanzadas que puede usar para referenciar variables de maneras más flexibles.

6.3.1 Referencias de sustitución

Una referencia de sustitución (substitution reference) sustituye el valor de una variable con las modificaciones que usted especifique. Tiene la forma ‘$(var:a=b)’ (o ‘${var:a=b}’) y su significado es tomar el valor de la variable var, reemplazar cada a que esté al final de una palabra por b en ese valor, y sustituir la cadena resultante.

Cuando decimos «al final de una palabra», queremos decir que a debe aparecer o bien seguida de un espacio en blanco, o bien al final del valor, para que se reemplace; las demás apariciones de a en el valor quedan inalteradas. Por ejemplo:

foo := a.o b.o l.a c.o
bar := $(foo:.o=.c)

establece ‘bar’ en ‘a.c b.c l.a c.c’. Véase Establecer variables.

Una referencia de sustitución es una abreviatura de la función de expansión patsubst (véase Funciones para la sustitución y el análisis de cadenas): ‘$(var:a=b)’ es equivalente a ‘$(patsubst %a,%b,var)’. Proporcionamos referencias de sustitución además de patsubst por compatibilidad con otras implementaciones de make.

Otro tipo de referencia de sustitución le permite usar toda la potencia de la función patsubst. Tiene la misma forma ‘$(var:a=b)’ descrita antes, salvo que ahora a debe contener un único carácter ‘%’. Este caso es equivalente a ‘$(patsubst a,b,$(var))’. Véase Funciones para la sustitución y el análisis de cadenas para una descripción de la función patsubst. Por ejemplo:

foo := a.o b.o l.a c.o
bar := $(foo:%.o=%.c)

establece ‘bar’ en ‘a.c b.c l.a c.c’.

6.3.2 Nombres de variable calculados

Los nombres de variable calculados son un concepto avanzado, muy útil en la programación de makefiles más sofisticada. En situaciones sencillas no necesita tenerlos en cuenta, pero pueden resultar extremadamente útiles.

Las variables pueden referenciarse dentro del nombre de una variable. Esto se denomina nombre de variable calculado (computed variable name) o referencia anidada a variable (nested variable reference). Por ejemplo,

x = y
y = z
a := $($(x))

define a como ‘z’: el ‘$(x)’ dentro de ‘$($(x))’ se expande a ‘y’, de modo que ‘$($(x))’ se expande a ‘$(y)’, que a su vez se expande a ‘z’. Aquí el nombre de la variable que se referencia no se indica explícitamente; se calcula mediante la expansión de ‘$(x)’. La referencia ‘$(x)’ está aquí anidada dentro de la referencia a variable exterior.

El ejemplo anterior muestra dos niveles de anidamiento, pero es posible cualquier número de niveles. Por ejemplo, aquí hay tres niveles:

x = y
y = z
z = u
a := $($($(x)))

Aquí el ‘$(x)’ más interno se expande a ‘y’, de modo que ‘$($(x))’ se expande a ‘$(y)’, que a su vez se expande a ‘z’; ahora tenemos ‘$(z)’, que se convierte en ‘u’.

Las referencias a variables de expansión recursiva dentro del nombre de una variable se vuelven a expandir de la manera habitual. Por ejemplo:

x = $(y)
y = z
z = Hello
a := $($(x))

define a como ‘Hello’: ‘$($(x))’ se convierte en ‘$($(y))’, que se convierte en ‘$(z)’, que se convierte en ‘Hello’.

Las referencias anidadas a variables también pueden contener referencias modificadas e invocaciones de funciones (véase Funciones para transformar texto), igual que cualquier otra referencia. Por ejemplo, usando la función subst (véase Funciones para la sustitución y el análisis de cadenas):

x = variable1
variable2 := Hello
y = $(subst 1,2,$(x))
z = y
a := $($($(z)))

define finalmente a como ‘Hello’. Es dudoso que alguien quiera escribir alguna vez una referencia anidada tan enrevesada como esta, pero funciona: ‘$($($(z)))’ se expande a ‘$($(y))’, que se convierte en ‘$($(subst 1,2,$(x)))’. Esto obtiene el valor ‘variable1’ de x y lo cambia por sustitución a ‘variable2’, de modo que la cadena completa se convierte en ‘$(variable2)’, una referencia a variable simple cuyo valor es ‘Hello’.

Un nombre de variable calculado no tiene por qué consistir enteramente en una única referencia a variable. Puede contener varias referencias a variables, así como texto invariable. Por ejemplo,

a_dirs := dira dirb
1_dirs := dir1 dir2

a_files := filea fileb
1_files := file1 file2

ifeq "$(use_a)" "yes"
a1 := a
else
a1 := 1
endif

ifeq "$(use_dirs)" "yes"
df := dirs
else
df := files
endif

dirs := $($(a1)_$(df))

dará a dirs el mismo valor que a_dirs, 1_dirs, a_files o 1_files, según los valores de use_a y use_dirs.

Los nombres de variable calculados también pueden usarse en las referencias de sustitución:

a_objects := a.o b.o c.o
1_objects := 1.o 2.o 3.o

sources := $($(a1)_objects:.o=.c)

define sources como ‘a.c b.c c.c’ o ‘1.c 2.c 3.c’, según el valor de a1.

La única restricción de este tipo de uso de las referencias anidadas a variables es que no pueden especificar parte del nombre de una función que se vaya a llamar. Esto se debe a que la comprobación de si un nombre de función es reconocido se hace antes de la expansión de las referencias anidadas. Por ejemplo,

ifdef do_sort
func := sort
else
func := strip
endif

bar := a d b g q c

foo := $($(func) $(bar))

intenta dar a ‘foo’ el valor de la variable ‘sort a d b g q c’ o ‘strip a d b g q c’, en lugar de dar ‘a d b g q c’ como argumento a la función sort o a la función strip. Esta restricción podría eliminarse en el futuro si se demuestra que tal cambio es una buena idea.

Los nombres de variable calculados también pueden usarse en el lado izquierdo de una asignación de variable, o en una directiva define, como en:

dir = foo
$(dir)_sources := $(wildcard $(dir)/*.c)
define $(dir)_print =
lpr $($(dir)_sources)
endef

Este ejemplo define las variables ‘dir’, ‘foo_sources’ y ‘foo_print’.

Tenga en cuenta que las referencias anidadas a variables son bastante distintas de las variables de expansión recursiva (véase Los dos tipos de variables), aunque ambas se usan juntas de maneras complejas al programar makefiles.

6.4 Cómo obtienen sus valores las variables

Las variables pueden obtener valores de varias maneras distintas:

6.5 Establecer variables

Para establecer una variable desde el makefile, escriba una línea que empiece con el nombre de la variable seguido de uno de los operadores de asignación ‘=’, ‘:=’, ‘::=’ o ‘:::=’. Lo que siga al operador, y cualquier espacio en blanco inicial de la línea, se convierte en el valor. Por ejemplo,

objects = main.o foo.o bar.o utils.o

define una variable llamada objects con el valor ‘main.o foo.o bar.o utils.o’. El espacio en blanco alrededor del nombre de la variable e inmediatamente después de ‘=’ se ignora.

Las variables definidas con ‘=’ son variables de expansión recursiva. Las variables definidas con ‘:=’ o ‘::=’ son variables de expansión simple; estas definiciones pueden contener referencias a variables que se expandirán antes de realizar la definición. Las variables definidas con ‘:::=’ son variables de expansión inmediata. Los distintos operadores de asignación se describen en Los dos tipos de variables.

El nombre de la variable puede contener referencias a funciones y a variables, que se expanden cuando se lee la línea para hallar el nombre de variable real que se va a usar.

No hay límite para la longitud del valor de una variable, salvo la cantidad de memoria del ordenador. Para mayor legibilidad, puede dividir el valor de una variable en varias líneas físicas (véase Dividir líneas largas).

Se considera que la mayoría de los nombres de variable tienen la cadena vacía como valor si nunca los ha establecido. Varias variables tienen valores iniciales incorporados que no están vacíos, pero puede establecerlos de las maneras habituales (véase Variables usadas por las reglas implícitas). Varias variables especiales se establecen automáticamente con un valor nuevo para cada regla; son las llamadas variables automáticas (véase Variables automáticas).

Si desea que una variable se establezca con un valor solo si aún no está establecida, puede usar el operador abreviado ‘?=’ en lugar de ‘=’. Estas dos definiciones de la variable ‘FOO’ son idénticas (véase La función origin):

FOO ?= bar

y

ifeq ($(origin FOO), undefined)
FOO = bar
endif

El operador de asignación de shell ‘!=’ puede usarse para ejecutar un script de shell y establecer una variable con su salida. Este operador primero evalúa el lado derecho y luego pasa ese resultado al shell para su ejecución. Si el resultado de la ejecución termina en un salto de línea, ese único salto de línea se elimina; todos los demás saltos de línea se reemplazan por espacios. La cadena resultante se coloca entonces en la variable de expansión recursiva indicada. Por ejemplo:

hash != printf '\043'
file_list != find . -name '*.c'

Si el resultado de la ejecución pudiera producir un $, y no pretende que lo que le siga se interprete como una referencia a una variable o función de make, debe reemplazar cada $ por $$ como parte de la ejecución. Como alternativa, puede establecer una variable de expansión simple con el resultado de ejecutar un programa usando la llamada a la función shell. Véase La función shell. Por ejemplo:

hash := $(shell printf '\043')
var := $(shell find . -name "*.c")

Al igual que con la función shell, el estado de salida del script de shell que se acaba de invocar se almacena en la variable .SHELLSTATUS.

6.6 Añadir más texto a las variables

A menudo resulta útil añadir más texto al valor de una variable ya definida. Esto se hace con una línea que contiene ‘+=’, así:

objects += another.o

Esto toma el valor de la variable objects y le añade el texto ‘another.o’ (precedido de un único espacio, si ya tiene un valor). Así:

objects = main.o foo.o bar.o utils.o
objects += another.o

establece objects en ‘main.o foo.o bar.o utils.o another.o’.

Usar ‘+=’ es similar a:

objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o

pero difiere en aspectos que se vuelven importantes cuando se usan valores más complejos.

Cuando la variable en cuestión no se ha definido antes, ‘+=’ actúa igual que un ‘=’ normal: define una variable de expansión recursiva. Sin embargo, cuando hay una definición previa, lo que hace exactamente ‘+=’ depende del tipo de variable que definió originalmente. Véase Los dos tipos de variables para una explicación de los dos tipos de variables.

Cuando añade algo al valor de una variable con ‘+=’, make actúa esencialmente como si hubiera incluido el texto adicional en la definición inicial de la variable. Si la definió primero con ‘:=’ o ‘::=’, convirtiéndola en una variable de expansión simple, ‘+=’ añade a esa definición de expansión simple y expande el texto nuevo antes de anexarlo al valor antiguo, igual que hace ‘:=’ (véase Establecer variables para una explicación completa de ‘:=’ o ‘::=’). De hecho,

variable := value
variable += more

es exactamente equivalente a:

variable := value
variable := $(variable) more

Por otra parte, cuando usa ‘+=’ con una variable que definió primero como de expansión recursiva usando un ‘=’ simple o ‘:::=’, make añade el texto sin expandir al valor existente, sea cual sea. Esto significa que

variable = value
variable += more

es aproximadamente equivalente a:

temp = value
variable = $(temp) more

salvo que, por supuesto, nunca define una variable llamada temp. La importancia de esto surge cuando el valor antiguo de la variable contiene referencias a variables. Tomemos este ejemplo habitual:

CFLAGS = $(includes) -O
…
CFLAGS += -pg # enable profiling

La primera línea define la variable CFLAGS con una referencia a otra variable, includes. (CFLAGS se usa en las reglas de compilación de C; véase Catálogo de reglas integradas.) Usar ‘=’ en la definición convierte a CFLAGS en una variable de expansión recursiva, lo que significa que ‘$(includes) -Ono se expande cuando make procesa la definición de CFLAGS. Por tanto, no es necesario que includes esté ya definida para que su valor surta efecto. Solo tiene que estar definida antes de cualquier referencia a CFLAGS. Si intentáramos añadir al valor de CFLAGS sin usar ‘+=’, podríamos hacerlo así:

CFLAGS := $(CFLAGS) -pg # enable profiling

Esto se acerca bastante, pero no es exactamente lo que queremos. Usar ‘:=’ redefine CFLAGS como una variable de expansión simple; esto significa que make expande el texto ‘$(CFLAGS) -pg’ antes de establecer la variable. Si includes aún no está definida, obtenemos ‘ -O -pg’, y una definición posterior de includes no tendrá efecto. A la inversa, usando ‘+=’ establecemos CFLAGS en el valor sin expandir$(includes) -O -pg’. Así conservamos la referencia a includes, de modo que si esa variable se define en algún punto posterior, una referencia como ‘$(CFLAGS)’ sigue usando su valor.

6.7 La directiva override

Si una variable se ha establecido con un argumento de la orden (véase Anular variables), las asignaciones ordinarias del makefile se ignoran. Si desea establecer la variable en el makefile aunque se haya establecido con un argumento de la orden, puede usar una directiva override, que es una línea con este aspecto:

override variable = value

o

override variable := value

Para añadir más texto a una variable definida en la línea de órdenes, use:

override variable += more text

Véase Añadir más texto a las variables.

Las asignaciones de variables marcadas con el indicador override tienen mayor prioridad que todas las demás asignaciones, salvo otra override. Las asignaciones o adiciones posteriores a esta variable que no estén marcadas con override se ignoran.

La directiva override no se inventó para escalar la guerra entre los makefiles y los argumentos de la orden. Se inventó para que pueda alterar y añadir a los valores que el usuario especifica con argumentos de la orden.

Por ejemplo, suponga que siempre quiere el modificador ‘-g’ cuando ejecuta el compilador de C, pero le gustaría permitir que el usuario especifique los demás modificadores con un argumento de la orden como de costumbre. Podría usar esta directiva override:

override CFLAGS += -g

También puede usar directivas override con directivas define. Esto se hace tal como cabría esperar:

override define foo =
bar
endef

Véase Definir variables de varias líneas.

6.8 Definir variables de varias líneas

Otra forma de establecer el valor de una variable es usar la directiva define. Esta directiva tiene una sintaxis poco habitual que permite incluir caracteres de salto de línea en el valor, lo cual resulta cómodo para definir tanto secuencias predefinidas de órdenes (véase Definir recetas predefinidas) como secciones de sintaxis de makefile que se usan con eval (véase La función eval).

A la directiva define le sigue, en la misma línea, el nombre de la variable que se va a definir y un operador de asignación (opcional), y nada más. El valor que se da a la variable aparece en las líneas siguientes. El final del valor se marca con una línea que contiene únicamente la palabra endef.

Aparte de esta diferencia de sintaxis, define funciona igual que cualquier otra definición de variable. El nombre de la variable puede contener referencias a funciones y a variables, que se expanden cuando se lee la directiva para hallar el nombre de variable real que se va a usar.

El salto de línea final antes de endef no se incluye en el valor; si quiere que su valor contenga un salto de línea final, debe incluir una línea en blanco. Por ejemplo, para definir una variable que contenga un carácter de salto de línea, debe usar dos líneas vacías, no una:

define newline


endef

Si lo prefiere, puede omitir el operador de asignación de variable. Si se omite, make supone que es ‘=’ y crea una variable de expansión recursiva (véase Los dos tipos de variables). Cuando se usa un operador ‘+=’, el valor se añade al valor anterior como en cualquier otra operación de adición: con un único espacio separando el valor antiguo y el nuevo.

Puede anidar directivas define: make llevará el seguimiento de las directivas anidadas e informará de un error si no se cierran todas correctamente con endef. Tenga en cuenta que las líneas que empiezan con el carácter de prefijo de receta se consideran parte de una receta, de modo que cualquier cadena define o endef que aparezca en tales líneas no se considerará una directiva de make.

define two-lines
echo foo
echo $(bar)
endef

Cuando se usa en una receta, el ejemplo anterior es funcionalmente equivalente a esto:

two-lines = echo foo; echo $(bar)

ya que dos órdenes separadas por punto y coma se comportan de forma muy parecida a dos órdenes de shell separadas. No obstante, tenga en cuenta que usar dos líneas separadas significa que make invocará el shell dos veces, ejecutando un subshell independiente para cada línea. Véase Ejecución de recetas.

Si quiere que las definiciones de variables hechas con define tengan prioridad sobre las definiciones de variables de la línea de órdenes, puede usar la directiva override junto con define:

override define two-lines =
foo
$(bar)
endef

Véase La directiva override.

6.9 Anular la definición de variables

Si quiere borrar una variable, normalmente basta con establecer su valor a vacío. Al expandir esa variable se obtendrá el mismo resultado (la cadena vacía) tanto si estaba establecida como si no. Sin embargo, si usa la función flavor (véase La función flavor) o la función origin (véase La función origin), hay una diferencia entre una variable que nunca se ha establecido y una variable con un valor vacío. En esos casos, quizá quiera usar la directiva undefine para hacer que parezca que una variable nunca se estableció. Por ejemplo,

foo := foo
bar = bar

undefine foo
undefine bar

$(info $(origin foo))
$(info $(flavor bar))

Este ejemplo muestra «undefined» para ambas variables.

Si quiere anular la definición de una variable de la línea de órdenes, puede usar la directiva override junto con undefine, igual que al definir variables:

override undefine CFLAGS

6.10 Variables del entorno

Las variables de make pueden tomarse del entorno en el que se ejecuta make. Toda variable de entorno que make ve al arrancar se convierte en una variable de make con el mismo nombre y valor. No obstante, una asignación explícita en el makefile, o una asignación con un argumento de la orden, sobrescribe el entorno. (Si se especifica el indicador ‘-e’, los valores del entorno sobrescriben las asignaciones del makefile. Véase Resumen de opciones. Pero este uso no es recomendable.)

Así, si establece la variable CFLAGS en el entorno, puede hacer que la mayoría de los makefiles usen sus modificadores de compilador preferidos en todas las compilaciones de C. Esto es seguro para las variables con un significado estándar o convencional, porque sabe que ningún makefile las usará para otro propósito. (Pero esto no es del todo fiable; algunos makefiles establecen CFLAGS explícitamente y, en ese caso, no se ven afectados por el valor del entorno.)

Cuando make ejecuta una receta, algunas variables definidas en el makefile se colocan en el entorno de cada orden que make invoca. De forma predeterminada, solo se colocan en el entorno de la orden las variables que provienen del entorno de make o que se establecieron en la línea de órdenes. Para pasar otras variables, puede usar la directiva export. Para todos los detalles, véase Comunicar variables a un sub-make.

Los demás usos de las variables tomadas del entorno no son recomendables. No es prudente que un makefile dependa para su funcionamiento de variables de entorno establecidas fuera de su control, porque eso haría que el mismo makefile diera resultados distintos para distintos usuarios. Esto va en contra del propósito mismo de la mayoría de los makefiles.

Un problema así es especialmente probable con la variable SHELL, que normalmente está presente en el entorno para especificar el shell interactivo elegido por el usuario. Sería muy poco deseable que esta elección afectara a make; por ello, make trata la variable de entorno SHELL de una manera especial. Véase Elegir el shell.

6.11 Valores de variables específicos de objetivo

Los valores de las variables de make son normalmente globales; es decir, son iguales sin importar dónde se evalúen (salvo, por supuesto, que se reestablezcan). Las excepciones son las variables definidas con la función let (véase La función let) o con la función foreach (véase La función foreach), y las variables automáticas (véase Variables automáticas).

Otra excepción son los valores de variables específicos de objetivo (target-specific variable value). Esta función le permite definir valores distintos para una misma variable según el objetivo que make esté construyendo en cada momento. Al igual que las variables automáticas, estos valores solo están disponibles dentro del contexto de la receta de un objetivo (y en otras asignaciones específicas de objetivo).

Un valor de variable específico de objetivo se establece así:

target … : variable-assignment

A las asignaciones de variable específicas de objetivo se les puede anteponer como prefijo cualquiera de las palabras clave especiales export, unexport, override o private, o todas ellas. Estas aplican su comportamiento habitual respectivo solo a esta instancia de la variable.

Si especifica varios target, se crea un valor de variable específico de objetivo independiente para cada miembro de la lista de objetivos.

En variable-assignment puede usar cualquier forma de asignación válida: recursiva (‘=’), simple (‘:=’ o ‘::=’), inmediata (‘::=’), de adición (‘+=’) o condicional (‘?=’). Todas las variables que aparecen en el variable-assignment se evalúan en el contexto del objetivo. Por tanto, todo valor de variable específico de objetivo definido antes surte efecto. Tenga en cuenta que esta variable es en realidad distinta de cualquier valor «global»; las dos variables no tienen por qué ser del mismo tipo (recursiva o simple).

Las variables específicas de objetivo tienen la misma prioridad que cualquier otra variable de makefile. Las variables proporcionadas en la línea de órdenes (y, si la opción ‘-e’ está activa, las variables del entorno) tienen prioridad. Especificar la directiva override permite dar prioridad al valor de variable específico de objetivo.

Las variables específicas de objetivo tienen otra característica especial: al definir una variable específica de objetivo, ese valor de variable surte efecto en todos los prerrequisitos de este objetivo, y en los prerrequisitos de aquellos, y así sucesivamente (salvo que esos prerrequisitos lo sobrescriban con su propio valor de variable específico de objetivo). Por ejemplo, una instrucción como esta:

prog : CFLAGS = -g
prog : prog.o foo.o bar.o

establece CFLAGS en ‘-g’ en la receta de prog, pero no solo eso: también establece CFLAGS en ‘-g’ en las recetas que crean prog.o, foo.o y bar.o, así como en las recetas que crean sus prerrequisitos.

No obstante, tenga en cuenta que un prerrequisito dado se construye, como mucho, una sola vez por cada invocación de make. Si el mismo archivo es prerrequisito de varios objetivos, y esos objetivos tienen valores distintos para la misma variable específica de objetivo, el primer objetivo que se construya hará que se construya ese prerrequisito, y el prerrequisito heredará el valor específico de objetivo del primer objetivo. Los valores específicos de objetivo de los demás objetivos se ignoran.

6.12 Valores de variables específicos de patrón

Además de los valores de variables específicos de objetivo (véase Valores de variables específicos de objetivo), GNU make admite también valores de variables específicos de patrón. En esta forma, la variable se define para cualquier objetivo que coincida con el patrón especificado.

Un valor de variable específico de patrón se establece así:

pattern … : variable-assignment

donde pattern es un patrón con %. Al igual que con los valores de variables específicos de objetivo, si especifica varios pattern se crea un valor de variable específico de patrón independiente para cada patrón. En variable-assignment puede usar cualquier forma de asignación válida. Las variables establecidas en la línea de órdenes tienen prioridad, salvo que se especifique override.

Por ejemplo,

%.o : CFLAGS = -O

asigna a CFLAGS el valor ‘-O’ en todos los objetivos que coinciden con el patrón %.o.

Si un objetivo coincide con varios patrones, las variables específicas de patrón coincidentes con la raíz (stem) más larga se interpretan primero. Esto hace que las variables más específicas tengan prioridad sobre las más genéricas. Por ejemplo,

%.o: %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

lib/%.o: CFLAGS := -fPIC -g
%.o: CFLAGS := -g

all: foo.o lib/bar.o

En este ejemplo, la segunda definición también es aplicable al objetivo lib/bar.o, pero es la primera definición de la variable CFLAGS la que se usa para actualizar lib/bar.o. Las variables específicas de patrón cuya raíz tiene la misma longitud se consideran en el orden en que están definidas en el makefile.

Las variables específicas de patrón se buscan después de las variables específicas de objetivo definidas explícitamente para ese objetivo, y antes de las variables específicas de objetivo definidas para el objetivo padre.

6.13 Suprimir la herencia

Como se ha indicado en las secciones anteriores, las variables de make se heredan a los prerrequisitos. Esta característica le permite cambiar el comportamiento de un prerrequisito según el objetivo que provocó su reconstrucción. Por ejemplo, podría establecer una variable específica de objetivo en un objetivo debug, de modo que al ejecutar ‘make debug’ esa variable se herede en todos los prerrequisitos de debug, mientras que ejecutar (por ejemplo) simplemente ‘make all’ no realiza esa asignación.

Sin embargo, a veces no querrá que una variable se herede. Para esas situaciones, make proporciona el modificador private. Aunque este modificador puede usarse en cualquier asignación de variable, tiene más sentido en las variables específicas de objetivo y específicas de patrón. Una variable marcada con private es visible para su objetivo local, pero no se hereda a los prerrequisitos de ese objetivo. Una variable global marcada con private es visible en el ámbito global, pero no se hereda a ningún objetivo y, por tanto, no es visible para ninguna receta.

Como ejemplo, considere el siguiente makefile:

EXTRA_CFLAGS =

prog: private EXTRA_CFLAGS = -L/usr/local/lib
prog: a.o b.o

Gracias al modificador private, a.o y b.o no heredan la asignación de la variable EXTRA_CFLAGS hecha desde el objetivo prog.

6.14 Otras variables especiales

GNU make admite algunas variables con propiedades especiales.

MAKEFILE_LIST

Contiene el nombre de cada makefile que make ha analizado, en el orden en que se analizaron. El nombre se anexa justo antes de que make comience a analizar ese makefile. Por tanto, si lo primero que hace un makefile es examinar la última palabra de esta variable, será el nombre del makefile actual. Sin embargo, una vez que el makefile actual ha usado include, la última palabra será el makefile que se acaba de leer.

Si un makefile llamado Makefile tiene el siguiente contenido:

name1 := $(lastword $(MAKEFILE_LIST))

include inc.mk

name2 := $(lastword $(MAKEFILE_LIST))

all:
        @echo name1 = $(name1)
        @echo name2 = $(name2)

entonces puede esperar la siguiente salida:

name1 = Makefile
name2 = inc.mk
.DEFAULT_GOAL

Establece la meta predeterminada que se usa si no se especifica ningún objetivo en la línea de órdenes (véase Argumentos para especificar las metas). La variable .DEFAULT_GOAL le permite examinar la meta predeterminada actual, borrar su valor para reiniciar el algoritmo de selección de la meta predeterminada, o establecer la meta predeterminada explícitamente. El siguiente ejemplo ilustra estos casos:

# Query the default goal.
ifeq ($(.DEFAULT_GOAL),)
  $(warning no default goal is set)
endif

.PHONY: foo
foo: ; @echo $@

$(warning default goal is $(.DEFAULT_GOAL))

# Reset the default goal.
.DEFAULT_GOAL :=

.PHONY: bar
bar: ; @echo $@

$(warning default goal is $(.DEFAULT_GOAL))

# Set our own.
.DEFAULT_GOAL := foo

Este makefile imprime lo siguiente:

no default goal is set
default goal is foo
default goal is bar
foo

Tenga en cuenta que asignar más de un nombre de objetivo a .DEFAULT_GOAL no es válido y produce un error.

MAKE_RESTARTS

Esta variable solo se establece si esta instancia de make se ha reiniciado (véase Cómo se regeneran los makefiles): contendrá el número de veces que esta instancia se ha reiniciado. Tenga en cuenta que esto es distinto de la recursión (que se cuenta con la variable MAKELEVEL). No debe establecer, modificar ni exportar esta variable.

MAKE_TERMOUT
MAKE_TERMERR

Al arrancar, make comprueba si la salida estándar y la salida de error estándar muestran su salida en un terminal, cada una por separado. Si es así, establece MAKE_TERMOUT y MAKE_TERMERR, respectivamente, con el nombre del dispositivo de terminal (o true si no se puede determinar). Si se establecen, estas variables se marcan para su exportación. make nunca modifica estas variables, ni las cambia si ya están establecidas.

Estos valores pueden usarse (en particular en combinación con la sincronización de la salida; véase Salida durante la ejecución paralela) para determinar si make está escribiendo él mismo en un terminal. Por ejemplo, puede comprobarlos para decidir si forzar la salida coloreada en las órdenes de una receta.

Si invoca un sub-make y redirige su salida estándar o su salida de error estándar, es responsabilidad suya reestablecer o desexportar también estas variables, en caso de que sus makefiles dependan de ellas.

.RECIPEPREFIX

El primer carácter del valor de esta variable se usa como el carácter que make considera que indica el comienzo de una línea de receta. Si la variable está vacía (como ocurre de forma predeterminada), ese carácter es el carácter de tabulación estándar. Por ejemplo, este es un makefile válido:

.RECIPEPREFIX = >
all:
> @echo Hello, world

El valor de .RECIPEPREFIX puede cambiarse cuantas veces se quiera. Una vez establecido, surte efecto para todas las reglas que se analicen a partir de entonces, hasta que se cambie.

.VARIABLES

Se expande a una lista con los nombres de todas las variables globales definidas hasta ese momento. Incluye las variables con un valor vacío y las variables incorporadas (véase Variables usadas por las reglas implícitas), pero no incluye las variables definidas únicamente en un contexto específico de objetivo. Tenga en cuenta que cualquier valor que asigne a esta variable se ignora; siempre devuelve este valor especial.

.FEATURES

Se expande a una lista de las características especiales admitidas por esta versión de make. Entre los valores posibles se incluyen (aunque no se limitan a) los siguientes:

archives

Admite archivos ar (de archivo) mediante una sintaxis especial de nombres de archivo. Véase Usar make para actualizar archivos de archivo (archive).

check-symlink

Admite el indicador -L (--check-symlink-times). Véase Resumen de opciones.

else-if

Admite condicionales «else if» no anidados. Véase Sintaxis de los condicionales.

extra-prereqs

Admite el objetivo especial .EXTRA_PREREQS.

grouped-target

Admite la sintaxis de objetivos agrupados en reglas explícitas. Véase Varios objetivos en una regla.

guile

GNU Guile está disponible como lenguaje de extensión incorporado. Véase Integración de GNU Guile.

jobserver

Admite la construcción en paralelo mejorada mediante un «jobserver». Véase Ejecución paralela.

jobserver-fifo

Admite la construcción en paralelo mejorada mediante un «jobserver» que usa tuberías con nombre. Véase Integrar GNU make.

load

Admite objetos cargables dinámicamente para crear extensiones personalizadas. Véase Carga de objetos dinámicos.

notintermediate

Admite el objetivo especial .NOTINTERMEDIATE. Véase Integrar GNU make.

oneshell

Admite el objetivo especial .ONESHELL. Véase Usar un solo shell.

order-only

Admite prerrequisitos de solo orden. Véase Tipos de prerrequisitos.

output-sync

Admite la opción de línea de órdenes --output-sync. Véase Resumen de opciones.

second-expansion

Admite la expansión secundaria de las listas de prerrequisitos.

shell-export

Admite la exportación de variables de make a la función shell.

shortest-stem

Usa el método de la «raíz más corta» para elegir qué patrón usar entre varias opciones aplicables. Véase Cómo se emparejan los patrones.

target-specific

Admite las asignaciones de variables específicas de objetivo y específicas de patrón. Véase Valores de variables específicos de objetivo.

undefine

Admite la directiva undefine. Véase Anular la definición de variables.

.INCLUDE_DIRS

Se expande a una lista de los directorios en los que make buscará los makefiles que se incluyen (véase Incluir otros makefiles). Tenga en cuenta que modificar el valor de esta variable no cambia la lista de directorios que se buscan.

.EXTRA_PREREQS

Cada palabra de esta variable es un nuevo prerrequisito que se añade al objetivo para el que está establecida. Estos prerrequisitos se diferencian de los prerrequisitos normales en que no aparecen en ninguna de las variables automáticas (véase Variables automáticas). Esto le permite definir prerrequisitos que no afectan a la receta.

Considere una regla para enlazar un programa:

myprog: myprog.o file1.o file2.o
       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)

Suponga ahora que quiere mejorar este makefile para que el programa se vuelva a enlazar si hay una actualización del compilador. Podría añadir el compilador como prerrequisito, pero debe asegurarse de que no se pase como argumento a la orden de enlazado. Necesitaría algo como esto:

myprog: myprog.o file1.o file2.o $(CC)
       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
           $(filter-out $(CC),$^) $(LDLIBS)

Considere ahora el caso en que hay varios prerrequisitos adicionales: tendría que excluirlos todos. Con .EXTRA_PREREQS y variables específicas de objetivo se obtiene una solución más sencilla:

myprog: myprog.o file1.o file2.o
       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
myprog: .EXTRA_PREREQS = $(CC)

Esta característica también resulta útil cuando quiere añadir prerrequisitos a un makefile que no es fácil de modificar. Cree un archivo nuevo, como extra.mk:

myprog: .EXTRA_PREREQS = $(CC)

y luego invoque make -f extra.mk -f Makefile.

Establecer .EXTRA_PREREQS de forma global añade esos prerrequisitos a todos los objetivos (que no lo hayan sobrescrito ellos mismos con un valor específico de objetivo). Tenga en cuenta que make es lo bastante inteligente para no añadir un prerrequisito listado en .EXTRA_PREREQS como prerrequisito de sí mismo.


Anterior | Siguiente | Índice | Original en inglés (gnu.org)