Estrutura de diretório de arquivo de objeto plano Saída com GNU Make
Pergunta
Eu tenho um pequeno projeto C ++ usando o GNU Make. Eu gostaria de poder girar os seguintes arquivos de origem:
src/
a.cpp
b/
b.cpp
c/
c.cpp
Na estrutura de saída a seguir (não estou preocupado com duplicatas neste momento):
build/
a.o
b.o
c.o
Até agora, eu tenho o seguinte, que infelizmente coloca o .o e .d ao lado de cada .cpp:
OBJS := $(foreach file,$(SRCS),$(file).o)
DEPS := $(patsubst %.o,%.d,$(OBJS))
sinclude $(DEPS)
$(OBJS) : %.o : %.cpp
@echo Compiling $<
$(CC) $(CC_FLAGS) $(INCS) -MMD -o $@ $<
Estou ciente da função $ (Notdir ...), mas neste momento meus esforços para usá -lo para filtrar os objetos falharam. Alguém pode lançar alguma luz sobre isso? Parece uma coisa bastante razoável de se fazer.
Solução
Existem pelo menos duas maneiras de fazer isso. Primeiro (e o que eu recomendo) é que você pode adicionar o diretório de compilação aos nomes de destino (mesmo ao usar uma regra de padrão). Por exemplo:
$(OBJS) : build/%.o : %.cpp
Segundo, você pode usar a variável vPath para dizer para pesquisar um diretório diferente para pré -requisitos. Esta é provavelmente a abordagem mais comumente usada. Ele tem pelo menos uma desvantagem séria, e é se você for com ele e, posteriormente, ter problemas com "duplicatas", não há como resolver o problema. Com a abordagem anterior, você sempre pode espelhar a estrutura do diretório de origem sob o diretório de construção para evitar duplicatas em conflito.
Editar: Minha resposta anterior foi um pouco pouco com detalhes, por isso vou expandir -o para mostrar que isso realmente funciona como anunciado. Aqui está um exemplo de trabalho completo que usa a primeira técnica descrita acima para resolver o problema. Basta colar isso em um Makefile e correr - ele fará o resto e mostrará que isso de fato funciona.
Editar: Não consigo descobrir como obter, para permitir os caracteres da guia no meu texto de resposta (ele os substituiu por espaços). Depois de copiar e colar este exemplo, você precisará converter os espaços principais nos scripts de comando em guias.
BUILD_DIR := build
SRCS := \
a.c \
b.c \
c.c \
a/a.c \
b/b.c \
c/c.c
OBJS := ${SRCS:%.c=${BUILD_DIR}/%.o}
foo: ${OBJS}
@echo Linking $@ using $?
@touch $@
${BUILD_DIR}/%.o: %.c
@mkdir -p $(dir $@)
@echo Compiling $< ...
@touch $@
${SRCS}:
@echo Creating $@
@mkdir -p $(dir $@)
@touch $@
.PHONY: clean
clean:
rm -f foo
rm -f ${OBJS}
Em particular, observe que existem arquivos de origem com nomes duplicados (AC e A/AC, BC e BC, etc.) e que isso não causa problemas. Observe também que não há uso do VPath, que eu recomendo evitar o uso devido às suas limitações inerentes.
Outras dicas
vpath %.cpp src src/b src/c
Em seguida, consulte os arquivos de origem sem o nome do diretório; Fazer vai pesquisar o VPath.
Criando a estrutura de diretório plana, conforme solicitado inicialmente.
Usa vpath
Para rastrear os arquivos de origem, mas todo o bookeeping é feito automaticamente a partir do SRC
Lista.
SRC = a/a.c a/aa.c b/b.c
TARGET = done
FILES = $(notdir $(SRC) )
#make list of source paths, sort also removes duplicates
PATHS = $(sort $(dir $(SRC) ) )
BUILD_DIR = build
OBJ = $(addprefix $(BUILD_DIR)/, $(FILES:.c=.o))
DEP = $(OBJ:.o=.d)
# default target before includes
all: $(TARGET)
include $(DEP)
vpath %.c $(PATHS)
# create dummy dependency files to bootstrap the process
%.d:
echo a=1 >$@
$(BUILD_DIR)/%.o:%.c
echo $@: $< > $(patsubst %.o,%.d,$@)
echo $< >$@
$(TARGET): $(OBJ)
echo $^ > $@
.PHONY: clean
clean:
del $(BUILD_DIR)/*.o
del $(BUILD_DIR)/*.d
Desculpe pelo feio echo
Mas eu só tinha minha caixa de vitória para testá -la.
Isto é para Win32 Mingw32-Make. funciona. A parte mais importante é
-mkdir $(patsubst %/,%,$(dir $@))
para Win32. Precisamos retirar o trailing / para o Win32.
GENERATED_DIRS = a b
# Dependency generator function
mkdir_deps =$(foreach dir,$(GENERATED_DIRS),$(dir)/.mkdir.done)
# Target rule to create the generated dependency.
# And create the .mkdir.done file for stop continuous recreate the dir
%/.mkdir.done: # target rule
-mkdir $(patsubst %/,%,$(dir $@))
echo $(patsubst %/,%,$(dir $@)) >$@
all: $(mkdir_deps)
@echo Begin
clean:
@echo Cleaning
Você pode não participar como essa abordagem, mas:
AUTOMAKE_OPTIONS =
O truque é muito bem em um makefile.am. Apenas dizendo que você não precisa escrever tudo manualmente.