Makefile - 2. Makefile의 기본 문법 (2-3. 패턴 규칙 (Pattern Rules))

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

📌 2-3. 패턴 규칙 (Pattern Rules)

1. 패턴 규칙(Pattern Rules)란?

패턴 규칙(Pattern Rules)은 Makefile에서 반복되는 규칙을 줄이고 유지보수를 쉽게 하기 위해 사용됩니다.
여러 개의 파일을 동일한 방식으로 처리해야 할 때 매우 유용하며, 특히 오브젝트 파일(.o) 생성 등에서 자주 활용됩니다.


2. 일반적인 패턴 규칙

📌 2-1. 패턴 규칙의 기본 구조

패턴 규칙의 기본 문법은 다음과 같습니다.

%.target: %.dependency
	commands
  • %는 와일드카드(wildcard) 역할을 하며, 파일명을 대체합니다.
  • %.o: %.c는 "어떤 파일명이든 .c 확장자를 가진 파일을 .o 파일로 변환"하라는 의미입니다.

📌 2-2. 패턴 규칙이 필요한 이유

코드 중복 제거

  • Makefile에서 모든 .c 파일을 일일이 지정하면 관리가 어렵습니다.
  • 패턴 규칙을 사용하면 규칙을 한 번만 정의하고 모든 파일에 적용할 수 있습니다.

확장성 증가

  • 새로운 소스 파일이 추가되었을 때, Makefile을 수정하지 않아도 자동으로 적용됩니다.

빌드 속도 최적화

  • 변경된 파일만 다시 컴파일할 수 있도록 증분 빌드(Incremental Build)를 수행합니다.

3. %.o: %.c 패턴 활용법

📌 3-1. %.o: %.c 기본 사용법

일반적으로 C 프로그램에서 오브젝트 파일(.o)을 생성할 때 사용됩니다.

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@
자동 변수 설명
$< 첫 번째 의존 파일(Dependency), 즉 .c 파일
$@ 현재 목표 파일(Target), 즉 .o 파일

🔹 예제

CC = gcc
CFLAGS = -Wall -g

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

위의 Makefile을 실행하면 다음과 같이 동작합니다.

make main.o

➡ 내부적으로 실행되는 명령어:

gcc -Wall -g -c main.c -o main.o
make utils.o

➡ 내부적으로 실행되는 명령어:

gcc -Wall -g -c utils.c -o utils.o

📌 3-2. 패턴 규칙을 활용한 최적화된 Makefile

패턴 규칙을 사용하면 Makefile을 더 깔끔하게 정리할 수 있습니다.

🔹 일반적인 Makefile (패턴 규칙 없이 작성된 경우)

CC = gcc
CFLAGS = -Wall -g

myprogram: main.o utils.o
	$(CC) $(CFLAGS) -o myprogram main.o utils.o

main.o: main.c
	$(CC) $(CFLAGS) -c main.c -o main.o

utils.o: utils.c
	$(CC) $(CFLAGS) -c utils.c -o utils.o

clean:
	rm -f *.o myprogram

이 경우, .o 파일이 많아질수록 같은 코드가 계속 반복되어 Makefile이 길어지고 관리가 어려워집니다.


🔹 패턴 규칙을 활용한 Makefile (최적화 버전)

CC = gcc
CFLAGS = -Wall -g

SRC = main.c utils.c
OBJS = $(SRC:.c=.o)
TARGET = myprogram

all: $(TARGET)

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

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -f $(OBJS) $(TARGET)

이점

  • SRC = main.c utils.c → 소스 파일을 추가할 때 한 줄만 수정하면 됨.
  • OBJS = $(SRC:.c=.o) → .c 파일 목록을 .o 파일로 자동 변환.
  • % 패턴 규칙을 사용하여 모든 .o 파일을 자동으로 컴파일하도록 설정.

🔹 실행 과정

make
  1. $(TARGET) (myprogram)을 빌드해야 함.
  2. myprogram을 만들려면 main.o utils.o가 필요함.
  3. main.o, utils.o가 없거나 변경되었으면 각각의 .c 파일을 컴파일 (%.o: %.c 패턴 규칙 적용).
  4. gcc -o myprogram main.o utils.o 실행됨.

📌 3-3. 다중 디렉토리에서 패턴 규칙 활용

만약 소스 코드가 여러 개의 디렉토리에 분산되어 있다면, 패턴 규칙을 활용하여 더 효과적으로 관리할 수 있습니다.

🔹 디렉토리 구조 예제

project/
├── src/
│   ├── main.c
│   ├── utils.c
│   ├── io.c
│   ├── io.h
│   ├── utils.h
├── build/
├── Makefile

🔹 Makefile

CC = gcc
CFLAGS = -Wall -g
SRCDIR = src
OBJDIR = build
SRC = $(wildcard $(SRCDIR)/*.c)
OBJS = $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRC))
TARGET = myprogram

all: $(TARGET)

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

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

clean:
	rm -f $(OBJDIR)/*.o $(TARGET)

이점

  • $(wildcard $(SRCDIR)/*.c) → src/ 디렉토리의 모든 .c 파일을 자동 검색.
  • $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRC)) → src/에서 .c → build/에서 .o로 변환.
  • 패턴 규칙 $(OBJDIR)/%.o: $(SRCDIR)/%.c을 사용하여 각 디렉토리에서 파일을 자동 변환.

🔹 실행 과정

make
  1. src/ 디렉토리의 .c 파일들을 build/ 디렉토리의 .o 파일로 변환.
  2. gcc -o myprogram build/main.o build/utils.o build/io.o 실행됨.

📌 2-3. 패턴 규칙 (Pattern Rules) 요약 정리

개념  설명
패턴 규칙 %를 사용하여 반복되는 빌드 규칙을 줄이는 방법
기본 형식 %.o: %.c
자동 변수 사용 $@ (타겟 파일), $< (첫 번째 의존성), $^ (모든 의존성)
Makefile 최적화 패턴 규칙을 사용하여 코드 중복 제거
다중 디렉토리 적용 SRCDIR과 OBJDIR을 활용하여 빌드 시스템 구축