El funcionamiento de Make se basa en un archivo llamado Makefile (si deseamos usar otro nombre tendremos que invocar a make después con "make -f nombre_makefile") en el que se disponen las reglas de dependencia entre los archivos y los objetivos(targets) del proyecto.
Supongamos que tenemos un proyecto en C que se compone de un archivo main.c en el que tenemos la función principal del programa, y luego tenemos un archivo funciones.c en el que tenemos las funciones que se llaman desde main. Supongamos también que queremos q nuestro programa se llame prueba (si estuvieramos en windows deberia ser prueba.exe, pero en UNIX no es necesario la extensión).
El formato del archivo es:
objetivo: dependencia1 dependencia2 .... dependenciaN
órdenes a ejecutar para la generación de "objetivo"
Para nuestro caso, el objetivo es prueba y sus dependencias son main.c y funciones.c, por lo tanto crearemos un archivo Makefile que contenga:
prueba: main.o funciones.o
gcc main.o funciones.o -o prueba
Lo guardamos y ejecutamos make. Como resultado, se creará el archivo prueba y además veremos que se ha llamado al compilador de c para generar main.o y funciones.o a partir de sus homólogos .c. Esto es debido a que el programa Make tiene cierta inteligencia y ya sabe como generar código objeto a partir de código fuente en C (también es capaz de hacer cosas parecidas para otros lenguajes). Podemos indicar nosotros todos los pasos a costa de que el Makefile sea mas complicado, pero eso si mas claro. El Makefile con todos los pasos sería:
prueba: main.o funciones.o
gcc main.o funciones.o -o prueba
main.o: main.c
gcc -c main.c
funciones.o: funciones.c
gcc -c funciones.c
En los makefiles podemos usar variables, por ejemplo para almacenar todas las dependencias, se suelen poner en mayúsculas para distinguirlas bien:
OBJS:= main.o funciones.o
prueba: $(OBJS)
gcc $(OBJS) -o prueba
El funcionamiento es el siguiente:
Make comprueba la lista de dependencias para prueba, comprueba si estas dependencias tienen a su vez dependencias (por ejemplo cuando hemos creado el Makefile poniendo que prueba dependía de main.o y funciones.o y estos a su vez dependían de main.c y funciones.c). Si alguna de las dependencias se incumple (entendiendo incumplir como que los archivos de los que depende un objetivo no existen, o su fecha de modificación es posterior a la del objetivo) se ejecutan las órdenes para dicho target.
Para ilustrarlo con nuestro ejemplo, supongamos que tenemos nuestros archivos fuente y nuestro Makefile, y que aún no hemos generado el ejecutable prueba, entonces, al ejecutar make, en primer lugar se determina si las dependencias de prueba existen y están actualizadas (comprueba que main.o y funciones.o existen y su fecha de modificación es anterior o igual que la de prueba) , en este caso los archivos no existen. A continuación se comprueban las dependencias de main.o (que es main.c) como main.o no existe, se ejecutan las ordenes para crearlo, esto es gcc -c main.c y se obtiene main.o, y lo mismo con funciones.o. Una vez cumplidas las dependencias de "2º nivel" se vuelve sobre las de "1er nivel" y dado que prueba no existe, se ejcuta la orden para crearlo a partir de main.o y funciones.o.
Imaginemos ahora que modificamos funciones.c porque había un error en el funcionamiento de una de las funciones. Naturalmente, queremos actualizar el ejecutable prueba para que incluya el cambio, pues bien aqui viene la potencia de los makefiles.
ejecutamos make y lo que ocurre es lo siguiente:
- Se intentan comprobar las dependencias de 1er nivel(prueba), pero como hay dependencias de 2º nivel se comprueban en primer lugar éstas últimas.
- Se comprueba las dependencias de 2º nivel y se determina que funciones.o es anterior a funciones.c, por lo que es necesario actualizar.
- Se ejecuta la orden para la dependencia de funciones.o
- Si no hay mas dependencias de 2º nivel, se pasa a las de 1er nivel.
- Se determina que prueba es anterior a una de sus dependencias (funcinoes.o) por lo que es necesario actualizar.
- Se ejecuta la orden para las dependencias de prueba, generándose de nuevo el ejecutable.
Continuaremos con cuestiones mas avanzadas sobre los makefiles en próximas entradas.
No hay comentarios:
Publicar un comentario