ProgramacionGTKenC/CapituloVII

De Wiki GNOME Chile
(Diferencias entre revisiones)
Saltar a: navegación, buscar
Línea 78: Línea 78:
 
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
 
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
+
<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.
 
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.
Línea 88: Línea 88:
 
Por ejemplo,  
 
Por ejemplo,  
  
AC_SUBST(CFLAGS)
+
<pre>AC_SUBST(CFLAGS)</pre>
  
 
CFLAGS es una variable que contiene, por ejemplo, el siguiente valor:  
 
CFLAGS es una variable que contiene, por ejemplo, el siguiente valor:  
  
-l -g -d --march="i686"  
+
<pre>-l -g -d --march="i686" </pre>
  
 
Si existe algo asi en el Makefile.in
 
Si existe algo asi en el Makefile.in
  
CFLAGS=$(CFLAGS)
+
<pre>CFLAGS=$(CFLAGS)</pre>
  
 
sera reemplazado asi
 
sera reemplazado asi
  
CFLAGS=-l -g -d --march="i686"
+
<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
 
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
Línea 106: Línea 106:
 
Hasta el momento, tengo creado un directorio con los siguientes archivos:
 
Hasta el momento, tengo creado un directorio con los siguientes archivos:
 
       .
 
       .
./configure.ac
+
<pre>./configure.ac
 
./src
 
./src
./src/diamante.c
+
./src/diamante.c</pre>
  
 
Por el momento no me voy a preocupar por los archivos faltantes, ya que no son necesarios para el proyecto.
 
Por el momento no me voy a preocupar por los archivos faltantes, ya que no son necesarios para el proyecto.
Línea 114: Línea 114:
 
Ahora, necesito que algunas plantillas (.m4) se copien al directorio de mi proyecto. Lo puedo hacer con aclocal:
 
Ahora, necesito que algunas plantillas (.m4) se copien al directorio de mi proyecto. Lo puedo hacer con aclocal:
  
$ aclocal
+
<pre>$ aclocal</pre>
  
 
lo que copiara un archivo llamado aclocal.m4
 
lo que copiara un archivo llamado aclocal.m4
Línea 120: Línea 120:
 
Luego, ejecutar autoheader, para que cree automaticamente el archivo config.h.in
 
Luego, ejecutar autoheader, para que cree automaticamente el archivo config.h.in
  
$ autoheader
+
<pre>$ autoheader</pre>
  
 
Ahora, ejecutar  
 
Ahora, ejecutar  
  
$ automake --add-missing --gnu
+
<pre>$ automake --add-missing --gnu</pre>
  
 
La salida sera la siguiente:
 
La salida sera la siguiente:
  
configure.ac: installing `./install-sh'
+
<pre>configure.ac: installing `./install-sh'
 
configure.ac: installing `./mkinstalldirs'
 
configure.ac: installing `./mkinstalldirs'
configure.ac: installing `./missing'
+
configure.ac: installing `./missing'</pre>
  
 
Ahora, ejecutemos autoconf
 
Ahora, ejecutemos autoconf
  
$ autoconf
+
<pre>$ autoconf</pre>
  
 
Y listo. Tendremos un configure limpiecito.
 
Y listo. Tendremos un configure limpiecito.
Línea 140: Línea 140:
 
ALTO! Veamos que pasa al ejecutar ./configure
 
ALTO! Veamos que pasa al ejecutar ./configure
  
$ ./configure
+
<pre>$ ./configure
 
[...challa...]
 
[...challa...]
 
configure: creating ./config.status
 
configure: creating ./config.status
config.status: error: cannot find input file: Makefile.in
+
config.status: error: cannot find input file: Makefile.in</pre>
  
 
Hmmm...Makefile.in...de donde vendra eso?
 
Hmmm...Makefile.in...de donde vendra eso?
Línea 155: Línea 155:
 
Veamos las ultimas lineas del archivo configure.ac:
 
Veamos las ultimas lineas del archivo configure.ac:
  
