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
은 다르다. - 보통
all
target 을 가장 처음에 써주기때문에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.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)
Previous post
[명령어] tmuxNext post
내가 원하는 크기로 파일 생성하기 (테스트용 Dummy 파일)