Autotools y amigos

De Wiki GNOME Chile
(Diferencias entre revisiones)
Saltar a: navegación, buscar
Línea 1: Línea 1:
 +
=Autotools y sus amigos=
  
 +
En esta leccion, aprenderemos a crear y distribuir un proyecto usando las no bien ponderadas Autotools (Autoconf/Automake y amigos).
 +
 +
==Comenzando==
 +
 +
Primero, debemos crear un directorio donde ira nuestro proyecto. En mi caso, /home/jci/code/proyecto1
 +
 +
<pre>$ mkdir ~/code/proyecto1
 +
$ cd ~/code/proyecto1</pre>
 +
 +
Pueden elegir el directorio que deseen
 +
 +
Dentro de ese directorio deben colocar los siguientes archivos:
 +
 +
* AUTHORS, donde iran los autores del programa
 +
* LICENSE, donde describiran la licencia que adoptaran para el programa
 +
* Changelog, un control de cambios del programa
 +
* COPYING, donde ira una copia de la licencia (en el caso de GPL, GPLv2, etc)
 +
* INSTALL, con instrucciones especiales para la instalacion del programa
 +
* README, con instrucciones acerca del programa, o bien para indicar algo que debe leer el usuario antes de ejecutar el programa
 +
 +
Los archivos anteriores no tienen que ver directamente con el sistema de construccion. Estan como manera informativa, indicar la licencia en la cual se distribuyen, entre otros elementos (como dependencias, autores, entre otros topicos).
 +
 +
Ahora, estos archivos SON requeridos por automake, al momento de construir la distribucion de nuestro proyecto. Lo veremos un poco mas adelante, cuando veamos en profundidad el uso de automake.\
 +
 +
Recordar que automake es parte de las herramientas de construccion de GNU para distribucion de programas de codigo abierto. Asi que es la razon de por que son necesarios. Aunque hay muchos proyectos que tienen esos mismos archivos en blanco, la regla del dedo gordo es que <b>no usen esos archivos en blanco</b> si quieren distribuir su proyecto con otras personas.
 +
 +
Empecemos.
 +
 +
==configure.ac==
 +
 +
Esta es la plantilla para el script de configure. Indica, por ejemplo, las dependencias para compilar, tests para ver si existe o no alguna aplicacion o biblioteca del sistema, entre otras.
 +
 +
Su mision es solamente proveer un unico punto para la configuracion del programa, ademas de hacerlo un poco mas portable. Es la base de la mayoria de las herramientas de construccion de GNU (o en otras partes, encuentran el termino como GNU tools). O bien, de las que se distribuyen como tal.
 +
 +
El unico inconveniente de este archivo es que esta escrito en lenguaje de macros, que una vez usando autoconf, seran expandidas a un shell script. Algo complicado al principio de entender.
 +
 +
Ahora, supongamos que mi proyecto se llama "diamante" y que el fuente del programa esta en la ruta src/diamante.c. Haremos un archivo configure.ac para mostrar la forma de crear uno correctamente.
 +
 +
<pre>AC_INIT([Diamante], [0.1], [[email protected]], [diamante])
 +
 +
AC_CONFIG_SRCDIR(src/diamante.c)
 +
 +
AC_CONFIG_HEADER(config.h)
 +
 +
AM_INIT_AUTOMAKE
 +
AM_MAINTAINER_MODE
 +
 +
AC_PROG_CC
 +
AC_HEADER_STDC
 +
 +
AC_SUBST(CFLAGS)
 +
AC_SUBST(CPPFLAGS)
 +
AC_SUBST(LDFLAGS)
 +
 +
GTK_MODULES="gtk+-2.0"
 +
PKG_CHECK_MODULES(GTK, $GTK_MODULES)
 +
AC_SUBST(GTK_CFLAGS)
 +
AC_SUBST(GTK_LIBS)
 +
 +
AC_OUTPUT([
 +
Makefile
 +
src/Makefile
 +
])</pre>
 +
 +
Veamos que significa cada cosa.
 +
 +
===Directivas y Variables===
 +
 +
AC_INIT indica que Autoconf debe iniciarse para crear el proyecto. Los argumentos son
 +
 +
(nombre_proyecto, version, email, nombrecorto)
 +
 +
AC_CONFIG_SRC indica cual es el directorio donde se encuentra el codigo fuente de nuestro programa (en este caso, src/diamante.c).
 +
 +
AC_CONFIG_HEADERS le indica al preprocesador de C que deba leer un archivo antes de compilar. Por lo general, es config.h. Este config.h se crea de forma automatica usando autoheader.
 +
 +
AM_INIT_AUTOMAKE hace que Automake inicie ;)
 +
 +
AM_MAINTAINER_MODE hace que se habilite la opcion --enable-maintainer-mode en la configuracion del programa, para agregar opciones tales como bibliotecas con soporte de debugging, entre otras.
 +
 +
