Se você quiser executar ou atualizar uma tarefa quando certos arquivos são atualizados, o utilitário make
pode ser útil. make
utilitário requer um arquivo, Makefile
(ou makefile
, que define o conjunto de tarefas a serem executadas. Você pode ter usado make
para compilar um programa a partir do código fonte. A maioria dos projetos de código aberto usam make
para compilar um executável binário final, que pode então ser instalado usando make install
.,
neste artigo, vamos explorar make
e Makefile
usando básico e avançado de exemplos. Antes de iniciar, certifique-se de que make
está instalado no seu sistema.
exemplos básicos
vamos começar por imprimir o clássico “Olá Mundo” no terminal. Criar um diretório vazio myproject
que contém um arquivo Makefile
com este conteúdo:
say_hello:
echo "Hello World"
Agora, execute o arquivo digitando make
dentro do diretório myproject
., A saída será:
$ make
echo "Hello World"
Hello World
No exemplo acima, say_hello
comporta-se como um nome de função, como em qualquer linguagem de programação. Isto chama-se o alvo. Os pré-requisitos ou dependências seguem o alvo. Por uma questão de simplicidade, não definimos quaisquer pré-requisitos neste exemplo. O comando echo "Hello World"
é chamado de receita. A receita usa pré-requisitos para fazer um alvo. O alvo, pré-requisitos e receitas juntos fazem uma regra.,
Para resumir, abaixo está a sintaxe de uma regra típica:
target: prerequisites
<TAB> recipe
Como um exemplo, um alvo pode ser um arquivo binário que depende de pré-requisitos (arquivos de origem). Por outro lado, um pré-requisito também pode ser um alvo que depende de outras dependências:
não é necessário que o alvo seja um arquivo; pode ser apenas um nome para a receita, como no nosso exemplo. Chamamos-lhes “alvos falsos”.,”
voltando ao exemplo acima, quando make
foi executado, a todo o comando echo "Hello World"
foi exibido, seguido pelo real da saída do comando. Muitas vezes não queremos isso. Para suprimir ecoando o comando real, precisamos iniciar echo
com @
:
say_hello:
@echo "Hello World"
Agora, tente executar o make
novamente., O resultado deve apresentar apenas isso:
$ make
Hello World
Vamos adicionar mais alguns falsos alvos: generate
e clean
Makefile
:
Se a gente tentar executar o make
após a mudança, só o destino say_hello
será executada. Isso porque apenas o primeiro alvo no makefile é o alvo padrão. Muitas vezes chamado de objetivo padrão, esta é a razão pela qual você vai ver all
como o primeiro alvo na maioria dos projetos., É da responsabilidade de all
chamar outros alvos. Podemos anular este comportamento usando um alvo falso especial chamado .DEFAULT_GOAL
.
Vamos incluir isso no início do nosso makefile:
.DEFAULT_GOAL := generate
Isto irá executar o alvo generate
como padrão:
$ make
Creating empty text files...
touch file-{1..10}.txt
Como o nome sugere, o falso destino .DEFAULT_GOAL
pode executado somente um alvo por vez. É por isso que a maioria dos makefiles incluem all
como um alvo que pode chamar tantos alvos quanto necessário.,
Vamos incluir o falso destino all
e remover .DEFAULT_GOAL
:
Antes de executar o make
, vamos incluir o outro especiais falso destino, .PHONY
, onde definimos todos os alvos que não são arquivos. make
irá executar a sua receita independentemente de existir um ficheiro com esse nome ou qual é a sua última hora de modificação., Aqui é a completa makefile:
make
deve chamar say_hello
e generate
:
$ make
Hello World
Creating empty text files...
touch file-{1..10}.txt
é uma boa prática para não chamar clean
no all
ou colocá-lo como o primeiro alvo., clean
deve ser chamado manualmente quando a limpeza é necessária como primeiro argumento para make
:
$ make clean
Cleaning up...
rm *.txt
Agora que você tem uma idéia de como uma base makefile funciona e como escrever um simples makefile, vamos olhar para alguns exemplos mais avançados.
exemplos avançados
variáveis
no exemplo acima, a maioria dos valores-alvo e pré-requisitos são hard-coded, mas em projetos reais, estes são substituídos por variáveis e padrões.,
A maneira mais simples de definir uma variável em um makefile é usar o operador =
., Por exemplo, para atribuir o comando gcc
para uma variável CC
:
CC = gcc
Este é também chamada recursiva expandida variável, e é usada em uma regra como mostrado abaixo:
hello: hello.c
${CC} hello.c -o hello
Como você pode ter adivinhado, a receita se expande conforme abaixo quando ele é passado para o terminal:
gcc hello.c -o hello
Os ${CC}
e $(CC)
são referências válidas para chamar gcc
. Mas se alguém tentar reatribuir uma variável a si mesmo, causará um loop infinito., Vamos verificar isso:
CC = gcc
CC = ${CC}
all:
@echo ${CC}
Com make
irá resultar em:
$ make
Makefile:8: *** Recursive variable 'CC' references itself (eventually). Stop.
Para evitar este cenário, podemos usar o :=
operador (isso também é chamado simplesmente expandido variável). Não devemos ter problemas em executar o makefile abaixo:
CC := gcc
CC := ${CC}
all:
@echo ${CC}
padrões e funções
o makefile seguinte pode compilar todos os programas C usando variáveis, padrões e funções., Vamos explorá-lo linha por linha:
abaixo está a reescrita do makefile acima, assumindo que ele é colocado no diretório com um único arquivo foo.c: