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.

Foi útil?

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 echoMas 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top