% JLdL 14Sep02.
%	Copyright (C) 2000-2002 by Jorge L. deLyra.
% Mail: <delyra@latt.if.usp.br>. Web: "http://latt.if.usp.br".
% Este documento pode ser copiado e/ou distribuído livremente.
% Ver os termos e condições nos arquivos do sub-diretório web/.
% This document may be copied and/or distributed freely. See the
% _ terms and conditions in the files in the web/ subdirectory.

\documentclass[12pt]{article}
\usepackage[brazil]{babel}\usepackage[latin1]{inputenc}

\title{ {\huge\bf FMA 215} \\ Aula 16: Automação de Procedimentos}

\author{Arnaldo G. de Oliveira F. \\ e \\ Jorge L. deLyra}

\date{16 de Setembro de 2002}

\begin{document}\maketitle

\section{Alguns Conceitos Relevantes}

 Vimos anteriormente o uso de programação de linha de comando e de shell
 scripts para a execução de tarefas repetitivas. Esses recursos são muito
 flexíveis porque há no Linux um grande número de programas que executam
 pequenas tarefas e que, combinados de forma adequada, podem executar
 sequências extensas de operações. Há situações, por outro lado, em que
 não só queremos executar certos conjuntos de tarefas, como também que
 sejam verificadas certas condições prévias para a sua realização. Por
 exemplo, para que seja criado um arquivo binário executável é necessário
 que exista antes um arquivo texto com o código fonte escrito em alguma
 linguagem de programação, de forma que este possa ser processado pelo
 compilador adequado para gerar o executável. Assim, a condição para a
 criação do executável é a existência de um arquivo com o código fonte.

 A ferramenta apropriada para lidar com esse tipo de situação é o comando
 {\tt make}. Esse comando lê um arquivo chamado {\tt Makefile}, escrito
 com uma sintaxe simples, que contém as instruções de como executar as
 tarefas desejadas. A estrutura do {\tt make} é baseada em três elementos
 básicos: o {\bf alvo} ({\bf ``target''}); um conjunto de {\bf
 dependências}; um conjunto de {\bf regras} ({\bf ``rules''}) de como
 produzir o alvo a partir das dependências. O alvo é, em geral, um arquivo
 a ser construído; no caso do exemplo acima, que será nosso exemplo nas
 tarefas, o alvo é o arquivo binário executável. As dependências são
 arquivos que devem existir previamente para que se possa gerar o alvo. As
 regras são as tarefas ou operações específicas sobre as dependências que
 geram o alvo. Essas regras podem ser operações de linha de comando,
 scripts ou programas, ou seja, todo o conjunto de elementos que já vimos
 antes.

\subsection{Estrutura Básica de uma {\tt Makefile}}

 Um exemplo da estrutura básica da tríade alvo -- dependência -- regra de
 uma Makefile é dado a seguir. Note que vários destes blocos básicos podem
 ser encadeados para codificar relações mais complexas de dependência
 entre muitos arquivos diferentes. Basta que uma das dependências de uma
 regra seja, além disso, o alvo de uma outra regra. O {\tt make} percorre
 recursivamente todas as relações de dependência contidas na {\tt
 Makefile}, até poder decidir que arquivos devem ou não ser refeitos.

\input{aula-16-verbatim01.tex}

