Heesung Yang

Makefile 정리

기본 개념

  • target, dependency, command 3개로 이루어져 있음
  • target 을 만들기 위한 command 정의
  • command 실행을 위한 dependency 정의
  • target 에는 결과 파일만 올 수 있지 않고 make clean 처럼 간단한 Label도 가능(여기서는 clean)
  • command 는 앞에 TAB 문자가 있어야만 함. 공백일 경우 에러

Tip

gcc 옵션

  • -M : 전체 시스템 헤더 파일들의 의존성 출력

  • -MM : 현재 Makefile 에 정의되어 있는 헤더 파일들의 의존성만 출력

  • -MD 또는 -MDD : 의존성 출력 결과가 (소스 파일명).d 로 생성됨

    • 실행 예
    ~$ gcc -M main.c
    main.o: main.c io.h /usr/include/stdio.h /usr/include/features.h \
     /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
     /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
     /usr/lib/gcc/x86_64-redhat-linux/4.4.7/include/stddef.h \
     /usr/include/bits/types.h /usr/include/bits/typesizes.h \
     /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
     /usr/lib/gcc/x86_64-redhat-linux/4.4.7/include/stdarg.h \
     /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
    
    ~$ gcc -MM main.c
    main.o: main.c io.h
    

간단한 예제

  • main.c read.c write.c 3개의 파일이 있고 모두 io.h 헤더 파일을 참조
  • 이들을 각각 컴파일 하여 test_program 이라는 실행 파일 생성

Step 1

직접 일일이 컴파일 하는 단계

~$ gcc -c main.c
~$ gcc -c read.c
~$ gcc -c write.c
~$ gcc -o test_program main.o read.o write.o

Step 2

기본적인 Makefile 을 작성

# target : dependency
#   command

test_program : main.o read.o write.o
    gcc -o test_program main.o read.o write.o

main.o : io.h main.c
    gcc -c main.c
read.o : io.h read.c
    gcc -c read.c
write.o : io.h write.c
    gcc -c write.c
~$ make
gcc -c main.c
gcc -c read.c
gcc -c write.c
gcc -o test_make main.o read.o write.o
~$ ls
Makefile  io.h  main.c  main.o  read.c  read.o  test_make  write.c  write.o

Step 3

소스 파일이 추가될 때마다 변경사항이 많으므로 다음과 같이 매크로를 사용

OBJS = main.o read.o write.o

test_program: $(OBJS)
    gcc -o test_program $(OBJS)

main.o : io.h main.c
    gcc -c main.c
read.o : io.h read.c
    gcc -c read.c
write.o : io.h write.c
    gcc -c write.c

Step 4

target 에 파일이 아닌 clean 과 같은 Label 생성

Label 은 dependency 정의를 하지 않아도 된다.

OBJS = main.o read.o write.o

test_program: $(OBJS)
    gcc -o test_program $(OBJS)

main.o : io.h main.c
    gcc -c main.c
read.o : io.h read.c
    gcc -c read.c
write.o : io.h write.c
    gcc -c write.c

clean :
    rm $(OBJS)

Step 5

미리 정의된 매크로 활용 (make -p 명령으로 확인 가능)

  • CC : 컴파일러
  • CFLAGS : 컴파일 옵션
  • $* : 확장자가 없는 현재 Target
  • $@ : 현재 Target
  • $< : 현재의 Target 보다 더 최근에 갱신된 파일 이름
  • $? : 현재의 Target 보다 더 최근에 갱신된 파일 이름(?)
  • Macro 치환
    • $(MACRO_NAME:OLD=NEW) 와 같은 식으로 일부 값만 변경 가능
    • 이를 활용하는 예 (obj 에 해당하는 c 파일을 일일히 열거하기 귀찮을 때)
      • OBJS = main.o read.o write.o
      • SRCS = $(OBJS:.o=.c) : main.o 중에 .o 부분을 .c로 치환
  • .SUFFIXES
    • 확장자에 따라 미리 정의되어 있는 행동을 할 수 있음.
    • 예) .SUFFIXES : .c .o
      • .c .o.c 를 컴파일해서 .o 를 만든다는 규칙이 미리 정의되어 있음
      • $(CC) $(CFLAGS) -c $< -o $@ 가 동작함
.SUFFIXES = .c.o
OBJS = main.o read.o write.o
SRCS = $(OBJS:.o=.c)

test_program: $(OBJS)
    gcc -o test_program $(OBJS)

.c.o :
    gcc -c $< 
main.o : io.h main.c
    gcc -c main.c
read.o : io.h read.c
    gcc -c read.c
write.o : io.h write.c
    gcc -c write.c

clean :
    rm $(OBJS)