首页 文章

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

提问于
浏览
157

我的项目有以下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

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

6 回答

  • 39

    你可以使用Target-specific Variable Values . 例:

    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
    

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

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

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

  • 2

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

    CFLAGS=-DDEBUG
    #CFLAGS=-O2 -DNDEBUG
    CC=g++ -g3 -gdwarf2 $(CFLAGS)
    

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

    DEBUG ?= 1
    ifeq ($(DEBUG), 1)
        CFLAGS =-DDEBUG
    else
        CFLAGS=-DNDEBUG
    endif
    
    .o: .c
        $(CC) -c $< -o $@ $(CFLAGS)
    

    然后使用:

    make DEBUG=0
    make DEBUG=1
    

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

  • 33

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

    下面是一个示例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)
    
  • 161

    请注意,您还可以同时使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
    

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

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

    作为记录:

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

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

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

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

  • 23

    你可以有一个变量

    DEBUG = 0
    

    那么你可以使用条件语句

    ifeq ($(DEBUG),1)
    
      else
    
      endif
    
  • 1

    完成前面的答案...您需要在命令中引用您定义信息的变量...

    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
    

相关问题