Eu tenho o seguinte makefile que uso para construir um programa (um kernel, na verdade) no qual estou trabalhando. É do zero e estou aprendendo sobre o processo, então não é perfeito, mas acho que é poderoso o suficiente neste ponto para o meu nível de experiência escrevendo makefiles.
AS = nasm
CC = gcc
LD = ld
TARGET = core
BUILD = build
SOURCES = source
INCLUDE = include
ASM = assembly
VPATH = $(SOURCES)
CFLAGS = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
-nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS = -f elf
#CFILES = core.c consoleio.c system.c
CFILES = $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES = assembly/start.asm
SOBJS = $(SFILES:.asm=.o)
COBJS = $(CFILES:.c=.o)
OBJS = $(SOBJS) $(COBJS)
build : $(TARGET).img
$(TARGET).img : $(TARGET).elf
c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img
$(TARGET).elf : $(OBJS)
$(LD) -T link.ld -o $@ $^
$(SOBJS) : $(SFILES)
$(AS) $(ASFLAGS) $< -o $@
%.o: %.c
@echo Compiling $<...
$(CC) $(CFLAGS) -c -o $@ $<
#Clean Script - Should clear out all .o files everywhere and all that.
clean:
-del *.img
-del *.o
-del assembly\*.o
-del core.elf
Meu principal problema com este makefile é que quando eu modifico um arquivo de cabeçalho que um ou mais arquivos C incluem, os arquivos C não são reconstruídos. Posso consertar isso facilmente fazendo com que todos os meus arquivos de cabeçalho sejam dependências de todos os meus arquivos C, mas isso efetivamente causaria uma reconstrução completa do projeto sempre que eu alterasse / adicionasse um arquivo de cabeçalho, o que não seria muito elegante.
O que eu quero é que apenas os arquivos C que incluem o arquivo de cabeçalho que alterei sejam reconstruídos e que todo o projeto seja vinculado novamente. Posso fazer a vinculação fazendo com que todos os arquivos de cabeçalho sejam dependências do destino, mas não consigo descobrir como fazer com que os arquivos C sejam invalidados quando seus arquivos de cabeçalho incluídos são mais recentes.
Ouvi dizer que o GCC tem alguns comandos para tornar isso possível (para que o makefile possa de alguma forma descobrir quais arquivos precisam ser reconstruídos), mas não consigo encontrar um exemplo de implementação real para examinar. Alguém pode postar uma solução que permitirá esse comportamento em um makefile?
EDIT: Devo esclarecer, estou familiarizado com o conceito de colocar os destinos individuais e ter cada destino.o exigir os arquivos de cabeçalho. Isso requer que eu edite o makefile toda vez que incluo um arquivo de cabeçalho em algum lugar, o que é um pouco chato. Estou procurando uma solução que possa derivar as dependências do arquivo de cabeçalho por conta própria, o que tenho quase certeza de ter visto em outros projetos.
fonte
Você poderia adicionar um comando 'make depend' como outros declararam, mas por que não fazer o gcc criar dependências e compilar ao mesmo tempo:
O parâmetro '-MF' especifica um arquivo para armazenar as dependências.
O traço no início de '-include' diz ao Make para continuar quando o arquivo .d não existir (por exemplo, na primeira compilação).
Observe que parece haver um bug no gcc em relação à opção -o. Se você definir o nome do arquivo do objeto para dizer
obj/_file__c.o
, o gerado_file_.d
ainda conterá_file_.o
, nãoobj/_file_c.o
.fonte
g++ -c -Wall -Werror -MM -MF main.d -o main.o main.cpp
Peguei o arquivo main.d, mas main.o tinha 0 bytes. No entanto, o sinalizador -MMD parece fazer exatamente o que era necessário. Então, minha regra de trabalho makefile tornou-se:$(CC) -c $(CFLAGS) -MMD -o $@ $<
Isso é equivalente à resposta de Chris Dodd , mas usa uma convenção de nomenclatura diferente (e coincidentemente não requer a
sed
mágica. Copiado de uma duplicata posterior .Se você estiver usando um compilador GNU, o compilador pode montar uma lista de dependências para você. Fragmento de Makefile:
Existe também a ferramenta
makedepend
, mas nunca gostei tanto quantogcc -MM
fonte
SRCS
eOBJS
. Eu concordaria na maioria das vezes, mas todos deveriam saber o que são.Você terá que criar destinos individuais para cada arquivo C e, em seguida, listar o arquivo de cabeçalho como uma dependência. Você ainda pode usar seus destinos genéricos e apenas colocar as
.h
dependências depois, como:fonte
Basicamente, você precisa criar dinamicamente as regras do makefile para reconstruir os arquivos-objeto quando os arquivos de cabeçalho forem alterados. Se você usar gcc e gnumake, isso é bastante fácil; basta colocar algo como:
em seu makefile.
fonte
Além do que @mipadi disse, você também pode explorar o uso da
-M
opção ' ' para gerar um registro das dependências. Você pode até mesmo gerá-los em um arquivo separado (talvez 'depend.mk') que você então inclui no makefile. Ou você pode encontrar umamake depend
regra ' ' que edita o makefile com as dependências corretas (termos do Google: "não remova esta linha" e depende).fonte
Nenhuma das respostas funcionou para mim. Por exemplo, a resposta de Martin Fido sugere que o gcc pode criar um arquivo de dependência, mas quando tentei, ele estava gerando arquivos de objeto vazios (zero bytes) para mim sem quaisquer avisos ou erros. Pode ser um bug do gcc. Eu estou em
Então aqui está meu Makefile completo que funciona para mim; é uma combinação de soluções + algo que não foi mencionado por ninguém (por exemplo, "regra de substituição de sufixo" especificada como .cc.o :):
Observe que usei .cc .. O Makefile acima é fácil de ajustar para arquivos .c.
Também é importante observar a importância dessas duas linhas:
então gcc é chamado uma vez para construir um arquivo de dependência primeiro, e então realmente compila um arquivo .cc. E assim por diante para cada arquivo de origem.
fonte
Solução mais simples: basta usar o Makefile para que a regra de compilação .c para .o seja dependente do (s) arquivo (s) de cabeçalho e de tudo o mais que seja relevante em seu projeto como uma dependência.
Por exemplo, no Makefile em algum lugar:
fonte
Eu acredito que o
mkdep
comando é o que você quer. Na verdade, ele verifica os arquivos .c em busca de#include
linhas e cria uma árvore de dependências para eles. Eu acredito que os projetos do Automake / Autoconf usam isso por padrão.fonte