\noindent
 O que está antes do sinal ``{\tt :}'' é o alvo, o que vem depois é uma
 lista de dependências separadas por espaços. As linhas de regra, contendo
 uma regra cada uma, vêm a seguir. Note o espaço em branco no início de
 cada uma destas linhas. Este é um importante elemento da sintaxe da {\tt
 Makefile}: trata-se na realidade de um caracter ``{\tt TAB}''. Linhas
 contendo regras devem sempre ser iniciadas por um {\tt TAB}, que {\em
 não} pode ser substituído por um conjunto de 8 espaços em branco.

 Cada linha de uma regra na {\tt Makefile} será executada por uma shell,
 sendo que por default é usada a {\tt bash}. Note que cada linha é
 executada por um processo de shell {\em independente} dos outros, de
 forma que o conjunto das regras que seguem uma linha de alvo e
 dependências {\em não} forma um shell script, pois neste todas as linhas
 são executadas pelo {\em mesmo} processo de shell. Se quisermos que um
 script longo e complexo seja executado como um bloco em uma regra, a
 opção mais apropriada é escrever o script em um arquivo executável
 separado e executá-lo como uma das linhas de regra. Só podemos incluir
 diretamente um script na {\tt Makefile} se o escrevermos na forma de uma
 única linha, o que em geral não é muito conveniente.

 A verificação da relação entre o alvo e as dependências é mais complexa
 do que aparenta até aqui, pois não é só a existência ou não dos arquivos
 que conta. Além disso o comando {\tt make} verifica quais as {\em datas}
 em que foram criados ou modificados pela última vez os diversos arquivos
 envolvidos para decidir se realiza ou não as operações que recriam o alvo
 a partir das dependências. Assim, se a data da última modificação de
 algum dos arquivos que constam nas dependências for mais recente do que a
 data correspondente do alvo, o comando {\tt make} repete as regras para a
 confecção deste. Se a data das dependências for anterior à do alvo, o
 comando {\tt make} nada faz.

 O comando {\tt make} contém muitos elementos adicionais de sintaxe, que o
 tornam extremamente poderoso e flexível. Não pretendemos esgotar aqui
 todos estes elementos, mas vale a pena mencionar alguns dos mais
 importantes e mais utilizados. Um destes elementos é o uso de variáveis
 dentro da {\tt Makefile}, as quais são também chamados de {\bf macros}.
 Trata-se, na realidade, de variáveis de environment. O programa {\tt
 make} herda da sessão que o inicia todo o conjunto de variáveis de
 environment, que ele pode utilizar internamente. Além disso, podemos
 acrescentar a este conjunto de variáveis herdadas novas variáveis que são
 definidas dentro da {\tt Makefile}, sempre em letras maiúsculas, como é
 próprio para variáveis de environment. Estas variáveis são úteis para
 evitar repetições desnecessárias de conjuntos de nomes de arquivos ou
 comandos, à maneira do uso destas variáveis em shell scripts. Um exemplo
 simples da estrutura global de uma {\tt Makefile} é dado abaixo, com os
 elementos mais comuns.

\input{aula-16-verbatim02.tex}

\noindent
 Inicialmente, definimos as variáveis auxiliares {\tt VARIAVEL1} e {\tt
 VARIAVEL2}. A seguir, são definidos os alvos {\tt alvo1} e {\tt alvo2},
 separados por dois pontos (``{\tt :}'') de suas respectivas dependências;
 algumas dessas dependências são definidas pelas variáveis previamente
 definidas. Observe que, nesse exemplo, tanto o {\tt alvo1} quanto o {\tt
 alvo2} dependem do conteúdo definido pela {\tt VARIAVEL1}. Na linha
 seguinte a cada alvo, são definidas as regras; é importante lembrar que o
 espaço entre o começo da linha e cada {\tt regra} é dado por um caracter
 de tabulação, isto é, deve-se sempre digitar um {\tt TAB} no início da
 linha de definição de cada regra.

 Outro conceito muito útil é o de {\bf variáveis automáticas}. Estas são
 variáveis especiais da {\tt Makefile}, com sua sintaxe própria, que
 permitem que o comando {\tt make} reconheça certos padrões gerais de
 nomes que estão envolvidos numa determinada regra como alvos ou
 dependências. São úteis em particular a variável {\tt \$@}, que
 representa o alvo envolvido na regra, a variável {\tt \$<} que representa
 o primeiro elemento da lista de dependências, bem como a variável {\tt
 \$+} que representa o conjunto das dependências. Estas estruturas tornam
 mais sintética a descrição das regras, como é ilustrado abaixo num caso
 um tanto trivial.

\input{aula-16-verbatim03.tex}

