si desea ejecutar o actualizar una tarea cuando se actualizan ciertos archivos, la utilidad make
puede ser útil. El make
utilidad requiere un archivo, Makefile
(o makefile
), que define el conjunto de tareas a ser ejecutadas. Puede haber utilizado make
para compilar un programa a partir del código fuente. La mayoría de los proyectos de código abierto usan make
para compilar un binario ejecutable final, que luego se puede instalar usando make install
.,
en este artículo, exploraremos make
y Makefile
usando ejemplos básicos y avanzados. Antes de comenzar, asegúrese de que make
esté instalado en su sistema.
ejemplos básicos
comencemos imprimiendo el clásico «Hello World» en la terminal. Crear un directorio vacío myproject
que contiene un archivo Makefile
con este contenido:
say_hello:
echo "Hello World"
Ahora, ejecute el archivo escribiendo make
dentro del directorio myproject
., La salida será:
$ make
echo "Hello World"
Hello World
En el ejemplo anterior, say_hello
se comporta como un nombre de función, como en cualquier lenguaje de programación. Esto se llama el objetivo. Los prerrequisitos o dependencias siguen al destino. En aras de la simplicidad, no hemos definido ningún prerrequisito en este ejemplo. El comando echo "Hello World"
se llama la receta. La receta utiliza requisitos previos para hacer un objetivo. El objetivo, los requisitos previos y las recetas juntos forman una regla.,
para resumir, a continuación se muestra la sintaxis de una regla típica:
target: prerequisites
<TAB> recipe
como ejemplo, un destino puede ser un archivo binario que depende de los requisitos previos (archivos de origen). Por otro lado, un prerrequisito también puede ser un destino que depende de otras dependencias:
no es necesario que el destino sea un archivo; podría ser solo un nombre para la receta, como en nuestro ejemplo. A estos los llamamos «objetivos falsos».,»
volviendo al ejemplo anterior, cuando se ejecutó make
, se mostró todo el comando echo "Hello World"
, seguido de la salida real del comando. A menudo no queremos eso. Para suprimir el eco de la orden real, tenemos que empezar a echo
@
:
say_hello:
@echo "Hello World"
Ahora, intente ejecutar make
nuevo., La salida debe mostrar sólo esto:
$ make
Hello World
Vamos a agregar un par más falso objetivos: generate
y clean
para el Makefile
:
Si tratamos de ejecutar make
después de los cambios, sólo el destino say_hello
será ejecutado. Esto se debe a que solo el primer destino en el makefile es el destino predeterminado. A menudo llamado el objetivo predeterminado, esta es la razón por la que verá all
como el primer objetivo en la mayoría de los proyectos., Es responsabilidad de all
llamar a otros destinos. Podemos anular este comportamiento usando un objetivo falso especial llamado .DEFAULT_GOAL
.
vamos a incluir que al principio de nuestro makefile:
.DEFAULT_GOAL := generate
esto ejecutará el objetivo generate
como el valor predeterminado:
$ make
Creating empty text files...
touch file-{1..10}.txt
como su nombre indica, el objetivo falso .DEFAULT_GOAL
solo puede ejecutar un objetivo a la vez. Esta es la razón por la que la mayoría de los makefiles incluyen all
como un destino que puede llamar a tantos destinos como sea necesario.,
vamos a incluir el objetivo falso all
y eliminar .DEFAULT_GOAL
:
antes de ejecutar make
, vamos a incluir otro objetivo falso especial, .PHONY
, donde definimos todos los destinos que no son Archivos. make
ejecutará su receta independientemente de si existe un archivo con ese nombre o cuál es su última hora de modificación., Aquí está la completa makefile:
El make
debe llamar say_hello
y generate
:
$ make
Hello World
Creating empty text files...
touch file-{1..10}.txt
es una buena práctica para no llamar clean
en el all
o ponerlo como el primer objetivo., clean
se debe llamar manualmente cuando se necesita limpieza como primer argumento para make
:
$ make clean
Cleaning up...
rm *.txt
ahora que tiene una idea de cómo funciona un makefile básico y cómo escribir un makefile simple, veamos algunos ejemplos más avanzados.
ejemplos avanzados
Variables
en el ejemplo anterior, la mayoría de los valores de destino y prerrequisitos están codificados, pero en proyectos reales, estos se reemplazan con variables y patrones.,
la forma más sencilla de definir una variable en un makefile es usar el operador =
., Por ejemplo, para asignar el comando gcc
variable CC
:
CC = gcc
Este es también llamada recursiva ampliado de la variable, y se utiliza en una regla, como se muestra a continuación:
hello: hello.c
${CC} hello.c -o hello
Como usted puede haber adivinado, la receta se expande como a continuación cuando se pasa a la terminal:
gcc hello.c -o hello
Ambos ${CC}
y $(CC)
son referencias válidas para llamar a gcc
. Pero si uno intenta reasignar una variable a sí mismo, causará un bucle infinito., Vamos a verificar esto:
CC = gcc
CC = ${CC}
all:
@echo ${CC}
Ejecutar make
dará como resultado:
$ make
Makefile:8: *** Recursive variable 'CC' references itself (eventually). Stop.
para evitar este escenario, podemos usar el operador :=
esto también se llama la variable simplemente expandida). No deberíamos tener ningún problema ejecutando el makefile de abajo:
CC := gcc
CC := ${CC}
all:
@echo ${CC}
patrones y funciones
el makefile siguiente puede compilar todos los programas de C usando variables, patrones y funciones., Vamos a explorarlo línea por línea:
a continuación se muestra la reescritura del makefile anterior, suponiendo que se coloca en el directorio que tiene un solo archivo foo.c: