2010-10-27 6 views
16

Estoy trabajando en un proyecto de tamaño medio que contiene varias bibliotecas con interdependencia que he convertido recientemente para compilar utilizando un archivo make no recursivo. Mi próximo objetivo es habilitar la creación de compilaciones tanto de depuración como de liberación del mismo árbol fuente al mismo tiempo (make debug; make release). Mi primer paso fue crear los objetivos de depuración y liberación que contenían los indicadores de compilación correctos. Hice esto usando variables específicas de destino, así: CXXFLAGS = -Wall -Wextra -Werror -DLINUXUsar GNU Make para compilar objetivos de depuración y liberación al mismo tiempo

CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL 
CXX_RELEASE_FLAGS=-O3 

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: build 

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: build 

Esto funcionó bien, pero sólo se podría construir de depuración, o liberación, no ambas al mismo tiempo. Y al mismo tiempo, no me refiero a que durante la misma construcción me refiero a una copia de seguridad en el mismo árbol de fuentes (make debug; make release). Para hacer esto, necesito ubicar los archivos del objeto en un directorio específico de depuración/liberación para que no se sobrescriban entre sí y necesito modificar el nombre binario del objetivo de depuración con una 'D'. I aunque esto sería fácil ya que sólo pudiera utilizar variables específicas de destino una vez más, como esto: CXXFLAGS = -Wall -Wextra -Werror -DLINUX

CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL 
CXX_RELEASE_FLAGS=-O3 

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: MODULE_BLD_TYPE=D 
debug: OUT_DIR=debug_obj 
debug: build 

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: MODULE_BLD_TYPE:= 
release: OUT_DIR=release_obj 
release: build 

.PHONY: build 
build: TARGET_NAME=HelloWorld$(MODULE_BLD_TYPE) 
build: TARGET_BUILD_DIR=$(PROJECT_ROOT_DIR)/$(OUT_DIR) 
build: TARGET_BUILD_OBJS=$(addprefix $(TARGET_BUILD_DIR)/,$(SOURCES:.cpp=.o)) 
build: $(TARGET_NAME) 

Haces expertos leyendo esto ya sé que esto no va a funcionar porque no puede usar variables específicas del objetivo para crear objetivos reales. Funcionaron bien para mi CXXFLAGS var porque la variable no se usó en un nombre de destino.

¿Existe un patrón de diseño y/o la mejor práctica para gestionar compilaciones de depuración/liberación utilizando makefiles no recursivos? Específicamente, ¿cómo construyo la ruta del directorio del archivo objeto y el nombre del objetivo (construyo un objetivo basado en un objetivo)?

+0

¿Qué es esta asignación de una variable en un requisito previo? – Michael

+0

Como era de esperar, la documentación tiene una respuesta para eso: https://www.gnu.org/software/make/manual/html_node/Target_002dspecific.html –

Respuesta

12

Uno de los problemas más persistentes con Make es su incapacidad para manejar más de un comodín a la vez. No hay una manera realmente limpia de hacer lo que pides (sin recurrir a la recursión, que no creo que sea realmente tan mala). Aquí es un enfoque razonable:

CXXFLAGS=-Wall -Wextra -Werror -DLINUX 
CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL 
CXX_RELEASE_FLAGS=-O3 

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: HelloWorldD 

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: HelloWorld 

DEBUG_OBJECTS = $(addprefix $(PROJECT_ROOT_DIR)/debug_obj/,$(SOURCES:.cpp=.o)) 
RELEASE_OBJECTS = $(addprefix $(PROJECT_ROOT_DIR)/release_obj/,$(SOURCES:.cpp=.o)) 

HelloWorldD: $(DEBUG_OBJECTS) 
HelloWorld: $(RELEASE_OBJECTS) 

# And let's add three lines just to ensure that the flags will be correct in case 
# someone tries to make an object without going through "debug" or "release": 

CXX_BASE_FLAGS=-Wall -Wextra -Werror -DLINUX 
$(DEBUG_OBJECTS): CXXFLAGS=$(CXX_BASE_FLAGS) $(CXX_DEBUG_FLAGS) 
$(RELEASE_OBJECTS): CXXFLAGS=$(CXX_BASE_FLAGS) $(CXX_RELEASE_FLAGS) 
+0

Esta es una solución interesante y lo pensaré y veré si puedo aplícalo al problema real. Ese es el problema con los problemas complejos de ebullición hasta un simple ejemplo. Así que no puedo decir de inmediato si esto funcionará o no, pero parece prometedor. – Richard

+0

@Richard: si no funciona, publique una actualización y lo intentaremos de nuevo. – Beta

+0

Creo que tengo algo que funciona. Una vez que me confirmaron que lo que estaba intentando simplemente no iba a funcionar, di un paso atrás y adopté un enfoque diferente. Comenta sobre el uso de la recursividad me recordó que mi archivo MAKE está envuelto por un archivo MAKE de nivel superior que hace una llamada recursiva a mi archivo MAKE, por lo que acabo de mover la lógica que crea la ruta del directorio que parece estar funcionando. Sin embargo, ahora he complicado mi objetivo 'limpio', ya que tiene que limpiar los archivos de depuración y objeto de liberación, pero parece ser un problema mucho más simple. – Richard

2

Uso VPATH para hacer la depuración y versión se basa utilizar el mismo conjunto de archivos de origen. La compilación de depuración y liberación puede tener su propio directorio, lo que significa que tendrán sus archivos de objeto separados.

De forma alternativa, utilice una herramienta de compilación que admita compilaciones fuera de la fuente de forma nativa, como automake o (ugh) cmake.

Si habilita la opción automake subdir-objects (como en AM_INIT_AUTOMAKE([foreign subdir-objects])), puede escribir un Makefile.am no recursivo.

+0

Desafortunadamente, otras herramientas de compilación no son una opción en este momento. Ya estoy usando VPATH (aunque no lo mostré en mi ejemplo) para encontrar mis archivos fuente.Sin embargo, no estoy seguro de cómo esto me ayuda con dónde colocar mis archivos de objeto. No se conoce en qué directorio colocar los archivos obj hasta el tiempo de ejecución cuando se elige un objetivo de "depuración" o "liberación". Sin embargo, creo que tengo una solución que está funcionando. Ver mi comentario anterior – Richard

+2

Crea makefiles separados en los directorios donde se generan los archivos de depuración y publicación. Use VPATH para señalarlos a la fuente común. Utilice un archivo makefile de nivel superior para decidir qué archivo MAKE invocar recursivamente en función del destino 'debug' o' release'. –

Cuestiones relacionadas