\noindent
 Além disso, há também algumas estruturas de controle que podem ser usadas
 dentro da {\tt Makefile}, bem como uma sintaxe especial usando o símbolo
 {\tt \%} dentro dos alvos e das dependências, o que permite a criação de
 regras especiais chamadas {\bf ``pattern rules''}. Estas regras especiais
 baseadas no reconhecimento de ``patterns'' têm uma aplicação muito geral,
 ampla e flexível. Elas tornam a escrita da {\tt Makefile} muito mais
 simples e sintética, pois codificam em uma única regra um grande conjunto
 de regras que satisfazem a um ``pattern'' definido, como veremos nas
 tarefas. Elas são de particular utilidade se combinadas com as variáveis
 especiais que mencionamos acima. Há inclusive uma variável especial de
 grande utilidade que é específica para este tipo de regra, a variável
 {\tt \$*} que representa a parte do ``pattern'' comum entre o alvo e as
 dependências.

 Observe que, apesar de que o comando {\tt make} foi criado no Unix para
 auxiliar no desenvolvimento e manutenção de projetos grandes e complexos
 de software, geralmente utilizando a linguagem C, a sua utilidade não se
 limita, em absoluto, a este tipo de uso. Só para dar alguns outros
 exemplos de nossa experiência imediata: estas apostilas são desenvolvidas
 e mantidas através do uso do {\tt make}, inclusive para manter atualizada
 a versão em HTML que se encontra na home-page da disciplina; toda a
 pesquisa de nosso pequeno grupo de pesquisa é baseada em uma coleção de
 programas, escritos primordialmente em Fortran, que são mantidos e
 desenvolvidos através do {\tt make}; o livro-texto sobre Teoria Quântica
 de Campos na Rede, que pode ser encontrado na home-page de nosso grupo, é
 escrito e mantido através de uma estrutura bastante complexa de {\tt
 make}.

 Pode-se entender uma {\tt Makefile} como uma forma de registro para a
 solução de um problema. Quando tentamos resolver o problema de como fazer
 uma determinada coisa no sistema, vamos descobrindo por tentativa e erro
 as relações relevantes e as operações necessárias para resolver cada
 parte do problema. A {\tt Makefile} funciona como um registro ativo das
 relações de dependência e da sequência de operações que resolve o
 problema. Mesmo muito tempo depois da sua formulação, a leitura de uma
 {\tt Makefile} nos recorda rapidamente e com precisão da solução que
 havíamos encontrado anteriormente para resolver o problema de como fazer
 uma determinada coisa no sistema.

\section{Tarefas}

 Nestas tarefas vamos comparar a utilidade do {\tt make} com a de um shell
 script convencional, cuja estrutura já conhecemos. Construiremos uma {\tt
 Makefile} para a compilação de um programa escrito em Fortran, começando
 com uma de estrutura bem simples e incluindo nela, aos poucos, várias das
 estruturas mais importantes suportadas pelo comando {\tt make}.

