logo titulo
anterior indice proximo

Compilação e instalação de software


Atualmente é muito simples instalar um programa já compilado, com package managers como o pgktools, rpm, dpkg (respectivamente do Slakware, RedHat e Debian), mas o administrador de sistemas encontrará muitos programas (geralmente os mais interessantes) disponíveis somente em fonte (source code) e às vezes nem tão bem documentados assim. Entretanto, compilar um programa não é algo reservado aos gênios, quando se tem um pouco de cuidado e precaução. Tarefa mais difícil sem dúvida é a conversão de um programa projetado para outro "sabor" de Unix para o Linux. Discutiremos nesse capítulo algumas operações comumente realizadas na instalação de programas a partir dos fontes, uma habilidade que todo administrador de sistema deve ter.

Alguns conselhos iniciais:

bibliotecas (libraries)


Há alguns anos atrás o Linux usava exclusivamente bibliotecas de carga dinâmica DLL. Este tipo de biblioteca é mais complicada para se criar e não permite a modificação de um programa durante a sua execução, Para ganhar estas vantagens, foi criado um novo tipo de bibliotecas, ELF. Contudo, muitos programas ainda usam os DLLs, portanto voce encontrará em seu sistema bibliotecas que aparentam ser cópias, mas são realmente dois tipos diferentes. Os carregadores destes dois tipos de bibliotecas são o ld.so (para DLL) e ld-linux.so.1 (para ELF). Com o advento do Glibc-2 (no lugar de libc-5, mais usado atualmente), novo carregador poderá também ser encontrado o ld-linux.so.2. Glibc-2 tem suporte para internacionalização e threads [38] já incluidos na biblioteca.

Um programa pode ser executado em qualquer sistema Linux quando ele é estaticamente ligado (linked). O que acontece nesse caso? A biblioteca é incluida na forma binária para fazer parte do programa. Dá para se perceber que, desta forma, o programa fica muito maior do que ele precisaria ser, se a bilbioteca fosse carregada no sistema, ademais a memória ocupada pela biblioteca poderia ser compartilhada pelos vários programas que utilizam estas bibliotecas, resultando numa economia de memória e aumento na velocidade (menos tempo carregando bibliotecas). Por que mesmo assim se usam programas ligados estaticamente? Porque existem bibliotecas comerciais (notadamente o Motif), permitidas de serem entregues em binário junto com um programa gratuito, mas não separadamente, para carga dinàmica. Felizmente o Lesstif já está bem desenvolvido e substitui o Motif em 90% dos casos.

Para sabermos quais bibliotecas são esperadas por um programa executável, podemos usar o comando ldd <programa> e ele listará as bibliotecas com suas versões instaladas e, na mesma linha com um separador "=>" a biblioteca presente que satisfaz o requisito e sua versão corrrespondente, ou uma mensagem dizendo que ela está ausente. Veja um exemplo:

~$ ldd `which netscape`
libXt.so.6 => /usr/X11R6/lib/libXt.so.6 (0x4000c000)
libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x4004a000)
libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x40052000)
libXmu.so.6 => /usr/X11R6/lib/libXmu.so.6 (0x40066000)
libXpm.so.4 => /usr/X11R6/lib/libXpm.so.4 (0x40077000)
libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x40083000)
libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x4008d000)
libdl.so.1 => /lib/libdl.so.1 (0x4011e000)
libc.so.5 => /lib/libc.so.5 (0x40121000)
libg++.so.27 => /usr/lib/libg++.so.27 (0x401dd000)
libstdc++.so.27 => /usr/lib/libstdc++.so.27 (0x40220000)
libm.so.5 => /lib/libm.so.5 (0x40252000)

Neste exemplo, todas as bibliotecas foram encontradas e carregadas e se encontram listadas ao lado direito. Para instalar uma biblioteca necessária mas ausente, devemos copiá-la em um dos diretórios listados no arquivo /etc/ld.so.conf e em seguida executar o comando ldconfig. Opcionalmente, podemo editar o arquivo e colocar outros diretórios para o ldconfig procurar as bibliotecas, e depois re-executá-lo. Para verificar todas as bibliotecas presentes usamos, ldconfig -p.

Se um programa apresenta problemas na hora de executar, nem sempre a causa são as bibliotecas usadas. Voce poderá depurar de várias formas essa execução, mas uma maneira simples e rápida é com o programa strace. Adicione strace no início da linha de comando que voce faria normalmente e verá todos as chamadas de sistema do comando executado. Outra forma mais interessante é fazendo strace -o saida.strace <comando a executar> e depois verifique a saida armazenada no arquivo saida.strace. Quando o programa executa um fork (cria um programa filho), o strace só o capturará se for executado com as chaves -f ou -ff.

