tutorial make create makefile gnu-make

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