Makefile - 5. Makefile 최적화 및 실전 프로젝트 적용 (5-3. 실제 프로젝트에서 Makefile 적용)

2025. 3. 11. 19:16개발/개발도구와 환경

📌 5-3. 실제 프로젝트에서 Makefile 적용

Makefile을 활용하면 대규모 프로젝트에서도 효율적인 빌드 시스템을 구축할 수 있습니다.
이번 섹션에서는 실제 프로젝트 구조를 기반으로 Makefile을 작성하는 방법을 살펴보겠습니다.


1. 프로젝트 구조 예시

다음과 같은 프로젝트 구조를 예제로 사용합니다.

project/
├── src/           # 소스 코드 디렉토리
│   ├── main.c
│   ├── utils.c
│   └── utils.h
├── include/       # 헤더 파일 저장 디렉토리
│   └── config.h
├── build/         # 빌드된 오브젝트 파일과 실행 파일이 저장될 디렉토리
├── Makefile       # 프로젝트 빌드를 위한 Makefile

각 디렉토리의 역할

  • src/ : C 소스 코드 (.c, .h 파일 포함)
  • include/ : 전역적으로 사용되는 헤더 파일 (config.h)
  • build/ : 빌드된 오브젝트 파일(.o) 및 실행 파일을 저장
  • Makefile : 빌드 자동화 규칙을 정의하는 파일

2. Makefile 작성: 기본 구조

이제 프로젝트 구조에 맞춰 Makefile을 작성해보겠습니다.
이 Makefile은 다음 기능을 포함합니다.

기능

  1. src/ 디렉토리의 .c 파일을 자동으로 build/ 디렉토리에 컴파일.
  2. include/ 디렉토리에 있는 헤더 파일을 포함하도록 설정.
  3. clean 명령을 추가하여 불필요한 파일 삭제 가능.

📌 2-1. 기본적인 Makefile

# 컴파일러 및 플래그 설정
CC = gcc
CFLAGS = -Wall -g -Iinclude

# 디렉토리 설정
SRCDIR = src
BUILDDIR = build

# 소스 및 오브젝트 파일 설정
SRC = $(wildcard $(SRCDIR)/*.c)
OBJS = $(patsubst $(SRCDIR)/%.c, $(BUILDDIR)/%.o, $(SRC))

# 실행 파일 이름
TARGET = $(BUILDDIR)/myprogram

# 기본 빌드 실행
all: $(TARGET)

# 실행 파일 빌드
$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

# 개별 .c -> .o 파일 변환 규칙
$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
	$(CC) $(CFLAGS) -c $< -o $@

# build 디렉토리가 없으면 생성
$(BUILDDIR):
	mkdir -p $(BUILDDIR)

# 클린 빌드 (불필요한 파일 제거)
clean:
	rm -rf $(BUILDDIR)

📌 2-2. Makefile 설명

구성 요소
설명
CC = gcc 컴파일러로 gcc 사용
CFLAGS = -Wall -g -Iinclude 경고 표시 -Wall, 디버깅 -g, include/ 헤더 포함
SRCDIR = src 소스 파일이 위치한 디렉토리
BUILDDIR = build 빌드된 .o 및 실행 파일을 저장할 디렉토리
SRC = $(wildcard $(SRCDIR)/*.c) src/ 디렉토리의 모든 .c 파일 목록을 자동으로 가져옴
OBJS = $(patsubst $(SRCDIR)/%.c, $(BUILDDIR)/%.o, $(SRC)) .c 파일을 .o 파일로 변환하여 build/ 디렉토리에 저장
$(TARGET): $(OBJS) 오브젝트 파일들을 링크하여 실행 파일 생성
$(BUILDDIR)/%.o: $(SRCDIR)/%.c 개별 .c 파일을 .o 파일로 변환
$(BUILDDIR): build/ 디렉토리가 없으면 생성
clean: build/ 디렉토리를 삭제하여 클린 빌드 수행

3. Makefile 실행 과정

빌드 실행

make

➡ 실행 결과:

mkdir -p build
gcc -Wall -g -Iinclude -c src/main.c -o build/main.o
gcc -Wall -g -Iinclude -c src/utils.c -o build/utils.o
gcc -Wall -g -o build/myprogram build/main.o build/utils.o

실행 파일 생성 완료 (build/myprogram)

클린 빌드 실행

make clean

➡ 실행 결과:

rm -rf build

build/ 디렉토리 삭제 및 초기화 완료


4. Makefile 확장: 디버그 및 최적화 모드 추가

디버깅이나 최적화가 필요할 경우, 다음과 같이 DEBUG 및 OPTIMIZE 모드를 추가할 수 있습니다.

# 기본 플래그 설정
CC = gcc
CFLAGS = -Wall -Iinclude

# 디버그 모드
ifdef DEBUG
  CFLAGS += -g -DDEBUG
endif

# 최적화 모드
ifdef OPTIMIZE
  CFLAGS += -O2
endif

# 기본 설정
SRCDIR = src
BUILDDIR = build
SRC = $(wildcard $(SRCDIR)/*.c)
OBJS = $(patsubst $(SRCDIR)/%.c, $(BUILDDIR)/%.o, $(SRC))
TARGET = $(BUILDDIR)/myprogram

all: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILDDIR):
	mkdir -p $(BUILDDIR)

clean:
	rm -rf $(BUILDDIR)

디버그 빌드 실행

make DEBUG=1

➡ -g -DDEBUG 플래그 추가됨.

최적화 빌드 실행

make OPTIMIZE=1

➡ -O2 플래그 추가됨.


📌 5-3. 실제 프로젝트에서 Makefile 적용 요약 정리

Makefile 기능 설명
SRC = $(wildcard $(SRCDIR)/*.c) src/ 디렉토리의 .c 파일을 자동으로 가져옴
OBJS = $(patsubst $(SRCDIR)/%.c, $(BUILDDIR)/%.o, $(SRC)) .c 파일을 .o 파일로 변환
$(BUILDDIR)/%.o: $(SRCDIR)/%.c .c 파일을 build/ 디렉토리의 .o 파일로 변환
DEBUG=1 -g -DDEBUG 플래그 추가
OPTIMIZE=1 -O2 플래그 추가
make clean 빌드된 파일을 삭제하여 클린 빌드 수행