Makefile 은 빌드 도구가 아니라 명령 목록입니다

요약. Makefile 을 C 프로그램 컴파일할 때 쓰는 것으로만 알고 계시면 쓸 자리를 대부분 놓칩니다. 제 홈 폴더의 Makefile 에는 컴파일이 한 줄도 없습니다. UAC 끄기, 방화벽에 규칙 추가하기, 드라이브 잠금 메뉴 등록하기 같은 것이 들어 있습니다. make 가 실제로 하는 일은 이름 하나에 명령 묶음을 붙여주는 것이고, 빌드는 그 용도 중 하나일 뿐입니다.

도토리 LG TV 리모컨 - 폰을 LG TV 의 리모컨으로

제가 만든 무료 앱입니다. 많이 써 주세요.

빌드와 상관없는 명령을 넣어도 됩니다

제 Makefile 에 있는 target 은 이런 것들입니다.

uac-off: ## UAC 끄기 (재부팅 필요)
	@echo "would disable UAC"

ping-open: ## 방화벽에 ICMP 허용 규칙 추가
	@echo "would add firewall rule"

한 달에 한 번 쓸까 말까 한 명령들입니다. 그래서 외우고 있을 수 없고, 검색해서 다시 찾으면 예전에 쓰던 것과 옵션이 달라집니다. 한 번 찾은 명령을 이름 하나에 묶어 두면 다음에는 make uac-off 로 끝납니다.

셸 스크립트로 만들어도 되는데 make 를 쓰는 이유가 있습니다. Makefile 은 그 폴더에서만 걸립니다. alias 는 컴퓨터 전체에 걸리므로 이름이 겹치지 않게 신경 써야 하고, 스크립트는 어디에 뒀는지 기억해야 합니다. Makefile 은 프로젝트마다 하나씩 두고 전부 make build 로 통일할 수 있습니다. 폴더에 들어가서 make 만 치면 그 프로젝트에서 할 수 있는 일이 나옵니다.

alias 를 다룬 앞 글에서 적었듯이 Makefile 안의 명령은 사람이 치는 셸이 아니라 프로그램이 부르는 셸에서 돕니다. 그래서 여기에는 alias 를 쓸 수 없고, 명령을 온전히 적거나 스크립트 파일을 불러야 합니다.

target 목록이 그대로 도움말이 됩니다

이 방식의 값은 여기서 나옵니다. target 줄 끝에 ## 설명 을 달아두면, 그 목록을 긁어 도움말로 출력할 수 있습니다. 블록 하나를 Makefile 맨 위에 넣습니다.

.DEFAULT_GOAL := help
.PHONY: help

help: ## 사용 가능한 target 목록
	@grep -hE '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
		| awk 'BEGIN{FS=":.*?## "}{printf "  \033[36m%-14s\033[0m %s\n", $$1, $$2}'

.DEFAULT_GOAL := help 때문에 인자 없이 make 만 쳐도 도움말이 뜹니다.

$ make
  help           사용 가능한 target 목록
  uac-off        UAC 끄기 (재부팅 필요)
  ping-open      방화벽에 ICMP 허용 규칙 추가

grep 이 이름: … ## 설명 형태의 줄만 골라내고 awk 가 ## 를 기준으로 잘라 정렬합니다. 그래서 target 을 추가하면 도움말이 저절로 늘어납니다. 설명을 따로 문서에 옮겨 적을 필요가 없고, 그러니 문서가 낡을 일도 없습니다. ## 를 붙이지 않은 target 은 목록에 나오지 않아서, 내부용으로 숨길 수도 있습니다.

윈도우에서 걸리는 세 가지

첫째, 명령 줄의 들여쓰기는 반드시 탭입니다. 스페이스로 넣으면 이렇게 멈춥니다.

Mbad:9: *** missing separator (did you mean TAB instead of 8 spaces?).  Stop.

make 가 친절하게 알려주기는 합니다. 편집기가 탭을 스페이스로 바꾸도록 설정돼 있으면 계속 당하므로, 그 폴더만 예외를 두는 편이 낫습니다. 웹에서 Makefile 을 복사해 붙일 때도 같은 일이 납니다.

둘째, 명령 줄의 echo 에 한글을 넣으면 깨집니다. make 가 셸을 부르는 경로에서 인코딩이 어긋나기 때문입니다.

$ make ko
?쒓? 異쒕젰 ?쒕룄

그런데 ## 설명 쪽 한글은 정상입니다. 앞의 도움말 출력에서 "UAC 끄기" 가 제대로 나온 것이 그 증거입니다. grep 과 awk 가 파일 바이트를 직접 읽어 내보내기 때문입니다. 정리하면 설명 주석에는 한글, echo 본문에는 영문입니다.

셋째, $ 는 $$ 로 적습니다. 위 help 블록의 $$1, $$2, .*$$ 가 그것입니다. $ 하나면 make 가 자기 변수로 먹어버려서 awk 에 빈 값이 넘어갑니다.

정리

항목규칙
들여쓰기탭만. 스페이스면 missing separator
한글## 설명 은 가능, echo 본문은 영문
$$$ 로 두 번
기본 target.DEFAULT_GOAL := help 로 make 만 쳐도 목록

Makefile 은 그 폴더에서 할 수 있는 일의 목록입니다. 한 달에 한 번 쓰는 명령, 찾는 데 시간이 걸렸던 명령, 남에게 알려줘야 하는 명령을 넣어 두면 됩니다.

지금 작업하는 프로젝트에 위의 help 블록을 넣고, 최근에 검색해서 찾은 명령 하나를 target 으로 만들어 보시면 값이 바로 보입니다.