¿Puedo compilar todos los archivos .cpp en src / a .o's en obj / y luego vincularlos al binario en ./?

116

El directorio de mi proyecto se ve así:

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

Lo que me gustaría que hiciera mi archivo MAKE sería compilar todos los .cpparchivos de la /srccarpeta en .oarchivos de la /objcarpeta, luego vincular todos los .oarchivos /objal binario de salida en la carpeta de nivel superior /project.

Casi no tengo experiencia con Makefiles y no estoy realmente seguro de qué buscar para lograrlo.

Además, ¿es esta una "buena" forma de hacer esto, o hay un enfoque más estándar para lo que estoy tratando de hacer?

Austin Hyde
fuente
6
@aaa: Supongo que el OP quiere una solución que no requiera enumerar explícitamente cada archivo fuente.
Cascabel
7
No quiero especificar cada archivo fuente que tengo, y he intentado leer ese manual antes, pero lo encuentro desorganizado y difícil de entender. Aprendo mucho mejor de un ejemplo real que hace lo que espero que haga y está bien explicado, en lugar de manuales técnicos secos.
Austin Hyde
bueno. Pero hacer que la documentación sea excelente con buenos ejemplos (no se prueba el manual técnico). está buscando reglas de patrones: gnu.org/software/make/manual/make.html#Pattern-Rules
Anycorn
11
Eso se parece un poco más a lo que quiero. Aunque, en mi humilde opinión, el manual de make es un poco seco, ya que parece más dirigido a desarrolladores que están en un nivel intermedio con make, y más allá de eso es muy grande y profundo. Quizás demasiado.
Austin Hyde

Respuestas:

180

Makefile parte de la pregunta

Esto es bastante fácil, a menos que no necesite generalizar, pruebe algo como el siguiente código (pero reemplace la sangría del espacio con pestañas cerca de 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 $@ $<

Generación automática de gráficos de dependencia

Una característica "imprescindible" para la mayoría de los sistemas de marcas. Con GCC en que se puede hacer en un solo paso como un efecto secundario de la compilación mediante la adición de -MMDbandera a CXXFLAGSy -include $(OBJ_FILES:.o=.d) al extremo del cuerpo makefile:

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

Y como los chicos ya han mencionado, siempre tenga a mano GNU Make Manual , es muy útil.

bobah
fuente
11
Ah, me ganaste por segundos. Pero sugiero OBJ_FILES = $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES)).
Beta
1
Tuve que cambiar esto para que funcionara: $<debería ser $^para la regla main.exe y creo que hay un error tipográfico con obj/%.o: src/%cpp.
1
@bobah Te falta un '.' en tu regla de objetos para el cpp
regomodo
1
Probablemente valga la pena explicar las variables especiales, ya que son específicas de makefile y difíciles de buscar: gnu.org/software/make/manual/html_node/Automatic-Variables.html
Blake
2
Sé que esta es una pregunta antigua, pero modifiqué un poco según mi proyecto, pero no está funcionando. Aquí está mi archivo MAKE: pastebin.com/4CksG9Wc Me meto en la consola:make: *** No rule to make target '/main.o', needed by 'bin/main'. Pare.
Mateus Felipe
5

El comodín también funciona para mí, pero me gustaría dar una nota al margen para aquellos que usan variables de directorio. Utilice siempre la barra diagonal para el árbol de carpetas (no la barra invertida), de lo contrario fallará:

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

MODULES = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(wildcard *.o)
xesf
fuente
¿Quisiste decir barra diagonal? Su ejemplo muestra lo que tradicionalmente se considera la barra inclinada. Específicamente, los que "se inclinan a la derecha" se consideran "adelante" y los que quedan a la izquierda se consideran "atrás"
Evan Teran
Sí, tienes razón, me refiero solo a "barra". Actualicé la publicación.
xesf