Apesar de existirem algumas outras alternativas às ferramentas automáticas do GNU, o GNU Autotools ainda é o mais utilizado no mundo por motivos de confiança em relação à resultados finais. Ou seja, a experiência levou à essa estabilidade.
Infelizmente, há muita documentação obsoleta na internet sobre o Autotools e muitas reclamações sobre ferramentas automáticas, por esse motivo decidi documentar um teste moderno e bem simplista que eu criei e vou compartilhar com vocês essa experiência que fiz questão de torná-la o mais básico possível para poder alcançar o entendimento.
Mas ainda assim, não deixe de exibir exemplos que funcionem em projetos maiores, que por sinal a ideia é a mesma, só precisa ter um pouco mais de atenção nas configurações.
Todos os tópicos foram separados com Passo à Passo e Listas ordenadas para facilitar a compreensão.
O GNU Autotools , também conhecido como GNU Build System , é um conjunto de ferramentas de programação projetadas para ajudar a tornar os pacotes de código-fonte portáteis para muitos sistemas Unix .
Pode ser difícil tornar um programa de software portátil: o compilador C difere de sistema para sistema; algumas funções da biblioteca estão ausentes em alguns sistemas; arquivos de cabeçalho podem ter nomes diferentes. Uma maneira de lidar com isso é escrever código condicional, com blocos de código selecionados por meio de diretivas de pré-processador (#ifdef
); mas devido à grande variedade de ambientes de construção, essa abordagem rapidamente se torna incontrolável. O Autotools foi projetado para solucionar esse problema de maneira mais fácil.
O Autotools faz parte da cadeia de ferramentas GNU e é amplamente utilizado em muitos pacotes de software livre e de código aberto . Suas ferramentas componentes são licenciadas por software livre sob a Licença Pública Geral GNU, com exceções especiais de licença permitindo seu uso com software proprietário .
O GNU Build System possibilita a criação de muitos programas usando um processo de duas etapas: configure seguido por make .
O Autotools consiste nos programas utilitários GNU Autoconf , Automake e Libtool . Outras ferramentas relacionadas frequentemente usadas ao lado dele incluem o programa GNU make, o GNU gettext , o pkg-config e o GNU Compiler Collection , também chamada GCC/G++.
mkdir testes && cd testes
mkdir doc examples man scripts src
touch doc/README.md examples/my-example-teste.dat man/teste.1 scripts/script-teste.sh src/teste.c
# Conteúdo para o arquivo em doc/
echo "Documentação para o teste" >> doc/README.md
# Conteúdo para o arquivo em examples/
echo -e '#!/bin/bash\necho "Teste em Bash"\nexit 0' >> examples/my-example-teste.dat
# Conteúdo para o arquivo em man/
echo -e '.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.8.
.TH teste "1" "October 2019" "teste 1.1" "User Commands"
.SH NAME
teste \- Only teste for Autotools.' > man/teste.1
# Conteúdo para o arquivo em scripts/
echo -e '#!/bin/sh\nprintf "Only a teste\\n" "%s"\nexit 0' > scripts/script-teste.sh
# Conteúdo para o arquivo em src/
echo -e '#include <stdio.h>
int main(){
printf("Somente um teste para o Autotools\\n");
return 0;
}' > src/teste.c
testes/
├── doc
│ └── README.md
├── examples
│ └── my-example-teste.dat
├── man
│ └── teste.1
├── scripts
│ └── script-teste.sh
└── src
└── teste.c
5 directories, 5 files
ls ../testes/ | md5sum
ac0bacadc6861ab22a44af572b255ff1 -
configure.ac
, execute:autoscan
Foram criados os arquivos:
autoscan-2.69.log
econfigure.scan
. Onde o conteúdo de autoscan-2.69.log está vazio e o conteúdo de configure.ac é:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([src/teste.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT
configure.scan
para configure.ac
:mv configure.scan configure.ac
configure.ac
que possui as informações: AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) para os nomes do seu projeto, ex.:
AC_INIT(teste, 1.0, teste@terminalroot.com.br) . Caso deseje, use o Sed para isso, assim:sed -i 's/FULL-PACKAGE-NAME\],/teste],/g' configure.ac
sed -i 's/VERSION\],/1.0],/g' configure.ac
sed -i 's/BUG-REPORT-ADDRESS\]/teste@terminalroot.com.br]/g' configure.ac
Ou use um editor de texto de preferência, exemplo: Vim .
Ao final meu arquivo ficou assim:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([teste], [1.0], [teste@terminalroot.com.br])
AC_CONFIG_SRCDIR([src/teste.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT
configure
inicial:autoconf
Foram criados: 1 novo diretório e 1 novo arquivo:
autom4te.cache/
e oconfigure
. O conteúdo dos mesmos são extensos, oconfigure
por exemplo possui 3549 linhas.
Makefile.am
:vim Makefile.am
E insira esse conteúdo dentro:
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src doc examples man scripts
Makefile.am
só que desta vez dentro do diretório src/
:vim src/Makefile.am
E insira esse conteúdo dentro:
# what flags you want to pass to the C compiler & linker
CFLAGS = --pedantic -Wall -std=c99 -O2
# LDFLAGS =
# this lists the binaries to produce, the (non-PHONY, binary) targets in
# the previous manual Makefile
bin_PROGRAMS = teste
teste_SOURCES = teste.c
Makefile.am
só que desta vez dentro do diretório man/
:vim man/Makefile.am
E insira esse conteúdo dentro:
man_MANS = teste.1
Makefile.am
só que desta vez dentro do diretório scripts/
:vim scripts/Makefile.am
E insira esse conteúdo dentro:
bin_SCRIPTS = script-teste.sh
Makefile.am
só que desta vez dentro do diretório doc/
:vim doc/Makefile.am
E insira esse conteúdo dentro:
docdir = $(datadir)/doc/@PACKAGE@
doc_DATA = README.md
Makefile.am
só que desta vez dentro do diretório examples/
:vim examples/Makefile.am
E insira esse conteúdo dentro:
exampledir = $(datarootdir)/doc/@PACKAGE@
example_DATA = my-example-teste.dat
Abra o arquivo
vim configure.ac
E insira o conteúdo AM_INIT_AUTOMAKE(teste, 1.0), logo depois do AC_INIT([teste], [1.0], [teste@terminalroot.com.br]):
Se quiser que fique mais fácil, basta usar esse comando abaixo( Sed ):
sed -i '/AC_INIT/{p;s/.*/AM_INIT_AUTOMAKE(teste, 1.0)/;}' configure.ac
Alterando a linha que contém: AC_OUTPUT com Sed (caso deseje use um editor de texto e faça manualmente):
sed -i 's@AC_OUTPUT@AC_OUTPUT(Makefile src/Makefile doc/Makefile examples/Makefile man/Makefile scripts/Makefile)@' configure.ac
configure
e os modelos de Makefile:aclocal
Foi gerado mais um arquivo no diretório raíz do projeto, com o nome:
aclocal.m4
Makefile.in
com o argumento --add-missing
:automake --add-missing
A saída será algo similar ou igual(se usou os arquivos desse tutorial) à:
configure.ac:6: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated. For more info, see:
configure.ac:6: https://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation
configure.ac:11: installing './compile'
configure.ac:6: installing './install-sh'
configure.ac:6: installing './missing'
configure.ac:8: error: required file 'config.h.in' not found
src/Makefile.am: installing './depcomp'
src/Makefile.am:2: warning: 'CFLAGS' is a user variable, you should not override it;
src/Makefile.am:2: use 'AM_CFLAGS' instead
src/Makefile.am:3: warning: 'LDFLAGS' is a user variable, you should not override it;
src/Makefile.am:3: use 'AM_LDFLAGS' instead
Perceba a linha: configure.ac:8: error: required file ‘config.h.in’ not found , se isso aparecer também para você, rode:
autoreconf -fi
configure
:autoconf
Se quiser verificar se está tudo certo, rode o ./configure
, o make
e teste a execução do programa: cd src/ && ./teste
, a saída será: Somente um teste para o Autotools .
E se quiser instalar no sistema, rode:
Considerando que você tem o
sudo
instalado e faz parte do grupo, caso contrário omake install
só funcionará com oroot
.
./configure
make
sudo make install
A instalação vai criar alguns diretório e fazer as seguintes cópias dos arquivos para os caminhos:
/bin/mkdir -p '/usr/local/bin'
/usr/bin/install -c teste '/usr/local/bin'
/bin/mkdir -p '/usr/local/share/doc/teste'
/usr/bin/install -c -m 644 README.md '/usr/local/share/doc/teste
/bin/mkdir -p '/usr/local/share/doc/teste'
/usr/bin/install -c -m 644 my-example-teste.dat '/usr/local/share/doc/teste'
/bin/mkdir -p '/usr/local/share/man/man1'
/usr/bin/install -c -m 644 teste.1 '/usr/local/share/man/man1'
/bin/mkdir -p '/usr/local/bin'
/usr/bin/install -c script-teste.sh '/usr/local/bin'
teste
(independente do diretório que você estiver) vai obter a saída da execução do programa: Somente um teste para o Autotools;script-teste.sh
(independente do diretório que você estiver) vai obter a saída da execução do programa: Only a teste;info teste
ou man teste
(independente do diretório que você estiver) vai obter o manual;cat /usr/local/share/doc/teste/README.md
;cat /usr/local/share/doc/teste/my-example-teste.dat
.Para desinstalar precisará estar no diretório de testes/
e rode o comando:
sudo make uninstall
Absolutamente TUDO será desinstalado, a saída será similar/igual:
marcos@gentoo ~/testes $ sudo make uninstall
Senha:
Making uninstall in src
make[1]: Entering directory '/home/marcos/testes/src'
( cd '/usr/local/bin' && rm -f teste )
make[1]: Leaving directory '/home/marcos/testes/src'
Making uninstall in doc
make[1]: Entering directory '/home/marcos/testes/doc'
( cd '/usr/local/share/doc/teste' && rm -f README.md )
make[1]: Leaving directory '/home/marcos/testes/doc'
Making uninstall in examples
make[1]: Entering directory '/home/marcos/testes/examples'
( cd '/usr/local/share/doc/teste' && rm -f my-example-teste.dat )
make[1]: Leaving directory '/home/marcos/testes/examples'
Making uninstall in man
make[1]: Entering directory '/home/marcos/testes/man'
( cd '/usr/local/share/man/man1' && rm -f teste.1 )
make[1]: Leaving directory '/home/marcos/testes/man'
Making uninstall in scripts
make[1]: Entering directory '/home/marcos/testes/scripts'
( cd '/usr/local/bin' && rm -f script-teste.sh )
make[1]: Leaving directory '/home/marcos/testes/scripts'
make[1]: Entering directory '/home/marcos/testes'
make[1]: Nothing to be done for 'uninstall-am'.
make[1]: Leaving directory '/home/marcos/testes'
marcos@gentoo ~/testes $
Caso deseje ver funcionando tudo que fizemos aqui, use arquivos pré-prontos ou execute um script simples de Bash:
git clone https://github.com/terroo/gnu-autotools
cd gnu-autotools/
E use os arquivos de ambiente já pré-criados: gnu-autotools/testes/
ou simplesmente rode o script que cria os arquivos do zero: ./gnu-autotools.sh
Ou gere tudo inclusive os comandos do Autotools via script com o arquivo: ./gnu-autotools-full.sh
Em resumo o GNU Autotools :
autoscan
tenta produzir uma arquivo configure.ac
correto pela execução de analises simples nos arquivos do pacote;autoconf
produz dois arquivos: autom4te.cache
e o configure
;autom4te.cache
é um diretório usado para acelerar o trabalho das ferramentas, e pode ser removido quando o pacote for liberado;configure
é o script shell que é chamado pelos usuários finais. Nesse ponto, o que o arquivo configure faz é somente checar por dependências como sugerido pelo autoscan, então nada muito conclusivo ainda;automake
o autoconf
. O automake
gera alguns “modelos” que os scripts gerados pelo autoconf
traduzirão nos Makefiles. Um arquivo makefile inicial é necessário na raiz do pacote: ./Makefile.am;automake
assumirá. O modo “foreign” significa não GNU, e é comum ser usado;Makefile.am
para cada um desses diretórios. O automake
irá passar por casa um deles para produzir o arquivo Makefile.in
correspondente. Esses arquivos *.in
serão usados pelos scripts do autoconf
para produzir os arquivos Makefile
finais.src/Makefile.am
definimos todos os arquivos que serão criados e compilados. Em geral, os sufixos em letras maiúsculas como “_PROGRAMS” são chamados primary e dizem parcialmente o que executar no seu argumento; os prefixos, em letras minúsculas (não tem um nome pré-fixado) dizem o diretório onde será instalado. Para informar diversos arquivos, usa-se assim mais ou menos:# what flags you want to pass to the C compiler & linker
CFLAGS = --pedantic -Wall -std=c99 -O2
LDFLAGS =
# this lists the binaries to produce, the (non-PHONY, binary) targets in
# the previous manual Makefile
bin_PROGRAMS = targetbinary1 targetbinary2 [...] targetbinaryN
targetbinary1_SOURCES = targetbinary1.c myheader.h [...]
targetbinary2_SOURCES = targetbinary2.c
.
.
targetbinaryN_SOURCES = targetbinaryN.c
scripts/
geralmente possuem o Shell Script que irá chamar o executável, bem como modelos de autocomplete(compgen) de parâmetros. Utilizamos um conteúdo de exemplo, mas o certo mesmo seria assim (exemplo do script do Firefox):#!/bin/sh
unset LD_PRELOAD
LD_LIBRARY_PATH="/usr/lib64/apulse:/opt/firefox/" \
GTK_PATH=/usr/lib64/gtk-3.0/ \
exec /opt/firefox/firefox "$@"
Ou seja, ele chamará o executável que foi compilado e instalado em /opt
no seu devido diretório ;
aclocal
cria as ferramentas que geram cada script gera o arquivo aclocal.m4
que contém macros para as coisas do automake
;automake
lê o configure.ac
e o Makefile.a
m, interpreta-os e, para cada Makefile.am
produz um Makefile.in
. O argumento --add-missing
diz ao automake
para fornecer scripts padrão para qualquer erro reportado, assim pode ser omitido nas próximas execuções;autoreconf
(usado para regularizar a falta de config.h.in
) compila todas as ferramentas relevantes na ordem correta e instala os arquivos ausentes. Os parâmetros -f
(considera que tudo está obsoleto e força a reconfiguração) e -i
(faz uma cópia de arquivos auxiliares presentes no sistema para seu projeto, chama o autoheader
) . Ainda poderíamos unir ao parâmetro -v
ficando -vfi
para ver os detalhes dos procedimentos.
autotools
→ autoscan
(configure.scan) → configure.ac
→ autoconf
(autom4te.cache e configure inicial) → Makefile.am
(*
) → aclocal
(aclocal.m4) → automake
(Makefile.in) → autoreconf
(config.h.in/header
) → autoconf(./configure
) → Makefile
(make && make install)
gnu autotools make linguagemc cpp