UTILIDAD MAKE Introducción La utilidad make determina automáticamente qué partes de un programa necesitan ser recompiladas y manda ejecutar los comandos apropiados para recompilarlas. Aunque nosotros vamos a utilizar make para compilar únicamente programas escritos en C, esta utilidad serviría para compilar programas escritos en cualquier lenguaje cuyo compilador pueda ejecutarse desde el intérprete de comandos. Incluso puede utilizarse para otras cosas que no sean programas: cualquier tarea en la que determinados ficheros tienen que ser actualizados de manera automática desde otros cuando en alguno de estos últimos se ha producido algún cambio. Para usar el comando make, es necesario escribir un fichero denominado Makefile, que describe las relaciones existentes entre los ficheros que componen el programa y proporciona comandos para actualizar cada fichero. En general, un programa ejecutable es actualizado desde ficheros objeto, los cuales se crean a su vez tras compilar los ficheros fuente. Una vez que se dispone de un fichero Makefile, cada vez que se produce un cambio en alguno de los programas fuente, lo único que hace falta hacer es ejecutar: $ make <INTRO> El programa make utiliza la información contenida en el fichero Makefile y la hora y fecha de última modificación de los ficheros para decidir qué ficheros necesitan ser recompilados. Para todos estos ficheros lanzará la ejecución de los comandos que así están establecidos en el fichero Makefile. Makefile Un fichero Makefile se compone de un conjunto de dependencias y reglas. Una dependencia tiene un fichero objetivo (target), que es el fichero a crear, y un conjunto de ficheros fuente de los cuales depende el fichero objetivo. Una regla describe cómo crear el fichero objetivo a partir de los ficheros de los que éste depende. Imaginemos un programa cuyos ficheros fuente son uno.c, dos.c y main.c, además de los ficheros cabecera a.h, b.h y c.h, con las siguientes dependencias entre ellos: /* main.c */ #include ``a.h'' ... /* uno.c */ #include ``a.h'' #include ``b.h'' ... /* dos.c */ #include ``b.h'' #include ``c.h'' ... donde, por ejemplo, el fichero dos.c depende de los ficheros cabecera b.h, y c.h. La lista de dependencias para nuestro programa sería la siguiente: 1 ejecutable: main.o uno.o dos.o main.o: main.c a.h uno.o: uno.c a.h b.h dos.o: dos.c b.h c.h donde ejecutable es el nombre del fichero ejecutable de nuestro programa. Si lo que deseamos es crear más de un fichero ejecutable, podemos añadir: all: ejecutable ejecutable1 y las dependencias del objetivo ejecutable1. La llamada make all analizará las dependencias de ambos ficheros (ejecutable y ejecutable1), compilando las partes necesarias para obtener una versión actualizada de cada uno de ellos. Si realizamos la llamada a make sin ningún parámetro, el comando realizará las actualizaciones necesarias para generar el primer ``objetivo'' (target) que se encuentre en el fichero Makefile. El otro punto importante del Makefile son las reglas que indican las acciones a llevar a cabo en cada una de las dependencias especificadas. Las reglas para el ejemplo anterior podrían ser las siguientes: ejecutable: main.o uno.o dos.o gcc -o ejecutable main.o uno.o dos.o main.o: main.c a.h gcc -c main.c uno.o: uno.c a.h b.h gcc -c uno.c dos.o: dos.c b.h c.h gcc -c dos.c Por último, para simplificar y flexibilizar el fichero Makefile es muy común el uso de macros. Las macros no son más que asociaciones nombre-valor: NOMBREMACRO=valor de forma que podemos acceder al valor de la macro utilizando la expresión $(NOMBREMACRO). En el ejemplo, podríamos utilizar una macro para especificar el compilador de C utilizado, lo que permitiría cambiarlo sin más que cambiar el valor de la macro. El Makefile sería el siguiente: CC = gcc ejecutable: main.o uno.o dos.o $(CC) -o ejecutable main.o uno.o dos.o main.o: main.c a.h $(CC) -c main.c uno.o: uno.c a.h b.h $(CC) -c uno.c dos.o: dos.c b.h c.h $(CC) -c dos.c Más información Para obtener más información sobre el uso de make, consultar la ayuda en línea man make. 2