Makefile - 4. 고급 Makefile 작성 (4-2. 병렬 빌드 (Parallel Build))
2025. 3. 11. 19:10ㆍ개발/개발도구와 환경
📌 4-2. 병렬 빌드 (Parallel Build)
Makefile에서 병렬 빌드(Parallel Build)는 여러 개의 컴파일 작업을 동시에 실행하여 빌드 속도를 향상시키는 기법입니다.
이를 위해 make -j 옵션과 $(MAKE) 변수를 활용할 수 있습니다.
1. 병렬 빌드(Parallel Build)란?
📌 1-1. 병렬 빌드의 개념
- 기본적으로 make는 직렬(Sequential)로 실행됩니다.
- 하지만, 여러 개의 소스 파일을 각각 독립적으로 컴파일할 수 있는 경우,
여러 개의 CPU 코어를 활용하여 동시에 컴파일을 수행하면 빌드 속도가 크게 향상됩니다.
📌 1-2. 병렬 빌드가 필요한 이유
✅ 빌드 속도 향상
- 멀티코어 CPU를 활용하여 여러 개의 파일을 동시에 컴파일
- 프로젝트 규모가 커질수록 빌드 시간이 단축됨
✅ 하드웨어 리소스 최적 활용
- 일반적으로 컴파일은 CPU 연산 중심이므로, 멀티코어 환경에서 더 빠르게 실행 가능
✅ 대규모 프로젝트에서 필수
- 리눅스 커널, 크로미움 브라우저, LLVM 같은 대형 프로젝트는 항상 병렬 빌드를 활용
2. make -j 옵션을 사용한 병렬 빌드
📌 2-1. make -j 기본 사용법
make -jN 옵션을 사용하면 N개의 작업을 병렬로 실행합니다.
make -j4
➡ 4개의 프로세스를 동시에 실행하여 컴파일 속도를 높임.
make -j8
➡ 8개의 프로세스를 실행 (멀티코어 CPU에서 추천).
make -j$(nproc)
➡ 시스템의 CPU 개수만큼 프로세스를 자동으로 사용 (nproc 명령어 활용).
📌 2-2. make -j 실행 예제
🔹 프로젝트 구조
project/
├── src/
│ ├── main.c
│ ├── utils.c
│ ├── io.c
├── Makefile
🔹 Makefile (병렬 빌드 적용)
CC = gcc
CFLAGS = -Wall -g
SRC = main.c utils.c io.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)
✅ 직렬 빌드 실행 (기본 실행)
make
➡ main.c, utils.c, io.c가 순차적으로 컴파일됨.
✅ 병렬 빌드 실행 (4개 프로세스 사용)
make -j4
➡ main.c, utils.c, io.c가 동시에 컴파일됨 → 빌드 속도 향상.
3. $(MAKE) 변수를 활용한 병렬 빌드
📌 3-1. $(MAKE)란?
- $(MAKE) 변수는 현재 실행 중인 make 명령어를 저장하는 특별한 변수입니다.
- 병렬 빌드(-j 옵션 포함)를 하위 Makefile에도 자동으로 전달할 수 있습니다.
📌 3-2. $(MAKE) 활용 예제
🔹 프로젝트 구조
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/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
✅ 병렬 빌드 실행
make -j4
➡ $(MAKE) -C $$dir에 의해 각 서브 디렉토리에서도 병렬 빌드가 적용됨.
✅ 하위 디렉토리에서도 -j 옵션 전달됨
make -j8
➡ lib/, src/, bin/ 내부에서도 make -j8이 적용되어 속도가 더욱 빨라짐.
4. 병렬 빌드의 주의점과 최적화 방법
📌 4-1. 병렬 빌드 시 발생할 수 있는 문제
❌ 의존성 문제
- 여러 개의 프로세스가 동시에 실행되므로, 의존성이 올바르게 설정되지 않으면 빌드가 실패할 수 있음.
❌ 링킹 문제
- .o 파일이 아직 생성되지 않았는데 gcc -o가 먼저 실행될 경우 에러 발생 가능.
📌 4-2. 병렬 빌드 최적화 방법
✅ 올바른 의존성 설정
- all 빌드 타겟이 실행되기 전에 모든 .o 파일이 먼저 생성되도록 의존성을 명확하게 설정해야 함.
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
✅ 디렉토리별 병렬 빌드 적용 ($(MAKE) -C)
- 하위 디렉토리에서 개별적으로 병렬 빌드 수행 가능
all:
$(MAKE) -j$(nproc) -C src
$(MAKE) -j$(nproc) -C lib
✅ 최적의 -j 값 선택
- 시스템의 CPU 개수(nproc 또는 sysctl -n hw.ncpu)를 기반으로 병렬 빌드 수행.
make -j$(nproc)
➡ 시스템의 CPU 개수에 맞춰 최적의 성능을 자동으로 조정.
📌 4-2. 병렬 빌드 요약 정리
개념 | 설명 |
make -jN | N개의 프로세스를 사용하여 병렬 빌드 수행 |
$(MAKE) | 하위 디렉토리에서도 make 실행 시 -j 옵션을 유지 |
의존성 문제 해결 | 타겟 의존성을 올바르게 설정해야 병렬 빌드 시 에러 방지 |
최적의 -j 값 설정 | make -j$(nproc)을 사용하여 CPU 개수에 맞춰 빌드 |