Posso compilar todos os arquivos .cpp em src / para .o's em obj / e vincular ao binário em ./?

116

Meu diretório de projeto se parece com este:

/project
    Makefile
    main
    /src
        main.cpp
        foo.cpp
        foo.h
        bar.cpp
        bar.h
    /obj
        main.o
        foo.o
        bar.o

O que eu gostaria que meu makefile fizesse seria compilar todos os .cpparquivos da /srcpasta para os .oarquivos da /objpasta e, em seguida, vincular todos os .oarquivos /objao binário de saída na pasta de nível superior /project.

Não tenho quase nenhuma experiência com Makefiles e não tenho certeza do que pesquisar para fazer isso.

Além disso, essa é uma "boa" maneira de fazer isso ou existe uma abordagem mais padrão para o que estou tentando fazer?

Austin Hyde
fonte
6
@aaa: Estou supondo que o OP deseja uma solução que não requeira listar explicitamente cada arquivo de origem.
Cascabel
7
Não quero especificar cada arquivo-fonte que tenho e já tentei ler esse manual antes, mas acho que é desorganizado e difícil de entender. Aprendo muito melhor com um exemplo real que faz o que espero que faça e seja bem explicado, em vez de manuais técnicos secos.
Austin Hyde
OK. Mas fazer documentação é excelente com bons exemplos (não é tentar manual técnico). você está procurando por regras de padrão: gnu.org/software/make/manual/make.html#Pattern-Rules
Anycorn
11
Isso parece um pouco mais com o que eu quero. Porém, IMHO, o manual do make é um pouco seco, já que parece mais direcionado para desenvolvedores que estão em um nível intermediário com o make, e além disso é muito amplo e detalhado. Talvez até demais.
Austin Hyde

Respostas:

180

Makefile parte da questão

Isso é muito fácil, a menos que você não precise generalizar, tente algo como o código abaixo (mas substitua a indentação de espaço por guias próximas a g ++)

SRC_DIR := .../src
OBJ_DIR := .../obj
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRC_FILES))
LDFLAGS := ...
CPPFLAGS := ...
CXXFLAGS := ...

main.exe: $(OBJ_FILES)
   g++ $(LDFLAGS) -o $@ $^

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
   g++ $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<

Geração de gráfico de dependência automática

Um recurso "obrigatório" para a maioria dos sistemas make. Com GCC in pode ser feito em uma única passagem como um efeito colateral da compilação, adicionando -MMDsinalizador CXXFLAGSe -include $(OBJ_FILES:.o=.d) ao final do corpo do makefile:

CXXFLAGS += -MMD
-include $(OBJ_FILES:.o=.d)

E como os caras já mencionaram, sempre tenha o GNU Make Manual por perto, é muito útil.

bobah
fonte
11
Ah, você me venceu por segundos. Mas eu sugiro OBJ_FILES = $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES)).
Beta
1
Tive que mudar isso para funcionar: $<deveria ser $^para a regra de main.exe e acho que há um erro de digitação com obj/%.o: src/%cpp.
1
@bobah Está faltando um '.' em sua regra de objetos para o cpp
regomodo
1
as variáveis ​​especiais provavelmente valem a pena explicar, já que são específicas de makefile e difíceis de pesquisar: gnu.org/software/make/manual/html_node/Automatic-Variables.html
Blake
2
Sei que é uma pergunta antiga, mas mudei um pouco de acordo com meu projeto, mas não está funcionando. Aqui está meu makefile: pastebin.com/4CksG9Wc que recebo no console:make: *** No rule to make target '/main.o', needed by 'bin/main'. Pare.
Mateus Felipe
5

O curinga também funciona para mim, mas gostaria de dar uma nota lateral para aqueles que usam variáveis ​​de diretório. Sempre use barra para a árvore de pastas (não barra invertida), caso contrário, ocorrerá falha:

BASEDIR = ../..
SRCDIR = $(BASEDIR)/src
INSTALLDIR = $(BASEDIR)/lib

MODULES = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(wildcard *.o)
xesf
fonte
você quis dizer barra? Seu exemplo mostra o que tradicionalmente é considerado a barra. Especificamente, os que estão "inclinados para a direita" são considerados "para a frente" e os que ficam à esquerda são considerados "para trás"
Evan Teran
Sim, você está certo, quero dizer apenas "barra". Eu atualizei a postagem.
xesf