Heesung Yang
Makefile 정리
기본 개념
- target, dependency, command 3개로 이루어져 있음
- target 을 만들기 위한 command 정의
- command 실행을 위한 dependency 정의
- target 에는 결과 파일만 올 수 있지 않고
make clean처럼 간단한 Label도 가능(여기서는clean) - command 는 앞에
TAB문자가 있어야만 함. 공백일 경우 에러
Tip
-
make대신$(MAKE)를 사용하는 이유- Makefile 내에서
make명령어를 사용하는 경우 (재귀적 사용이라고 부름),$(MAKE)변수를 사용하는 것이 좋음 - http://korea.gnu.org/manual/4check/make-3.77/ko/make_5.html#SEC50
- https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html
- Makefile 내에서
-
make를 인자없이 실행할 경우 가장 처음 만나는 target 을 실행한다.- 그렇기 때문에
make와make all은 다르다. - 보통
alltarget 을 가장 처음에 써주기때문에make와make all이 같다고 오해하는 경우가 있는 듯 - https://stackoverflow.com/questions/6856263/what-is-the-difference-between-make-and-make-all/6856463
- 그렇기 때문에
-
명령어 앞에
-문자를 붙이는 이유- make 는 기본적으로 명령어 여러개가 있을 경우, 앞의 명령어가 에러가 발생하면 실행을 멈춘다.
-를 붙이면 에러가 발생하더라도 다음 명령어를 실행한다.- https://stackoverflow.com/questions/2989465/rm-rf-versus-rm-rf
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.cread.cwrite.c3개의 파일이 있고 모두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.oSRCS = $(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)
Previous post
[명령어] tmuxNext post
내가 원하는 크기로 파일 생성하기 (테스트용 Dummy 파일)