[makefile] 디버그 및 릴리스 빌드를 위해 makefile을 구성하려면 어떻게해야합니까?

내 프로젝트에 다음과 같은 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

명확히하기 위해 릴리스 / 디버그 빌드를 말할 때 makefile의 내용을 수동으로 주석 처리하지 않고 make릴리스 빌드를 입력 하고 make debug디버그 빌드를 얻을 수 있기를 원합니다 .



답변

대상별 변수 값을 사용할 수 있습니다 . 예:

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’에는 ‘make’가 아닌 -DDEBUG 및 -g와 같은 추가 플래그가 있습니다.

참고로, 다른 게시물에서 제안한 것처럼 Makefile을 훨씬 간결하게 만들 수 있습니다.


답변

이 질문은 비슷한 문제를 검색 할 때 자주 나타 났으므로 완전히 구현 된 솔루션이 필요하다고 생각합니다. 특히 나는 (그리고 다른 사람들을 가정 할 것이므로) 모든 다양한 답을 하나로 묶는 데 어려움을 겪었다.

다음은 별도의 디렉토리에서 여러 빌드 유형을 지원하는 샘플 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)


답변

릴리스 / 빌드를 구성한다고해서 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

두 구성을 동시에 제어 해야하는 경우 빌드 디렉토리와 하나의 빌드 디렉토리 / 구성을 갖는 것이 좋습니다.


답변

동시에 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가 어떤 규칙이 요구를 충족시킬 수 있는지 알아내는 작업을 수행합니다 …

기록을 위해 :

  • $@ 대상 파일의 이름 (콜론 앞의 이름)

  • $< 첫 번째 (또는 유일한) 전제 조건 파일의 이름 (콜론 다음의 첫 번째 파일)

  • $^ 모든 전제 조건 파일 이름 (공백으로 구분)

  • $*스템 ( %규칙 정의에서 와일드 카드 와 일치하는 비트)


답변

당신은 변수를 가질 수 있습니다

DEBUG = 0

그런 다음 조건문을 사용할 수 있습니다

  ifeq ($(DEBUG),1)

  else

  endif


답변

이전 답변을 완료하는 중 … 명령에서 정보를 정의하는 변수를 참조해야합니다 …

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


답변

Makefile에 간단한 것과 같은 것을 추가 할 수도 있습니다.

ifeq ($(DEBUG),1)
   OPTS = -g
endif

그런 다음 디버깅을 위해 컴파일하십시오.

make DEBUG=1