AC_PROG_CC y AC_HEADER_STDC le indica a Autoconf que debe aceptar un compilador de C y que debe poseer las cabeceras estandar. Por lo general, si no estan instaladas, el error sera el siguiente
 +
 +
<pre>C compiler error : cannot create executables</pre>
 +
 +
Autoconf permite el uso de variables. En este caso, cree la variable GTK_MODULES, donde agregue los modulos necesarios para que el programa pudiera compilar. En este caso, gtk+-2.0.
 +
 +
PKG_CHECK_MODULES permite que pkg-config (importante, lo vimos en la primera leccion) pueda verificar si los modulos existen. Y los comprueba desde la variable GTK_MODULES. Ademas, llena una variable llamada GTK.
 +
 +
La macro AC_SUBST pasa valores desde autoconf a automake (para la creacion del Makefile). Es decir, si existe una cadena para reemplazo (generalmente, $(CADENA) ) en un Makefile.in, configure reemplazara la cadena con el valor que exista en los parentesis de AC_SUBST.
 +
 +
Por ejemplo,
 +
 +
<pre>AC_SUBST(CFLAGS)</pre>
 +
 +
CFLAGS es una variable que contiene, por ejemplo, el siguiente valor:
 +
 +
<pre>-l -g -d --march="i686" </pre>
 +
 +
Si existe algo asi en el Makefile.in
 +
 +
<pre>CFLAGS=$(CFLAGS)</pre>
 +
 +
sera reemplazado asi
 +
 +
<pre>CFLAGS=-l -g -d --march="i686"</pre>
 +
 +
al crear el archivo Makefile desde la plantilla. Esto se vera mas claro una vez que explique mas adelante el uso de AC_OUTPUT. Asi que sigan leyendo! :D
 +
 +
<blockquote>CFLAGS es una variable muy importante al momento de construir cualquier proyecto que requiere el compilador de C (GNU C Compiler, Compilador GNU de C o mas conocido como GCC en este caso particular).
 +
 +
Esta variable indica que modificadores, opciones, variables o banderas pasar al compilador al momento de construir el proyecto. Algunas veces contiene elementos de optimizacion, otras veces contiene elementos para la depuracion del proyecto, entre otras.
 +
 +
Por ejemplo, la opcion -g indica que el compilador debe agregar opciones para depuracion.
 +
 +
Si requieren mas info, pueden consultar la pagina de manual de gcc.
 +
</blockquote>
 +
 +
Hasta el momento, tengo creado un directorio con los siguientes archivos:
 +
 +
<pre>./configure.ac
 +
./src
 +
./src/diamante.c</pre>
 +
 +
Por el momento no me voy a preocupar por los archivos faltantes (NEWS, README, AUTHORS y ChangeLog), ya que no son necesarios para la construccion proyecto por ahora. Pero para distribuir nuestro proyecto, los necesitaremos.
 +
 +
Ahora, necesito que algunas plantillas (.m4) se copien al directorio de mi proyecto. Lo puedo hacer con aclocal:
 +
 +
<pre>$ aclocal</pre>
 +
 +
lo que copiara un archivo llamado aclocal.m4
 +
 +
Luego, ejecutar autoheader, para que cree automaticamente el archivo config.h.in
 +
 +
<pre>$ autoheader</pre>
 +
 +
Ahora, ejecutar
 +
 +
<pre>$ automake --add-missing --gnu</pre>
 +
 +
La salida sera la siguiente:
 +
 +
<pre>configure.ac: installing `./install-sh'
 +
configure.ac: installing `./mkinstalldirs'
 +
configure.ac: installing `./missing'</pre>
 +
 +
Ahora, ejecutemos autoconf
 +
 +
<pre>$ autoconf</pre>
 +
 +
Y listo. Tendremos un configure limpiecito.
 +
 +
ALTO! Veamos que pasa al ejecutar ./configure
 +
 +
<pre>$ ./configure
 +
[...challa...]
 +
configure: creating ./config.status
 +
config.status: error: cannot find input file: Makefile.in</pre>
 +
 +
Hmmm...Makefile.in...de donde vendra eso?
 +
 +
Un Makefile en una distribucion con autotools esta creado con una serie de plantillas. Primero Makefile.am para automake que genera un Makefile.in, que es una plantilla para un archivo Makefile.
 +
 +
Como no existe el archivo Makefile.in, no puede generar el archivo Makefile.
 +
 +
Como se sabe esto?
 +
 +
Veamos las ultimas lineas del archivo configure.ac:
 +
 +
<pre>AC_OUTPUT([
 +
Makefile
 +
src/Makefile
 +
])</pre>
 +
 +
AC_OUTPUT le indica a autoconf que genere esos archivos de forma automagica usando plantillas, o bien archivos .in. En este caso, Makefile.in y src/Makefile.in van a generar los archivos Makefile y src/Makefile, en ese orden. Ninguno de ellos esta. Tampoco podremos crear los archivos a mano, ya que esa es pega de Automake.
 +
 +
Creamos entonces un Makefile.am en el directorio raiz:
 +
 +
<pre>$ touch Makefile.am</pre>
 +
 +
y volvemos a ejecutar
 +
 +
<pre>$ automake --gnu --add-missing</pre>
 +
 +
La salida es un poco mas larga que la vez anterior:
 +
 +
<pre>Makefile.am: installing `./COPYING'
 +
