martes, mayo 07, 2013

Autotools, tutorial de uso (II): Un ejemplo sencillo

En esta segunda entrada sobre las autotools voy a describir un sencillo ejemplo que compila un programa en C. El código fuente del mismo se puede bajar del git autotools-tutorial. En el directorio tut1 se encuentran las plantillas Makefile.am y configure.ac, un subdirectorio m4 con un fichero de macros ,acexample.m4 - vacío de momento - , el código fuente que se va a compilar, tut1.c y por último un shell script que va a ejecutar los diferentes herramientas de las autotools para generar los ficheros intermedios.

Cuando las distintas herramientas procesan las plantillas, se va sustituyendo aquellas construcciones que reconoce copiando a los ficheros de salida el resto de la entrada. El resultado de procesar el fichero configure.ac, será un fichero configure, que no es más que un shell script, con lo cual se podrá incluir código Bourne Shell1 que las diferentes herramientas copiaran sin tocar - o haciendo las sustituciones correspondientes - , mientras que la plantilla Makefile.am se puede incluir código de Makefile que será copiado sin modificar a la salida.

A continuación se describe un pequeño ejemplo de las plantillas para generar el script configure y a partir de la ejecución del mismo se generan los Makefile, que permitirá compilar un programa simple:

configure.ac

 1 dnl Esto es un comentario
 2 dnl Esta macro fuerza a una versión mínima de autoconf
 3 AC_PREREQ([2.59])
 4 AC_INIT([tut1],[1.0],[cterron@users.sourceforge.net],[tut1.tar.gz],
 5         [https://sourceforge.net/p/autotutorial/])
 6 dnl Necesitamos el compilador de C
 7 AC_CONFIG_HEADERS([config.h])
 8 AC_PROG_CC
 9 dnl Init automake 
10 AM_INIT_AUTOMAKE
11 dnl Debe de ir al final de la plantilla. Genera el fichero config.status
12 AC_CONFIG_FILES([Makefile])
13 AC_OUTPUT

El fichero configure.ac es procesado por varias utilidades - autoconf, autoheader y automake -. Es procesado por el macroprocesador m4. En este pequeño ejemplo se pueden ver algunas de las características de este lenguaje de macros:

  • En primer lugar tenemos la macro dnl. Esto lo que hace es descartar toda la entrada del fichero hasta el fin de línea, lo cual es útil para poner comentarios. También nos puede server el símbolo #.
  • AC_PREREQ es una macro es opcional, pero nos sirve para indicar cual es la versión mínima de autoconf que se va a usar. En este caso se necesita como mínimo la versión 2.59. Aquí se puede ver una característica del lenguaje m4, que es el paso de parámetros: Estos tienen que ir encerrados entre corchetes, [2.59]
  • AC_INIT es la macro que se encarga de emitir el código en el configure que se encargará de realizar la inicialización del script. Tiene dos parámetros obligatorios, que son el nombre del paquete y la versión (tut1 y 1.0 en el ejemplo). Los otros tres parámetros son opcionales. Esta macro debe de estar presente en el fichero antes de cualquier macro que genere una salida. La definición de esta macro generará una serie de variables que se podrán usar en el fichero configure, así como unas macros de preprocesador, que también podremos usar.
  • AC_CONFIG_HEADERS Esta macro va a generar un fichero de definiciones en C, cuyo nombre final se pasa como parámetro, en este caso config.h. Pero para generar dicho fichero, por defecto el script configure que se generará espera encontrar un fichero config.h.in que se genera a partir del procesamiento de este fichero por autoheader..
  • AM_INIT_AUTOMAKE Esta macro es la encargada de inicializar todo el conjunto de código necesario para poder procesar los ficheros Makefile.in y generar los Makefiles. Puede llevar una lista de parámetros opciones que se utiliza para procesar cada fichero Makefile.am.
  • AC_CONFIG_FILES Esta macro especifica que ficheros de salida debe de crear el automake. En este ejemplo sólo queremos crear el fichero Makefile en el directorio actual.
  • AC_OUTPUT Procesa la lista de ficheros que se especifica. En este caso, puesto que los Makefile se están especificando con la macro AC_CONFIG_FILES no es necesario poner parámetros. Si se le da una lista de parámetros, son nombres de fichero separados por espacios, lo que hará el sistema es procesar el nombre junto al sufijo .in cuando se ejecute. Por ejemplo AC_OUTPUT([start.py]), hará que cuando se ejecute el configure el sistema busque start.py.in y lo procese de manera adecuada. Puede llevar dos parámetros opcionales que indican comandos antes y después de ejecutar la salida del fichero.

Makefile.am

1 bin_PROGRAMS= tut1
2 tut1_SOURCES = tut1.c

El formato que sigue la plantilla de Makefile.am es muy similar: Siempre un nombre y un sufijo separado por un subrayado. Así:

  • En primer lugar está bin_PROGRAMS que es una lista separada por espacios de los programas que se van a compilar y que se instalarán cuando tras compilar se ejecute la orden make install. La instalación por defecto será en $prefix/bin, lo que en la terminología de GNU se llama bindir2
  • La segunda línea nos define cuales son los ficheros fuentes necesarias para compilar el binario tut1, en este caso sólo tenemos tut1.c

Generación de los scripts

Aunque el script autogen.sh que hay en el directorio de ejemplo hace todos los pasos, a continuación se detallan para que se puedan ver cuales son pasos:

1 aclocal -I m4
2 rm -rf autom4te.cache/
3 autoheader
4 automake --foreign
5 autoconf

En primer lugar se genera el fichero aclocal.m4 ejecuanto aclocal, en el mismo directorio donde está el resto de ficheros de plantilla. Se va a usar las macros que estén en el directorio m4, cosa que pasamos como parámetro con la opción -I. Decir que, aunque no estaba en el dibujo que se publicó en la entrada anterior, al ejecutar aclocal se incluirá diversas definiciones de macros en el fichero aclocal.m4, entre otras, aquellas que definen las macros que usará automake

La segunda orden borra un directorio caché que crea las diversas ejecuciones de las autotools para ir más rápido en la ejecución

autoheader va a recorrer el fichero configure.ac, para encontrar la primera llamada a la macro AC_CONFIG_HEADERS de donde tomará el nombre del fichero de salida que va a generar, añadiéndole el sufijo .in. Así si dicha macro tiene como parámetro el nombre config.h, generará un fichero llamado config.h.in donde estará las posibles definiciones que se hayan hecho en el configure.ac.

automake va a generar los ficheros Makefile.in a partir de los Makefile.am que se tengan en los directorios. Generará las reglas por defecto, definirá variables, definirá todos los objetivos estándar de construcción (install, install-exec,clean, ....). Algunas definiciones que serán procesadas cuando se ejecute el configure quedará entre símbolos @, para ser procesado posteriormente por configure. El parámetro --foreign le indica al automake que es un proyecto que no sigue con los estándares GNU a la hora de tener ciertos ficheros de documentación. Un trozo de un fichero Makefile.in generado a partir del Makefile.am puede verse a continuación.

....
 15 @SET_MAKE@
 16 
 17 VPATH = @srcdir@
 18 pkgdatadir = $(datadir)/@PACKAGE@
 19 pkglibdir = $(libdir)/@PACKAGE@
 20 pkgincludedir = $(includedir)/@PACKAGE@
....

Pueden verse variables que definirá el proceso (por ejemplo $(libdir)) o zonas de texto cuyo valor será sustituido cuando se ejecute el configure y procese este fichero (por ejemplo @SET_MAKE@ o @PACKAGE)

Por último, autoconf procesará el fichero configure.ac para generar el fichero configure. Una vez generado lo podemos ejecutar con ./configure, y podremos ver como se procesa los ficheros, y se generan los ficheros Makefile.

Documentación

Notas

  1. Curiosamente, hay que usar construcciones lo más compatibles posible, porque no todos los Bourne Shell se comportan igual.
  2. Estoy adelantando información, ya que el configure define una serie de variables - a fin de cuenta es un shell script - que se pueden usar a lo largo de todo nuestro sistema para especificar directorios u otros valores de configuración.

Technorati Tags: ,

No hay comentarios: