Makefile – pequeno tutorial
Já escrevi diversos makefiles para projetos pequenos, porém precisei escrever um mais elaborado para um projeto mais elaborado que estou trabalhando.
Encontrei este tutorial no qual me baseei para a escrever o makefile abaixo (recomendo a leitura deste tutorial, especialmente quem não sabe muito sobre makefile):
A vantagem de um makefile como este é que mesmo que vários arquivos .h e .cpp sejam adicionados ao projeto eu não precisarei editá-lo, afinal este makefile procura todos os arquivos e os compila sem a necessidade de especificação.
Abaixo uma explicação com maiores detalhes:
SOURCES_DIR = src/ e TINYXML_DIR = src/tinyxml/ –> As variáveis SOURCES_DIR e
TINYXML_DIR recebem, respectivamente, os caminhos para os fontes a serem compilados (/src) e para arquivos da TinyXML necessários à sua compilação. Por que utilizar variáveis para diretórios? Porque desta forma, se for necessário fazer qualquer alteração na localização dos arquivos eu só mexo em uma variável e não no makefile inteiro.
CFLAGS e TINYXML_FLAGS –> Este projeto utiliza a Libvirt e para sua compilação é necessário a “linkagem” -lvirt. Qualquer outra biblioteca que eu venha a utilizar neste projeto que necessite “linkagem” pode ser acrescentado na variável CFLAGS, assim fica mais organizado. Como mencionado, a TinyXML requer a inclusão de alguns arquivos para a compilação do código, estes aquivos são incluídos na variável TINYXML_FLAGS com a ajuda da variável TINYXML_DIR que aponta o caminho correto para os arquivos.
Aqui começa a parte mais interessante!
OBJECTS = $(wildcard $(SOURCES_DIR)*.cpp) –> Com isto todo o diretório apontado pela variável SOURCES_DIR é varrido em busca de arquivos do tipo .cpp e armazena seus nomes na variável OBJECTS.
all: executable –> o primeiro alvo é all: cuja regra é que o alvo executable deve ser executado.
executable: $(OBJECTS:.cpp=.o) –> Por sua vez o alvo executable tem como regra que todos os objetos devem ser criados. $(OBJECTS:.cpp=.o) cria um alvo .o para cada arquivo .cpp contido na variável OBJECTS. Por exemplo, para um arquivo class.cpp existente será criada um alvo class.o.
%.o: %.cpp %.h –> Para cada alvo .o criado serão verificadas alterações nos arquivos .cpp e .h correspondentes e então compilados com $(CC) -Wall -c mce_markerlt; -o $@. $(CC) é o compilador g++, -Wall é para a exibição de advertências e -c é para a criação do objeto .o; mce_markerlt; é substituída pelas dependências do alvo e -o $@ é subtituída pelo nome do alvo.
Após a compilação dos objetos a compilação retorna para o alvo executable e o compila com $(CC) -o $(EXECUTABLE_NAME) $(OBJECTS:.cpp=.o) $(CFLAGS) $(TINYXML_FLAGS). Um arquivo executável (binário) é criado com o nome contido na variável EXECUTABLE_NAME, os objetos são incluídos na compilação através de $(OBJECTS:.cpp=.o) que já foi explicado, a “linkagem” da libvirt é feita pela variável CFLAGS e os arquivos da TinyXML são incluídos pela variável TINYXML_FLAGS.
Reforço que é muito interessante ler o tutorial em –> http://ubuntuforum-pt.org/index.php/topic,21155.0.html.
O makefile pode ser visto e obtido em -> https://gist.github.com/798862
Fonte: http://ubuntuforum-pt.org/index.php/topic,21155.0.html