Go to the first, previous, next, last section, table of contents.


Makefile 소개(An Introduction to Makefiles)

여러분은 makefile이라고 불리는, make에게 무엇을 할 것인가를 말하는, 파일이 필요하다. 대개 makefile은 make에게 어떤 프로그램을 컴파일하고 링크하는 방법을 설명한다.

이 장에서 우리는 8개의 C 소스 파일들과 3개의 헤더 파일들로 이루어진 텍스트 에디터를 컴파일하고 링크하는 방법을 기술하는, 단순한 makefile에 대해서 얘기할 것이다. makefile은 또한 make에게, 명시적으로 요구되었을 때 다양한 명령들을 실행하는 방법을 말할 수 있다(예를 들어서 어떤 파일들을 청소 작업으로써 제거하기). makefile의 좀 더 복잡한 예제를 보려면 section 복잡한 makefile 예제(Complex Makefile Example)을 참조하기 바란다.

make가 에디터를 재컴파일할 때 각 변경된 C 소스 파일들은 반드시 재컴파일되어야 한다. 헤더 파일이 변경되면, 해당 헤더 파일을 include하는 각 C 소스파일도 반드시 재컴파일되어야 한다. 각 컴파일은 소스 파일에 대응하는 오브젝트 파일을 생성한다. 마지막으로 어떤 소스 파일이 재컴파일되었다면, 모든 오브젝트 파일들은 그들이 새로 만들어진 것이든 아니든 반드시 같이 링크되어서 새로운 편집기 실행 파일을 만들어야 한다.

규칙의 모습(What a Rule Looks Like)

단순한 makefile은 다음과 같은 모양의 "규칙들"로 이루어진다:

target ... : dependencies ...
        command
        ...
        ...

target은 일반적으로 프로그램에 의해서 생성되는 파일의 이름이다; 실행 파일이나 오브젝트 파일 등이 target 파일의 예이다. target은 또한, `clean' (see section 가짜 목적물(Phony Targets))와 같은, 실행할 액션의 이름이 될 수도 있다.

dependency는 target을 만들기 위한 입력으로 사용되는 파일이다. target은 종종 여러개의 파일에 의존한다.

commandmake가 실행하는 액션이다. 규칙은 하나 이상의 command를 가질수도 있는 데, 각각은 자신의 라인 위에 있다. Please note: 여러분은 모든 command 라인의 처음에 하나의 탭 문자를 가져야 한다! 이것은 조심성 없음을 잡는 방해물이다.

일반적으로 command는 dependencies와 함께 한 규칙 안에 존재하고 dependencies들 중의 어떤 것이라도 변했다면 target 파일을 생성하는 일을 한다. 그러나, target을 위한 command들을 지정하는 규칙이 반드시 dependencies를 가질 필요는 없다. 예를 들어서 `clean'이라는 target과 연관된 삭제 command를 담고 있는 규칙은 dependencies를 가지지 않는다.

그렇다면 rule은 특정한 규칙의 target인 어떤 파일들을 언제 어떻게 리메이크할 것인가를 설명하는 것이 될 것이다. make는 target을 생성하거나 업데이트하기 위해서 dependencies에 command를 수행한다. 규칙은 또한 어떤 액션을 언제 어떻게 수행할 것인가를 설명할 수 있다.See section 규칙 작성(Writing Rules).

makefile은 규칙들 외에 다른 텍스트들을 담고 있을 수 있지만 단순한 makefile은 단지 규칙들을 담고 있을 뿐이다. 규칙들은 이런 템플리트에서 보여지는 것보다 어쩌면 좀 더 복잡해 보일 수 있지만, 모두가 이 패턴에 큰 오차없이 맞아 떨어진다.

단순한 Makefile(A Simple Makefile)

여기에 edit 라고 불리는 실행 파일 하나가, 8개의 C 소스와 3개의 헤더 파일들에 의존하는, 8개의 오브젝트 파일들에 의존하는 모습을 설명한 직설적인 makefile 예제가 있다.

이 예제에서 모든 C 파일들은 `defs.h'을 include하지만 편집 명령들을 정의한 것들만이 `command.h'를 include하고 편집기 버퍼를 변경하는 낮은 레벨의 파일들만이 `buffer.h'를 include한다.

edit : main.o kbd.o command.o display.o \
       insert.o search.o files.o utils.o
        cc -o edit main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o

main.o : main.c defs.h
        cc -c main.c
kbd.o : kbd.c defs.h command.h
        cc -c kbd.c