Makefile.am: installing `./INSTALL'
 +
Makefile.am: required file `./NEWS' not found
 +
Makefile.am: required file `./README' not found
 +
Makefile.am: required file `./AUTHORS' not found
 +
Makefile.am: required file `./ChangeLog' not found</pre>
 +
 +
Me indica que los archivos NEWS, README, AUTHORS y ChangeLog no existen. Creemos estos archivos en blanco:
 +
 +
<pre>$ touch NEWS README AUTHORS ChangeLog</pre>
 +
 +
No es necesario volver a ejecutar automake, ya que no hemos modificado Makefile.am
 +
 +
Ahora, un configure nuevamente:
 +
 +
<pre>$ ./configure</pre>
 +
 +
Esta vez, magicamente, funciono. Sin ningun error. Pero aun falta.
 +
 +
Por ahora, configure.ac y configure dejemoslo de lado. Concentremonos en el archivo Makefile.am
 +
 +
==Makefile.am==
 +
 +
Por el momento el archivo Makefile.am de la raiz del proyecto esta vacio. Pero agreguemos lo siguiente en el:
 +
 +
<pre>SUBDIRS=src</pre>
 +
 +
La directiva SUBDIRS indica a Automake cuales subdirectorios seguir una vez que termine con el make del directorio raiz. Por ejemplo, si hubiera puesto
 +
 +
<pre>SUBDIRS=src po intltool foo bar</pre>
 +
 +
Al ejecutar make, hubiera ejecutado  los makefiles de los directorios src, po, intltool, foo y bar, y luego el del raiz. Y en ese orden.
 +
 +
Volvamos a ejecutar automake
 +
 +
<pre>$ automake --gnu --add-missing</pre>
 +
 +
Y ahora
 +
 +
<pre>$ ./configure</pre>
 +
 +
Si todo va bien, ejecutemos
 +
 +
<pre>$ make</pre>
 +
 +
Deberia pasar el proyecto sin ningun problema. Mi salida fue la siguiente:
 +
 +
<pre>$ make
 +
make  all-recursive
 +
make[1]: Entering directory `/home/jci/code/diamante'
 +
Making all in src
 +
make[2]: Entering directory `/home/jci/code/diamante/src'
 +
make[2]: Nothing to be done for `all'.
 +
make[2]: Leaving directory `/home/jci/code/diamante/src'
 +
make[2]: Entering directory `/home/jci/code/diamante'
 +
make[2]: Leaving directory `/home/jci/code/diamante'
 +
make[1]: Leaving directory `/home/jci/code/diamante'</pre>
 +
 +
Perfecto, nuestro sistema esta casi listo.
 +
 +
Pero solo falta ahora crear un programa, ya que diamante.c esta vacio! Y ademas, poder construirlo.
 +
 +
Asi que coloquemos un miserable hola mundo de la primera leccion. O bien, el programa que quieran.
 +
 +
Yo voy a ir con este :)
 +
 +
<pre>#include <gtk/gtk.h>
 +
 +
int main(int argc, char * argv[])
 +
{
 +
GtkWidget * ventana;
 +
GtkWidget * boton;
 +
 +
gtk_init(&argc, &argv);
 +
 +
ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 +
boton = gtk_button_new_with_label("Hola Mundo");
 +
 +
gtk_container_add(GTK_CONTAINER(ventana), boton);
 +
gtk_widget_show_all(ventana);
 +
 +
gtk_main();
 +
}</pre>
 +
 +
Ahora, el siguiente actor : src/Makefile.am Ya que Autotools es un sistema de construccion automatica, y hemos dicho en el archivo Makefile.am, de la raiz del proyecto, que uno de los subdirectorios a ejecutar un Makefile es src/, entonces debemos tambien tener una plantilla (src/Makefile.am) para Automake.
 +
 +
Agreguemos lo siguiente en src/Makefile.am:
 +
 +
<pre>INCLUDES = -I$(top_srcdir) $(GTK_CFLAGS)
 +
 +
LIBS = $(GTK_LIBS)
 +
 +
bin_PROGRAMS = diamante</pre>
 +
 +
Recuerdan que AC_SUBST en Autoconf permitia reemplazar cadenas con los valores que tuvieran las variables? Las que se reemplazan son GTK_CFLAGS y GTK_LIBS.
 +
 +
La directiva INCLUDES indica que rutas de archivos de cabeceras agregar para compilar efectivamente un programa. Recuerdan que para compilar un programa en GTK+ era necesario usar el metodo de los backquotes para no colocar una tremenda linea?
 +
 +
