make, Makefile 이해
gcc
C언어의 컴파일 과정
- 전처리기 : #으로 시작하는 전처리 구문을 처리
gcc -E test.c -o test.i
- 컴파일러 : 고급언어를 저급언어로 번역
gcc -S test.i -o test.s
- 어셈블러 : 저급언어를 기계어로 번역
gcc -c test.s -o test.o
- 링커 :
gcc test.o -o test.exe
-o
: 생성 된 파일의 이름을 지정
출처 : https://reakwon.tistory.com/52
make
지금부터 작성한 글은 아래 포스트를 많이 참고해서 작성했습니다.
출처 : https://bowbowbow.tistory.com/12#make-와-makefile
파일이 많으면 컴파일하기 힘들다.
컴파일 및 관리를 편하게 하기 위해서 Makefile
과 make
를 이용한다.
Makefile
에 컴파일 및 관리를 수행하는 방식을 규정하고 make
명령어로 실행한다.
Makefile의 구성
-목적파일(Target) : 명령어가 수행되어 나온 결과를 저장할 파일
-의존성(Dependency) : 목적파일을 만들기 위해 필요한 재료
-명령어(Command) : 실행 되어야 할 명령어들
-매크로(macro) : 코드를 단순화 시키기 위한 방법
CC = gcc // 매크로 정의
// 타겟 : 의존성 의존성
target1 : dependency1 denpendency2
command1 // 명령어
command2
target2 : dependency3 denpendency4
command3
command4
매크로 정의
목표파일 : 목표파일을 만들기 위해서 필요한 구성요소들 (dependency는 없어도 된다.)
(tab)목표 달성을 위한 명령1
(tab)목표 달성을 위한 명령2
길이가 긴 공백은 tab를 사용한다.
예시
//diary.h
#include<stdio.h>
void memo();
void calendar();
//meno.c
#include "diary.h"
void memo(){
printf("memo func \n");
}
//calendar.c
#include "diary.h"
void calendar(){
printf("calendar func \n");
}
//main.c
#include"diary.h"
int main(void){
memo();
calendar();
return 0;
}
gcc 명령어 사용
gcc -c -o memo.o memo.c
gcc -c -o calendar.o calendar.c
gcc -c -o main.o main.c
gcc -o diary_exe main.o memo.o calendar.o
# 혹은
gcc -o diary_exe memo.c calendar.c main.c
make 명령어 사용
vim Makefile
# 대문자 M 사용.
diary_exe : memo.o calendar.o main.o
gcc -o diary_exe memo.o calendar.o main.o
memo.o : memo.c
gcc -c -o memo.o memo.c
calendar.o : calendar.c
gcc -c -o calendar.o calendar.c
main.o : main.c
gcc -c -o main.o main.c
clean :
rm *.o diary_exe
기본적으로 make 명령어를 사용하는 방법은 make [targetName]
을 쉘에 입력한다.
$ make diary_exe
gcc -c -o calendar.o calendar.c
gcc -c -o main.o main.c
gcc -o diary_exe memo.o calendar.o main.o
$ make memo.o
gcc -c -o memo.o memo.c
$ make clean
rm *.o diary_exe
make clean
: 현재 디렉터리에 있는 object 파일과 diary_exe를 지운다.
clean
은 더미타겟으로 파일을 생성하지 않는 타겟이다.
$ make
gcc -c -o memo.o memo.c
gcc -c -o calendar.o calendar.c
gcc -c -o main.o main.c
gcc -o diary_exe memo.o calendar.o main.o
아무런 targetName
없이 make
명령을 입력했을때는 default target
을 생성한다.
별도의 default target
지정 없으면 가장 상단에 위치한 target 파일을 생성한다.
default target
을 지정하는 방법은 아래와 같다.
all : diary_exe
따로 가장 상단에 all
이라는 타겟을 설정하고 의존성에 정말 우리가 필요한 타겟을 넣으면 된다.
Makefile 매크로
diary_exe : memo.o calendar.o main.o
gcc -o diary_exe memo.o calendar.o main.o
memo.o : memo.c
gcc -c -o memo.o memo.c
calendar.o : calendar.c
gcc -c -o calendar.o calendar.c
main.o : main.c
gcc -c -o main.o main.c
clean :
rm *.o diary_exe
Makefile을 더 단순하게 작성하기 위해서 중복되는 코드를 특정한 단어로 치환한다.
이 과정을 매크로라고 한다.
짧은 코드면 오히려 복잡하다고 느낄 수 있지만 코드가 길어지고 복잡해질수록 매크로를 사용했을 때 얻을 수 있는 효과가 크다.
사용할 수 있는 매크로 몇가지와 관용적으로 사용하는 변수 이름을 살펴보자.
Option | Desciption |
$@ | 해당 블록의 Target |
$^ | 해당 블록의 Dependencies 중 전체로 대치됨 |
$< | 해당 블록의 Dependencies 중 첫 번째로 대치됨 |
$* | 확장자가 없는 Target으로 대치됨 |
$? | 해당 블록의 Dependencies 중에 Target보다 새로운 파일들 목록으로 대치됨 |
Variables | Description |
CC | C compiler, cc, gcc |
CXX | C++ compiler, g++ |
CFLAGS | Extra flags to give to the C compiler |
CXXFLAGS | Extra flags to give to the C++ compiler |
CPPFLAGS | Extra flags to give to the C preprocessor |
LDFAGS | Extra flags to give to compilers when they are supposed to invoke linker |
SRCS | Source codes |
OBJS | Object codes |
TARGET | Target file |
.SUFFIXES | 확장자 규칙 |
INC | Include path |
이외에도 사용자의 기호에 맞춰 매크로를 설정할 수 있다.
매크로 이름은 보통 대문자로 작성한다.
$(매크로 이름)
로 매크로의 값을 참조할 수 있다.
diary_exe : memo.o calendar.o main.o
gcc -o diary_exe memo.o calendar.o main.o
memo.o : memo.c
gcc -c -o memo.o memo.c
calendar.o : calendar.c
gcc -c -o calendar.o calendar.c
main.o : main.c
gcc -c -o main.o main.c
clean :
rm *.o diary_exe
- CC, TARGET, OBJS 정의
CC = gcc
TARGET = diary_exe
OBJS = memo.o calendar.o main.o
all : $(Target)
$(TARGET) : $(OBJS)
$(CC) -o $(TARGET) $(OBJS)
memo.o : memo.c
$(CC) -c -o memo.o memo.c
calendar.o : calendar.c
$(CC) -c -o calendar.o calendar.c
main.o : main.c
$(CC) -c -o main.o main.c
clean :
rm $(OBJS) $(TARGET)
- $@, $^ 사용
CC = gcc
TARGET = diary_exe
OBJS = memo.o calendar.o main.o
all : $(Target)
$(TARGET) : $(OBJS)
$(CC) -o $@ $^
calendar.o : calendar.c
$(CC) -c -o $@ $<
main.o : main.c
$(CC) -c -o $@ $<
clean :
rm $(OBJS) $(TARGET)
- %.o, %.c 사용
CC = gcc
TARGET = diary_exe
OBJS = memo.o calendar.o main.o
all : $(Target)
$(TARGET) : $(OBJS)
$(CC) -o $@ $^
%.o : %.c
$(CC) -c -o $@ $<
clean :
rm $(OBJS) $(TARGET)
많이 짧아졌다!
%.o
의 의미는 .o로 끝나는 어떤 파일을 의미한다.
%.c
는 .c로 끝나는 어떤 파일이고 앞선 %.o
와는 확장자를 제외하고 같은 파일이름을 지녔을 것이다.
마지막으로 주의할 점에대해 알아보자.
clean :
rm $(OBJS) $(TARGET)
만약 디렉토리내에 clean이라는 파일이 있으면 정상적으로 Makefile이 작동하지 않을 것이다.
이때는 …
clean :
rm $(OBJS) $(TARGET)
.PHONY : clean
.PHONY : clean
을 추가하면 된다.
Phony는 '가짜의, 허위의' 이라는 뜻이다.
PHONY가 다수라면 옆에 띄어쓰고 열거하면 된다.
.PHONY : a b c
Makefile 보충
:=
, ?=
와 +=
는 뭐지?
출처 : https://leehc257.tistory.com/67
=
사용
T=A
W=$(T)
T=B
run :
echo $(T)
echo $(W)
// 결과
$ make
echo B
B
echo B
B
=
는 T=A
를 무시한다.
=
는 어디에서든 상관없이 나중에 작성된 T=B
로 일관성을 유지한다.
:=
사용
T=A
W:=$(T)
T=B
run :
echo $(T)
echo $(W)
// 결과
$ make
echo B
B
echo A
A
:=
는 T=A
를 무시하지 않고 반영하는 것을 알 수 있다.
실제 W
가 정의된 시점의 T
값 A
를 반영했다.
+=
사용
T=A
T+=B
run :
echo $(T)
// 결과
$ make
echo A B
A B
기존의 문자열에 이어쓰기하는 방식이다.
?=
사용
This is called a conditional variable assignment operator, because it only has an effect if the variable is not yet defined.
변수가 정의되지않으면 변수의 값을 대입한다.
$(OBJS:.o=.d)
는 뭐지?
$(OBJS:.o=.d)
부분은 OBJS
에서 .o
로 끝나는 부분을 .d
로 모두 대체한다는 뜻이다.
Makefile 조건문
//같은지 비교하고 싶다면 ifeq ~ else ~endif 사용.
//equal
ifeq ($(CC),gcc)
//같지 않은지 비교하고 싶다면 ifneq ~ else ~ endif 사용.
//not equal
ifneq ($(CC),gcc)
//매크로가 정의되었는지 되지 않았는지에 따라 Makefile을 다르게 구성하고 싶다면
//ifdef ~ else ~ endif 또는 ifndef ~ else ~ endif 사용.
//define? not define?
ifdef CC
ifndef CC
Makefile 함수
$(shell 쉘 명령어)
shell 명령에 대한 결과를 저장한다. $(변수명) <- 이 자리에 해당 결과가 들어가는 셈이다.
이것말고도 엄청나게 많은 함수를 지원한다.
필요하면 찾아서 사용하자.
참고
- 헤더파일 작성 방법 : https://heroine-day.tistory.com/9
- #include <>와 “”의 차이 : https://shjz.tistory.com/97
- Makefile 작성법 : http://shumin.co.kr/linux-makefile/
- Makefile 작성법 : https://bowbowbow.tistory.com/12#make-와-makefile
- Makefile 작성법 : https://velog.io/@woodstock1993/Makefile
- Makefile 작성법 : https://modoocode.com/311
- =, :=, += 차이점 : https://leehc257.tistory.com/67
- Makefile 조건문 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=muri1004&logNo=220027346833
- Makefile 함수 : https://kcoder.tistory.com/358