Makefile 에는 타겟(Target), 의존성(Dependencies), 레시피(Recipe)로 빌드 규칙을 정의한다. 진짜다. 이게 거의 90% 이다. 나머지는 보통 빌드 전후 처리를 어떻게 할 것인지를 나타내는 규칙이며 본질이 아니다(참고4).

<타겟>: <의존성>
	<레시피>

타겟은 보통 생성하고자 하는 파일의 이름이다. 의존성은 생성하고자 하는 파일을 만드는 데 필요한 파일이다. 이 파일이 타겟으로 정의되어 있다면 Makefile 이 이 부분을 인지하고 그래프를 만들거나 하지 않을까.

그림(참고1): 실제로 Makefile 이 그래프를 만드는지 아닌지는 모르겠지만, 의존관계를 정의한다는 것은 아래 그림처럼 상상해볼 수 있을 것이다.

Untitled

레시피는 타겟이 의존하는 파일들과 관련된 명령을 모두 실행한 이후 실행할 명령이다. 의존성을 정의했고 특정 파일을 만드는 명령어를 다 적어 두었으니, 어떤 파일이 약간 변했을 때(미적분의 $dx$ 가 생각난다. 이를 소스코드의 ‘증분’ 이라고 표현하는 듯하다) 이 파일과 관련된 파일들만 모조리 빌드해줄 수 있게 된다. 이를 증분 빌드(Incremental build)라고 한다. Makefile 이 가지는 강력한 기능이다(참고2).

app.out: foo.o bar.o
	gcc -o app.out foo.o bar.o

bar.o: foo.c bar.c bar.h 
	# 참고로, bar.h 는 bar.c 등에 의해 자동으로 호출되지만 
	# makefile 은 이를 자동으로 추적하지 못한다. 
	# 그래서 거추장스럽지만 bar.h 를 이렇게 작성해 주어야 한다.
	gcc -c foo.c
	gcc -c bar.c

... 이하 생략

위와 같은 Makefile 을 실행하는 커맨드는 아래와 같다. 그냥 생성하고자 하는 파일의 이름을 적어 주는 것이다. 정말 자명하지 않은가!

make app.out

또는 변경사항과 관련된 모든 파일들을 다시 생성하도록 다음 명령을 사용할수도 있겠다. 아래 명령이 동작하는 이유는, make 을 실행했을 때 첫 번째 타겟을 만들기를 시도하는데(참고3) 맨 위에 최종 결과물인 app.out 이 타겟이기 때문이다.

make

parse me : 언젠가 이 글에 쓰이면 좋을 것 같은 재료들.

  1. None

from : 과거의 어떤 생각이 이 생각을 만들었는가?

  1. bb2. title: CMake와 같은 높은 추상의 도구들이 나타나기 전에는, 빌드관계를 정의하고 간단한 변수를 선언할 수 있는 스크립트 수준의 간단명료한 Makefile이 있었다.

supplementary : 어떤 새로운 생각이 이 문서에 작성된 생각을 뒷받침하는가?

  1. None