AC_OUTPUT([
+
<pre>AC_OUTPUT([
 
Makefile
 
Makefile
 
src/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.
 
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.
Línea 164: Línea 164:
 
Creamos entonces un Makefile.am en el directorio raiz:
 
Creamos entonces un Makefile.am en el directorio raiz:
  
$ touch Makefile.am
+
<pre>$ touch Makefile.am</pre>
  
 
y volvemos a ejecutar
 
y volvemos a ejecutar
  
$ automake --gnu --add-missing
+
<pre>$ automake --gnu --add-missing</pre>
  
 
La salida es un poco mas larga que la vez anterior:
 
La salida es un poco mas larga que la vez anterior:
  
Makefile.am: installing `./COPYING'
+
<pre>Makefile.am: installing `./COPYING'
 
Makefile.am: installing `./INSTALL'
 
Makefile.am: installing `./INSTALL'
 
Makefile.am: required file `./NEWS' not found
 
Makefile.am: required file `./NEWS' not found
 
Makefile.am: required file `./README' not found
 
Makefile.am: required file `./README' not found
 
Makefile.am: required file `./AUTHORS' not found
 
Makefile.am: required file `./AUTHORS' not found
Makefile.am: required file `./ChangeLog' 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:
 
Me indica que los archivos NEWS, README, AUTHORS y ChangeLog no existen. Creemos estos archivos en blanco:
  
$ touch NEWS README AUTHORS ChangeLog
+
<pre>$ touch NEWS README AUTHORS ChangeLog</pre>
  
 
No es necesario volver a ejecutar automake, ya que no hemos modificado Makefile.am
 
No es necesario volver a ejecutar automake, ya que no hemos modificado Makefile.am
Línea 187: Línea 187:
 
Ahora, un configure nuevamente:
 
Ahora, un configure nuevamente:
  
$ ./configure
+
<pre>$ ./configure</pre>
  
 
Esta vez, magicamente, funciono. Sin ningun error. Pero aun falta.  
 
Esta vez, magicamente, funciono. Sin ningun error. Pero aun falta.  
Línea 195: Línea 195:
 
Por el momento esta vacio. Pero agreguemos lo siguiente en el
 
Por el momento esta vacio. Pero agreguemos lo siguiente en el
  
----Makefile.am-----
+
<pre>SUBDIRS=src</pre>
SUBDIRS=src
+
----Makefile.am-----
+
  
 
La directiva SUBDIRS indica a Automake cuales subdirectorios seguir una vez que termine con el make del directorio raiz. Por ejemplo, si hubiera puesto
 
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
+
<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.
 
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.
Línea 207: Línea 205:
 
Volvamos a ejecutar automake
 
Volvamos a ejecutar automake
  
$ automake --gnu --add-missing
+
<pre>$ automake --gnu --add-missing</pre>
  
 
Y ahora
 
Y ahora
  
$ ./configure
+
<pre>$ ./configure</pre>
  
 
Si todo va bien, ejecutemos
 
Si todo va bien, ejecutemos
  
$ make
+
<pre>$ make</pre>
  
 
Deberia pasar el proyecto sin ningun problema. Mi salida fue la siguiente:
 
Deberia pasar el proyecto sin ningun problema. Mi salida fue la siguiente:
  
$ make
+
<pre>$ make
 
make  all-recursive
 
make  all-recursive
 
make[1]: Entering directory `/home/jci/code/diamante'
 
make[1]: Entering directory `/home/jci/code/diamante'
Línea 228: Línea 226:
 
make[2]: Entering directory `/home/jci/code/diamante'
 
make[2]: Entering directory `/home/jci/code/diamante'
 
make[2]: Leaving directory `/home/jci/code/diamante'
 
make[2]: Leaving directory `/home/jci/code/diamante'
make[1]: Leaving directory `/home/jci/code/diamante'
+
make[1]: Leaving directory `/home/jci/code/diamante'</pre>
  
 
Perfecto, nuestro sistema esta casi listo.
 
Perfecto, nuestro sistema esta casi listo.
Línea 238: Línea 236:
 
Yo voy a ir con este :)
 
Yo voy a ir con este :)
  
-----diamante.c
+
<pre>#include <gtk/gtk.h>
 
+
#include <gtk/gtk.h>
+
  
 
int main(int argc, char * argv[])
 
int main(int argc, char * argv[])
Línea 256: Línea 252:
  
 
gtk_main();
 
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 (Makefile.am) para Automake.
 
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 (Makefile.am) para Automake.
Línea 262: Línea 258:
 
Agreguemos lo siguiente en src/Makefile:
 
Agreguemos lo siguiente en src/Makefile:
  
---src/Makefile.am
+
<pre>INCLUDES = -I$(top_srcdir) $(GTK_CFLAGS)
INCLUDES = -I$(top_srcdir) $(GTK_CFLAGS)
+
  
 
LIBS = $(GTK_LIBS)
 
LIBS = $(GTK_LIBS)
  
bin_PROGRAMS = diamante
+
bin_PROGRAMS = diamante</pre>
----src/Makefile.am
+
  
 
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.
 
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.
Línea 274: Línea 268:
 
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?
 
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`
+
<pre>$ gcc -o diamante.o diamante `pkg-config --cflags gtk+-2.0`</pre>
  
 
INCLUDES es equivalente.  
 
INCLUDES es equivalente.  
Línea 282: Línea 276:
 
La directiva LIBS es la directiva para enlazar con las bibliotecas necesarias. En los ejemplos anteriores era algo asi
 
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`
+
<pre>$ gcc -o diamante diamante.o `pkg_config --libs gtk+-2.0`</pre>
  
 
En este caso, es equivalente.  
 
En este caso, es equivalente.  
Línea 288: Línea 282:
 
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
 
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  
+
De nuevo, ejecutamos automake en la raiz de nuestro proyecto.
  
$ automake --gnu --add-missing
+
<pre>$ automake --gnu --add-missing</pre>
  
 
Luego
 
Luego
  
$ ./configure
+
<pre>$ ./configure</pre>
  
 
Y despues
 
Y despues
  
$ make
+
<pre>$ make</pre>
  
 
Y veran que empezara a compilar el fuente que estaba en el directorio src. Excelente!
 
Y veran que empezara a compilar el fuente que estaba en el directorio src. Excelente!
  
$ ls src/
+
<pre>$ ls src/
diamante  diamante.c  diamante.o  Makefile  Makefile.am  Makefile.in
+
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!
 
Perfecto! Es justo lo que necesito. Y hemos generado nuestro primer proyecto con Autotools!
  
---Creando la distribucion de nuestro proyecto.
+
==Creando la distribucion de nuestro proyecto==
  
 
Ahora veamos como podemos distribuirlo para colocarlo en nuestra pagina web y cachiporrearnos en el asado con los amigos que "publique mi primer programa en GTK+" :) . Para eso, primero debemos limpiar absolutamente todo.
 
Ahora veamos como podemos distribuirlo para colocarlo en nuestra pagina web y cachiporrearnos en el asado con los amigos que "publique mi primer programa en GTK+" :) . Para eso, primero debemos limpiar absolutamente todo.
Línea 313: Línea 307:
 
No, no es borrar todo. Debemos sacar rastros de los Makefiles existentes. Para eso, una vez que ejecuten
 
No, no es borrar todo. Debemos sacar rastros de los Makefiles existentes. Para eso, una vez que ejecuten
  
$ ./configure
+
<pre>$ ./configure</pre>
  
 
por enesima vez :) ejecuten  
 
por enesima vez :) ejecuten  
  
$ make
+
<pre>$ make
$ make distclean
+
$ make distclean</pre>
  
 
Con make distclean, los archivos que se generan de forma automatica en el sistema de construccion son eliminados. Asi queda nuestro proyecto sin Makefiles ni archivos de dependencias, etc.  
 
Con make distclean, los archivos que se generan de forma automatica en el sistema de construccion son eliminados. Asi queda nuestro proyecto sin Makefiles ni archivos de dependencias, etc.  
  
$ make distclean
+
<pre>$ make distclean
 
make[1]: Entering directory `/home/jci/code/diamante/src'
 
make[1]: Entering directory `/home/jci/code/diamante/src'
 
test -z "diamante" || rm -f diamante
 
test -z "diamante" || rm -f diamante
Línea 339: Línea 333:
 
make[1]: Leaving directory `/home/jci/code/diamante'
 
make[1]: Leaving directory `/home/jci/code/diamante'
 
rm -f config.status config.cache config.log configure.lineno
 
rm -f config.status config.cache config.log configure.lineno
rm -f Makefile
+
rm -f Makefile</pre>
  
 
Va a sonar a chiste, pero hay que ejecutar de nuevo
 
Va a sonar a chiste, pero hay que ejecutar de nuevo
  
$ ./configure
+
<pre>$ ./configure</pre>
  
 
Y una vez que termine, ejecutar
 
Y una vez que termine, ejecutar
  
$ make distcheck
+
<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:
 
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
 
diamante-0.1.tar.gz is ready for distribution
=============================================
+
=============================================</pre>
  
 
Ese archivo .tar.gz podremos pasarselos a nuestros amigos, o bien respaldarlo donde queramos. :D
 
Ese archivo .tar.gz podremos pasarselos a nuestros amigos, o bien respaldarlo donde queramos. :D
Línea 359: Línea 353:
 
Veamos que tiene dentro...
 
Veamos que tiene dentro...
  
$ tar tfz diamante-0.1.tar.gz
+
<pre>$ tar tfz diamante-0.1.tar.gz
 
diamante-0.1/
 
diamante-0.1/
 
diamante-0.1/aclocal.m4
 
diamante-0.1/aclocal.m4
Línea 380: Línea 374:
 
diamante-0.1/mkinstalldirs
 
diamante-0.1/mkinstalldirs
 
diamante-0.1/configure.ac
 
diamante-0.1/configure.ac
diamante-0.1/COPYING
+
diamante-0.1/COPYING</pre>
 
+
 
+
  
 
La pregunta mas logica que se deben estar haciendo es "por que supo que era la version 0.1?"
 
La pregunta mas logica que se deben estar haciendo es "por que supo que era la version 0.1?"
Línea 388: Línea 380:
 
Recuerdan la primera linea de AC_INIT del archivo configure.ac?
 
Recuerdan la primera linea de AC_INIT del archivo configure.ac?
  
AC_INIT([Diamante], [0.1], [[email protected]], [diamante])
+
<pre>AC_INIT([Diamante], [0.1], [[email protected]], [diamante])</pre>
  
 
El segundo parametro es la version de nuestro programa.
 
El segundo parametro es la version de nuestro programa.
Línea 394: Línea 386:
 
No me creen? Cambien el valor de 0.1 a 0.2. Vuelvan a ejecutar todo en este orden:
 
No me creen? Cambien el valor de 0.1 a 0.2. Vuelvan a ejecutar todo en este orden:
  
$ autoheader
+
<pre>$ autoheader
 
$ autoconf
 
$ autoconf
 
$ automake --gnu --add-missing
 
$ automake --gnu --add-missing
Línea 404: Línea 396:
 
=============================================
 
=============================================
 
diamante-0.2.tar.gz is ready for distribution
 
diamante-0.2.tar.gz is ready for distribution
=============================================
+
=============================================</pre>
  
 
Bonito, no?
 
Bonito, no?

Revisión de 06:33 28 jul 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 con el sistema de construccion, son solamente una manera de prevenir problemas con las licencias e indicar los autores, entre otros.

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 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

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

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, ya que no son necesarios para el proyecto.

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

Por el momento 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 (Makefile.am) para Automake.

Agreguemos lo siguiente en src/Makefile:

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 colocarlo en nuestra pagina web y cachiporrearnos en el asado con los amigos que "publique mi primer programa en GTK+" :) . Para eso, primero debemos limpiar absolutamente todo.

No, no es borrar todo. Debemos sacar rastros de los Makefiles existentes. Para eso, una vez que ejecuten

$ ./configure

por enesima vez :) ejecuten

$ make
$ make distclean

Con make distclean, los archivos que se generan de forma automatica en el sistema de construccion son eliminados. Asi queda nuestro proyecto sin Makefiles ni archivos de dependencias, etc.

$ 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

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 pasarselos a nuestros amigos, o bien respaldarlo 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