Búsqueda de sitios web

Una breve introducción a los 'Makefiles' en el desarrollo de software de código abierto con GNU Make


GNU Make es una utilidad de desarrollo que determina las partes de una base de código particular que se deben recompilar y puede emitir comandos para realizar esas operaciones en la base de código. Esta utilidad make en particular se puede utilizar con cualquier lenguaje de programación siempre que su compilación se pueda realizar desde el shell mediante la emisión de comandos.

Para utilizar GNU Make, necesitamos tener un conjunto de reglas que definan la relación entre los diferentes archivos en nuestro programa y comandos para actualizar cada archivo. Estos se escriben en un archivo especial llamado "makefile". El comando 'make' utiliza la base de datos 'makefile' y los últimos tiempos de modificación de los archivos para decidir que todos los archivos deben volver a compilarse.

Contenido de un Makefile

Generalmente, los 'makefiles' contienen 5 tipos de cosas, a saber: reglas implícitas, reglas explícitas, definiciones de variables. , directivas y comentarios.

  1. Una regla explícita especifica cómo crear/rehacer uno o más archivos (llamados destinos, se explicarán más adelante) y cuándo hacer lo mismo.
  2. Una regla implícita especifica cómo crear/rehacer uno o más archivos en función de sus nombres. Describe cómo se relaciona un nombre de archivo de destino con un archivo con un nombre similar al de destino.
  3. Una definición de variable es una línea que especifica un valor de cadena para una variable que se sustituirá más adelante.
  4. Una directiva es una instrucción para que make haga algo especial mientras lee el archivo MAKE.
  5. Se utiliza un símbolo '#' que representa el inicio de un comentario dentro de makefiles . Una línea que comienza con "#" simplemente se ignora.

Estructura de archivos Make

La información que le dice a make cómo recompilar un sistema proviene de la lectura de una base de datos llamada makefile. Un makefile simple constará de reglas con la siguiente sintaxis:

target ... : prerequisites ... 
	recipe 
... 
...

Un destino se define como el archivo de salida generado por el programa. También pueden ser objetivos falsos, como se explicará a continuación. Ejemplos de archivos de destino incluyen ejecutables, archivos objeto u objetivos falsos como clean, instalar, desinstalar, etc.

Un requisito previo es un archivo que se utiliza como entrada para crear los archivos de destino.

Una receta es la acción que make realiza para crear el archivo de destino según los requisitos previos. Es necesario poner un carácter de tabulación antes de cada receta dentro de los makefiles a menos que especifiquemos la variable '.RECIPEPREFIX' para definir algún otro carácter como prefijo. a la receta.

Un archivo Makefile de muestra

final: main.o end.o inter.o start.o
	gcc -o final main.o end.o inter.o start.o
main.o: main.c global.h
	gcc -c main.c
end.o: end.c local.h global.h
	gcc -c end.c
inter.o: inter.c global.h
	gcc -c inter.c
start.o: start.c global.h
	gcc -c start.c
clean:
	rm -f main.o end.o inter.o start.o

En el ejemplo anterior utilizamos archivos fuente 4 C y dos archivos de encabezado para crear el ejecutable final. Aquí, cada archivo '.o' es a la vez un destino y un requisito previo dentro del makefile. Ahora eche un vistazo al último nombre del objetivo clean. Es solo una acción en lugar de un archivo de destino.

Como normalmente no necesitamos esto durante la compilación, no está escrito como un requisito previo en ninguna otra regla. Los objetivos que no hacen referencia a archivos sino que son simplemente acciones se denominan objetivos falsos. No tendrán ningún requisito previo como otros archivos de destino.

Cómo GNU Make procesa un Makefile

De forma predeterminada, make comienza con el primer objetivo en el 'makefile' y se denomina ' objetivo predeterminado'. Considerando nuestro ejemplo, tenemos final como nuestro primer objetivo. Dado que sus requisitos previos incluyen otros archivos objeto, estos deben actualizarse antes de crear final. Cada uno de estos requisitos previos se procesa según sus propias reglas.

La recompilación se produce si se realizan modificaciones en los archivos fuente o los archivos de encabezado o si el archivo objeto no existe en absoluto. Después de volver a compilar los archivos de objetos necesarios, make decide si vuelve a vincular final o no. Esto debe hacerse si el archivo final no existe, o si alguno de los archivos objeto es más nuevo que él.

Por lo tanto, si cambiamos el archivo inter.c, al ejecutar make se volverá a compilar el archivo fuente para actualizarlo. el archivo objeto inter.o y luego enlace final.

Usando variables dentro de Makefiles

En nuestro ejemplo, tuvimos que enumerar todos los archivos objeto dos veces en la regla para final como se muestra a continuación.

final: main.o end.o inter.o start.o
	gcc -o final main.o end.o inter.o start.o

Para evitar tales duplicaciones, podemos introducir variables para almacenar la lista de archivos objeto que se utilizan dentro del makefile. Al usar la variable OBJ podemos reescribir el makefile de muestra a uno similar que se muestra a continuación.

OBJ = main.o end.o inter.o start.o
final: $(OBJ)
	gcc -o final $(OBJ)
main.o: main.c global.h
	gcc -c main.c
end.o: end.c local.h global.h
	gcc -c end.c
inter.o: inter.c global.h
	gcc -c inter.c
start.o: start.c global.h
	gcc -c start.c
clean:
	rm -f $(OBJ)

Reglas para limpiar el directorio fuente.

Como vimos en el ejemplo makefile, podemos definir reglas para limpiar el directorio de origen eliminando los archivos objeto no deseados después de la compilación. Supongamos que tenemos un archivo de destino llamado limpio. ¿Cómo puede hacer diferenciar las dos situaciones anteriores? Aquí surge el concepto de objetivos falsos.

Un objetivo falso es aquel que no es realmente el nombre de un archivo, sino simplemente el nombre de una receta que se ejecutará cada vez que se realice una solicitud explícita desde el makefile . Una razón principal para utilizar objetivo falso es evitar un conflicto con un archivo del mismo nombre. Otra razón es mejorar el rendimiento.

Para explicar esto, revelaré un giro inesperado. La receta para clean no se ejecutará de forma predeterminada al ejecutar make. En su lugar, es necesario invocar lo mismo emitiendo el comando make clean.

.PHONY: clean
clean:
	rm -f $(OBJ)

Ahora intenta crear makefiles para tu propio código base. No dudes en comentar aquí tus dudas.