create - makefile linux c
¿Cómo puedo configurar mi makefile para compilaciones de depuración y liberación? (8)
Completando las respuestas de antes ... Necesita hacer referencia a las variables que define la información en sus comandos ...
DEBUG ?= 1
ifeq (DEBUG, 1)
CFLAGS =-g3 -gdwarf2 -DDEBUG
else
CFLAGS=-DNDEBUG
endif
CXX = g++ $(CFLAGS)
CC = gcc $(CFLAGS)
all: executable
executable: CommandParser.tab.o CommandParser.yy.o Command.o
$(CXX) -o output CommandParser.yy.o CommandParser.tab.o Command.o -lfl
CommandParser.yy.o: CommandParser.l
flex -o CommandParser.yy.c CommandParser.l
$(CC) -c CommandParser.yy.c
CommandParser.tab.o: CommandParser.y
bison -d CommandParser.y
$(CXX) -c CommandParser.tab.c
Command.o: Command.cpp
$(CXX) -c Command.cpp
clean:
rm -f CommandParser.tab.* CommandParser.yy.* output *.o
Tengo el siguiente archivo MAKE para mi proyecto, y me gustaría configurarlo para versiones de lanzamiento y depuración. En mi código, tengo un montón de macros #ifdef DEBUG
en su lugar, por lo que es simplemente una cuestión de establecer esta macro y agregar los -g3 -gdwarf2
a los compiladores. ¿Cómo puedo hacer esto?
$(CC) = g++ -g3 -gdwarf2
$(cc) = gcc -g3 -gdwarf2
all: executable
executable: CommandParser.tab.o CommandParser.yy.o Command.o
g++ -g -o output CommandParser.yy.o CommandParser.tab.o Command.o -lfl
CommandParser.yy.o: CommandParser.l
flex -o CommandParser.yy.c CommandParser.l
gcc -g -c CommandParser.yy.c
CommandParser.tab.o: CommandParser.y
bison -d CommandParser.y
g++ -g -c CommandParser.tab.c
Command.o: Command.cpp
g++ -g -c Command.cpp
clean:
rm -f CommandParser.tab.* CommandParser.yy.* output *.o
Solo para aclarar, cuando digo compilaciones de liberación / depuración, quiero poder simplemente make
y obtener una compilación de lanzamiento o make debug
y obtener una compilación de depuración, sin comentar manualmente las cosas en el archivo MAKE.
Esta pregunta ha aparecido a menudo cuando se busca un problema similar, por lo que creo que una solución totalmente implementada está garantizada. Especialmente porque yo (y supongo que otros) han tenido problemas para juntar todas las respuestas.
A continuación se muestra un archivo de muestra que admite múltiples tipos de compilación en directorios separados. El ejemplo ilustrado muestra las versiones de depuración y liberación.
Admite ...
- directorios de proyectos separados para compilaciones específicas
- fácil selección de una construcción de destino predeterminada
- objetivo de preparación silenciosa para crear directorios necesarios para construir el proyecto
- indicadores de configuración del compilador específicos de compilación
- El método natural de GNU Make para determinar si el proyecto requiere una reconstrucción
- reglas de patrón en lugar de las reglas de sufijo obsoletos
#
# Compiler flags
#
CC = gcc
CFLAGS = -Wall -Werror -Wextra
#
# Project files
#
SRCS = file1.c file2.c file3.c file4.c
OBJS = $(SRCS:.c=.o)
EXE = exefile
#
# Debug build settings
#
DBGDIR = debug
DBGEXE = $(DBGDIR)/$(EXE)
DBGOBJS = $(addprefix $(DBGDIR)/, $(OBJS))
DBGCFLAGS = -g -O0 -DDEBUG
#
# Release build settings
#
RELDIR = release
RELEXE = $(RELDIR)/$(EXE)
RELOBJS = $(addprefix $(RELDIR)/, $(OBJS))
RELCFLAGS = -O3 -DNDEBUG
.PHONY: all clean debug prep release remake
# Default build
all: prep release
#
# Debug rules
#
debug: $(DBGEXE)
$(DBGEXE): $(DBGOBJS)
$(CC) $(CFLAGS) $(DBGCFLAGS) -o $(DBGEXE) $^
$(DBGDIR)/%.o: %.c
$(CC) -c $(CFLAGS) $(DBGCFLAGS) -o $@ $<
#
# Release rules
#
release: $(RELEXE)
$(RELEXE): $(RELOBJS)
$(CC) $(CFLAGS) $(RELCFLAGS) -o $(RELEXE) $^
$(RELDIR)/%.o: %.c
$(CC) -c $(CFLAGS) $(RELCFLAGS) -o $@ $<
#
# Other rules
#
prep:
@mkdir -p $(DBGDIR) $(RELDIR)
remake: clean all
clean:
rm -f $(RELEXE) $(RELOBJS) $(DBGEXE) $(DBGOBJS)
Estoy de acuerdo con @davidlin, use variables específicas del objetivo para establecer diferentes indicadores para cada configuración. Sin embargo, probablemente también desee colocar sus archivos de salida en directorios separados, para que pueda construir diferentes configuraciones sin reconstruir todo. Usando el ejemplo de @ davidlin, podrías hacer:
debug: CONFIG=debug
debug: executable
executable: output/$(CONFIG)/myprog
# Always use "$@" when referring to the target file.
output/$(CONFIG)/myprog: ...
$(CXX) ... -o $@
Puede usar valores de variables específicos del objetivo . Ejemplo:
CXXFLAGS = -g3 -gdwarf2
CCFLAGS = -g3 -gdwarf2
all: executable
debug: CXXFLAGS += -DDEBUG -g
debug: CCFLAGS += -DDEBUG -g
debug: executable
executable: CommandParser.tab.o CommandParser.yy.o Command.o
$(CXX) -o output CommandParser.yy.o CommandParser.tab.o Command.o -lfl
CommandParser.yy.o: CommandParser.l
flex -o CommandParser.yy.c CommandParser.l
$(CC) -c CommandParser.yy.c
Recuerda usar $ (CXX) o $ (CC) en todos tus comandos de compilación.
Luego, ''make debug'' tendrá indicadores adicionales como -DDEBUG y -g donde ''make'' no lo hará.
En una nota lateral, puedes hacer que tu Makefile sea mucho más conciso como lo sugirieron otras publicaciones.
Si al configurar / lanzar, significa que solo necesita una configuración por archivo MAKE, entonces es simplemente una cuestión y desacopla CC y CFLAGS:
CFLAGS=-DDEBUG
#CFLAGS=-O2 -DNDEBUG
CC=g++ -g3 -gdwarf2 $(CFLAGS)
Dependiendo de si puede usar gnu makefile, puede usar condicional para hacer esto un poco más elegante, y controlarlo desde la línea de comando:
DEBUG ?= 1
ifeq ($(DEBUG), 1)
CFLAGS =-DDEBUG
else
CFLAGS=-DNDEBUG
endif
.o: .c
$(CC) -c $< -o $@ $(CFLAGS)
y luego usa:
make DEBUG=0
make DEBUG=1
Si necesita controlar ambas configuraciones al mismo tiempo, creo que es mejor tener directorios de compilación y un directorio / configuración de compilación.
Tenga en cuenta que también puede hacer su Makefile más simple, al mismo tiempo:
DEBUG ?= 1
ifeq (DEBUG, 1)
CFLAGS =-g3 -gdwarf2 -DDEBUG
else
CFLAGS=-DNDEBUG
endif
CXX = g++ $(CFLAGS)
CC = gcc $(CFLAGS)
EXECUTABLE = output
OBJECTS = CommandParser.tab.o CommandParser.yy.o Command.o
LIBRARIES = -lfl
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CXX) -o $@ $^ $(LIBRARIES)
%.yy.o: %.l
flex -o $*.yy.c $<
$(CC) -c $*.yy.c
%.tab.o: %.y
bison -d $<
$(CXX) -c $*.tab.c
%.o: %.cpp
$(CXX) -c $<
clean:
rm -f $(EXECUTABLE) $(OBJECTS) *.yy.c *.tab.c
Ahora no tiene que repetir los nombres de los archivos por todos lados. Cualquier archivo .l pasará por flex y gcc, cualquier archivo .y pasará por bison y g ++, y cualquier archivo .cpp solo por g ++.
Simplemente liste los archivos .o que espera encontrar, y Make hará el trabajo de averiguar qué reglas pueden satisfacer las necesidades ...
para el registro:
$@
El nombre del archivo de destino (el anterior al colon)$<
El nombre del primer (o único) archivo de requisitos previos (el primero después de los dos puntos)$^
Los nombres de todos los archivos de requisitos previos (espacio separado)$*
El valor raíz (el bit que coincide con el comodín%
en la definición de la regla.
puedes tener una variable
DEBUG = 0
entonces puedes usar un enunciado condicional
ifeq ($(DEBUG),1)
else
endif
ifeq (DEBUG, 1)
debe reemplazarse con ifeq ($(DEBUG), 1)
.