web-dev-qa-db-fra.com

Comment configurer mon makefile pour les versions de débogage et de publication?

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 .

163
samoz

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

176
David Lin

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.

40
David Cournapeau

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

  • répertoires de projets séparés pour des constructions spécifiques
  • sélection facile d'une construction cible par défaut
  • cible de préparation silencieuse pour créer les répertoires nécessaires à la construction du projet
  • drapeaux de configuration du compilateur spécifiques à la construction
  • La méthode naturelle de GNU Make pour déterminer si un projet nécessite une reconstruction
  • règles de modèle plutôt que les règles de suffixe obsolètes

#
# 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)
36
ffhaddad

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.

24
Stobor

vous pouvez avoir une variable

DEBUG = 0

alors vous pouvez utiliser une déclaration conditionnelle

  ifeq ($(DEBUG),1)

  else

  endif
3
Tiberiu

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
1
Stobor