<pre>$ gcc -o diamante.o diamante `pkg-config --cflags gtk+-2.0`</pre>
 +
 +
INCLUDES es equivalente.
 +
 +
Ahora, en INCLUDES hay ademas una variable $top_srcdir. Esa indica el directorio raiz de nuestro proyecto. Es solo en caso que usemos el archivo config.h para algo.
 +
 +
La directiva LIBS es la directiva para enlazar con las bibliotecas necesarias. En los ejemplos anteriores era algo asi
 +
 +
<pre>$ gcc -o diamante diamante.o `pkg_config --libs gtk+-2.0`</pre>
 +
 +
En este caso, es equivalente.
 +
 +
bin_PROGRAMS indica cual es el archivo binario a generar despues que se compilo el archivo. Recordar que se indica cuales archivos compilar en la directiva AC_CONFIG_SRCDIR de Autoconf :-D
 +
 +
De nuevo, ejecutamos automake en la raiz de nuestro proyecto.
 +
 +
<pre>$ automake --gnu --add-missing</pre>
 +
 +
Luego
 +
 +
<pre>$ ./configure</pre>
 +
 +
Y despues
 +
 +
<pre>$ make</pre>
 +
 +
Y veran que empezara a compilar el fuente que estaba en el directorio src. Excelente!
 +
 +
<pre>$ ls src/
 +
diamante  diamante.c  diamante.o  Makefile  Makefile.am  Makefile.in</pre>
 +
 +
Perfecto! Es justo lo que necesito. Y hemos generado nuestro primer proyecto con Autotools!
 +
 +
==Creando la distribucion de nuestro proyecto==
 +
 +
Ahora veamos como podemos distribuirlo para colocar en nuestra pagina web y cachiporrearnos en el asado con los amigos que "publique mi primer programa en GTK+" :) .
 +
 +
Antes de seguir, voy a explicar algunas opciones que son basicas.
 +
 +
Despues de ejecutar
 +
 +
<pre>$ ./configure</pre>
 +
 +
Pueden construir el proyecto con
 +
 +
<pre>$ make</pre>
 +
 +
para construirlo.
 +
 +
===make install===
 +
 +
<pre>$ make install</pre>
 +
 +
(una vez que tengan los privilegios para instalar el programa) para instalarlo de forma que sea para todo el sistema (o bien, que todos los usuarios puedan ejecutar el programa). Requiere privilegios de superusuario.
 +
 +
===make clean===
 +
 +
<pre>$ make clean </pre>
 +
 +
lo que hace es limpiar de los archivos de construccion y archivos resultantes de nuestro proyecto. No borra los Makefiles y podremos ejecutar <code>make</code> cuando queramos.
 +
 +
En mi caso,
 +
 +
<pre>$ make clean</pre>
 +
 +
dio el siguiente resultado:
 +
 +
<pre>$ make clean
 +
Making clean in src
 +
make[1]: Entering directory `/home/jci/code/diamante/src'
 +
test -z "diamante" || rm -f diamante
 +
rm -f *.o core *.core
 +
make[1]: Leaving directory `/home/jci/code/diamante/src'
 +
Making clean in .
 +
make[1]: Entering directory `/home/jci/code/diamante'
 +
make[1]: Nothing to be done for `clean-am'.
 +
make[1]: Leaving directory `/home/jci/code/diamante'</pre>
 +
 +
===make distclean===
 +
 +
Lo interesante viene si quieren distribuir su proyecto. Para eso pueden usar
 +
 +
<pre>$ make distclean</pre>
 +
 +
Con make distclean, los archivos que se generan de forma automatica en el sistema de construccion son eliminados, junto con los archivos que se compilan. Asi queda nuestro proyecto sin Makefiles ni archivos de dependencias, corefiles, entre otros.
 +
 +
<pre>$ make distclean
 +
make[1]: Entering directory `/home/jci/code/diamante/src'
 +
test -z "diamante" || rm -f diamante
 +
rm -f *.o core *.core
 +
rm -f *.tab.c
 +
rm -f
 +
rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 +
rm -rf ./.deps
 +
rm -f Makefile
 +
make[1]: Leaving directory `/home/jci/code/diamante/src'
 +
Making distclean in .
 +
make[1]: Entering directory `/home/jci/code/diamante'
 +
rm -f
 +
rm -f config.h stamp-h1
 +
rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 +
make[1]: Leaving directory `/home/jci/code/diamante'
 +
rm -f config.status config.cache config.log configure.lineno
 +
rm -f Makefile</pre>
 +
 +
===make distcheck===
 +
 +
Va a sonar a chiste, pero hay que ejecutar de nuevo
 +
 +
<pre>$ ./configure</pre>
 +
 +
Y una vez que termine, ejecutar
 +
 +
<pre>$ make distcheck</pre>
 +
 +
La opcion distcheck realiza una compilacion limpia, copia el arbol de compilacion completo en un directorio y ve si puede construir el proyecto. Si es asi, al final tendremos este lindo mensaje:
 +
 +
<pre>=============================================
 +
diamante-0.1.tar.gz is ready for distribution
 +
=============================================</pre>
 +
 +
Ese archivo .tar.gz podremos pasarlo a nuestros amigos, o bien respaldar donde queramos. :D
 +
 +
Veamos que tiene dentro...
 +
 +
<pre>$ tar tfz diamante-0.1.tar.gz
 +
diamante-0.1/
 +
diamante-0.1/aclocal.m4
 +
diamante-0.1/AUTHORS
 +
diamante-0.1/Makefile.am
 +
diamante-0.1/README
 +
diamante-0.1/install-sh
 +
diamante-0.1/depcomp
 +
diamante-0.1/config.h.in
 +
diamante-0.1/INSTALL
 +
diamante-0.1/ChangeLog
 +
diamante-0.1/configure
 +
diamante-0.1/src/
 +
diamante-0.1/src/Makefile.am
 +
diamante-0.1/src/diamante.c
 +
diamante-0.1/src/Makefile.in
 +
diamante-0.1/missing
 +
diamante-0.1/Makefile.in
 +
diamante-0.1/NEWS
 +
diamante-0.1/mkinstalldirs
 +
diamante-0.1/configure.ac
 +
diamante-0.1/COPYING</pre>
 +
 +
La pregunta mas logica que se deben estar haciendo es "por que supo que era la version 0.1?"
 +
 +
Recuerdan la primera linea de AC_INIT del archivo configure.ac?
 +
 +
<pre>AC_INIT([Diamante], [0.1], [[email protected]], [diamante])</pre>
 +
 +
El segundo parametro es la version de nuestro programa.
 +
 +
No me creen? Cambien el valor de 0.1 a 0.2. Vuelvan a ejecutar todo en este orden:
 +
 +
<pre>$ autoheader
 +
$ autoconf
 +
$ automake --gnu --add-missing
 +
$ make distclean
 +
$ ./configure
 +
$ make distcheck
 +
...[challa]...
 +
 +
=============================================
 +
diamante-0.2.tar.gz is ready for distribution
 +
=============================================</pre>
 +
 +
Bonito, no?

Revisión de 08:35 7 ago 2007

Contenido

Autotools y sus amigos

En esta leccion, aprenderemos a crear y distribuir un proyecto usando las no bien ponderadas Autotools (Autoconf/Automake y amigos).

Comenzando

Primero, debemos crear un directorio donde ira nuestro proyecto. En mi caso, /home/jci/code/proyecto1

$ mkdir ~/code/proyecto1
$ cd ~/code/proyecto1

Pueden elegir el directorio que deseen

Dentro de ese directorio deben colocar los siguientes archivos:

  • AUTHORS, donde iran los autores del programa
  • LICENSE, donde describiran la licencia que adoptaran para el programa
  • Changelog, un control de cambios del programa
  • COPYING, donde ira una copia de la licencia (en el caso de GPL, GPLv2, etc)
  • INSTALL, con instrucciones especiales para la instalacion del programa
  • README, con instrucciones acerca del programa, o bien para indicar algo que debe leer el usuario antes de ejecutar el programa

Los archivos anteriores no tienen que ver directamente con el sistema de construccion. Estan como manera informativa, indicar la licencia en la cual se distribuyen, entre otros elementos (como dependencias, autores, entre otros topicos).

Ahora, estos archivos SON requeridos por automake, al momento de construir la distribucion de nuestro proyecto. Lo veremos un poco mas adelante, cuando veamos en profundidad el uso de automake.\

Recordar que automake es parte de las herramientas de construccion de GNU para distribucion de programas de codigo abierto. Asi que es la razon de por que son necesarios. Aunque hay muchos proyectos que tienen esos mismos archivos en blanco, la regla del dedo gordo es que no usen esos archivos en blanco si quieren distribuir su proyecto con otras personas.

Empecemos.

configure.ac

Esta es la plantilla para el script de configure. Indica, por ejemplo, las dependencias para compilar, tests para ver si existe o no alguna aplicacion o biblioteca del sistema, entre otras.

Su mision es solamente proveer un unico punto para la configuracion del programa, ademas de hacerlo un poco mas portable. Es la base de la mayoria de las herramientas de construccion de GNU (o en otras partes, encuentran el termino como GNU tools). O bien, de las que se distribuyen como tal.

El unico inconveniente de este archivo es que esta escrito en lenguaje de macros, que una vez usando autoconf, seran expandidas a un shell script. Algo complicado al principio de entender.

Ahora, supongamos que mi proyecto se llama "diamante" y que el fuente del programa esta en la ruta src/diamante.c. Haremos un archivo configure.ac para mostrar la forma de crear uno correctamente.

AC_INIT([Diamante], [0.1], [[email protected]], [diamante])

AC_CONFIG_SRCDIR(src/diamante.c)

AC_CONFIG_HEADER(config.h)

AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE

AC_PROG_CC
AC_HEADER_STDC

AC_SUBST(CFLAGS)
AC_SUBST(CPPFLAGS)
AC_SUBST(LDFLAGS)

GTK_MODULES="gtk+-2.0"
PKG_CHECK_MODULES(GTK, $GTK_MODULES)
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)

AC_OUTPUT([
Makefile
src/Makefile
])

Veamos que significa cada cosa.

Directivas y Variables

AC_INIT indica que Autoconf debe iniciarse para crear el proyecto. Los argumentos son

(nombre_proyecto, version, email, nombrecorto)

AC_CONFIG_SRC indica cual es el directorio donde se encuentra el codigo fuente de nuestro programa (en este caso, src/diamante.c).

AC_CONFIG_HEADERS le indica al preprocesador de C que deba leer un archivo antes de compilar. Por lo general, es config.h. Este config.h se crea de forma automatica usando autoheader.

AM_INIT_AUTOMAKE hace que Automake inicie ;)

AM_MAINTAINER_MODE hace que se habilite la opcion --enable-maintainer-mode en la configuracion del programa, para agregar opciones tales como bibliotecas con soporte de debugging, entre otras.

AC_PROG_CC y AC_HEADER_STDC le indica a Autoconf que debe aceptar un compilador de C y que debe poseer las cabeceras estandar. Por lo general, si no estan instaladas, el error sera el siguiente

C compiler error : cannot create executables

Autoconf permite el uso de variables. En este caso, cree la variable GTK_MODULES, donde agregue los modulos necesarios para que el programa pudiera compilar. En este caso, gtk+-2.0.

PKG_CHECK_MODULES permite que pkg-config (importante, lo vimos en la primera leccion) pueda verificar si los modulos existen. Y los comprueba desde la variable GTK_MODULES. Ademas, llena una variable llamada GTK.

La macro AC_SUBST pasa valores desde autoconf a automake (para la creacion del Makefile). Es decir, si existe una cadena para reemplazo (generalmente, $(CADENA) ) en un Makefile.in, configure reemplazara la cadena con el valor que exista en los parentesis de AC_SUBST.

Por ejemplo,

AC_SUBST(CFLAGS)

CFLAGS es una variable que contiene, por ejemplo, el siguiente valor:

-l -g -d --march="i686" 

Si existe algo asi en el Makefile.in

CFLAGS=$(CFLAGS)

sera reemplazado asi

CFLAGS=-l -g -d --march="i686"

al crear el archivo Makefile desde la plantilla. Esto se vera mas claro una vez que explique mas adelante el uso de AC_OUTPUT. Asi que sigan leyendo! :D

CFLAGS es una variable muy importante al momento de construir cualquier proyecto que requiere el compilador de C (GNU C Compiler, Compilador GNU de C o mas conocido como GCC en este caso particular). Esta variable indica que modificadores, opciones, variables o banderas pasar al compilador al momento de construir el proyecto. Algunas veces contiene elementos de optimizacion, otras veces contiene elementos para la depuracion del proyecto, entre otras. Por ejemplo, la opcion -g indica que el compilador debe agregar opciones para depuracion. Si requieren mas info, pueden consultar la pagina de manual de gcc.

Hasta el momento, tengo creado un directorio con los siguientes archivos:

./configure.ac
./src
./src/diamante.c

Por el momento no me voy a preocupar por los archivos faltantes (NEWS, README, AUTHORS y ChangeLog), ya que no son necesarios para la construccion proyecto por ahora. Pero para distribuir nuestro proyecto, los necesitaremos.

Ahora, necesito que algunas plantillas (.m4) se copien al directorio de mi proyecto. Lo puedo hacer con aclocal:

$ aclocal

lo que copiara un archivo llamado aclocal.m4

Luego, ejecutar autoheader, para que cree automaticamente el archivo config.h.in

$ autoheader

Ahora, ejecutar

$ automake --add-missing --gnu

La salida sera la siguiente:

configure.ac: installing `./install-sh'
configure.ac: installing `./mkinstalldirs'
configure.ac: installing `./missing'

