Ficheros Make

Anuncio
Ficheros Make
FICHEROS MAKE
A todos nos llega la hora de tratar con los dichosos archivos Makefile. Aun si no vamos a programar
es esencial conocer un poco el funcionamiento de estos archivos usados por el compilador make.
Normalmente no tendremos muchos problemas con ellos, pero cuando surgen debemos saber mas o
menos a que es debido el error. En este manual intentaré explicar las bases de este tipo de archivos.
Consideraciones previas
Con make creamos un fichero de forma escalonada. Si tenemos varios archivos y uno solo cambia
podemos recompilar solo el archivo que ha cambiado sin necesidad de recompilar todo el código.
Debemos saber como actúa gcc, del que depende make, entre otros. Teniendo un archivo fuente llamado
"ZX80.c" debemos obtener el ejecutable "ZX80" mediante un archivo objeto que se creará al compilar
llamado "ZX80.o". La sintaxis es la siguiente:
gcc -o ZX80 ZX80.c
El compilador creará el archivo objeto "ZX80.o" que luego transformará en ZX80, el deseado
ejecutable.En caso de que hayan más de un archivo fuente se deberian compilar todos de la siguiente
manera:
gcc -c ZX80-1.c
gcc -c ZX80-2.c
gcc -c ZX80-3.c
gcc -o ZX80 ZX80-1.o ZX80-2.o ZX80-3.o
Lo que nos dará el archivo ejecutable "ZX80". Imaginaos si en vez de 3 archivos fuente hubieran 200 y
en varios directorios..... La faena sería demasiado engorrosa, ¿no creeis?.
Cómo funciona MAKE
Make trabaja con resultados y requisitos.Vamos a ver un ejemplo de un fichero Makefile muy sencillo:
edimh: main.o edit.o
gcc -o edimh main.o edit.o
main.o: main.c
gcc -c main.c
edit.o: edit.c
gcc -c edit.c
Este fichero define la construcción de un programa llamado "edimh" a partir de 2 archivos fuentes
llamados "edit.c" y "main.c". El orden de las entradas es lo de menos ya que no va por orden de escritura,
si no por orden de dependencias aunque es bueno poner en la primera línea la construcción del ejecutable
para que se establezca el nombre del ejecutable. Make ya sabe lo que tiene que hacer.
file:///E|/Archivos de programa/explore2fs/make.html (1 de 6) [18/04/2003 23:23:24]
Ficheros Make
Hay tres entradas en el make. Cada una tiene una Linea de dependencias que muestra como construir el
archivo. Así la primera linea dice que "edimh" (el resultado antes de los dos puntos) se construye a partir
de "main.o" y "edit.o" (los requisitos, detras de los dos puntos y que se ejecuta primero). Obtenemos los
objeto a partir de fuentes y el ejecutable a partir de los objeto.
NOTA: La linea que contiene comandos ha de empezar con tabulador, no con espacios.
El comando "make edimh" ejecuta la linea gcc correspondiente si no hay ningún fichero llamado
"edimh", aunque tambien lo hace si "edimh" cambia alguno de sus archivos objeto. ¿Y como sabe make
que un fichero ha cambiado?. Simplemente comparando la fecha y hoa de modificación de ambos
ficheros. Probemos lo siguiente:
ZX80# make edimh
gcc -c main.c
gcc -c edit.c
gcc -o edimh edit.o main.o
Ahora modificamos main.c y volvemos a lanzar make:
ZX80# make edimh
gcc -c main.c
gcc -o edimh edit.o main.o
UFFFF !!!!! Un descanso por favor....Ahora se muestra un script algo más elaborado. Haber si sabes que
hace:
install: all
mv edimh /usr/local
mv readimh /usr/local
all: edimh readimh
readimh: read.o edit.o
gcc -o readimh main.o read.o
edimh: main.o edit.o
gcc -o edimh main.o edit.o
main.o: main.c
gcc -c main.c
edit.o: edit.c
gcc -c edit.c
read.o: read.c
gcc -c read.c
En primer lugar se define como resultado install con all como requisito (se le denomina resultado falso o
phony target) que permite que se ejecuten todos los comandos relacionados. De esta manera make presta
atención al resultado "all" que carece de comandos pero que depende de "edimh" y "readimh", por lo que
se sigue retrocediendo para buscar dependencias hasta llegar a los .c que no dependen de nada.
La ejecución de dicho programa daria la siguiente salida:
Ficheros Make
ZX80# make install
gcc -c main.c
gcc -c edit.c
gcc -o edimh edit.o main.o
gcc -c read.c
gcc -o readimh main.o read.o
mv edimh /usr/local
mv readimh /usr/local
Se crean los objeto, luego se consiguen los ejecutables y con ambos ejecutables creados se satisfacen las
condiciones de "all" por lo que se procede a "install" que cambia de lugar los ejecutables. ¿SENCILLO
NO?
Algunas reglas de escritura
Make en este aspecto es bastante "tonto". Si usamos espacios en vez de tabuladores se nos quejará y los
mensajes de error suelen ser bastante confusos.
● Los comandos van SIEMPRE precedidos de Tabuladores. No pongas nunca un tabulador en otro sitio
que no sea un comando.
● Los comentarios se escriben detras de una almohadilla (#). Todo lo que le siga se ignora.
● Si queremos extender una linea larga en dos porque sea muy larga se pondrá una barra invertida (\)
● Si se quiere evitar el eco de un comando pondremos una arroba (@) delante de la llamada: @if [-x
/bin/user]; then
● Con un guión (-) delante de un comando forzamos a que se continúe con el proceso aunque falle el
comando.
Macros
Se usan para utilizar repetidamente una expresión y no tener que escribirla cada dos por tres, es decir, se
expande en el valor que tiene. Se escriben de la siguiente manera: $(expresion). Vamos a poner un
ejemplo:
OBJECTS = main.o edit.o
PATHS = /usr/local/bin
edimh: $(OBJECTS)
gcc -o edimh &(OBJECTS)
mv edimh $(PATH)/nuevo
Este programa hará que se efectue el ejecutable edimh con los objetos que marca OBJECTS que son
"main.o" y "edit.o". Luego copiará el ejecutable a la ruta que le marca PATH que es /usr/local/bin con el
Ficheros Make
añadido /nuevo que se especificadetras de $(PATH). Las mayúsculas no son imprscindibles, pero ayudan
a diferenciar a simple vista las macros.
Una extensión del GNU Make es la de añadiruna expresión a la que ya tiene la macro. Se hace con el
operador :=
DRIVERS = drivers/block/block.a
ifdef CONFIG_SCSI
DRIVERS := $(DRIVERS) drivers/scsi/scsi.a
endif
La expresión DRIVERS equivale a drivers/block/block.a pero si se define la macro CONFIG_SCSI la
expresión equivaldrá a drivers/scsi/scsi.a por lo que la macro valdrá entoces drivers/block/block.a
drivers/scsi/scsi.a.
¿Y como definimos CONFIG_SCSI?. Pues sencillamente añadiendo una linea del tipo: CONFIG_SCSI =
yes. Tambien se puede definir externamente, en la propia llamada: # make CONFIG_SCSI=yes install.
Sufijos y precedencias
Linux funciona de una manera simple con las dependencias ya expuesta: Hacer los objetos de los fuente
y los ejecutables de los objetos. Para aprovechar esto se echa mano de la "regla de sufijos":
.c.o:
gcc -c $(CFLAGS) $<
La linea .c.o le dice a make que use los .c como requisitos para los .o. La macro CFLAGS es de propósito
general y sirve para escribir cualquier opción de compilación que queramos, por ejemplo -g para depurar.
La expresión $< significa "el requisito", por lo tanto sustituye al nombre de listado C. Para usarlo se
escribe:
ZX80# make CFLAGS="-g" edit.o
gcc -c -g edit.c
No hay por qué asignar CFLAGS en el make, ya que se puede especificar dentro del script mediante:
CFLAGS = -g.
Hay una opción que merece la pena citar. Se trata de la opción -D, que define algunos simbolos en el
listado fuente. Se emplean en C muchos símbolos (-DDEBUG, -DBSD, -DKERNEL...)marcados por la
directiva "ifdefs" por lo que necesitamos alguna manera de pasárselos al make. Se puede hacer mediante
la linea de comandos: make CFLAGS="-DDEBUG _DKERNEL..."; o tambien se pueden añadir en el
script mediante las "Reglas de patrones", que son más potentes que las reglas de sufijos. Se usa el signo
de porcentaje (%) para definirlas en vez del nombre completo:
%.o: &.c
gcc -c -o $@ $(CFLAGS) $<
En este caso el fichero de salida %.o aparece en primer lugar y su requisito %.c el último y tras dos
Ficheros Make
puntos. La expresión $< se refiere a los requisitos mientras que $@ a la salida (resultado), de manera que
representa al nombre del archivo objeto que queremos conseguir (por el que pusimos un % antes). Estas
dos expresiones son macros prestablecidas y se actualizan cada vez que se ejecuta una entrada.
Otra macro preestablecida es $* que representa el nombre de los requisitos pero sin su extensión (tipo
comodin de consola). Por ejemplo, si el requisito es edit.c la expresión $*.s valdría edit.s, que sería un
archivo fuente en ensamblador.
Bueeeeeeeeno.... Vamos a darle una vuelta de turca más.
Veamos algo que se puede hacer con estas reglas pero no con la regla de sufijos: Añadir una expresión al
nombre del resultado. Añadiremos _gdb que indica que el objeto tiene información de depuración:
%_gdb.o: %.c
gcc -c -g -o $@ $(CFLAGS) $<
DEBUG_OBJECTS = main_dbg.o edit_dbg.o
edimh_dbg: $(DEBUG_OBJECTS)
gcc -o $@ $(DEBUG_OBJECTS)
Ahora se puede construir los objetos con o sin depuración. Al tener nombres distintos no se reescribirán:
ZX80# make edimh_dbg
gcc -c -g -o main_dbg.o main.c
gcc -c -g -o edit_dbg.o edit.c
gcc -o edimh_dbg main_dbg.o edit_dbg.o
Comandos múltiples
Podemos ejecutar cualquier comando de intérprete dsde el fichero make, aunque la ejecución es algo
más complicada porque cada comando se lanza bajo un intérprete distinto. La siguiente sintaxis no haría
lo que se espera:
target: cd obj
HOST_DIR=/home/zx80
mv *.o $HOST_DIR
Ni "cd" ni "HOST_DIR" tienen el menor efecto en los comandos. Para que lo tengan se deben escribir en
la misma linea separados por punto y coma (;):
target:
cd obj ; HOST_DIR=/home/zx80 ; mv *.o $HOST_DIR
Una anotación: Para usar las variables de entorno dentro de los comandos hay que ponerles doble signo
de dólar ($$). Esto informa a make de que se trta de una variable de entorno y no de una macro:
target:
cd obj ; HOST_DIR=/home/zx80 ; mv *.o $$HOST_DIR
A veces los propios ficheros hacen una llamada a make, lo que da lugar a un "make recursivo", estas
Ficheros Make
llamdas son algo así:
linuxsubdirs: dummy
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
La macro $(MAKE) hace una llamada a make. Una posible aplicación de esta técnica es la construcción
en varios directorios, cada uno de los cuales debería tener su propio fichero make. Además se permite
lanzar un intérprete de comandos y asignar la salida a una macro. Por ejemplo con HOST_NAME =
$(shell uname -n). Con esto se consigue asignar el nombre del nodo de red a la macro HOST_NAME.
Inclusión de otros ficheros make
Un proyecto de cierta envergadura crea varios ficheros make, lo que permite compartir ciertos recursos,
sobre todo definiciones de macros. Para incluir un fichero dentro de otro usamos: include nombrefichero.
A veces estas inclusiones pueden hacer referencia a macros:
include $(INC_FILE)
Autoconf y Automake
Escribir un fichero de configuración de complilación es una tarea demasiado pesada por lo que se
dispone de las herramientas Automake y Autoconf. Son muy difíciles de explicar en este mini-manual,
pero si os interesa el tema podeis visitar: ftp://ftp.gnu.org/gnu
Descargar