o gerador de comandos make


No pacote .tar.gz de um programa distribuido em fonte, normalmente voce encontrará um arquivo de nome Makefile. O conteúdo desse arquivo são as regras para a partir do fonte e dos compiladores instalados (não só compiladores, na realidade, também formatadores de texto, scripts em shell ou outras linguagens, macro-processadores, etc) produzir os objetos que constituirão o programa final: executáveis, man pages, outras documentações, e até scripts para a instalação automática do programa.

O Makefile (ou vários, dependendo do programa), é uma espécie de "programa" em linguagem declarativa, onde colocamos do lado esquerdo o objeto desejado e do lado direito do que ele depende, separados por ":", e na linha logo abaixo, indentado, as instruções para produzir o "alvo". Parâmetros de um make podem ser passados na linha de comando, mas é mais comum passá-los no próprio Makefile ou no environment (variáveis do shell). Quando o make é executado ele procura um arquivo de nome Makefile e o interpreta. A vantagem do make, é que ele testa a data dos alvos contra a data das dependências e só compila o que for mais antigo, salvando assim tempo na fase de desenvolvimento. Ademais, ele se presta à automação da instalação do programa.

Vejamos um exemplo de Makefile:

comentários





variáveis
(macros)






regras
#
# Makefile for tcl/tk extensions
# this is part of slidedraw
#

sldlib=libsldw.so.1.0
CC=gcc
CFLAGS=-O -fPIC -g
SHLIB_LD_LIBS= -ljpeg
SHLIB_LD=gcc
SHLIB_LD_FLAGS=-shared -Wl,-E -Wl,-soname,libsldw.so.1.0
OBJS=slide.o sldInit.o sldImage.o jpeg.o sldPs.o sldShow.o sldDrawText.o

${sldlib}: $(OBJS)
   ${SHLIB_LD} ${SHLIB_LD_FLAGS} -o $@ $(OBJS) ${SHLIB_LD_LIBS}

.c.o:
   ${CC} ${CFLAGS} -c $< -o $@

install: libsldw.so.1.0
   cp libsldw.so.1.0 /usr/local/lib
   ldconfig     

clean:
   rm -f *.o *~

distclean:
   rm -f *.o *~ libsldw.so.1.0

Voce deve procurar regras com o nome install e verificar os comandos abaixo desta regra. Os programas usualmente encontrados são o ginstall, install, ou mesmo o cp. Verifique também algum ln (cria link). Todos estes escrevem arquivos nos diretórios do seu sistema.

Entre um make e outro, voce deverá usar, de preferência make distclean. Podemos também verificar quais as operações que seriam realizadas por um make sem realmente executá-las, introduzindo make -n. (este comando irá imprimir todos os comandos na sequência correnta, mas não executará nenhum, servindo para verificação.)

portabilidade com imake e autoconf


O imake e o autconf são programas para automatizar a geração de Makefiles e assim obter maior portabilidade entre diversos sistemas operacionais. Eles tentam descobrir aonde se encontram certos arquivos (include files) que são necessários para a compilação do programa.

Um programa que utiliza o imake irá requerer que voce execute xmkmf para produzir o Makefile resultante a partir de um arquivo Imakefile que foi distribuido com o fonte do programa a ser instalado. Com o imake a configuração dependente da máquina e sistema operacional fica no seu sistema, e não no programa que está sendo distribuido, permitindo o progamador criar programas que compilam e executam numa variedade de ambientes diferentes. No Linux, o arquivo com esta configuração é o /usr/X11/lib/X11/config/Imake.tmpl.

A sequência de comandos usual para compilar e instalar um programa que é distribuido com uma Imakefile é:

~$ xmkmf
~$ make clean
~$ make depend
~$ make
~$ make install

Como imake foi criado para distribuir os programas do X-Windows, o diretório de instalação default (se a aplicação não forçar outro) para os executáveis é /usr/X11/bin. A grande maioria dos programas que usam esse método de configuração é desenvolvida para o X11, apesar dele poder ser usado com um programa qualquer.

O autoconf é um programa similar, mas muito mais difundido que o imake, com objetivo similar. Além de criar o Makefile, ele cria um arquivo para inclusão (include file) que será usado no programa fonte para definir dependências do hardware ou do sistema operacional que serão referenciadas nos programas. O programa executado na hora de compilar toma o nome de configure.