Ahora, ejecutemos autoconf

$ autoconf

Y listo. Tendremos un configure limpiecito.

ALTO! Veamos que pasa al ejecutar ./configure

$ ./configure
[...challa...]
configure: creating ./config.status
config.status: error: cannot find input file: Makefile.in

Hmmm...Makefile.in...de donde vendra eso?

Un Makefile en una distribucion con autotools esta creado con una serie de plantillas. Primero Makefile.am para automake que genera un Makefile.in, que es una plantilla para un archivo Makefile.

Como no existe el archivo Makefile.in, no puede generar el archivo Makefile.

Como se sabe esto?

Veamos las ultimas lineas del archivo configure.ac:

AC_OUTPUT([
Makefile
src/Makefile
])

AC_OUTPUT le indica a autoconf que genere esos archivos de forma automagica usando plantillas, o bien archivos .in. En este caso, Makefile.in y src/Makefile.in van a generar los archivos Makefile y src/Makefile, en ese orden. Ninguno de ellos esta. Tampoco podremos crear los archivos a mano, ya que esa es pega de Automake.

Creamos entonces un Makefile.am en el directorio raiz:

$ touch Makefile.am

y volvemos a ejecutar

$ automake --gnu --add-missing

La salida es un poco mas larga que la vez anterior:

