Jugando con Automake para generar Makefiles automáticos

written by uve 14 December 2010

Estos días estoy empezando a implemetar un pequeño programita para un Reto Tecnológico que organiza el Departamento de Teoría de la Señal, Telemática y Comunicaciones de la Universidad de Granada. Lo estoy desarrollando en C++ y sinceramente no me apetece hacer el Makefile. Así que estoy aprendiendo a usar las Autotools de GNU, empezando por Automake.

He empezado por un ejemplo simple que está disponible aquí. Para empezar, veamos el código fuente de nuestro ejemplo:

$ cat src/main.cc
#include <config.h>
#include <iostream>

using namespace std;

int main()
{
    cout << "Prueba de Automake" << endl;
    cout << PACKAGE_STRING << endl;
    return 0;
}

Para la generación de Makefiles automáticos, debemos crear Makefiles de alto nivel. Estos Makefiles tienen extensión .am (automake). Necesitamos tener un fichero Makefile.am en el directorio raíz del proyecto y un fichero Makefile.am en cada subdirectorio con fuentes (donde haya que compilar). En este ejemplo, los fuentes están en el directorio src, por tanto necesitamos los ficheros Makefile.am y src/Makefile.am.

Para este ejemplo, todos los fuentes se resumen al fichero src/main.cc, y vamos a crear un ejecutable llamado mema. Por tanto, tendríamos los siguientes Makefiles de alto nivel:

$ cat src/Makefile.am
bin_PROGRAMS = mema
mema_SOURCES = main.cc
$ cat Makefile.am
SUBDIRS = src
dist_doc_DATA = README

Ahora vamos creamos el fichero README, que contendrá información útil acerca de como compilar y ejecutar la aplicación. Lo dejo libre para cada cual escriba lo que quiera.

Pero, ¿quién se encarga de generar un Makefile de verdad? Autoconf. A través del script configure se generarán los Makefiles necesarios para poder hacer un simple make.

Para poder generar el script configure, debemos de definir una serie de reglas para Autoconf. Esto se define en el fichero configure.ac:

$ cat configure.ac
AC_INIT([Menudo Problema], [1.0], [mantainer@miaplicacion.com])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CXX
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
Makefile
src/Makefile
])
AC_OUTPUT

Analicemos un poco este fichero:

  • AC_INIT: Indicamos el nombre de la aplicación, la versión y un correo de contacto

  • AM_INIT_AUTOMAKE: opciones utilizadas para Automake

  • AC_PROG_CXX: vamos a compilar con C++, para C debemos de usar AC_PROG_CC
  • AC_CONFIG_HEADERS: el script configure generará la lista de ficheros con una serie de #define's de la aplicación
  • AC_CONFIG_FILES: el script configure generará la lista de ficheros a través de plantillas *.in
  • AC_OUTPUT: esta línea cierra el comando actual

Una vez todo esto hecho, sólo queda generar el script configure:

$ autoreconf --install
configure.ac:2: installing `./install-sh'
configure.ac:2: installing `./missing'
src/Makefile.am: installing `./depcomp'

Ahora nuestros fuentes están listos para ser distribuidos y compliados. Vamos a ver un ejemplo de como compilar y ejecutar:

$ ./configure 
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... gawk
checking whether make sets $(MAKE)... yes
checking for g++... g++
checking whether the C++ compiler works... yes
checking for C++ compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking for style of include used by make... GNU
checking dependency style of g++... gcc3
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating config.h
config.status: executing depfiles commands

Ya está creado el Makefile. Ya podemos compilar de verdad:

$ make
make  all-recursive
make[1]: se ingresa al directorio «/home/user/prueba/automake»
Making all in src
make[2]: se ingresa al directorio «/home/user/prueba/automake/src»
g++ -DHAVE_CONFIG_H -I. -I..     -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.cc
mv -f .deps/main.Tpo .deps/main.Po
g++  -g -O2   -o mema main.o 
make[2]: se sale del directorio «/home/user/prueba/automake/src»
make[2]: se ingresa al directorio «/home/user/prueba/automake»
make[2]: se sale del directorio «/home/user/prueba/automake»
make[1]: se sale del directorio «/home/user/prueba/automake»

El Makefile generado tiene una serie de opciones estándar, como son:

  • make all
  • make install
  • make uninstall
  • make clean
  • make distclean

Una vez compilado ya podemos ejecutar nuestra aplicación:

$ src/mema 
Prueba de Automake
Menudo Problema 1.0

Si el tiempo me lo permite iré asrc/mema vanzando algo más en el tema durante estos días.

 

Tags

La teoría es cuando crees saber algo, pero no funciona.
La práctica es cuando algo funciona, pero no sabes por qué.
Los programadores combinan la teoría y la práctica:
Nada funciona y no saben por qué.