Toda a vez que eu leio Autotools eu lembro dos Autobots, não sei porque a associação. Mas esse post não é sobre isso, e talvez ele renda mais do que um post. Nas últimas semanas ajudei a migrar dois projetos que utilizavam Makefiles hand-crafted para utilizarem todo o pacote das Autotools.O primeiro passo para que a migração fosse tranquila foi ensinar os conceitos básicos das Autotools para todos os envolvidos no projeto.
Existem diversos tutoriais, livros e blogs explicando como utilizar estas ferramentas, mas a maioria exige bastante tempo para deglutir todas as informações expostas e conseguir utilizar o sistema. Para facilitar, criei uma página na wiki interna mostrando os arquivos necessários para se criar um projeto básico utilizando autotools. Este post é uma tentativa de extender este conteúdo e divulgar o uso das Autotools.
Alguns arquivos essênciais
Basicamente todo o conjunto de ferramentas necessita de dois arquivos para funcionar:
- configure.ac: diretivas para gerar o script de configuração, testar a existência de bibliotecas, headers, comandos, etc.
- Makefile.am: o que deve ser compilado, bibliotecas, binários, sub-diretórios, programas de teste, etc.
Com esses dois arquivos na raiz do projeto e mais alguns Makefile.am nos subdiretórios, é tudo o que se necessita para utilizar as Autotools. Obviamente isto é só o inicio da brincadeira, diversos detalhes devem ser adicionados para deixar o sistema de build de forma adequada ao projeto.
Aos arquivos!
configure.ac
AC_INIT([project_name],[version],[maintainer_email]) AC_CONFIG_SRCDIR([.]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign]) AM_MAINTAINER_MODE AC_PROG_LIBTOOL AC_PROG_CC AC_CONFIG_FILES([Makefile]) AC_OUTPUT
Bom, olhando assim, esses comandos parecem uma grande sopa de letrinhas, sem sentido algum. Então, como Jack faria (piada fraca, eu sei), vamos por partes. A primeira linha inicializa o autoconf, e portanto ali estão definidos o nome do projeto, a versão, e o endereço de email do mantenedor. As próximas três linhas definem configurações gerais do autoconf, como diretório onde se encontram os arquivos de source, onde devem ser guardadas e lidas as macros utilizadas pelo autoconf, e finalmente qual é o nome do arquivo de header que o autoheader irá gerar.
Destas diretivas, duas devem ser destacadas,AC_CONFIG_SRCDIR
que define qual é o diretório onde se encontram os arquivos fontes do programa, que é de escolha do programador; e a AC_CONFIG_MACRO_DIR
que define o diretório onde estão as macros do autoconf, no exemplo, os arquivos são salvos no subdiretório m4
. É importante que este diretório exista, pois caso contrário, gerará um erro quando rodarmos o autoreconf
– mais sobre esta ferramenta no final do post.
Depois de inicializado o autoconf deve-se inicializar o automake, uma vez que optamos por utilizar todo o conjunto das Autotools. As duas diretivas iniciadas em AM são responsáveis por inicializar o automake e por optar pelo modo maintainer, que evita alguns arquivos sejam refeitos quando distribuidos para o usuário final. A diretiva AC_PROG_CC
é responsável por testar a existência de um compilador C instalado no sistema. Já a AC_PROG_LIBTOOL
testa e inicializa o uso da ferramenta libtool, necessária para gerar bibliotecas.
As últimas duas linhas são extremamente importantes, e deve-se tomar bastante cuidado para que todos os arquivos que se deseja gerar após rodar um ./configure
estejam listados na diretiva AC_CONFIG_FILES
.
Makefile.am
Com o arquivo configure.ac escrito, é hora de definir o que será gerado: um programa, uma biblioteca, ambos, arquivos extras que devem ser instalados, etc. Para isso é necessário escrever as diretivas necessárias no Makefile.am.
ACLOCAL_AMFLAGS = -I m4 bin_PROGRAMS = myproject lib_LTLIBRARIES = libproject.la myproject_SOURCES = \ myproject.c \ mymem.c libproject_la_SOURCES = \ myhash.c \ mylib.c libproject_ladir = $(includedir)/libproject libproject_la_HEADERS = \ mylib.h
A primeira diretiva só adiciona a flag -I m4
quando o aclocal
é chamado, indicando qual o diretório que contêm os script m4. Se o seu projeto possuiu um hierarquia de makefiles você só precisa adicionar essa diretiva no Makefile.am da raiz do projeto.
As próximas duas linhas definem o que será gerado pelo automake. A primeira linha define os executáveis a serem gerados, já a segunda define as bibliotecas geradas pelo projeto. Para programas gerados, podemos usar alguns prefixos diferentes a diretiva PROGRAMS
como: bin
, sbin
, libexec
e pkglib
, isso instruirá o autotools o local onde o binário será instalado. Também há a opção de não instalar o programa usando o prefixo noinst
, ou ainda check
que só irá gerar o binário quando executado make check
. Para bibliotecas os prefixos possíveis são lib
, pkglib
e noinst
, seguidos da diretiva LTLIBRARIES
. O que segue após o sinal de igualdade são os nomes dos binários ou bibliotecas que serão gerados.
Para cada objeto a ser gerado é necessário definir quais são os arquivos fontes necessários. Também é possível definir flags, biblotecas, etc. específicas para cada objeto, para mais informações sobre estas outras variáveis leia aqui. O mais comum é usar a diretiva SOURCES
com uma lista de arquivos fonte necessários para gerar o objeto em questão. Para a biblioteca também foi definido o diretório de instalação dos headers (ladir
) e o header da biblioteca – necessário para outros projetos poderem linkar com a nossa biblioteca.
Com isso temos um Makefile.am
básico, hora de gerarmos os scripts de configuração.
Gerando os arquivos!
Tendo os dois arquivos no diretório do projeto (configure.ac
e Makefile.am
) é hora de gerar o script de configuração e o Makefile do projeto. Por muito tempo os diversos projetos que usam Autotools mantiveram scripts próprios para rodar as diversas ferramentas necessárias (automake, autoconf, autoheader, aclocal, etc) para gerar todo o sistema de build, os famosos scripts autogen.sh
. Atualmente não é mais necessário utilizar estes scripts, basta chamar o programa autoreconf
. Eu gosto de utilizar as flags -i, para copiar os arquivos necessários para o diretório do projeto, e -v para exibir as mensagens dos programas executados.
autoreconf -iv
Wrap up & Links
Este post talvez nunca esteja pronto, e irá evoluir aos poucos. Seguem alguns link úteis!