Makefile.am: installing `./COPYING'
Makefile.am: installing `./INSTALL'
Makefile.am: required file `./NEWS' not found
Makefile.am: required file `./README' not found
Makefile.am: required file `./AUTHORS' not found
Makefile.am: required file `./ChangeLog' not found

Me indica que los archivos NEWS, README, AUTHORS y ChangeLog no existen. Creemos estos archivos en blanco:

$ touch NEWS README AUTHORS ChangeLog

No es necesario volver a ejecutar automake, ya que no hemos modificado Makefile.am

Ahora, un configure nuevamente:

$ ./configure

Esta vez, magicamente, funciono. Sin ningun error. Pero aun falta.

Por ahora, configure.ac y configure dejemoslo de lado. Concentremonos en el archivo Makefile.am

Makefile.am

Por el momento el archivo Makefile.am de la raiz del proyecto esta vacio. Pero agreguemos lo siguiente en el:

SUBDIRS=src

La directiva SUBDIRS indica a Automake cuales subdirectorios seguir una vez que termine con el make del directorio raiz. Por ejemplo, si hubiera puesto

SUBDIRS=src po intltool foo bar

Al ejecutar make, hubiera ejecutado los makefiles de los directorios src, po, intltool, foo y bar, y luego el del raiz. Y en ese orden.

Volvamos a ejecutar automake

$ automake --gnu --add-missing

Y ahora

$ ./configure

Si todo va bien, ejecutemos

$ make

Deberia pasar el proyecto sin ningun problema. Mi salida fue la siguiente:

$ make
make  all-recursive
make[1]: Entering directory `/home/jci/code/diamante'
Making all in src
make[2]: Entering directory `/home/jci/code/diamante/src'
make[2]: Nothing to be done for `all'.
make[2]: Leaving directory `/home/jci/code/diamante/src'
make[2]: Entering directory `/home/jci/code/diamante'
make[2]: Leaving directory `/home/jci/code/diamante'
make[1]: Leaving directory `/home/jci/code/diamante'

Perfecto, nuestro sistema esta casi listo.

Pero solo falta ahora crear un programa, ya que diamante.c esta vacio! Y ademas, poder construirlo.

Asi que coloquemos un miserable hola mundo de la primera leccion. O bien, el programa que quieran.

Yo voy a ir con este :)

#include <gtk/gtk.h>

int main(int argc, char * argv[])
{
	GtkWidget * ventana;
	GtkWidget * boton;

	gtk_init(&argc, &argv);
	
	ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	boton = gtk_button_new_with_label("Hola Mundo");
	
	gtk_container_add(GTK_CONTAINER(ventana), boton);
	gtk_widget_show_all(ventana);

	gtk_main();
}

Ahora, el siguiente actor : src/Makefile.am Ya que Autotools es un sistema de construccion automatica, y hemos dicho en el archivo Makefile.am, de la raiz del proyecto, que uno de los subdirectorios a ejecutar un Makefile es src/, entonces debemos tambien tener una plantilla (src/Makefile.am) para Automake.

Agreguemos lo siguiente en src/Makefile.am:

INCLUDES = -I$(top_srcdir) $(GTK_CFLAGS)

LIBS = $(GTK_LIBS)

bin_PROGRAMS = diamante

Recuerdan que AC_SUBST en Autoconf permitia reemplazar cadenas con los valores que tuvieran las variables? Las que se reemplazan son GTK_CFLAGS y GTK_LIBS.

La directiva INCLUDES indica que rutas de archivos de cabeceras agregar para compilar efectivamente un programa. Recuerdan que para compilar un programa en GTK+ era necesario usar el metodo de los backquotes para no colocar una tremenda linea?

$ gcc -o diamante.o diamante `pkg-config --cflags gtk+-2.0`

INCLUDES es equivalente.

Ahora, en INCLUDES hay ademas una variable $top_srcdir. Esa indica el directorio raiz de nuestro proyecto. Es solo en caso que usemos el archivo config.h para algo.

La directiva LIBS es la directiva para enlazar con las bibliotecas necesarias. En los ejemplos anteriores era algo asi

$ gcc -o diamante diamante.o `pkg_config --libs gtk+-2.0`

En este caso, es equivalente.

bin_PROGRAMS indica cual es el archivo binario a generar despues que se compilo el archivo. Recordar que se indica cuales archivos compilar en la directiva AC_CONFIG_SRCDIR de Autoconf :-D

De nuevo, ejecutamos automake en la raiz de nuestro proyecto.

$ automake --gnu --add-missing

Luego

$ ./configure

Y despues

$ make

Y veran que empezara a compilar el fuente que estaba en el directorio src. Excelente!

$ ls src/
diamante  diamante.c  diamante.o  Makefile  Makefile.am  Makefile.in

Perfecto! Es justo lo que necesito. Y hemos generado nuestro primer proyecto con Autotools!

Creando la distribucion de nuestro proyecto

Ahora veamos como podemos distribuirlo para colocar en nuestra pagina web y cachiporrearnos en el asado con los amigos que "publique mi primer programa en GTK+" :) .

Antes de seguir, voy a explicar algunas opciones que son basicas.

Despues de ejecutar

$ ./configure

Pueden construir el proyecto con

$ make

para construirlo.

make install

$ make install

(una vez que tengan los privilegios para instalar el programa) para instalarlo de forma que sea para todo el sistema (o bien, que todos los usuarios puedan ejecutar el programa). Requiere privilegios de superusuario.

make clean

$ make clean 

lo que hace es limpiar de los archivos de construccion y archivos resultantes de nuestro proyecto. No borra los Makefiles y podremos ejecutar make cuando queramos.

En mi caso,

$ make clean

dio el siguiente resultado:

$ make clean
Making clean in src
make[1]: Entering directory `/home/jci/code/diamante/src'
test -z "diamante" || rm -f diamante
rm -f *.o core *.core
make[1]: Leaving directory `/home/jci/code/diamante/src'
Making clean in .
make[1]: Entering directory `/home/jci/code/diamante'
make[1]: Nothing to be done for `clean-am'.
make[1]: Leaving directory `/home/jci/code/diamante'

