본문 바로가기
Framework and Tool/Makefile

Makefile 기초

by ocwokocw 2023. 4. 22.

- 출처: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html

- 출처: http://doc.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make.html#toc2

- 출처: https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html

Makefile의 구조

 

Makefile은 target, dependency, command 3개의 요소로 이루어져 있으며 아래와 같은 요소를 갖는다. GNU make 에서는 target, prerequisties, recipe 라는 용어를 사용하는데, 개발자가 이해하기에는 출처2에서 사용하는 dependency, command라는 용어가 더 적합한것 같아 이를 사용한다.

 

target ... : dependency ...
                command
                ...
                ...

 

  • target: 대게 command가 수행되어 나온 결과파일(실행파일 or Object file)이다. 하지만 반드시 그런것은 아니며 단순히 command를 수행하기 위한 action명일 수 있다. (label 이라고도 함)
  • dependency: target을 수행하기 위해 필요한 파일들이라고 보면 된다. 여러개가 될 수 있다.
  • command: 실제 수행되는 부분이며 아래 조건을 만족해야 한다. 반드시 TAB으로 시작해야 한다. (TAB 대신 빈칸 X)
    • dependency 부분에 정의된 파일 내용이 변경
    • target에 해당하는 파일이 존재하지 않음

Example

Golang으로 작성된 프로그램의 build 및 실행 명령을 Makefile로 작성해보자. 원하는 언어 아무거나 하나 골라잡아서 "Hello world" 출력을 작성한다.

 

Golang 에서는 build를 위해 go build -o [Exec file] [main package] 명령어를 입력하고 생성되는 실행파일을 실행하면 된다.

makefiletest % go build -o build/test_main ./cmd
makefiletest % ./build/test_main 
Hello world!!

이를 Makefile로 작성해보면 아래와 같이 작성할 수 있다.

build:
    @echo "build test_main"
    go build -o build/test_main ./cmd

run: build
    @echo "run test_main"
    ./build/test_main

Macro

위의 Makefile 에서 test_main 이라는 실행파일 이름을 변경하고 싶으면 4군데는 건드려야 한다. Makefile은 Macro 기능을 지원한다.

OBJECT = test_main

build:
    @echo "build $(OBJECT)"
    go build -o build/$(OBJECT) ./cmd

run: build
    @echo "run $(OBJECT)"
    build/$(OBJECT)

Macro 변수 참조시에는 $(), ${} 와 같이 사용할 수 있지만 $() 를 권고한다고 한다.


Label

Makefile 구조 설명시 target 이 반드시 결과파일을 가리키지는 않는다고 했다. 생성된 실행파일을 clean 하는 명령을 작성한다고 가정해보자.

clean:
    rm -rf build

위에서 작성한 clean은 특정 파일이 아니라 삭제를 하는 기능의 label성 target이다.


Phony Targets

현재까지 우리가 작성한 Makefile은 아래와 같다. 

OBJECT = test_main

build:
	@echo "build $(OBJECT)"
	go build -o build/$(OBJECT) ./cmd

run: build
	@echo "run $(OBJECT)"
	build/$(OBJECT)

clean:
	rm -rf build

make build를 2번 이상 수행할 경우 아래와 같이 up to date와 같은 문구를 보았을것이다. 이는 Make 요청시 target과 dependency의 최종 변경 시간을 검사하기 때문이다. build한 결과 파일이 이미 존재하므로 build를 또 하지 않는것이다. 다시 build 하고 싶으면 clean으로 삭제 후 다시 build 해야 한다.

makefiletest % make build
make: `build' is up to date.
makefiletest % make clean
rm -rf build
makefiletest % make build
build test_main

때에 따라서 이런 과정이 굉장히 귀찮을 수 있다. 이때 사용할 수 있는것이 Phony target 이라는 개념이다. Phony 라는 뜻을 알면 아래에서 설명하는 내용을 한층 더 이해하기 쉬운데 "위조품"이라는 뜻을 갖고 있다.

Phony target은 2가지 용도로 사용된다.

  • 같은 이름의 파일과의 충돌 회피
  • 성능 향상

make build 명령을 2번 이상 수행시 이미 build에 대한 폴더가 존재하기 때문에 수행되지 않았었다. 이때 .PHONY 라는 특별한 target을 주면 이 문제를 회피할 수 있다.

 

.PHONY: build
build:
	@echo "build $(OBJECT)"
	go build -o build/$(OBJECT) ./cmd
    
==== Result

makefiletest % make build
build test_main
go build -o build/test_main ./cmd
makefiletest % make build
build test_main
go build -o build/test_main ./cmd
makefiletest % make build
build test_main
go build -o build/test_main ./cmd

Makefile의 기본 사용법만 알아볼 목적이었으므로 성능 향상에 대해서는 자세히 알아보지 않았다. 궁금하다면 https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html 를 참조하면 될것 같다.

댓글