\begin{enumerate}

 \item Vamos inicialmente criar um ``shell script'' capaz de compilar um
 programa escrito em várias subrotinas, separadas em arquivos diferentes.
 Para isso, use um browser para copiar o arquivo

 {\tt http://latt.if.usp.br/fma215/materiais/aula-16/decmat.tgz}

\noindent
 dentro de um diretório de trabalho de temporário com o nome, digamos,
 {\tt makeaula}. Entre no diretório {\tt makeaula} e dê o comando

 {\tt tar xzvf decmat.tgz}

\noindent
 Dê um {\tt ls -l} e verifique que foi criado o seguinte conjunto de
 arquivos:

\input{aula-16-verbatim04.tex}

 \item Crie o script {\tt comp.tcsh}, dado abaixo. Esse script verifica
 que existem os arquivos Fortran, compila cada arquivo {\tt *.f} gerando
 seu correspondente objeto binário {\tt *.o} e, então, cria o executável.

\input{aula-16-verbatim05.tex}

 Dê um {\tt ls -l}, verifique que o script pode ser executado, altere as
 autorizações do arquivo com {\tt chmod} se necessário e rode-o. Dê o
 comando {\tt file *} para identificar cada arquivo criado e verificar que
 são o que esperamos.

 Observe que {\em todas} as operações são efetuadas {\em toda vez} que o
 script for executado, independentemente de existir ou não o executável, o
 que poderia tomar muito tempo caso o programa contivesse muitos módulos.
 Para eliminar essa redundância de operações, seria necessário
 acrescentar-se ao script uma série de ``{\tt if}s'' condicionais que
 verificassem quais módulos já foram compilados e quais deveriam ser
 refeitos, o que aumentaria muito a complexidade do script.

 \item Vamos criar agora uma {\tt Makefile} bastante simples, com as
 regras necessárias apenas para a compilação de nosso programa, como no
 script acima. Crie o arquivo abaixo (sem autorização de execução pois não
 se trata de um executável) com o nome {\tt Makefile}.

\input{aula-16-verbatim06.tex}

 Para efetuar a compilação, simplesmente execute o comando {\tt make}.
 Esse comando procurará automaticamente um arquivo {\tt Makefile} no
 diretório corrente. Se não houver tal arquivo, o comando terminará com
 uma mensagem de erro. Se o arquivo tiver outro nome, rode o comando

 {\tt make -f <nome\_da\_makefile>}

\noindent
 Como padrão, o {\tt make} busca o primeiro alvo (``target''), determina
 as suas dependências e tenta efetuar as suas regras. No caso acima, há
 uma série de arquivos que devem existir antes de se executar a compilação
 final, que faz a linkagem. A barra invertida (\verb|\|), no final da
 linha, indica que a linha seguinte é uma continuação. Se os arquivos {\tt
 *.o} não existem, o comando {\tt make} entende que deve procurar regras
 para criá-los, ou seja, procurará alvos cujos nomes sejam essas
 dependências. Assim, as regras do segundo, terceiro e quarto ``targets''
 serão efetuadas antes do primeiro. Se isso não for possível por qualquer
 motivo, {\tt make} interromperá seu procedimento e apresentará uma
 mensagem de erro.

 Agora, rode

 {\tt ./decmat}

\noindent
 para verificar que o programa gerado funciona.

 \item\label{parametro} Vamos agora observar como o comando {\tt make} se
 comporta com a alteração de algum arquivo. Edite, por exemplo, o arquivo
 {\tt fp\_def.f} e altere o valor do parâmetro {\tt ndim} para $2$. Rode
 novamente o comando {\tt make}. Quais compilações foram efetuadas?

 \item Mova o arquivo {\tt checkmats.f} para {\tt checkmats.f.OLD}. Edite
 novamente o arquivo {\tt fp\_def.f}, recoloque o valor anterior do
 parâmetro modificado e rode {\tt make}. Houve compilação? Qual? Agora,
 mova {\tt checkmats.f.OLD} de volta para {\tt checkmats.f} e rode

 {\tt make checkmats.o}

\noindent
 o que deve gerar o objeto {\tt checkmats.o}. Como se vê, é possível
 ordenar ao {\tt make} que execute qualquer um dos alvos existentes na
 {\tt Makefile}, o primeiro é apenas o default. Repita o comando
 acima. Por que não houve compilação? Agora, rode {\tt make} sem
 argumentos novamente e analise as mensagens apresentadas. Quais arquivos
 foram compilados e por quê? Mais uma vez, rode o programa {\tt decmat}
 criado para confirmar que ele funciona como antes.

 \item Até aqui, procuramos entender qual a estrutura básica de uma {\tt
 Makefile} e como funciona o processo de execução das regras segundo
 alterações nas dependências. O passo seguinte é sofisticar um pouco a
 {\tt Makefile}, usando variáveis. Edite a {\tt Makefile} e modifique-a
 para que fique como segue:

\input{aula-16-verbatim07.tex}

 Dê um

 {\tt touch Decompmat.f}

\noindent
 e rode novamente {\tt make} para verificar que tudo funciona
 perfeitamente. Você sabe dizer porque foi necessário o {\tt touch}?

 Analisemos a nova forma da {\tt Makefile}. Primeiramente, definimos uma
 variável {\tt OBJ} cujo valor é o conjunto de objetos a serem produzidos
 na compilação. A seguir, criamos um alvo ``default'', com o nome {\tt
 all}; neste caso, esse ``target'' não possui nenhuma regra para ser
 executada, pois ele apenas depende de outro alvo, o {\tt decmat}. Assim,
 {\tt all} funciona apenas como um apelido ou ``alias'' para a
 compilação. Depois, informamos na {\tt Makefile} como gerar o executável
 a partir dos objetos definidos por {\tt OBJ}. Finalmente, dizemos quais
 objetos dependem de que arquivos, sem especificar as regras para
 produzi-los.

 Nesse ponto, lançamos mão de ``pattern rules'', isto é, regras do tipo
 ``pattern'', que são regras comuns a vários alvos. Estas, por sua vez,
 fazem uso de variáveis automáticas, definidas por símbolos especiais como
 {\tt \%} e {\tt @}.

 O símbolo de percentagem ({\tt \%}) num ``target'' indica o ``pattern'' a
 ser considerado como nome. A repetição de {\tt \%} na dependência indica
 que o mesmo nome deve ser considerado na dependência, como um curinga
 repetido. Logo,

 {\tt \%.o: \%.f}

\noindent
 diz que todo arquivo cujo nome termina com {\tt .o} depende de um arquivo
 com a mesma parte inicial do nome-base mas cujo nome termina com {\tt
 .f}. A regra de nossa {\tt Makefile} para efetuar a compilação apresenta
 duas variáveis:

 {\tt \$@} (cifrão, arroba) -- representa o nome completo do ``target'';
 em nosso caso, podem ser os objetos {\tt Decompmat.o}, {\tt checkmats.o},
 {\tt writemat.o}, \\ {\tt getseed.o} ou {\tt ranr.o};
 
 {\tt \$<} (cifrão, menor) -- representa a primeira dependência apenas, o
 que é apropriado em nosso caso pois as outras são arquivos incluídos na
 primeira.

 \item Há vários outros tipos de variáveis automáticas compreendidas pelo
 comando {\tt make}. Como exercício, execute o comando

 {\tt info make}

\noindent
 e procure por ``automatic variables''. Encontre uma segunda variável que
 substitui todo o conjunto de dependências. Qual variável substitui apenas
 o nome do diretório dado no alvo? E o nome do arquivo?

 \item Já vimos toda a estrutura básica da {\tt Makefile} incluindo o uso
 de algumas variáveis. No entanto, essa ferramenta é bastante robusta,
 apresentando ainda muitos recursos. Para dar um exemplo de como podem ser
 as relações entre os vários alvos, criaremos uma estrutura de compilação
 um pouco mais sofisticada, com maior nível de organização e,
 consequentemente, mais complexa.

 Na nova estrutura, a compilação será feita dentro de sub-diretórios, e
 tentaremos automatizar a {\tt Makefile} ao máximo. Doravante os arquivos
 fonte deverão permanecer dentro de um diretório {\tt src} e os objetos,
 num diretório {\tt lib}. Se os diretórios não existem, deverão ser
 criados; logo, temos dois alvos com suas respectivas regras:

\input{aula-16-verbatim08.tex}

 Tudo foi feito com variáveis para evitar repetições, pois passaremos a
 nos referir aos objetos e às fontes sempre acompanhados de seus
 respectivos diretórios.

 \item Com isso, a estrutura de dependências e as regras para compilação
 mudam. A nova {\tt Makefile} deve ter o aspecto que é dado a seguir.

\input{aula-16-verbatim09.tex}

 Observe que a própria regra de compilação exige a existência do diretório
 {\tt lib} para que possa ser executada.

 Dê um {\tt touch} em algum arquivo fonte e rode {\tt make}.

 Por que não é efetuada a compilação? A mensagem de erro deve dizer algo
 como que não encontra uma regra para criar um ``target'' {\tt
 src/Decompmat.f}, exigido por {\tt lib/Decompmat.o}. Isso ocorre porque
 informamos na {\tt Makefile} que os novos arquivos fonte estão dentro de
 um diretório {\tt src}, mas não definimos uma regra para colocá-los ali.
 Assim, devemos introduzir uma regra que diz como extrair arquivos {\tt
 *.f} de {\tt decmat.tgz} dentro do diretório {\tt src}:

\input{aula-16-verbatim10.tex}

 Nessa estrutura, todo arquivo {\tt *.f} dentro de {\tt src} depende da
 existência de {\tt decmat.tgz} e do próprio diretório {\tt src}. A
 variável {\tt \$*} carrega o valor da parte do ``pattern'' definido por
 ``{\tt \%}'' que é comum ao alvo e às dependências. A opção {\tt m} no
 comando {\tt tar} não preserva as datas originais dos arquivos; isso é
 feito para se evitar problemas de comparação das datas dos arquivos pelo
 {\tt make} em caso de termos uma {\tt Makefile} mais complexa, em que são
 efetuadas alterações recorrentes dos arquivos extraídos.

 Rode {\tt make} e, então, {\tt decmat}. Dê {\tt ls -l *} para
 certificar-se de que toda a estrutura está correta.

 \item Agora você pode remover os arquivos {\tt *.f}, {\tt *.o} e {\tt
 decmat} do diretório corrente. Para esse tipo de tarefa, é usual e
 conveniente criar-se uma regra que ``limpa'' a área de trabalho,
 eliminando todos os arquivos desnecessários e, eventualmente, até os
 ``targets'' da {\tt Makefile}. Acrescente à sua {\tt Makefile} a seguinte
 estrutura:

\input{aula-16-verbatim11.tex}

 Observe que o alvo {\tt verycleanindeed} depende de {\tt veryclean}, que
 por sua vez depende de {\tt clean}; por outro lado, este último é
 efetuado sempre que se roda o comando

 {\tt make clean}

\noindent
 pois {\tt clean} não tem dependências. Logo, todos são sempre efetuados
 sempre que se roda {\tt make verycleanindeed}; tome bastante cuidado com
 estruturas desse tipo, pois, apesar de úteis, podem, também, apagar os
 dados inadvertidamente em certas circunstâncias.

 Execute o alvo {\tt clean} e rode {\tt make} novamente. O que acontece?
 Como você modificaria os alvos acima para que {\tt make clean} não force
 a recompilação de {\tt decmat}?

 \item Vale aqui uma observação. Depois de um {\tt veryclean} seguido de
 {\tt make}, os alvos são feitos e {\tt decmat} é gerado. Repare na última
 linha das mensagens; deve haver um comando para remover uma série de
 arquivos {\tt *.f}. Como isso é possível se não demos tal ordem?

 Quando colocamos regras gerais (``pattern rules'') na {\tt Makefile}, ela
 interpreta que certos arquivos, gerados em passos intermediários por
 essas regras e que não foram explicitados, são dispensáveis. Assim,
 elimina-os depois que termina suas tarefas. Esse é o motivo pelo qual
 alguns passos são repetidos se executamos {\tt make} seguidamente, ou
 seja, mesmo que os alvos já estejam atualizados. Para evitarmos esse tipo
 de conduta ou se quisermos preservar alguns dos arquivos gerados nos
 passos intermediários, devemos classificar esses alvos segundo uma classe
 especial, que corresponde a um grupo especial de nomes reservados para
 casos como esse, os ``Special Built-in Target Names'' (execute {\tt info
 make} e procure esse ítem). Isso é feito com o alvo ``{\tt .PRECIOUS}'',
 colocando-se na {\tt Makefile} a linha

 {\tt .PRECIOUS: arquivo1 arquivo2 etc.}

 Introduza uma variável {\tt SRC} em sua {\tt Makefile}, cujo valor são
 todos os arquivos {\tt src/*.f} (escreva-os explicitamente). Depois,
 defina {\tt \$(SRC)} como ``{\tt .PRECIOUS}''.

 \item Vale citar outro caso de ``Special Built-in Target Names''. O alvo
 {\tt clean} e seus semelhantes não correspondem a arquivos, bem como o
 alvo {\tt all}; são apenas nomes de alvos para indicar certas regras. É
 possível que existam arquivos com esses mesmos nomes, por coincidência ou
 incidentalmente, o que interferiria na execução dos alvos. Ou, ainda, é
 possível que queiramos, por algum motivo excêntrico, manter arquivos com
 o mesmo nome do alvo, mas que sejam independentes deste. Para desvincular
 nomes de alvos dos respectivos arquivos, devemos caracterizar esses
 alvos, segundo a classe especial citada acima, como ``phony
 targets''. Isso é feito introduzindo na {\tt Makefile} a linha

 {\tt .PHONY: all clean veryclean verycleanindeed}

 \item Suponhamos que você estivesse satisfeito e executado

 {\tt make verycleanindeed}

\noindent
 o que apaga tudo exceto a {\tt Makefile}. No entanto, você verifica que
 faltaram alguns testes com o programa {\tt decmat} e você precisa
 baixá-lo novamente. Para evitar esse transtorno toda vez, vamos adicionar
 a estrutura abaixo:

\input{aula-16-verbatim12.tex}

 O comando {\tt wget} puxa o arquivo pela rede, segundo o protocolo {\tt
 http}. A opção {\tt -q} corresponde a ``quiet'', isto é, sem avisos. A
 opção {\tt -N} faz com que o arquivo só seja puxado pelo {\tt wget} caso
 não exista ou seja mais antigo do que o arquivo que está nas páginas da
 disciplina, bem no espírito do {\tt make}. Assim, nossa {\tt Makefile}
 está completa e bastante automatizada. Execute o alvo {\tt
 verycleanindeed}, dê um {\tt ls -l} para verificar que a área está vazia
 (exceto pela {\tt Makefile}) e, então, {\tt make}. Finalmente, execute
 novamente {\tt ls -lR} e rode {\tt decmat} para confirmar que a operação
 foi bem sucedida.

\end{enumerate}

\section{Problemas e dicas}

\begin{enumerate}

 \item É comum querermos gerar um arquivo PS a partir de um arquivo
 \LaTeX. Para tanto, é necessário que exista o arquivo fonte, que o
 compilemos para gerar um arquivo DVI e, então, façamos a conversão para
 deste para PS com o comando

 {\tt dvips arquivo.dvi -o arquivo.ps}

 Crie uma {\tt Makefile} capaz de realizar essas tarefas. Não se esqueça
 de incluir nas dependências eventuais arquivos que sejam incluídos por
 meio do comando {\tt input}. Sugestão: puxe do servidor o arquivo fonte
 desta apostila e crie sua {\tt Makefile}.

 \item Consulte a apostila sobre arquivos ``tar e backups'' e desenvolva
 uma {\tt Makefile} capaz de gerar tais tipos de arquivos num certo tipo
 de mídia (floppies ou zips), verificando antes a existência prévia desses
 arquivos. Use a própria capacidade de comparação de datas da {\tt
 Makefile} para que ela considere ou não necessária a atualização do
 arquivamento. A {\tt Makefile} deve ser capaz de montar a mídia num
 diretório e executar o comando {\tt tar} convenientemente.

 \item A {\tt Makefile} que produzimos nas tarefas apresenta todos os
 comandos que executa. Imagine que você estivesse preparando essa {\tt
 Makefile} para impressionar seus amigos e não quisesse que nenhum deles
 soubesse o que se passa. Como silenciar o comando {\tt make}? Dica:
 consulte ``Summary of Options'' em {\tt info make}. Descubra qual é a
 variável especial definida na {\tt Makefile} que cumpre essa
 exigência. Inspecione as outras opções e verifique qual delas permite que
 a {\tt Makefile} execute tarefas paralelamente.

 \item Suponhamos que você não esteja conseguindo resolver algum problema
 no processo de ``debugging'' de sua {\tt Makefile}. Dê o comando

 {\tt make -d >\& log.txt}

\noindent
 respire fundo e leia o arquivo {\tt log.txt} para saber como {\tt make}
 se comporta com sua {\tt Makefile}. Trata-se de um {\em longo} arquivo.

 \item Descubra como alterar a shell default da {\tt Makefile} de {\tt
 bash} para {\tt tcsh} ou alguma outra. Dica: há uma variável na seção
 ``Quick reference'' de {\tt info make} que trata disso.

 \item {\it Desafio}. No ítem \ref{parametro}, efetuamos a modificação do
 arquivo {\tt fp\_def.f} para que o parâmetro lá definido fosse
 alterado. Complete a {\tt Makefile} das tarefas para que ela possa
 alterar automaticamente esse arquivo ao lhe darmos como argumento um
 número. Observe que deverá haver um alvo padrão (``default'') caso não
 forneçamos nenhum argumento. Dicas: crie um ``target'' extremamente
 genérico que dependa do arquivo {\tt fp\_def.f} e que saiba como editá-lo
 (provavelmente você terá de fazer uso do editor {\tt sed}); chame a
 própria {\tt Makefile} recursivamente para construir o executável.
 Sugestões: construa um ``fake target'' com o nome {\tt Makefile} para
 evitar recursão infinita ou ``crashes'' (por quê?); dê um {\tt touch} num
 arquivo de controle para evitar compilações redundantes (isso é
 necessário?).

\end{enumerate}

\section{Uma Lista de Comandos Relevantes}

\begin{description}\setlength{\itemsep}{0ex}

 \item[\tt info <nome-de-comando>]: mostra uma página de informação sobre
 o comando; para sair, basta digitar a letra {\tt q} (de ``quit'').

 \item[\tt make]: é um programa que permite a execução automática de
 programas que atuam em arquivos, segundo configurações colocadas em um
 arquivo chamado {\tt Makefile} no diretório de trabalho.

 \item[\tt wget <URL>]: puxa um arquivo pela Internet através da WWW;
 tanto o site da WWW quanto o arquivo são dados na {\tt <URL>}.

\end{description}

\end{document}

###

