Como posso configurar meu makefile para depuração e compilações?
Pergunta
Eu tenho o seguinte makefile para o meu projeto, e eu gostaria de configurá-lo para a liberação e compilações de depuração. No meu código, eu tenho um monte de macros #ifdef DEBUG
no lugar, por isso é simplesmente uma questão de definir esta macro e adicionando as bandeiras -g3 -gdwarf2
para os compiladores. Como posso fazer isso?
$(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
Só para esclarecer, quando eu digo liberação / compilações de depuração, eu quero ser capaz de tipo apenas make
e obter uma compilação de lançamento ou make debug
e obter uma compilação de depuração, sem comentar manualmente as coisas no makefile.
Solução
Você pode usar valores de variáveis ??específicas-alvo . Exemplo:
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
Lembre-se de usar $ (CXX) ou $ (CC) em todos os seus comandos de compilação.
Em seguida, 'make debug' terá bandeiras extras, como -DDEBUG e -g onde como 'make' não vai.
Em uma nota lateral, você pode fazer o seu Makefile muito mais concisa como outras mensagens tinha sugerido.
Outras dicas
Se por liberação configure / compilação, você significa que você só precisa de uma configuração por makefile, então é simplesmente uma questão e desacoplamento CC e CFLAGS:
CFLAGS=-DDEBUG
#CFLAGS=-O2 -DNDEBUG
CC=g++ -g3 -gdwarf2 $(CFLAGS)
Dependendo se você pode usar o GNU makefile, você pode usar condicional para tornar este um apreciador pouco, e controlá-lo a partir da linha de comando:
DEBUG ?= 1
ifeq ($(DEBUG), 1)
CFLAGS =-DDEBUG
else
CFLAGS=-DNDEBUG
endif
.o: .c
$(CC) -c $< -o $@ $(CFLAGS)
e, em seguida, use:
make DEBUG=0
make DEBUG=1
Se você precisa controlar ambas as configurações, ao mesmo tempo, eu acho que é melhor ter diretórios construir, e um diretório de compilação / config.
Esta questão tem aparecido muitas vezes na busca de um problema semelhante, então eu sinto uma solução totalmente implementado se justifica. Especialmente desde que eu (e eu assumiria outros) têm lutado montando todas as várias respostas juntos.
Abaixo está uma amostra Makefile que suporta vários tipos de compilação em diretórios separados. A mostras de depuração e libertação exemplo ilustrado constrói.
Apoia ...
- diretórios do projeto separados para específico constrói
- fácil selecção de uma compilação de destino padrão
- alvo de preparação silenciosa para criar os diretórios necessários para a construção do projeto
- bandeiras de configuração do compilador específico da construção
- método natural do GNU make de determinar se o projeto requer uma reconstrução
- regras padrão, em vez das regras de sufixo 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)
Note que você também pode fazer o seu Makefile simples, ao mesmo tempo:
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
Agora você não tem que repetir nomes de arquivos em todo o lugar. Quaisquer arquivos .L serão passados ??através de flex e gcc, todos os arquivos Y. serão passados ??através de bisões e g ++, e quaisquer arquivos .cpp através de apenas g ++.
lista apenas os arquivos .o que você espera acabar com, e fazer vai fazer o trabalho de descobrir que as regras podem satisfazer as necessidades ...
para o registro:
-
$@
O nome do arquivo de destino (aquele antes dos dois pontos) -
$<
O nome do primeiro (ou único) ficheiro pré-requisito (o primeiro após os dois pontos) -
$^
Os nomes de todos os arquivos de pré-requisitos (espaço) -
$*
O caule (o pouco que combina o curinga%
na definição da regra.
Você pode ter uma variável
DEBUG = 0
então você pode usar uma instrução condicional
ifeq ($(DEBUG),1)
else
endif
Completando as respostas de mais cedo ... você precisa referenciar as variáveis ??que definem informação em seus 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