Probablemente muchos desarrolladores habituados a IDEs de hoy día (Eclipse, Visual Studio…) coincidirán conmigo en que la forma de desarrollar utilizando software libre es cuanto menos extraña. Todos conocemos la típica compilación de un paquete de código o tarball en cualquier sistema unix: “./configure & make & make install”. Estos tres comandos parecen mágicamente usables pero a la vez extremadamente complejos en su interior. Los archivos Makefile y configure que vemos en la mayoría de los tarballs de código son habitualmente, cuanto menos, infernales. La razón es que estos archivos no han sido escritos a mano (como antiguamente) sino mediante un proceso automatizado.
Muchos conoceréis autotools, son herramientas de desarrollo mas abstractas que make y configure, finalmente con ellas obtenemos nuestros amados ./configure y Makefile. ¿Pero cuantos habéis desarrollado algo utilizando autotools? Yo no lo había hecho nunca, pero esta tarde me he dispuesto a aprender y hacer algunas pruebas.
¿Para quién está dirigido autotools? Algunas consideraciones previas:
- No es aplicable para el desarrollo en windows si no tienes cygwin.
- Está especialmente para desarrollar en los lenguajes C y C++ aunque en principio es independiente del lenguaje, Mono (la implementación libre de .net) por ejemplo utiliza autotools.
- No apto para la gente que odie montones de archivos autogenerados (aclocal.m4, config.h.in, Makefilem config.status, autom4te.cache , config.sub, stamp-h1,config.guess…)
¿Que herramientas/lenguajes/procesos tienes que controlar para desarrollar minimamente con autotools?
Autotools está compuesta de dos herramientas principales: Automake y Autoconf.
Su misión es autogenerar los mastodónticos Makefile y configure mediante scripts mas abstractos: Makefile.am y configure.ac.
1- Saber construir ficheros “configure.ac” y entender su lenguaje de script. Para tareas básicas es muy fácil y puedes inspirarte en los configure.ac básicos que hay en las referencias.
2- Saber construir ficheros “Makefile.am” y entender su lenguaje de script.
Objetivo: Construir un programa con autotools a partir de un único fichero fuente main.c
1.1 Creando fichero Makefile.am:
Se trata de un script de alto nivel, sus responsabilidades son definir que archivos serán generados, su tipo (programa, librería estática, librería dinámica, librería temporal…), a par tir de que archivos fuentes serán generados y que dependencias tiene cada uno. También forma parte de sus responsabilidades definir donde se instalarán cada uno de los archivos generados#crearé un ejecutable que se localizará en la carpeta estandar bin llamado main
bin_PROGRAMS=main
# El código de main es en main.c
main_SOURCE=main.c1.2 Creando fichero configure.ac:
Se trata de un script de alto nivel, sus responsabilidades son principalmente definir que aplicaciones son necesarias en este proyecto de desarrollo(Compilador, parseadores, linkadores…) así como la comprobación de qué librerías y paquetes deben estar instalados en el sistema. También es responsabilidad de este script pedir al usuario todo tipo de parametrizaciones y metainformación para el proceso de construcción. Finalmente es el encargado de generar todos los Makefile.in a partir de todos los Makefile.am existentes en la estructura de directorios del proyecto.
#el programa lo llamaré miprograma y su versión será la 0.1
AC_INIT(miprograma,0.1)
#inicializa automake
AM_INIT_AUTOMAKE
#indicamos un requerimiento: programa compilador de C en esta maquina
AC_PROG_CC
#una vez chekeado lo anterior habrá que generar el fichero Makefile a partir de su Makefile.am a partir de su Makefile.in
AC_OUTPUT([Makefile])1.3 Creando la estructura estandar de directorio raíz de desarrollo
Autotools nos obliga a tener la estrucutra de directorio raíz de desarrollo estándar, esto implica tener que crear una serie de ficheros de información para el usuario (Authors, Readme…). Algunos de ellos pueden ser autogenerados cuando invocamos el comando automake añadiendo el argumento –add-missing, el resto debemos crearlos manualmente.
geus@geuset:~/tutorial$ touch NEWS README AUTHORS ChangeLog
geus@geuset:~/tutorial$ ls
AUTHORS ChangeLog configure.ac main.c Makefile.am NEWS README
geus@geuset:~/tutorial$ aclocal
geus@geuset:~/tutorial$ autoconf
geus@geuset:~/tutorial$ automake –add-missing
configure.ac:2: installing `./install-sh’
configure.ac:2: installing `./missing’
Makefile.am: installing `./INSTALL’
Makefile.am: installing `./COPYING’
Makefile.am: installing `./depcomp’
geus@geuset:~/tutorial$ ls
aclocal.m4 ChangeLog configure.ac INSTALL Makefile missing
AUTHORS config.status COPYING install-sh Makefile.am NEWS
autom4te.cache configure depcomp main.c Makefile.in README
Observad que los tres comandos utilizados son típicamente agrupados en un ./autogen.sh. Por otra parte es interesante ver como se ha creado el archivo Makefile.in que será la fuente para la generación del archivo Makefile cuando ejecutemos la configuración del proyecto. Es interesante tener siempre presente quien generó cada archivo ya que un cambio en el origen requerirá una nueva generación del mismo. También encontramos varios archivos temporales que de momento no deberían importarnos.
1.4 Configuración y compilación
Ahora podemos aplicar nuestro clásico ./configure con todas sus opciones estándar.geus@geuset:~/tutorial$ ./configure –prefix=’/opt/prueba’
checking for a BSD-compatible install… /usr/bin/install -c
checking whether build environment is sane… yes
checking for a thread-safe mkdir -p… /bin/mkdir -p
checking for gawk… no
checking for mawk… mawk
checking whether make sets $(MAKE)… yes
checking for gcc… gcc
checking for C compiler default output file name… a.out
checking whether the C compiler works… yes
checking whether we are cross compiling… no
checking for suffix of executables…
checking for suffix of object files… o
checking whether we are using the GNU C compiler… yes
checking whether gcc accepts -g… yes
checking for gcc option to accept ISO C89… none needed
checking for style of include used by make… GNU
checking dependency style of gcc… gcc3
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commandsEn este punto tenemos un archivo Makefile construido que podemos utilizar las reglas típicas: all, clean, install, uninstall… En este caso continuaremos el proceso de construcción estandar.
geus@geuset:~/tutorial$ make
gcc -DPACKAGE_NAME=\”miprograma\” -DPACKAGE_TARNAME=\”miprograma\” -DPACKAGE_VERSION=\”0.1\” -DPACKAGE_STRING=\”miprograma\ 0.1\” -DPACKAGE_BUGREPORT=\”\” -DPACKAGE=\”miprograma\” -DVERSION=\”0.1\” -I. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
gcc -g -O2 -o main main.o1.5 Instalación y prueba
geus@geuset:/Datos/Archivos/Proyectos/tutorial$ sudo make install
make[1]: Entering directory `/media/Datos/Archivos/Proyectos/tutorial’
test -z “/opt/prueba/bin” || /bin/mkdir -p “/opt/prueba/bin”
/usr/bin/install -c ‘main’ ‘/opt/prueba/bin/main’
make[1]: Nothing to be done for `install-data-am’.
make[1]: Leaving directory `/media/Datos/Archivos/Proyectos/tutorial’geus@geuset:~/tutorial$ cd /opt/prueba
geus@geuset:/opt/prueba$ ls
bin
geus@geuset:/opt/prueba$ ./bin/main
Hello world
geus@geuset:/opt/prueba$
Resumen
1. Crear archivo configure.ac
2. Crear archivo Makefile.ac
3. Crear archivos de estructura estandar de directorio de desarrollo
4. Ejecutar comandos (aclocal,autoconf,automake)
5. Ejecutar build clásico: ./configure & make & make install
Proximos posts:
- Aplicar el proceso de construcción a todo un proyecto con una estructura recursiva de subdirectorios. Crear librerías estáticas y dinámicas redistribuibles.
- Comprobar paquetes instalados en el sistema durante el proceso de configuración y linkarlos en el proceso de construcción.
Referencias
Estas referencias son interesantes para comenzar desde cero.
http://www.openismus.com/documents/linux/automake/automake.shtml
http://www.delorie.com/gnu/docs/automake/automake_35.html
De esta última es interesante especialmente el chapter 9. Especificando claramente las diferencias para generar un programa ejecutable, una librería distribuible (sea dinámica o estática) y una libreria no distribuible (solo útil en el proceso para ser linkada con otro objeto distribuible)
También muy interesante el libro “Programming with gnu software” (no el de o’really). Nos muestra una visión completa del desarrollo software libre. En concreto los chapters 9, 10, 11 y 12 tratan sobre autotools.
www.lrde.epita.fr/~akim/gnuprog2.pdf
Mas profundidad y como referencia:
http://sources.redhat.com/autobook/autobook/autobook_toc.html#SEC_Contents




