Makefile - 4. 고급 Makefile 작성 (4-1. 다중 디렉토리 관리 (Managing Multiple Directories))

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

📌 4-1. 다중 디렉토리 관리 (Managing Multiple Directories)

대규모 프로젝트에서는 소스 코드가 여러 개의 서브 디렉토리(Subdirectories)에 분산될 수 있습니다.
이때, 각각의 서브 디렉토리에서 Makefile을 실행하면 빌드를 더욱 효율적으로 관리할 수 있습니다.

Makefile에서 다중 디렉토리를 관리하는 대표적인 방법으로 다음과 같은 기법이 사용됩니다.

  1. SUBDIRS 패턴을 사용하여 서브 디렉토리별로 make 실행
  2. make -C subdir을 활용하여 서브 디렉토리에서 개별적으로 빌드 수행

1. 다중 디렉토리를 관리하는 이유

📌 1-1. 왜 다중 디렉토리 관리가 필요한가?

대규모 프로젝트 관리 용이

  • 하나의 Makefile에서 모든 소스 파일을 관리하는 것은 비효율적
  • 디렉토리별로 Makefile을 분리하면 모듈 단위로 관리 가능

빌드 속도 향상

  • 특정 디렉토리에서 변경된 파일만 다시 빌드 가능
  • 서브 디렉토리 단위로 병렬 빌드(make -j) 수행 가능

재사용성 증가

  • 라이브러리(lib/), 실행 파일(bin/), 소스 코드(src/) 등으로 분리하여 유지보수 편리

2. SUBDIRS 패턴을 활용한 서브 디렉토리 Makefile 실행

📌 2-1. SUBDIRS를 활용한 다중 디렉토리 관리

Makefile에서 서브 디렉토리를 순차적으로 빌드하기 위해 SUBDIRS 변수를 사용하여 관리할 수 있습니다.


📌 2-2. SUBDIRS 활용 예제

🔹 프로젝트 구조

project/
├── src/
│   ├── main.c
│   ├── utils.c
│   ├── Makefile
├── lib/
│   ├── math.c
│   ├── Makefile
├── bin/
│   ├── Makefile
├── Makefile (최상위 Makefile)

🔹 project/src/Makefile

CC = gcc
CFLAGS = -Wall -g
SRC = main.c utils.c
OBJS = $(SRC:.c=.o)

all: $(OBJS)
	$(CC) $(CFLAGS) -c $^

clean:
	rm -f $(OBJS)

🔹 project/lib/Makefile

CC = gcc
CFLAGS = -Wall -g
SRC = math.c
OBJS = $(SRC:.c=.o)

all: $(OBJS)
	$(CC) $(CFLAGS) -c $^

clean:
	rm -f $(OBJS)

🔹 project/bin/Makefile

CC = gcc
CFLAGS = -Wall -g
LDFLAGS = -L../lib
LDLIBS = -lmath

all: myprogram

myprogram: ../src/main.o ../src/utils.o ../lib/math.o
	$(CC) $(CFLAGS) $(LDFLAGS) -o myprogram $^ $(LDLIBS)

clean:
	rm -f myprogram

🔹 project/Makefile (최상위 Makefile)

SUBDIRS = lib src bin

all:
	for dir in $(SUBDIRS); do $(MAKE) -C $$dir; done

clean:
	for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done

설명

  • SUBDIRS 변수를 활용하여 lib/, src/, bin/ 디렉토리를 순차적으로 빌드
  • $(MAKE) -C $$dir를 사용하여 각 디렉토리에서 make 실행
  • clean 목표를 실행하면 각 디렉토리의 clean이 실행됨

실행 과정

make

➡ lib/Makefile 실행
➡ src/Makefile 실행
➡ bin/Makefile 실행

make clean

➡ lib/Makefile의 clean 실행
➡ src/Makefile의 clean 실행
➡ bin/Makefile의 clean 실행


3. make -C subdir를 활용한 서브 디렉토리 빌드

📌 3-1. make -C의 개념

  • make -C subdir 명령을 사용하면 서브 디렉토리로 이동한 후 Makefile을 실행할 수 있습니다.
  • cd subdir && make를 실행하는 것과 동일한 효과

📌 3-2. make -C 활용 예제

🔹 project/Makefile (최상위 Makefile)

all:
	$(MAKE) -C lib
	$(MAKE) -C src
	$(MAKE) -C bin

clean:
	$(MAKE) -C lib clean
	$(MAKE) -C src clean
	$(MAKE) -C bin clean

실행 과정

make

➡ make -C lib 실행
➡ make -C src 실행
➡ make -C bin 실행

make clean

➡ make -C lib clean 실행
➡ make -C src clean 실행
➡ make -C bin clean 실행


📌 3-3. make -C를 활용한 빌드 옵션 전달

  • make -C를 사용할 때, 변수를 전달할 수도 있음
make -C src DEBUG=1

➡ src/Makefile에서 DEBUG=1을 적용하여 빌드 수행

make -C lib CC=clang

➡ lib/Makefile에서 CC=clang을 적용하여 clang으로 빌드


4. SUBDIRS vs make -C 차이점

방법  설명  장점  단점
SUBDIRS 패턴 for dir in $(SUBDIRS); do $(MAKE) -C $$dir; done 여러 디렉토리를 반복적으로 빌드 가능 쉘 스크립트 구문이므로 일부 환경에서 오류 가능
make -C $(MAKE) -C src 각 디렉토리를 독립적으로 실행 가능, 가독성 높음 디렉토리 수가 많으면 반복 코드 증가

추천

  • 소규모 프로젝트: make -C가 가독성이 좋음
  • 대규모 프로젝트: SUBDIRS 패턴이 확장성이 뛰어남

📌 4-1. 다중 디렉토리 관리 요약 정리

개념  설명
SUBDIRS 패턴 for 루프를 사용하여 서브 디렉토리 빌드를 반복 실행
make -C subdir 특정 디렉토리에서 make를 실행
다중 Makefile 관리 서브 디렉토리별 Makefile을 사용하여 프로젝트를 모듈화
변수 전달 (make -C) make -C src DEBUG=1 처럼 특정 빌드 옵션 전달 가능