본문 바로가기
Computer Science/C 언어

[C# 11] Makefile 분석

by rnasterofmysea 2024. 12. 9.
반응형

Makefile이란?

  • Makefilemake 명령을 이용해 프로그램의 컴파일과 빌드 과정을 자동화하는 파일입니다.
  • 다중 소스 파일을 관리하며, 파일 의존성을 기반으로 필요한 부분만 재컴파일하여 시간을 절약합니다.

Makefile의 기본 구성 요소

1) 목표(Target)

  • 빌드해야 할 대상 파일(예: 실행 파일 이름).

2) 의존성(Dependencies)

  • 대상 파일이 생성되기 위해 필요한 파일(예: 소스 파일, 헤더 파일).

3) 명령(Rules)

  • 의존성을 만족하기 위해 실행할 명령어(예: 컴파일 명령).

기본 Makefile 구조

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

# 소스 및 타겟 설정
TARGET = program             # 최종 생성될 실행 파일
SRC = main.c module.c        # 소스 파일 목록
OBJ = main.o module.o        # 객체 파일 목록

# 기본 타겟
$(TARGET): $(OBJ)            # 실행 파일 생성 규칙
	$(CC) $(CFLAGS) -o $@ $^  # 객체 파일을 링크하여 실행 파일 생성

# 객체 파일 생성 규칙
%.o: %.c                     # 모든 .c 파일 -> 대응하는 .o 파일 생성
	$(CC) $(CFLAGS) -c $< -o $@

# 클린업 규칙
clean:
	rm -f $(OBJ) $(TARGET)    # 객체 파일 및 실행 파일 삭제

Makefile 코드 상세 설명

1. 변수 정의

변수는 Makefile에서 반복되는 값을 간단히 설정하기 위해 사용됩니다.

CC = gcc
CFLAGS = -Wall -g
  • CC: 사용할 컴파일러를 지정. 대부분 gcc 또는 clang 사용.
  • CFLAGS: 컴파일러 플래그 설정.
    • -Wall: 컴파일 시 모든 경고 표시.
    • -g: 디버깅 정보를 포함.

2. 타겟과 의존성

타겟은 Makefile의 주요 목적입니다. 타겟은 의존성과 명령으로 구성됩니다.

$(TARGET): $(OBJ)
	$(CC) $(CFLAGS) -o $@ $^
  • $(TARGET): 생성할 최종 실행 파일.
  • $(OBJ): 실행 파일을 생성하기 위해 필요한 객체 파일 목록.
  • 명령: 객체 파일을 링크하여 실행 파일 생성.
    • $@: 현재 타겟의 이름 (program).
    • $^: 모든 의존성 파일 목록 (main.o module.o).

3. 패턴 규칙

패턴 규칙은 특정 파일 유형에 대해 공통 작업을 정의합니다.

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@
  • %.o: 어떤 .o 파일이든 타겟이 될 수 있음.
  • %.c: 대응하는 .c 파일.
  • 명령:
    • $<: 첫 번째 의존성 파일(현재 .c 파일).
    • $@: 현재 타겟 파일(생성될 .o 파일).
  • 작동 방식:
    • main.c → main.o
    • module.c → module.o

4. 클린업 규칙

clean은 빌드 과정에서 생성된 파일을 삭제하는 규칙입니다.

clean:
	rm -f $(OBJ) $(TARGET)
  • rm -f: 강제로 파일을 삭제. 오류 메시지 방지.
  • $(OBJ): 모든 객체 파일(main.o, module.o) 삭제.
  • $(TARGET): 실행 파일(program) 삭제.

사용 방법:

make clean

Makefile의 동작 흐름

  1. 실행 파일 생성 타겟:
    • program 실행 파일 생성.
    • 객체 파일(main.o, module.o)이 필요한 의존성.
  2. $(TARGET): $(OBJ) $(CC) $(CFLAGS) -o $@ $^
  3. 객체 파일 생성 규칙:
    • .c 파일을 컴파일하여 대응하는 .o 파일 생성.
  4. %.o: %.c $(CC) $(CFLAGS) -c $< -o $@
  5. 클린업:
    • 중간 파일과 실행 파일 삭제.
  6. clean: rm -f $(OBJ) $(TARGET)

확장된 Makefile 기능

1. 자동 의존성 생성

헤더 파일 변경 시 관련 객체 파일을 자동으로 재컴파일하도록 설정.

# 자동 의존성 생성
DEP = $(OBJ:.o=.d)

%.d: %.c
	$(CC) -M $(CFLAGS) $< > $@

include $(DEP)
  • .d 파일: .c 파일의 의존성을 저장.
  • -M 옵션: 헤더 파일 의존성 생성.

2. 다중 타겟

다양한 실행 파일을 한 Makefile로 관리.

all: program test

program: main.o module.o
	$(CC) $(CFLAGS) -o program main.o module.o

test: test.o
	$(CC) $(CFLAGS) -o test test.o
  • all 타겟: program과 test를 모두 빌드.

Makefile 실행 예제

  1. make 실행:
    • 실행 파일(program) 생성.
  2. make
  3. 파일 변경 후 재컴파일:
    • main.c 수정 시, Make는 main.o만 다시 컴파일.
  4. clean 실행:
    • 빌드 과정에서 생성된 파일 삭제.
  5. make clean

예제 프로젝트

파일 구조

project/
├── Makefile
├── main.c
├── module.c
├── module.h

Makefile

# 변수 설정
CC = gcc
CFLAGS = -Wall -g
TARGET = program
SRC = main.c module.c
OBJ = main.o module.o

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

# 개별 객체 파일 컴파일
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

# 클린업
clean:
	rm -f $(OBJ) $(TARGET)

main.c

#include "module.h"

int main(void) {
    printMessage();
    return 0;
}

module.c

#include <stdio.h>
#include "module.h"

void printMessage() {
    printf("Hello, Makefile!\n");
}

module.h

#ifndef MODULE_H
#define MODULE_H

void printMessage();

#endif

실행

  1. 컴파일 및 빌드:
  2. make
  3. 실행:
  4. ./program
  5. 출력 결과:
  6. Hello, Makefile!
  7. 클린업:
  8. make clean

Makefile은 복잡한 프로젝트의 빌드 과정을 단순화하는 강력한 도구입니다. 위 내용을 실습하며 이해를 심화시킬 수 있습니다. 추가로 궁금한 점이 있으면 질문해주세요! 😊

반응형