command.o : command.c defs.h command.h
        cc -c command.c
display.o : display.c defs.h buffer.h
        cc -c display.c
insert.o : insert.c defs.h buffer.h
        cc -c insert.c
search.o : search.c defs.h buffer.h
        cc -c search.c
files.o : files.c defs.h buffer.h command.h
        cc -c files.c
utils.o : utils.c defs.h
        cc -c utils.c
clean :
        rm edit main.o kbd.o command.o display.o \
           insert.o search.o files.o utils.o

우리는 기다란 라인을 백슬래시-개행을 사용해서 두 라인으로 분할했다; 이것은 하나의 긴 라인을 쓰는 것과 동일하지만 읽기에 더 쉬운 것이다.

`edit'라고 불리는 실행 파일을 만들도록 makefile을 쓰기 위해서는 다음과 같이 입력한다:

make

이 makefile을 사용해서 실행 파일과 모든 오브젝트 파일들을 삭제하려면 다음과 같이 입력한다:

make clean

이 예제 makefile에서 target들은 `edit'라는 실행 파일과 `main.o'`kbd.o'라는 오브젝트 파일들을 포함한다. dependencies는 `main.c'`defs.h'와 같은 파일들이다. 실제로 각 `.o' 파일은 target이면서 동시에 dependency이다. command는 `cc -c main.c'`cc -c kbd.c'를 포함한다

target이 파일일 때, 어떤 dependencies 들중 하나가 변경되었을 때 재컴파일되거나 재링크되어야 한다. 게다가 스스로 자동적으로 생성된 어떤 dependencies는 맨먼저 업데이트되어야 한다. 이 예제에서 `edit'는 8개의 오브젝트 파일들에 의존한다; `main.o'는 소스 파일 `main.c'와 헤더 파일 `defs.h'에 의존한다.

target과 dependencies을 담고 있는 각 라인 뒤에 쉘 명령이 따른다. 이런 쉘 명령들은 target 파일을 업데이트 하는 방법을 말하는 것이다. 탭 문자 하나가 각 명령 라인의 맨 앞에, makefile의 다른 라인들과 명령 라인들 간의 구분이 되도록, 반드시 와야 한다. (make는 command가 어떻게 작옹하는지에 대해서 아무것도 모른다는 것을 기억하기 바란다. target 파일을 적절하게 업데이트할 명령들을 제공하는 것은 여러분들에게 달려 있다. target 파일이 업데이트되어야 할 때 여러분이 지정한 규칙들에 있는 command들을 실행하는 것이 `make'가 하는 모든 것이다.)

`clean'이라는 target은 파일이 아니고 단지 액션의 이름이다. 이 규칙안에 있는 액션이 일반적인 경우에 실행되는 것을 바라지 않을 것이기 때문에 이 규칙은 자신 스스로가 dependency가 아닐뿐더러 어떤 dependencies도 가지지 않는다. 그래서 이 규칙의 단 하나의 목적은 특정 명령들을 실행하는 것이다. 파일이 아닌 단지 액션을 지칭하는 target은 phony targets이라고 불린다. 이런 종류의 target에 대한 정보를 보려면 See section 가짜 목적물(Phony Targets)을 참조하기 바란다. makerm이나 다른 명령으로부터 에러를 무시하도록 하는 방법에 대해서는 See section 명령에서 에러(Errors in Commands), 를 참조하기 바란다.

make가 Makefile를 처리하는 방법(How make Processes a Makefile)

디폴트로 make는 첫번째 target(그것의 이름이 `.'으로 시작하지 않는 target)으로 시작한다. 이것은 default goal이라고 불리는 것이다.(Goalsmake궁극적으로 업데이트하려고 하는 target이다 See section goal을 지정하는 매개변수(Arguments to Specify the Goals).)

