Makefile (mínimo!)

Quem trabalha com programação sabe que é necessário manter tudo em ordem: não importa se o trabalho é solo ou em grupo. Além de se utilizar um software de gerenciamento de códigos (eg., CVS, Subversion, git), à medida em que o(s) código(s) cresce(m), torna-se necessário (e desejável também), a utilização de algum software para o gerenciamento do projeto (eg., Redmine, Trac). Mas no meio disso tudo – na verdade, antes disso tudo, há um pequeno pedaço de software que é responsável pela organização hierárquica de todo o projeto. Estamos falando sobre o Makefile.

O Makefile é o arquivo lido pelo comando “make” (ou GNUmakefile, se estivermos utilizando o comando “gmake”) e é ele quem vai dizer para o compilador por onde começar e como compilar o código. Obviamente, se temos apenas uma rotina (eg., exemplo.f90, ou exemplo.coloqueaquiasualinguagempreferida), não há necessidade de se construir um Makefile (a menos que você precise lincar contra várias bibliotecas – libraries, e incluir vários cabeçalhos – headers). Para o caso mais simples, fazemos a seguinte compilação (utilizando a linguagem fortran e a suíte GCC como exemplo):

$ gfortran exemplo.f90

Se o programa exemplo.f90 não contiver erros, como resultado obteremos um executável de nome “a.out”. Para executá-lo, basta fazer:

$ ./a.out

Caso queiramos especificar um nome diferente para o executável, podemos fazê-lo com a opção “-o”:

$ gfortran exemplo.f90 -o exemplo.x

Nesse caso, ao invés de obtermos um executável com o nome padrão “a.out”, o compilador (no nosso caso, o gfortran) vai gerar um executável com o nome “exemplo.x”. É possível especificar qualquer nome, desde que este não contenha espaços e/ou caracteres especiais.

Podemos considerar também a situação em que o programa exemplo.f90 faz referência a um módulo que está escrito dentro de uma outra rotina de nome “modulo.f90”. Neste caso, para que possamos gerar um executável para o programa principal (exemplo.f90), podemos fazer da seguinte maneira:

$ gfortran -c modulo.f90 exemplo.f90
$ gfortran modulo.o exemplo.o -o exemplo.x

Observe que desta vez, utilizamos a opção “-c” do compilador ( assim como a opção “-o”, essa opção deve funcionar para qualquer compilador). A opção “-c” faz com que o compilador, ao invés de gerar um executável, crie dois arquivos diferentes para cada arquivo fonte compilado: um com a extensão “.mod” e outro com a extensão “.o”. O primeiro, é um arquivo binário que contém todas as instruções específicas daquele módulo. O segundo é um objeto que pode ser utilizado para compor uma biblioteca (geralmente com a extensão “.a”). Imagine que a rotina module.f90 contenha vários módulos. Quando você a compilar com a opção “-c”, o compilador vai gerar um par de arquivos “.mod” e “.o” para cada um dos módulos contidos na rotina modulo.f90. Neste caso, a compilação seria feita da mesma forma acima, e é neste tipo de situação (também) que o Makefile cumpre o seu papel.

Então, um Makefile mínimo é aquele que vai resolver o seu problema sem exigir muitos conhecimentos sobre o assunto.

Mas antes, para tornar este exemplo um pouco mais palpável, vamos considerar o seguinte:

  • exemplo.f90 – é o programa principal;
  • modulo1.f90 – é o módulo 1, que pode conter vários módulos e funções embutidas;
  • modulo2.f90 – é o módulo 2, que pode conter vários módulos e funções embutidas;
  • modulo3.f90 – é o módulo 3, que pode conter vários módulos e funções embutidas;

Tudo o que você precisa saber para construir manualmente o seu Makefile é a seguinte sintaxe (e sim, há alguns programas que criam os Makefiles automaticamente, como por exemplo, o fgen):

alvo: dependências
[TAB] comandos

Só isso. Observe bem que os parágrafos – ou melhor, a identação dentro do Makefile, é feita com a tecla TAB e nunca com espaços.

Então, para escrever o seu Makefile, abra o se editor de textos preferido e digite as seguintes instruções (na mesma ordem) abaixo:

OBJS = modulo1.o modulo2.o modulo3.o exemplo.o
FC = gfortran
RM = rm
main: $(OBJS)
        $(FC) -o exemplo.x $(OBJS)
%.o: %.f90
        $(FC) -c $<
clean:
        $(RM) *.o *.mod exemplo.x

A primeira linha do Makefile com a variável “OBJS”, faz referências a todos os objetos de todos os arquivos fontes (incluindo o programa principal) que serão criados. Na segunda linha, a variável “FC” refere-se ao compilador que será utilizado (que no nosso caso, é o gfortran). Na próxima linha, fazemos referência ao programa “rm”, utilizando uma variável de nome “RM”. Observe que, eventualmente, pode ser uma boa idéia especificar o caminho absoluto, ou seja, ao invés de indicar apenas “FC = gfortran” e “RM = rm”, pode-se indicar “FC = /usr/bin/gfortran”  e “RM = /usr/bin/rm”. Estes caminhos podem mudar de sistema para sistema. Para saber onde se encontram estes comandos no seu Shell, basta utilizar o comando “which” (por exemplo, “which gfortran” e “which rm”). Além disso, o Makefile acima contém duas funções: a primeira, é a função “main” que se encarrega de criar os objetos necessários para a compilação da rotina exemplo.f90; a segunda função “clean” é a responsável por apagar ou “limpar” a compilação. Observe que neste caso, a função “clean” vai apagar qualquer arquivo com extensão “.o”, “.mod” e também o executável do programa principal “exemplo.x”. Você pode querer utilizar esta função quando for necessário fornecer o seu código para alguém.

Observe também as seguintes instruções contidas nesse Makefile:

%.o: %.f90
        $(FC) -c $<

É esta instrução que indica que os objetos devem ser gerados a partir de todos os arquivos com a extensão “.f90”. Se o seu projeto possui arquivos com a extensão “.F90” (maiúsculo – neste caso, o seu programa pode conter instruções de pré-processamento, como instruções em MPI etc), a partir dos quais você queira também criar os objetos, então basta acrescentar:

%.o: %.f90
        $(FC) -c $<
%.o: %.F90
        $(FC) -c $<

Para utilizar este Makefile, basta digitar “make” para então compilar o seu projeto ou “make clean” para apagar os arquivos “.mod” e “.o”. Estes comando devem ser executados na mesma pasta em que o Makefile estiver:

$ make
$ make clean

Você pode ainda querer renomear o arquivo Makefile para um outro nome. Neste caso, basta utilizar o modificador “-f” do comando make e indicar o arquivo:

$ make -f MeuMakefile

Ok, mas afinal, qual é a vantagem de um Makefile? Se o seu projeto é muito complexo, contendo vários programas, módulos e etc, certamente a compilação também é complexa. Se você quiser fazer uma pequena alteração em um módulo qualquer, ou em um outro programa qualquer dentro do seu projeto, a menos que você esteja utilizando um Makefile, você vai ter que compilar todas as rotinas novamente, para criar todos os objetos novamente e possivelmente, todas as bibliotecas também. Então, como o Makefile sabe quais são as rotinas que precisam ser compiladas, quais os objetos que devem ser criados e quais são as instruções para a compilação, logo, quando você fizer uma alteração qualquer no seu projeto, ele vai compilar apenas aquelas rotinas que foram modificadas. Isso reduz muito o tempo de compilação e ajuda a evitar erros.

É isso!

Referências:

 

 

Anúncios

Autor: cfbastarz

craftmind.wordpress.com

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s