如何为调试和发布版本配置makefile?

sam*_*moz 169 makefile gnu-make

我的项目有以下makefile,我想为发布和调试版本配置它.在我的代码中,我有很多#ifdef DEBUG宏,所以这只是设置这个宏并将-g3 -gdwarf2标志添加到编译器的问题.我怎样才能做到这一点?

$(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
Run Code Online (Sandbox Code Playgroud)

只是为了澄清,当我说发布/调试版本时,我希望能够只键入make并获得发布版本或make debug获得调试版本,而无需手动注释掉makefile中的内容.

Dav*_*Lin 187

您可以使用特定于目标的变量值.例:

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
Run Code Online (Sandbox Code Playgroud)

请记住在所有编译命令中使用$(CXX)或$(CC).

然后,'make debug'将有额外的标志,如-DDEBUG和-g,其中'make'不会.

另外,您可以像其他帖子建议的那样使Makefile更加简洁.

  • 您永远不应该在Makefile或BadThingsMayHappen(TM)中更改CXX或CC,它们包含要运行的可执行文件的路径和/或名称.CPPFLAGS,CXXFLAGS和CFLAGS就是为了这个目的. (42认同)
  • 这个建议很差,因为它混合了调试和非调试目标文件,因此最终会出现损坏的构建. (9认同)
  • @MauriceRandomNumber将调试/发布构建到自己的文件夹中.示例:/sf/answers/3415514091/ (3认同)

Dav*_*eau 42

如果通过configure release/build,你的意思是你只需要为每个makefile配置一个配置,那么它只是一个问题并且解耦CC和CFLAGS:

CFLAGS=-DDEBUG
#CFLAGS=-O2 -DNDEBUG
CC=g++ -g3 -gdwarf2 $(CFLAGS)
Run Code Online (Sandbox Code Playgroud)

根据您是否可以使用gnu makefile,您可以使用条件使它更有点发烧,并从命令行控制它:

DEBUG ?= 1
ifeq ($(DEBUG), 1)
    CFLAGS =-DDEBUG
else
    CFLAGS=-DNDEBUG
endif

.o: .c
    $(CC) -c $< -o $@ $(CFLAGS)
Run Code Online (Sandbox Code Playgroud)

然后使用:

make DEBUG=0
make DEBUG=1
Run Code Online (Sandbox Code Playgroud)

如果你需要同时控制两个配置,我认为最好有构建目录和一个构建目录/配置.

  • 我不知道我是否做了一些奇怪的事情,但为了让我的调试if语句起作用(`ifeq(DEBUG,1)`),``DEBUG`变量需要包含在括号中,如下所示:`ifeq( $(DEBUG),1)`. (18认同)

ffh*_*dad 37

在搜索类似问题时经常出现这个问题,所以我觉得有充分实施的解决方案是有道理的.特别是因为我(我会假设其他人)一直努力拼凑所有各种答案.

下面是一个示例Makefile,它在不同的目录中支持多种构建类型.图示的示例显示了调试和发布版本.

支持......

  • 用于特定构建的单独项目目录
  • 轻松选择默认目标构建
  • 静默准备目标,用于创建构建项目所需的目录
  • 特定于构建的编译器配置标志
  • GNU Make确定项目是否需要重建的自然方法
  • 模式规则而不是过时的后缀规则

#
# 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)
Run Code Online (Sandbox Code Playgroud)

  • 我不喜欢的是重复调试和发布的所有规则和变量。我有一个类似的Makefile,但是在扩展它时,我需要仔细复制粘贴每个新内容以进行调试和发布,然后仔细进行转换。 (2认同)

Sto*_*bor 24

请注意,您还可以同时使Makefile更简单:

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
Run Code Online (Sandbox Code Playgroud)

现在,您不必在整个地方重复文件名.任何.l文件都将通过flex和gcc传递,任何.y文件都将通过bison和g ++以及任何.cpp文件通过g ++传递.

只需列出您希望最终得到的.o文件,Make将完成确定哪些规则可以满足需求的工作......

作为记录:

  • $@ 目标文件的名称(冒号前面的文件)

  • $< 第一个(或唯一的)先决条件文件的名称(冒号后的第一个)

  • $^ 所有必备文件的名称(空格分隔)

  • $*词干(与%规则定义中的通配符匹配的位).

  • 我希望有更多这些简短的指南来编写一个相当小的Makefile,包括自动变量. (2认同)
  • 该解决方案存在调试和发布输出文件混合在同一目录中的问题。如果它们不兼容,除非您每次在调试和不调试之间进行更改时都小心地进行清理,否则这将以奇怪而美妙的方式爆炸。即使它们是兼容的,如果没有清理,它也不会达到您所期望的效果:如果您将项目构建为发布版,然后使 DEBUG=1,它只会重建源已更改的文件,因此您通常不会以这种方式获得“调试”版本。 (2认同)