이전 섹션에 있는 단순 예제에서 default goal은 실행 프로그램 `edit'를 업데이트하는 것이다;그래서 우리는 그 규칙을 맨 처음에 놓았던 것이다.

그래서 다음과 같이 명령을 주면 make는 현재 디렉토리에서 makefile을 읽고 첫번째 규칙을 처리하기 시작한다:

make

예제에서 이 규칙은 `edit'를 리링킹하는 것이다; 그러나 make가 이 규칙을 완전히 처리할 수 있기 전에, `edit'가 의존하고 있는 파일들에 대한 규칙들을 반드시 처리해야 한다. 이것은 이경우 오브젝트 파일들이다. 이런 파일들 각가은 그 자신의 규칙에 따라서 처리된다. 이런 규칙들은 각 `.o'파일을 그의 소스 파일을 컴파일해서 업데이트하라고 말한다. 소스 파일이 또는 dependencies에 있는 헤더파일들 중 어떤 것이라도 오브젝트 파일보다 더 최근의 것이라면 또는 오브젝트 파일이 존재하지 않는다면 재컴파일이 반드시 일어나야 한다.

다른 규칙들은, 그들의 target들이 goal의 dependencies로 나타나기 때문에, 처리된다. 어떤 다른 규칙이 goal이 의존하는 것이 아니라면(또는 그것이 의존하는 어떤 것도 없다면), make에게 그렇게 하라고 말하지(make clean과 같은 명령으로) 않는 한, 그 규칙은 처리되지 않는다.

오브젝트 파일을 재컴파일하기 전에, make는 그것의 dependencies, 소스 파일과 헤더 파일들을 업데이트하는 것을 고민한다. 이 makefile은 그것들을 위해서 행해진 어떤 것도 지정하지 않은 것이다-- `.c'`.h'파일들은 어떤 규칙들의 target도 아니다--그래서 make는 이런 파일들에 대해서 아무것도 하지 않는다. 그러나 make는 Bison이나 Yacc에 의해서 만들어진 것들과 같은,C 프로그램들을, 이 순간 그들의 규칙에 의해서 자동으로 생성한다.

오브젝트 파일들이 필요로 하는 것이면 무엇이든 재컴파일한 후, make`edit'를 리링크할 것인가를 결정한다. 이것은, `edit'파일이 존재하지 않거나 오브젝트 파일들 중 어떤 것이라도 그것보다 더 최근의 것이라면, 반드시 수행되어야 한다. 어떤 오브젝트 파일이 단지 재컴파일되었다면 그것은 이제 `edit'보다 더 새로운 것이고 그래서 `edit'는 재링크된다.

그래서, 우리가 `insert.c' 를 변경하고 make를 실행하면, make`insert.o'를 갱신하기 위해서 그 파일을 컴파일할 것이고 `edit'를 링크할 것이다. 우리가 `command.h' 를 변경하고 make를 실행하면 make`kbd.o', `command.o' 그리고 `files.o'들을 재컴파일할 것이고 그리고 나서 `edit'를 링크할 것이다.

Makefile을 좀 더 쉽게 만드는 변수들(Variables Make Makefiles Simpler)

우리의 예제에서 `edit'를 위한 규칙에서 우리는 모든 오브젝트 파일들을 두번씩 기술했다 (여기에 반복되어 있다):

edit : main.o kbd.o command.o display.o \
              insert.o search.o files.o utils.o
        cc -o edit main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o

이렇게 반복하는 것은 에러를 발생시킬 수 있는 여지가 있다; 새로운 오브젝트 파일이 시스템에 추가되면 우리는 그것을 한 리스트에는 추가하지만 다른 것에는 잊어 버리고 추가하지 않을 수 있다. 우리는 어떤 변수를 사용하여 이런 리스크를 없애고 makefile을 단순하게 만들 수 있다. Variables는 한번 정의되고 나중에 여러곳에서 대입되는 텍스트 문자열을 허락한다(see section 변수 사용 방법(How to Use Variables)).

모든 makefile이, 모든 오브젝트 파일 이름들의 리스트에 대해서 objects, OBJECTS, objs, OBJS, obj, 또는 OBJ 라는 이름의 변수를 쓰는 것은 표준 관례(standard practice)이다. 우리는 다음과 같은 makefile에서 처럼 그런 변수 objects를 하나의 라인으로 정의할 것이다:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

그리고 나서 우리가 오브젝트 파일 이름들의 리스트를 놓고자 하는 곳마다 그 변수의 값을, `$(objects)'라고 써서 대입할 수 있다(see section 변수 사용 방법(How to Use Variables)).

오브젝트 파일들에 대한 변수를 사용할 때 단순한 makefile이 어떻게 보이는지에 대한 예시가 있다:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)
main.o : main.c defs.h
        cc -c main.c
kbd.o : kbd.c defs.h command.h
        cc -c kbd.c
command.o : command.c defs.h command.h
        cc -c command.c
display.o : display.c defs.h buffer.h
        cc -c display.c
insert.o : insert.c defs.h buffer.h
        cc -c insert.c
search.o : search.c defs.h buffer.h
        cc -c search.c
files.o : files.c defs.h buffer.h command.h
        cc -c files.c
utils.o : utils.c defs.h
        cc -c utils.c
clean :
        rm edit $(objects)

