Linux,  Programming

[Linux] Makefile 소개

Introduction

Software로 과제를 할 때 makefile은 땔 수 없는 프로그램이다. Makefile은 빌드 도구로, 각 파일에 대한 의존성과 명령을 정의함으로써 최종 목적 프로그램을 빌드해서 만든다. 또한 불필요한 compile을 줄일 수 있으며 command log를 쉽게 확인 할 수 있다. 기본적인 구조는 아래와 같다.

Target: Dependencies
[TAB] Command

어떤 Target을 만들기 위해 필요한 Dependencies들을 준비하고 난 뒤, Command를 실행하는 방식이다. 따라서 dependencies가 준비가 되지 않으면 dependencies에 해당하는 구문으로 이동해서 수행하게 된다.

# all is default target
all: main.o read.o write.o
    gcc main.o read.o write.o -o output

main.o: main.c
    gcc -c main.c -o main.o

read.o: read.c
    gcc -c read.c -o read.o

write.o: write.c
    gcc -c write.c -o write.o

clean:
    rm -rf main.o read.o write.o output

Makefile은 초단위로 target과 dependencies들의 update 시간을 비교하게 되는데, 만약 target보다 dependencies의 update 시간이 더 최신이라면 새롭게 target을 만든다. 참고로 Makefile에서 all은 default target이다.

위 예시 Makefile 기준으로 설명하자면, main.cmain.o보다 더 최신으로 업데이트 되었다고 한다면 자동으로 main.o를 새롭게 만든다.

$ make # make all
$ make -f Makefile1

기본적으로 makefile 수행 방법은 make이며, 해당 directory에 Makefile 또는 makefile을 default로 읽으며 그 외 다른 이름으로 수행할 경우 -f 옵션을 통해 수행 가능하다.

Automatic Variables

Makefile에서 target과 dependencies를 자주 가리키며 사용하게 되는데 이를 위한 automatic variable을 makefile에선 다음과 같이 제공한다. (그 외는 아래 출처를 참고)
링크

OptionDescription
$<Dependencies 중에 첫 번째로 대치됨
$^Dependencies 중 전체로 대치됨
$@Target으로 대치됨
$*확장자가 없는 Target으로 대치됨
$?Dependencies 중에 Target보다 새로운 파일들 목록으로 대치됨

위 내용을 통해 기존 처음 Makefile을 수정해보면 다음과 같이 automatic variable을 적용해 만들 수 있다.

# all is default target
all: main.o read.o write.o
    gcc $^ -o output

main.o: main.c
    gcc -c $^ -o $@

read.o: read.c
    gcc -c $^ -o $@

write.o: write.c
    gcc -c $^ -o $@

clean:
    rm -rf main.o read.o write.o output

Fancy Rules

Implicit rules & macro

Makefile에서 암묵적으로 사용되는 변수들은 다양하게 존재하는데, 대표적으로 사용되는 변수들은 다음과 같다.

VariablesDescription
CCC compiler, cc 또는 gcc
CXXC++ compiler, g++
CFLAGSExtra flags to give to the C compiler
CXXFLAGSExtra flags to give to the C++ compiler
CPPFLAGSExtra flags to give to the C preprocessor
LDFLAGSExtra flags to give to compilers when they are supposed to invoke the linker
SRCSSource codes
OBJECTSObject codes
TARGETTarget file
.SUFFIXES확장자 규칙
특정 확장자를 가진 file들에 대해 규칙에 의거에 수행되도록 한다.
Ex.) .SUFFIXES : .c .o
위 예시는 *.c file을 *.o로 만드는 루틴이 자동으로 동작하게 된다. 따라서 target이 .c.o로 된 부분을 수행하게 된다.
INCInclude path

그 외에 makefile에 정의된 매크로를 확인하는 방법은 다음과 같다.

$ make -p

좀 더 자세한 내용은 아래 링크를 참고 바란다.
링크

최종적으로 fancy rule을 적용하게 되면 다음과 같이 업데이트 할 수 있다.

CC = gcc
SRCS = main.c read.c write.c
OBJS = main.o read.o write.o
TARGET = output
INC =
CFLAGS = -Wall

# all is default target
all: $(OBJS)
    $(CC) $(CFLAGS) $^ -o $(TARGET)

# all is default target
all: $(OBJS)
    $(CC) $(CFLAGS) $^ -o $(TARGET)

clean:
    rm -rf $(OBJS) $(TARGET)

Simple Type 변수

Makefile 내부에선 변수를 활용해서 반복되는 단어를 변수로 정의해서 사용한다. 만약 동일한 변수를 두 번 정의하게 되면 에러가 발생하기 때문에, 이 때는 simple type 변수를 정의해줘야 한다.

CC = gcc
CC = $(CC) -Wall

all: main.o func.o
    $(CC) main.o func.o -o a.out

main.o: main.c
    $(CC) -c main.c

func.o: func.c
    $(CC) -c func.c
$ make 
 Makefile:2: *** Recursive variable 'CC' references itself (eventually).  Stop.

이럴 때는 := 를 통해서 simple type 변수로 선언해줘야 한다. 또는 += 연산자를 통해서 추가 가능하다.

CC := gcc
# CC += Wall
CC := $(CC) -Wall

all: main.o func.o
    $(CC) main.o func.o -o a.out

main.o: main.c
    $(CC) -c main.c

func.o: func.c
    $(CC) -c func.c
CC := gcc 
CFLAGS = -Wall -c
OBJS = main.o func.o
TARGET = a.out

$(TARGET): $(OBJS)
    $(CC) $(OBJS) -o $(TARGET)

main.o: main.c
    $(CC) $(CFLAGS) $<

func.o: func.c
    $(CC) $(CFLAGS) $<

$<가 뜻하는 것은, 현재의 dependencies 중 첫 번째 이름을 대체한다는 의미다.

Verbose

Makefile을 통해 명령을 수행하다 문제가 발생해 debugging을 할 때 verbose option을 통해 요약된 명령어를 자세하게 살펴볼 수 있다.

$ make test VERBOSE=2
Verbose LevelDescription
VERBOSE=0이 모드에서는 Make에서 실행되는 명령어의 출력이 숨겨진다. 대신 실행되는 명령어의 이름만 표시됩니다.
VERBOSE=1이 모드에서는 Make에서 실행되는 명령어의 출력이 자세하게 나타난다. 이 모드에서는 실행되는 명령어와 해당 명령어가 출력하는 결과 모두가 터미널에 표시된다.
VERBOSE=2가장 높은 verbose level로, 이 모드에서는 Make에서 실행되는 명령어의 출력이 매우 자세하게 나타난다. 이 모드에서는 실행되는 명령어와 해당 명령어가 출력하는 모든 결과가 터미널에 표시된다.

Reference

  1. https://makefiletutorial.com/
  2. http://doc.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-7.html
  3. http://doc.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-3.html

Leave a Reply

Your email address will not be published. Required fields are marked *