Um procedimento típico para instalar um programa que é distribuido com autoconf é o seguinte:

./configure <chaves (switches)>
make
make check
make install

revisando versões de um programa com patch


Programas muito grandes tomam tempo de download se voce os está carregando pela internet, por exemplo. Para aliviar esse problema, o autor do programa deixa disponível arquivos com patches (remendos) dos programas. Esses patches contém a informação necessária para, a partir de uma versão anterior do programa, transformar todos os fontes de modo a transformá-lo na versão mais nova. Geralmente essas diferenças são bem menores que o novo programa completo.

Os arquivos de patch são construido a partir do programa diff, que compara dois arquivos gerando um texto (opcionalmente com algumas linhas que identificam o contexto) com símbolos que indicam o que deve ser retirado e o que deve ser adicionado para converter um arquivo em um outro, após a edição. Veja um pequeno texto, o mesmo após a edição e o arquivo gerado pelo diff:

Se fizermos um estudo da história dos povos americanos,
verificamos que foi o Brasil o último daqueles países a dar 
a liberdade aos escravos.  Entretanto, a forma gradual que 
adotamos ensejou que não herdássemos um forte preconceito
racial, como nos Estados Unidos, nem mesmo um sistema de
castas que atingiu vários países hispano-americanos.  As
nossas razões históricas também foram outras.

Arquivo frase1.txt:

Se fizermos um estudo da história dos povos americanos,
verificamos que foi o Brasil o último daqueles paíse a dar 
a liberdade aos escravos.  Entretanto, a forma gradual que 
adotamos ensejou que não herdássemos um forte preconceito (discutível)
racial, como nos Estados Unidos, nem mesmo um sistema de
castas que atingiu vários países hispano-americanos.  
O problema norte-americano foi resolvido de forma
abrupta e violenta.
As nossas razões históricas também foram outras.

Diferença gerada a partir do comando diff frase.txt frase1.txt :

4c4
< adotamos ensejou que não herdássemos um forte preconceito
---
> adotamos ensejou que não herdássemos um forte preconceito (discutível)
6,7c6,9
< castas que atingiu vários países hispano-americanos.  As
< nossas razões históricas também foram outras.
---
> castas que atingiu vários países hispano-americanos.  
> O problema norte-americano foi resolvido de forma
> abrupta e violenta.
> As nossas razões históricas também foram outras.

Diferença com contexto (mais seguro de que as alterações são aplicáveis à versão corrente), resultante da execução do comando: diff -c frase.txt frase1.txt : (que chamamos de patchfile)

*** frase.txt        Sat Jan 16 23:44:16 1999
--- frase1.txt        Sat Jan 16 23:48:30 1999
***************
*** 1,7 ****
  Se fizermos um estudo da história dos povos americanos,
  verificamos que foi o Brasil o último daqueles paíse a dar 
  a liberdade aos escravos.  Entretanto, a forma gradual que 
! adotamos ensejou que não herdássemos um forte preconceito
  racial, como nos Estados Unidos, nem mesmo um sistema de
! castas que atingiu vários países hispano-americanos.  As
! nossas razões históricas também foram outras.
--- 1,9 ----
  Se fizermos um estudo da história dos povos americanos,
  verificamos que foi o Brasil o último daqueles paíse a dar 
  a liberdade aos escravos.  Entretanto, a forma gradual que 
! adotamos ensejou que não herdássemos um forte preconceito (discutível)
  racial, como nos Estados Unidos, nem mesmo um sistema de
! castas que atingiu vários países hispano-americanos.  
! O problema norte-americano foi resolvido de forma
! abrupta e violenta.
! As nossas razões históricas também foram outras.

Obs: Neste exemplo, o patchfile ficou maior do que o "fonte", e não justificaria o seu uso. Na prática, programas têm pequenas (e localizadas) alterações, em relação ao tamanho total do arquivo, o que gera um patchfile muitas vezes menor que o fonte completo.

O que o programa patch faz é, a partir de um destes arquivos transformar a versão frase.txt na versão (depois da edição) frase1.txt. Se o diff for usado na forma com contexto (segunda versão), patches de vários arquivos podem ser concatenados em um úncio arquivo e assim regenerar vários fontes (inclusive em sub-diretórios) a partir de um só patch file.

A utilização do comando patch se faz na forma:

     patch -p0 patchfile

no diretório aonde frase.txt se encontra. A chave -p0 dá como resultado o arquivo "consertado" com o mesmo path do original.


rpragana
Sat Jan 16 09:37:11 EDT 1999