make distclean

Lo interesante viene si quieren distribuir su proyecto. Para eso pueden usar

$ make distclean

Con make distclean, los archivos que se generan de forma automatica en el sistema de construccion son eliminados, junto con los archivos que se compilan. Asi queda nuestro proyecto sin Makefiles ni archivos de dependencias, corefiles, entre otros.

$ make distclean
make[1]: Entering directory `/home/jci/code/diamante/src'
test -z "diamante" || rm -f diamante
rm -f *.o core *.core
rm -f *.tab.c
rm -f 
rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
rm -rf ./.deps
rm -f Makefile
make[1]: Leaving directory `/home/jci/code/diamante/src'
Making distclean in .
make[1]: Entering directory `/home/jci/code/diamante'
rm -f 
rm -f config.h stamp-h1
rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
make[1]: Leaving directory `/home/jci/code/diamante'
rm -f config.status config.cache config.log configure.lineno
rm -f Makefile

make distcheck

Va a sonar a chiste, pero hay que ejecutar de nuevo

$ ./configure

Y una vez que termine, ejecutar

$ make distcheck

La opcion distcheck realiza una compilacion limpia, copia el arbol de compilacion completo en un directorio y ve si puede construir el proyecto. Si es asi, al final tendremos este lindo mensaje:

=============================================
diamante-0.1.tar.gz is ready for distribution
=============================================

Ese archivo .tar.gz podremos pasarlo a nuestros amigos, o bien respaldar donde queramos. :D

Veamos que tiene dentro...

$ tar tfz diamante-0.1.tar.gz
diamante-0.1/
diamante-0.1/aclocal.m4
diamante-0.1/AUTHORS
diamante-0.1/Makefile.am
diamante-0.1/README
diamante-0.1/install-sh
diamante-0.1/depcomp
diamante-0.1/config.h.in
diamante-0.1/INSTALL
diamante-0.1/ChangeLog
diamante-0.1/configure
diamante-0.1/src/
diamante-0.1/src/Makefile.am
diamante-0.1/src/diamante.c
diamante-0.1/src/Makefile.in
diamante-0.1/missing
diamante-0.1/Makefile.in
diamante-0.1/NEWS
diamante-0.1/mkinstalldirs
diamante-0.1/configure.ac
diamante-0.1/COPYING

La pregunta mas logica que se deben estar haciendo es "por que supo que era la version 0.1?"

Recuerdan la primera linea de AC_INIT del archivo configure.ac?

AC_INIT([Diamante], [0.1], [[email protected]], [diamante])

El segundo parametro es la version de nuestro programa.

No me creen? Cambien el valor de 0.1 a 0.2. Vuelvan a ejecutar todo en este orden:

$ autoheader
$ autoconf
$ automake --gnu --add-missing
$ make distclean
$ ./configure
$ make distcheck
...[challa]...

=============================================
diamante-0.2.tar.gz is ready for distribution
=============================================

Bonito, no?

Herramientas personales
Espacios de nombres

Variantes
Acciones
Navegación
Herramientas