Oct 28 2009
Emacs TAGS, ETAGS, GNU/make, Automake y Autoconf
Préviamente hemos comentado en otros artículos algunas opciones de usar Emacs como IDE para muchos de los lenguajes de programación que conocemos, y así poder usar un mismo entorno para todos ellos sin necesidad de ir cambiando, con el consiguiente tiempo perdido que ello conlleva.
Comentamos en artículos anteriores el usar el c-mode, con los keystrokes habituales y más útiles. También comentamos el uso de CEDET como un conjunto de utilidades destinadas a este fin. Aquí comentaremos el uso de algunas técnicas específicas para hacer de emacs un entorno cómodo para el desarrollo en c, y algunas otras que son generales a todos o la mayoría de lenguajes.
Comentar que desde emacs tenemos funciones (algunas mapeadas y otras no) referentes a TAGS y ETAGS. La diferencia entre TAGS y ETAGS básicamente es que el formato de TAGS es un formato general que puede ser interpretado por distintas herramientas, mientras que ETAGS es específico de emacs. Comentar que existen más posibilidades desde emacs para trabajar con TAGS tales como Icicles, EtagsSelect, Vtags, etc.
El comando etags puede ser usado desde consola para crear el fichero de ETAGS para un directorio tan sólo ejecutando el comando:
etags *.c *.h
O bien para todo el árbol y subdirectorios del mismo y común para c y c++ mediante:
find . | egrep ‘\.(h|c|hpp|cpp)$’ | etags –
Antes de comenzar a explicar como usar ETAGS en emacs, debemos decir que es recomendable tener tres herramientas básicas instaladas (que por norma general vienen en cualquier distribución de GNU moderna: GNU/make, autoconf y automake. Realmente no es necesaria la instalación de autoconf ni automake, pero decir que es interesante, debido a que automake genera los ETAGS automáticamente, y autoconf es una dependencia de automake. Antes de continuar daré una noción básica de ejemplo para trabajar con Makefiles.
Aquí podemos ver un ejemplo de Makefile lo más simple posible para un sólo fichero .c:
main.o : main.c
gcc -c main.c
Aquí otro ejemplo esta vez con dos ficheros .c:
main : main.o foo.o
gcc main.o foo.o -o main
main.o : main.c
gcc -c main.c
foo.o : foo.c
gcc -c foo.c
Aquí otro ejemplo esta vez usando cabeceras propias .h:
all : main.o list.o stack.
gcc main.o list.o stack.o -o main
clean :
rm main.o list.o stack.o
list.o : list.c list.h
gcc -c list.c
stack.o : stack.c stack.h
gcc -c stack.c
main.o : main.c list.h list.c stack.h stack.c
gcc -c main.c
Éste último ejemplo se suele simplificar usando variables que se refieren a la lista de argumentos usados y al listado de objetos útil para cuando se tienen bastantes ficheros y parámetros para el compilador, tal que así:
.SUFFIXES: .o .c
.c.o:
$(CC) -c $(CFLAGS) $<
CC = @gcc
CFLAGS = -W -Wall -ansi -pedantic -Wbad-function-cast \
-Wcast-align -Wcast-qual -Wchar-subscripts -Winline \
-Wmissing-prototypes -Wnested-externs -Wpointer-arith \
-Wredundant-decls -Wshadow -Wstrict-prototypes -Wwrite-strings
SRC = main.c list.c list.h stack.c stack.h circular.c circular.h double.c double.h queue.c queue.h tree.c tree.h avl.c avl.h
OBJ = main.o list.o stack.o circular.o double.o queue.o tree.o avl.o
all: $(OBJ)
$(CC) $(CFLAGS) $(OBJ) -o main
clean:
$(RM) $(OBJ) main
list.o: list.c list.h
$(CC) $(CFLAGS) -c list.c
stack.o: stack.c stack.h
$(CC) $(CFLAGS) -c stack.c
circular.o: circular.c circular.h
$(CC) $(CFLAGS) -c circular.c
double.o: double.c double.h
$(CC) $(CFLAGS) -c double.c
queue.o: queue.c queue.h
$(CC) $(CFLAGS) -c queue.c
tree.o: tree.c tree.h
$(CC) $(CFLAGS) -c tree.c
avl.o: avl.c avl.h
$(CC) $(CFLAGS) -c avl.c
main.o: $(SRC)
$(CC) $(CFLAGS) -c main.c
Obviamente para éste último ejemplo deberemos tener el código organizado tal que así:
- En las cabeceras (.h) deberemos incluir todas las macros, definición de tipos y prototipos de funciones.
- En los fuentes que se refieran a parte de la librería creada (todos los .c excepto main.c) debemos incluir los includes correspondientes necesarios de la libc, así como el include específico donde se implementen las funciones a las que hacíamos referencia en los .h, es decir incluir list.h en list.c, stack.h en stack.c, etc. En dichos fuentes también debemos incluir la implementación de cada función declarada por su correspondiente .h (implementar los prototipos de funciones que veíamos en list.h, en list.c, declarar los prototipos de funciones que veíamos en stack.h, en stack.c, etc).
- En el fuente principal o que use dicha librería (compuesta por cabeceras o .h) debemos incluir cada .h (tanto de la libc que necesitemos entre <> como los de nuestra librería propia entre «» para cada .h). Acto seguido podremos usar aquí cualquier función declarada en nuestros .h e implementada en nuestros .c.
Sabiendo el ABC de Makefiles y como trabajar con múltiples ficheros .c y .h propios y/o ajenos a nuestro proyecto, ya podemos proceder a continuar con la herramienta GNU/Make, para interpretar makefiles y así poder construir el build mediante el comando make. La herramienta Automake, que además soporta ETAGS y por lo tanto nos permitirá crear dicho fichero de símbolos al realizar el make automático, y Autoconf, herramienta y dependencia necesaria para poder trabajar con Automake. Además de ello podemos utilizar un bootstrap para generar el Makefile.am y así tener todo el proceso automatizado desde el principio. Es decir que todo este entramado quedaría algo así (donde -> implica que genera, crea y/o procesa):
(./bootstrap) -genera-> ./configure
Makefile.am -genera-> Makefile.in (mediante automake)
Makefile.in -genera-> Makefile (mediante ./configure)
En el caso de querer crear un tarball para distribuir el paquete, se aconseja inlcuir el configure, para evitar obligar a instalar dependencias como automake y autoconf en los ordenadores donde se distribuya, sólo requerirá GNU/make.
El bootstrap (extraído del proyecto GNU PDF) debe tener un formato tal que así:
#!/bin/sh
# $Id: bootstrap,v 1.6 2007/11/08 02:19:09 jemarch Exp $
# Created 2003-08-29, Karl Berry. Public domain.
if test «x$1» = x-n; then
chicken=true
echo «Ok, playing chicken; not actually running any commands.»
else
chicken=
fi
echo «Bootstrapping the GNU PDF Library with:»
# This overwrites lots of files with older versions.
# I keep the newest versions of files common between distributions up to
# date in CVS (see util/srclist.txt), because it’s not trivial for every
# developer to do this.
#cmd=»autoreconf –verbose –force –install –include=m4″
: ${AUTORECONF=autoreconf}
: ${ACLOCAL=aclocal}
: ${LIBTOOLIZE=libtoolize}
: ${AUTOHEADER=autoheader}
: ${AUTOMAKE=automake}
: ${AUTOCONF=autoconf}
# So instead:
cmd=»$AUTORECONF -i»
echo » $cmd»
$chicken eval $cmd || exit 1
echo
echo «Now run configure with your desired options, for instance:»
echo » ./configure CFLAGS=-g»
echo
Modificándolo y adaptándolo a las necesidades de cada uno. En caso de no tener las herramientas GNU/make, automake y/o autoconf instaladas pueden descargarse e instalarse de la siguiente manera:
Para descargar la última versión de GNU/make (manual):
cvs -z3 -d:ext:anonymous@cvs.savannah.gnu.org:/sources/make co make
Para descargar la última versión de Autoconf (manual):
cvs -d :pserver:anonymous@pserver.git.sv.gnu.org:/autoconf.git co -d autoconf HEAD
Para descargar la última versión de Automake (manual):
cvs -d :pserver:anonymous@pserver.git.sv.gnu.org:/automake.git checkout -d automake HEAD
Los paquetes pueden ser actualizados mediante cvs update para obtener la última versión.
Como Automake soporta y crea los ETAGS automáticamente, podemos aprovecharnos de esto en nuestro entorno emacs. Tenemos las siguientes funciones referentes a ETAGS:
M-. : ‘find-tag‘; busca un símbolo dado.
M-* : ‘pop-tag-mark‘; devuelve el cursor al punto de comienzo de búsqueda de símbolos.
(sin keystroke asociada) : ‘tags-search‘; busca un símbolo.
(sin keystroke asociada) : ‘tags-query-replace‘; reemplaza un símbolo.
(sin keystroke asociada) : ‘tags-apropos‘; busca un símbolo o parte de él.
(sin keystroke asociada) : ‘list-tags‘; lista los símbolos de un fichero.
M-, ó M-0 M-. : ‘tags-loop-continue‘; se desplaza al siguiente símbolo buscado.
C-u – M-. ; se desplaza al anterior símbolo buscado.
C-u M-. ; se desplaza al siguiente símbolo buscado.
C-x 4 . : ‘find-tag-other-window’; busca un símbolo dado y crea una nueva ventana para ello.
C-u 5 . : ‘find-tag-other-frame’; busca un símbolo dado y crea un nuevo frame para ello.
M-/ ; autocompleta mediante dabbrev (teniendo en cuenta los ETAGS).
M-/ M-/ (o más repeticiones); autocomplea con la segunda, tercera, etc… opción.
Cuando nos referimos a un símbolo nos referimos al nombre de funciones, variables, constantes o macros.
Para más información sobre como mantener programas de un tamaño considerable, se puede leer en el manual de emacs «how to maintain large programs».