J'ai le makefile suivant pour mon projet et j'aimerais le configurer pour les versions release et debug. Dans mon code, de nombreuses macros #ifdef DEBUG
sont en place. Il suffit donc de définir cette macro et d'ajouter les indicateurs -g3 -gdwarf2
aux compilateurs. Comment puis-je faire ceci?
$(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
Juste pour clarifier, quand je parle des versions release/debug, je veux pouvoir taper make
et obtenir une version release ou make debug
et obtenir une version debug, sans commenter manuellement les éléments du makefile .
Vous pouvez utiliser valeurs variables spécifiques à la cible . Exemple:
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
N'oubliez pas d'utiliser $ (CXX) ou $ (CC) dans toutes vos commandes de compilation.
Ensuite, 'make debug' aura des drapeaux supplémentaires comme -DDEBUG et -g alors que 'make' ne le fera pas.
Sur une note de côté, vous pouvez rendre votre Makefile beaucoup plus concis comme d'autres posts l'ont suggéré.
Si par configure release/build, vous voulez dire que vous n'avez besoin que d'une seule configuration par fichier, alors il s'agit simplement de découpler CC et CFLAGS:
CFLAGS=-DDEBUG
#CFLAGS=-O2 -DNDEBUG
CC=g++ -g3 -gdwarf2 $(CFLAGS)
Selon que vous puissiez ou non utiliser gnu makefile, vous pouvez utiliser conditionnel pour rendre cela un peu plus sophistiqué, et le contrôler à partir de la ligne de commande:
DEBUG ?= 1
ifeq ($(DEBUG), 1)
CFLAGS =-DDEBUG
else
CFLAGS=-DNDEBUG
endif
.o: .c
$(CC) -c $< -o $@ $(CFLAGS)
et ensuite utiliser:
make DEBUG=0
make DEBUG=1
Si vous devez contrôler les deux configurations en même temps, je pense qu’il est préférable d’avoir des répertoires de construction, et un répertoire de construction/config.
Cette question est souvent apparue lors de la recherche d'un problème similaire. Je pense donc qu'une solution entièrement mise en œuvre est justifiée. Surtout que je (et je suppose que d’autres) ont eu du mal à rassembler toutes les réponses.
Vous trouverez ci-dessous un exemple de fichier Makefile qui prend en charge plusieurs types de construction dans des répertoires distincts. L'exemple illustré montre des versions de débogage et de publication.
Les soutiens ...
#
# 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)
Notez que vous pouvez également simplifier votre Makefile en même temps:
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
Maintenant, vous n'avez pas à répéter les noms de fichiers un peu partout. Tous les fichiers .l seront transmis via flex et gcc, tous les fichiers .y seront transmis par bison et g ++, et les fichiers .cpp uniquement par g ++.
Il vous suffit de répertorier les fichiers .o que vous souhaitez obtenir et Make se chargera de déterminer quelles règles peuvent satisfaire les besoins ...
pour le compte rendu:
$@
Le nom du fichier cible (celui avant les deux points)
$<
Nom du premier (ou du seul) fichier de prérequis (le premier après les deux points)
$^
Les noms de tous les fichiers prérequis (séparés par des espaces)
$*
The stem (le bit qui correspond au caractère générique %
dans la définition de la règle.
vous pouvez avoir une variable
DEBUG = 0
alors vous pouvez utiliser une déclaration conditionnelle
ifeq ($(DEBUG),1)
else
endif
Compléter les réponses précédentes ... Vous devez référencer les variables pour lesquelles vous définissez les informations dans vos commandes ...
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