`make'가 명령을 추론하도록 하기(Letting make Deduce the Commands)

개별 C 소스 파일들을 컴파일하기 위한 명령들을 전부 나열하는 것은 불필요하다. 왜냐면 make는 그것을 추측해낼 수 있기 때문이다:그것은 `cc -c'명령을 사용해서 대응되는 `.c'파일로부터 `.o'파일을 갱신하기 위한 implicit rule을 가지고 있다. 예를 들어서, `main.c'`main.o'로 컴파일하기 위해서 `cc -c main.c -o main.o'라는 명령을 사용할 것이다. 그러므로 우리는 그 오브젝트 파일들에 대한 규칙들로부터 그 명령들을 생략할 수 있다. See section 묵시적 규칙(Using Implicit Rules).

`.c'파일이 이런 식으로 자동으로 사용될 때, 그것은 또한 dependencies 리스트에 자동으로 추가된다. 그러므로 우리는, 우리가 그 명령들을 생략했다면, dependencies로부터 `.c'파일들을 생략할 수 있다

이런 변화들과 위에서 제시된 것과 같은 변수 objects 를 모두 예시한 다음 예제를 보자:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)

main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean
clean :
        -rm edit $(objects)

이것은 우리가 실제 상황에서 makefile을 작성하는 방법이다. (`clean'과 연관된 복잡함은 다른 곳에 기술되었다. section 가짜 목적물(Phony Targets), and section 명령에서 에러(Errors in Commands), 참조.)

묵시적 규칙은 아주 편리하기 때문에 중요하다. 여러분은 자주 사용되는 그것들을 볼 것이다.

Makefile의 다른 스타일(Another Style of Makefile)

makefile의 오브젝트들이 단지 묵시적 규칙에 의해서만 생성된다면 makefile의 다른 대체 스타일이 가능해진다. 이런 makefile 스타일에서 여러분은 그들의 target들에 의해서가 아니라 그들의 dependencies에 의해서 엔트리들을 그룹 짓는다. 여기에 비슷하게 보이는 예제가 있다:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)

$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h

여기서 `defs.h'는 모든 오브젝트 파일들의 dependency로 주어졌다; `command.h'`buffer.h'는 그것들을 위해서 리스트된 특정 오브젝트 파일들의 dependencies이다.

이것이 더 나은가 아닌가는 취향의 문제이다: 이것이 좀 더 컴팩트하지만 어떤 사람들은 이것을, 그들이 한자리에 각 target에 대한 정보 모두를 넣는 것이 좀 더 분명하다고 생각하기 때문에, 싫어 한다.

디렉토리를 청소하는 규칙(Rules for Cleaning the Directory)

어떤 프로그램을 컴파일하는 것이 여러분이 규칙을 쓰고자 하는 유일한 목적은 아니다. makefile들은 프로그램 하나를 컴파일하는 것 외에 몇 가지 다른 일들을 하는 방법을 보통 얘기한다: 예를 들어서 디렉토리가 `clean'되도록 모든 오브젝트 파일들과 실행 파일들을 지우는 방법.

여기에 우리의 예제 editor를 청소하는 make규칙을 어떻게 쓸 수 있는가에 대한 예제가 있다:

clean:
        rm edit $(objects)

실제로 우리는 예견하지 못한 상황들을 처리하기 위해서 어쩌면 좀 더 복잡한 방법으로 규칙을 쓰려고 할련지도 모른다. 우리는 이것을 할 것이다:

.PHONY : clean
clean :
        -rm edit $(objects)

이것은 make`clean'이라고 불리는 실제 파일에 의해서 혼동되어지는 것을 막고 rm으로부터의 에러들에도 불구하고 그것이 계속되도록 한다. (section 가짜 목적물(Phony Targets), section 명령에서 에러(Errors in Commands), 참조)

이것과 같은 규칙은 makefile의 맨처음에 위치하면 안된다. 왜냐면 우리는 그것이 디폴트로 실행되기를 원하지 않기 때문이다! 그래서, makefile 예제에서 우리는, 그 에디터를 재컴파일하는, edit에 대한 규칙이 default goal로 남아있기를 원한다.

cleanedit의 dependency가 아니기 때문에, 이 규칙은 우리가 `make'명령에게 매개변수를 주지 않는다면, 전혀 실행되지 않을 것이다. 이 규칙이 실행되도록 하기 위해서는 `make clean'이라고 입력해야 한다. See section make 실행 방법(How to Run make).


Go to the first, previous, next, last section, table of contents.