O objetivo principal de um arquivo makefile é criar regras de compilação para programas de software. Ele é utilizado pelo programa make para compilar, linkar, montar arquivos de projeto, dentre outras tarefas.
Vantagens
- Se alguma modificação altera apenas poucos arquivos, a compilação não precisa necessariamente recompilar todo o projeto. Por exemplo, o comando "-o file" ('pretend that source file has not changed, even though it has changed') diz para o programa fazer de conta que aquele arquivo não foi modificado, mesmo que tenha sido, dispensando assim sua recompilação.
- É possível integrar com ferramentas de documentação, verificação, e outras ferramentas, como doxygen e clang-format.
- É uma forma de garantia de gerar sempre 'a mesma coisa' em computadores diferentes ou por desenvolvedores diferentes.
Estrutura
Como muitos tipos de arquivos, o makefile tem uma estrutura definida que deve ser seguida para o bom funcionamento de suas 'receitas':
target: dependencies [tab] command
Vamos lá, o que significa cada uma dessas pequenas partes?
- target: pode ser dito que o target é o nome da ação a ser tomada, cada target possui suas dependências e seus comandos. Para ficar mais clara sua interpretação, você pode imaginar o target como uma receita de bolo, então o target seria 'bolo' (não é um bom exemplo mas é de fácil compreensão);
- dependencies: são os materiais necessários para executar as ações correspondentes aquele target;
- [tab]: é uma regra no makefile que o tab são 4 espaços, e deve ser dado o tab, caso sejam dados os espaços será gerado um erro em sua execução;
- command: é o comando ou os comandos necessários para satisfazer todas as necessidades daquele target.
Além da estrutura citada acima, os arquivos makefile permitem criar macros para facilitar o reuso de comandos e sua manutenção.
A definição de uma macro é a seguinte:
PROJ=Projeto_Teste
E posteriormente você pode utilizar esta macro utilizando a seguinte sintaxe:
$(PROJ)
Exemplo:
# Esta é uma linha comentada CC=g++ # CFLAGS são opções passadas para o compilador CFLAGS= -c -Wall all: prog prog: main.o fatorial.o hello.o $(CC) main.o fatorial.o hello.o -o prog main.o: main.cpp $(CC) $(CFLAGS) main.cpp fatorial.o: fatorial.cpp $(CC) $(CFLAGS) fatorial.cpp hello.o: hello.cpp $(CC) $(CFLAGS) hello.cpp clean: rm -rf *.o
Abaixo são listados algumas variáveis internas que auxiliam o desenvolvimento de um makefile:
$@ Nome da regra $< Nome da primeira dependência $^ Lista de dependências $? Lista de dependências mais recentes que a regra. $* Nome do arquivo sem sufixo
Automatizando
Como pode ser visualizado no arquivo acima, não é muito simples adicionar um novo arquivo no makefile. ERRADO. Da forma que foi feito o makefile acima, realmente pode se tornar complicado o crescimento de um projeto com mais arquivos, ter que criar uma nova regra para cada novo arquivo. Porém o que é muito comum é criar receitas reutilizáveis, ou seja, independente do arquivo a ser utilizado, a forma de compilar é a mesma. E isto facilita muito a interpretação do arquivo, e sua manutenção.
Abaixo segue a estrutura do mesmo makefile mostrado acima, porém com algumas melhorias agora que simplificam a inclusão de arquivos.
CC=g++ CFLAGS=-c –Wall OBJECTS = main.o hello.o fatorial.o all: prog prog: $(OBJECTS) $(CC) $(OBJECTS) -o prog %.o: %.cpp $(CC) $(CFLAGS) $< clean: rm -rf *.o
Conclusão
Podemos dizer que o uso de makefiles ajuda em muito nossos desenvolvimentos, desde garantir a repetibilidade da forma de compilação, até a documentação e verificação do código.
Entre em contato conosco.
Referências
https://www.gnu.org/software/make/
https://www.embarcados.com.br/introducao-ao-makefile/
https://pt.wikibooks.org/wiki/Programar_em_C/Makefiles
https://www3.nd.edu/~zxu2/acms60212-40212/Makefile.pdf
0 Comentários