1. 사용 목적
Makefile은 (C/C++로 이루어진) 큰 프로그램에서 어떤 부분이 다시 컴파일 되어야 하는지 알려준다.
Make의 대안으로 SCons, CMake, Bazel, Ninja 등이 있고, Java로는 Ant, Maven, Gradle이 있다.
각 언어마다 Makefile 역할을 하는 Tool 들이 존재한다.
2. Makefile을 사용하지 않은 경우
먼저 Make를 사용하지 않고 빌드 해 보자
g++(gcc) -c main.c -o main.o : 오브젝트 파일을 만들어 주는 명령어
g++(gcc) -c foo.c -o foo.o : 오브젝트 파일을 만들어 주는 명령어
g++(gcc) -c -o bar.o bar.c : 오브젝트 파일을 만들어 주는 명령어
g++(gcc) -o app.out main.o foo.o bar.o : 최종 바이너리를 만드는 명령어
위의 명령어를 수행하는 쉘 스크립트를 만들어 줄 수도 있지만, Makefile에는 쉘 스크립트가 가지고 있지 않은 Incremental build 기능(많은 소스 코드 중 바뀐 부분만을 골라내서 재빌드하는 기능)이 있다.
이는 서버 프로그래밍을 하거나 게임 프로그래밍과 같은 대규모 프로젝트의 프로그래밍에서는 굉장히 중요한 기능이다. 따라서, Makefile을 사용한다.
3. 문법
구조 <Target>: <Dependencies> <Command/Recipe> |
목적파일(Target) : 명령어가 수행되어 나온 결과를 저장한다.
의존성(Dependency) : 목적 파일을 만들기 위한 의존성 라이브러리
명령어(Command/Recipe) : 실행 되어야 할 명령어
매크로(Macro)
예시)
- 아래의 예시를 보자. make blah를 수행할 경우 Target인 blah를 수행한다. 하지만, Dependency가 blah.o이다.
- Target인 blah.o를 수행한다. Dependency가 blah.c이다.
- Target인 blah.c를 수행한다. Dependency가 없다.
- 이제, cc -c 명령이 실행된다. 이후 cc 명령이 실행된다.
#!/bin/sh/
blah: blah.o
cc blah.o -o blah # Runs third
blah.o: blah.c
cc -c blah.c -o blah.o # Runs second
blah.c:
echo "int main() { return 0; }" > blah.c # Runs first
예시2)
- 아래의 예시는 맨 처음 등장하였던 그림의 Makefile 적용 예시이다.
- 코맨트 상의 숫자는 실행 순서이다.
#!/bin/sh
app.out: main.o foo.o bar.o # (2) app.out은 main.o, foo.o, bar.o Dependency를 가진다.
gcc -o app.out main.o foo.o bar.o
main.o: foo.h bar.h main.c # (1) main.o 는 foo.h, bar.h, main.c Dependency를 가진다.
gcc -c -o main.o main.c
foo.o: foo.h foo.c # (1) foo.o 는 foo.h, foo.c Dependency를 가진다.
gcc -c -o foo.o foo.c
bar.o: bar.h bar.c # (1) bar.o 는 bar.h, bar.c Dependency를 가진다.
gcc -c -o bar.o bar.c
3-1. 문법 - 변수
- 지금부터 Makefile을 강력하게 만들어주는 변수가 등장한다.
- 변수는 상단에 정의하고 $() 혹은 ${}로 불러다 사용한다.
- 아래 예시의 CC, CFLAGS, LDFLAGS, LDLIBS, OBJS, TARGET 모두 사용자가 정의한 변수이다. 내장된 것이 아니다.
CC = g++ : CC는 Make 내장 변수, 컴파일러
CFLAGS = -g -Wall : 컴파일 옵션
LDFLAGS = : 링커 옵션
LDLIBS = : 링크 라이브러리
OBJS = main.o foo.o bar.o : 중간 산물 Object 파일 목록
TARGET = app.out : 빌드 대상 이름
변수를 사용하였을 때 구조
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS) :
예시)
- 아래 예시는 변수를 사용하였을 때 맨 처음 등장하였던 그림의 Makefile 적용 예시이다.
CC=g++
CFLAGS=-g -Wall
LDFLAGS=
LDLIBS =
OBJS=main.o foo.o bar.o
TARGET=app.out
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS) :
main.o: foo.h bar.h main.c
foo.o : foo.h foo.c
bar.o : bar.h bar.c
all : $(TARGET)
clean:
rm -f *.o
rm -f $(TARGET)
install:
$@
- 최종 타겟을 의미한다.
- 다중 타겟이 있을 경우, 해당 변수는 각 타겟을 가리킨다.
- 쉘 스크립트와 동일 문법이다(SO). 쉘스크립트 실행 뒤에 이어지는 인자를 뜻한다.
$^
- 타켓을 생성하기 위해 필요한 모든 의존 오브젝트(.o)를 뜻한다.
$<
- 타겟을 생성하기 위해 가장 왼쪽에 기술된 첫번째 오브젝트
$?
- 타겟을 생성하기 위해 기술된 것 중에 가장 최근에 변경된 오브젝트
*, %
- 와일드 카드이다.
$ ./arg.sh "a b c" d e
-->
$0 ./arg.sh
$1 a b c
$2 d
$* a b c d e
$@ a b c d e
$# 3
$? 0
출처
https://stackoverflow.com/questions/9994295/what-does-mean-in-a-shell-script
http://www.itmoa.co.kr/gzboard.php?code=techqna&mode=gz_read&Page=5&no=222
'운영체제 > 리눅스(Linux)' 카테고리의 다른 글
tee 명령어 (0) | 2022.09.06 |
---|---|
쉘 프로그래밍(Shell Programming) (0) | 2022.01.13 |
리눅스 소소한 질문 모음 (0) | 2022.01.11 |