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


규칙 작성(Writing Rules)

rule은 makefile에 나타나고 언제 그리고 어떻게 규칙의 targets(대개 하나의 규칙에 하나만 존재)이라고 불리는 어떤 파일들을 리메이크하는지를 지정한다. 이것은 목적물의 dependencies인 다른 파일들 리스트와 그 목적물을 생성하거나 갱신하는 데 사용될 "명령"을 담고 있다.

규칙들의 순서는, 디폴트 목표(default goal)을 결정하는 것을 제외하고는, 중요한 것이 아니다: 여기서 디폴트 목표(default goal이란 make가, 여러분이 아무것도 지정하지 않는 경우, 생각하는 타겟. 디폴트 목표는 첫번째 makefile의 첫번째 규칙의 타겟이다. 첫번째 규칙이 다수의 타겟들을 가지고 있으면 첫번째 타겟만이 디폴트로 취급된다. 그러나 두가지 예외들이 있다: 점으로 시작하는 타겟은 그것이 하나 이상의 슬래쉬, `/'를 담고 있지 않으면 디폴트가 아니다; 패턴 규칙을 정의하는 타겟은 디폴트 목표에 영향을 미치지 않는다. (See section 패턴 규칙을 정의하고 재정하기(Defining and Redefining Pattern Rules).)

그러므로 우리는 보통 첫번째 규칙이, 전체 프로그램 또는 makefile에 의해서 기술된 모든 프로그램들을 컴파일하는 것이 되도록, makefile을 작성한다(종종 `all'라는 이름의 타겟으로). See section goal을 지정하는 매개변수(Arguments to Specify the Goals).

규칙 문법(Rule Syntax)

일반적으로 규칙은 다음과 같이 생겼다:

targets : dependencies
        command
        ...

또는 다음과 같이 생겼다:

targets : dependencies ; command
        command
        ...

targets 은 공백으로 분리된 파일 이름들이다. 와일드카드 문자들이 사용될 수도 있으며(see section 파일 이름에 와일드카드 사용(Using Wildcard Characters in File Names)) `a(m)' 형태의 이름은 archive 파일a(see section 타겟으로써 아카이브 멤버(Archive Members as Targets0)안에 있는 멤버 m을 표현한다. 일반적으로 규칙 하나당 하나의 타겟이 존재하지만 종종 좀 더 많은 타겟들을 가질 수도 있다(see section 하나의 규칙안의 다수의 타겟들(Multiple Targets in a Rule)).

command 라인들은 탭 문자로 시작한다. 첫번째 명령은 종속물 다음 라인에 탭 문자를 가진 라인으로 나타날 수도 있고 아니면 세미콜론을 가진 동일한 라인에 나타날 수 있다. 양쪽다 그 효과는 동일하다. See section 규칙내 명령 작성(Writing the Commands in Rules).

달러 기호들은 변수 참조를 시작하는 데 사용되기 때문에 여러분이 실제로 규칙에서 하나의 달러 기호를 쓰고자 한다면 달러 두개 `$$'를 반드시 써야 한다(see section 변수 사용 방법(How to Use Variables)). 여러분은 기다란 라인을 백슬레시 더하기 개행 문자를 넣어서 분할할 수 있지만 이것은 반드시 필요한 것이 아니다. 왜냐면 make가 makefile의 각 라인의 최대 길이를 제한하지 않기 때문이다.

규칙은 make에게 두가지 것을 말한다: 타겟들이 언제 out of date인가와 그것들을 필요할 때 어떻게 업데이트할 것인가를 말한다.

out of date인지 아닌지를 판단하는 기준은 DEPENDENCIES 라는 용어로 지정된다. 이것은 공백으로 분리되는 파일 이름들로 구성된다. (와일드카드들과 아카이브 멤버들(see section 아카이브 파일을 갱신하기 위해서 make 사용하기(Using make to Update Archive Files))도 여기서 역시 허용된다.) 타겟은 그것이 존재하지 않거나 종속물들중의 어떤것이라도 이것보다 더 오래된 것이라면 out of date이다(최종-변경 시간을 비교해서). 타겟 파일의 내용물은 종속물들의 정보에 기반을 두고 계산된다는 생각때문에 종속물들 중의 하나라도 변경되면 존재하는 타겟의 내용물은 더이상 유효한 것이 아니다.

업데이트하는 방법은 commands에 의해서 지정된다. 이들은 쉘에 의해서 실행될 라인들이다(일반적으로 `sh'). 그러나 어떤 예외 기능들을 가진다 (see section 규칙내 명령 작성(Writing the Commands in Rules)).

파일 이름에 와일드카드 사용(Using Wildcard Characters in File Names)

하나의 파일 이름은 wildcard characters을 사용해서 많은 파일들을 지정할 수 있다. make에서 와일드카드 문자들은 본 쉘(Bourne shell)과 동일하게 `*', `?' 그리고 `[...]'이다. 예를 들어서, `*.c'는 그것의 이름이 `.c'로 끝나는 모든 파일들(현재 작업 디렉토리 안에서)의 리스트를 지정한다.

파일 이름의 맨 처음에 있는 문자 `~'는 특수한 중요성을 가진다. 혼자 존재하거나 뒤에 slash가 따라오면, 그것은 여러분의 홈 디렉토리를 가르킨다. 예를 들어서 `~/bin'`/home/you/bin'으로 확장된다. `~' 다음에 단어 하나가 붙으면 이 문자열은 그 단어로 지정된 사용자의 홈 디렉토리를 표현한다. 예를 들어서 `~john/bin'`/home/john/bin'로 확장된다. 각 유저에 대한 홈 디렉토리르 갖지 못하는 시스템들(MS-DOS나 MS-Windows와 같이)에서 이 기능은 환경 변수 HOME를 설정함으로써 비슷하게 작동될 수 있다.

와일드카드 확장은 타겟, 종속물, 그리고 명령(여기서는 쉘이 확장을 한다)에서 자동으로 일어난다. 다른 위치에서 와일드카드 확장은 여러분이 확장이 일어나도록 wildcard함수로 명시했을 때에만 일어난다.

와일드카드 문자의 특별한 용도는 그 앞에다 역슬래쉴르 붙임으로써 꺼질수 있다. 그래서 `foo\*bar'는 그것의 이름이 `foo', 별표, 그리고 `bar'으로 이루어진 이름의 특정 파일을 참조하는 것이 될것이다.

와일드카드 예제(Wildcard Examples)

와일드카드들은 규칙의 명령에서 사용될 수 있다. 이곳에서 그들은 쉘에 의해서 확장된다. 예를 들어서 모든 오브젝트 파일들을 삭제하는 규칙을 보자:

clean:
        rm -f *.o

와일드카드들은 규칙의 종속물에서도 유용하다. makefile의 다음 규칙에서 `make print' 는 여러분이 그것들을 인쇄한 마지막 시간 이후로 변경된 모든 `.c' 파일들을 인쇄할 것이다:

print: *.c
        lpr -p $?
        touch print

이 규칙은 `print'를 빈 타겟 파일로 사용한다; section 이벤트를 기록하기 위한 빈 타겟 파일(Empty Target Files to Record Events), 참조. (자동 변수 `$?'는 변경된 파일들만 인쇄하는 데 사용된다; section 자동 변수들(Automatic Variables), 참조.)

여러분이 변수를 정의할 때는 와일드카드 확장이 일어나지 않는다. 그래서 다음과 같이 작성하면:

objects = *.o

objects라는 변수의 값은 `*.o'라는 실제적인 문자열이 된다. 그러나 objects의 값을 타겟에서 사용한다면 종속물이나 명령, 와일드카드 확장은 그 때 일어난다. objects를 확장되게 설정하려면 대신 다음과 같이 써야 한다:

objects := $(wildcard *.o)

See section wildcard 함수(The Function wildcard).

와일드카드를 사용할 때 결점(Pitfalls of Using Wildcards)

다음은 여러분이 의도한 바대로 작동하지 않을, 와일드카드 확장을 사용하는 소박한 방식의 예제이다. 여러분이 실행 파일 `foo'가 모든 오브젝트 파일들로부터 만들어지도록 하기를 원하고 다음과 같이 작성했다고 가정하자:

objects = *.o

foo : $(objects)
        cc -o foo $(CFLAGS) $(objects)

objects의 값은 실제 문자열 `*.o'이다. 와일드카드 확장은 `foo'를 위한 규칙에서 일어난다. 그래서 각 현존하는 `.o' 파일은 `foo'의 종속물이 되고, 필요하다면 재컴파일될 것이다.

그런데 여러분이 모든 `.o' 파일들을 지워버렸다면 어떻게 될 것인가. 와일드카드가 어떤 파일과도 매치되지 않으면 이것은 있는 그대로 남게 된다. 그래서 `foo'은 이상한 이름의 파일 `*.o'에 의존하게 될 것이다. 어떤 그런 파일도 존재하지 않을것이기 때문에 make는 여러분에 `*.o'를 만드는 방법을 알수가 없다는 에러를 낼 것이다. 이것은 여러분이 원하는 것이 아니다!

실제로 와일드카드 확장의 원하는 결과를 얻는 것이 가능하지만, wildcard 함수와 문자열 치환(substitution)을 포하하여, 좀 더 복잡한 기술들이 필요한다. 이것들은 다음 섹션에서 설명된다.

마이크로소프트 운영체제(MS-DOS와 MS-Windows)는 역슬래쉬를 다음과 같이 경로명에서 디렉토리들을 구분하는 것으로 사용한다:

  c:\foo\bar\baz.c

이것은 유닉스-스타일 `c:/foo/bar/baz.c' (`c:' 부분은 소위 드라이브 문자이다)와 동일하다. make가 이런 시스템들 위에서 작동할 때 경로명에서 유닉스-스타일 슬래쉬와 함께 역슬래쉬들을 지원한다. 그러나 이런 지원은 역슬래쉬가 인용부호인, 와일드카드 확장을 포함하지 않는다. 그러므로 여러분은 반드시 이런 경우에 유닉스-스타일 슬래쉬들을 사용해야 한다.

wildcard 함수(The Function wildcard)

와일드 카드는 규칙 안에서 자동으로 확장된다. 그러나 와일드 카드 확장은 일반적으로 변수가 설정되었을 때, 또는 함수의 매개변수 안에서는, 일반적으로 일어나지 않는다. 그런 장소에서 와일드카드 확장을 하려고 한다면 다음과 같이 wildcard 함수를 사용해야 한다.

$(wildcard pattern...)

makefile안의 어떤 곳에서도 사용되는 이 문자열은 주어진 파일 이름 패턴들 중의 하나와 매치되는 현존하는 파일들 이름들의 공백으로 분리된 리스트에 의해서 대체된다. 어떤 파일 이름도 패턴과 매치되는 것이 없으면 그 패턴은 wildcard 함수의 결과로부터 제거된다. 이것은 규칙안에서 매치되지 않은 와일드카드가 행동하는 방식과 다르다는 점에 주의하자. 여기서 그들은 무시된다기보다는 있는 그대로 사용된다(see section 와일드카드를 사용할 때 결점(Pitfalls of Using Wildcards)).

wildcard 함수의 한가지 사용법은 한 디렉토리에 있는 모든 C 소스 파일들의 리스트를 획득하는 것이다. 다음과 같이:

$(wildcard *.c)

우리는 C 소스 파일들의 리스트를 `.c' 접미사를 `.o'로 변경해서 오브젝트 파일들의 리스트로 변경할 수 있다. 다음과 같이:

$(patsubst %.c,%.o,$(wildcard *.c))

(여기서 우리는 다른 함수 patsubst를 사용했다. See section 문자 대입과 분석을 위한 함수들(Functions for String Substitution and Analysis).)

그래서 한 디렉토리에 있는 모든 C 파일들을 컴파일하고 이들을 모두 모아서 링크하려고 하는 makefile은 다음과 같이 작성될 수 있다:

objects := $(patsubst %.c,%.o,$(wildcard *.c))

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

(이것은 C 프로그램들에 대한 묵시적 규칙을 활용하고 있다. 그래서 파일들을 컴파일하는 명시적 규칙들을 작성할 필요가 없다. `='의 변종인 `:='에 대한 설명을 보려면 See section 변수의 두 취향(The Two Flavors of Variables).)

종속물을 위한 디렉토리 검색(Searching Directories for Dependencies)

커다란 시스템들의 경우 바이너리들과 다른 디렉토리에 소스들을 넣는 것이 종종 바람직하다. makedirectory search 기능은 종속물(dependency)을 찾기 위해서 여러 디렉토리들을 자동으로 검색함으로써 이것을 지원한다. 여러분이 디렉토리들 사이로 파일들을 재배포할 때 여러분은 개별 규칙들을 변경할 필요가 없고 검색 패스들만 변경하면 된다.

VPATH: 모든 종속물에 대한 검색 패스(Search Path for All Dependencies)

make의 변수 VPATH의 값은 make가 검색할 디렉토리들의 리스트를 지정한다. 대개의 경우 이 디렉토리들은 현재 디렉토리에는 없는 종속 파일들을 담고 있을 것이다; 그러나 VPATH는 규칙들의 타겟들인 파일들을 포함해서 모든 파일들에 대해서 make가 적용하는 검색 리스트를 지정한다.

그래서 타겟이나 종속물로 리스트된 어떤 파일이 현재 디렉토리에 존재하지 않으면 makeVPATH에 있는 디렉토리들을 검색한다. 이 디렉토리들 중 하나에서 어떤 파일이 있으면 그 파일은 종속물이 될 것이다 (아래를 참조) 규칙들은 그러면, 종속물 리스트안에 있는 파일들이 모두 현재 디렉토리에 있는 것처럼 이들을 지정할 것이다. See section 디렉토리 검색 쉘 명령 작성(Writing Shell Commands with Directory Search).

VPATH 변수안에 디렉토리 이름들은 콜론이나 공백들로 구분된다. 디렉토리들이 나열된 순서로 make가 검색한다. (MS-DOS와 MS-Windows에서는 세미-콜론들이 VPATH에서 디렉토리 이름들을 구분하는 데 사용된다. 왜냐면 콜론이 드라이브 명 뒤에서 경로명 자체에서 사용될 수 있기 때문이다.)

예를 들어서,

VPATH = src:../headers

이것은 make가 이 순서로 검색하는, 두 디렉토리들, `src'`../headers', 을 담고 있는 경로를 지정하고 있다.

VPATH의 이런 값으로 다음 규칙은

foo.o : foo.c

이것이 다음과 같이 쓰여진 것처럼 해석된다:

foo.o : src/foo.c

파일 `foo.c'이 현재 디렉토리에는 없지만 `src' 디렉토리에 있는 것으로 가정하면서 말이다.

vpath 지시어

VPATH 변수와 비슷하게, 좀 더 선택적이게, vpath라는 지시어(소문자를 주목하자)가 있다. 이것은 여러분이 특정한 클래스의 파일 이름들을 위한 검색 경로를 지정하도록 허락한다: 특정 패턴과 매치되는 것들. 그래서 여러분은 한 클래스의 파일 이름들을 위한 검색 디렉토리들을, 다른 파일 이름들에 대해서 다른 디렉토리들(또는 아무것도 지정하지 않을 수 있다)을 제공할 수 있다.

vpath 지시어는 다음과 같은 세가지 형태가 있다:

vpath pattern directories
이것은 pattern와 매치되는 파일 이름들에 대한 검색 경로 directories를 지정한다. directories라는 검색 경로는 검색될 디렉토리들의 리스트이며, VPATH 변수에서 사용된 검색 경로와 비슷하게, 콜론(MS-DOS와 MS-Windows에 대해서는 세미-콜론)과 공백들에 의해서 구분된다.
vpath pattern
이것은 pattern에 연결된 검색 경로를 청소하다.
vpath
이것은 vpath 지시어로 이전에 지정된바 있던 모든 검색 경로들을 삭제한다.

vpath 패턴은 `%' 문자를 담고 있는 문자열이다. 이 문자열은 검색대상인 종속물의 파일 이름과 반드시 매치되어야 하며 `%' 문자는 0개 또는 그이상의 문자들의 임의의 시퀀스와 매치되는 것이다(패턴 규칙에서와 비슷하다; see section 패턴 규칙을 정의하고 재정하기(Defining and Redefining Pattern Rules)). 예를 들어서 %.h.h로 끝나는 파일들과 매치된다. (어떤 `%'도 없다면 패턴 규칙은 반드시 종속물과 정확하게 매치되어야 한다. 이런것은 유용한 것이 아니다.)

vpath 지시어의 패턴에 있는 `%' 문자는 앞에 역슬래쉬 (`\')로 인용될 수 있다. 다른 식으로 `%' 문자들을 인용할 수 있는 역슬래쉬들은 좀 더 많은 역슬래쉬들로 인용될 수 있다. `%' 문자들을 인용하는 역슬래쉬들이나 다른 역슬래쉬들은 패턴에서 이것이 파일 이름들과 비교되기 전에 제거된다. `%' 문자들을 인용하는 위험에 있지 않는 역슬래쉬들은 간섭받지 않는다.

종속물들이 현재 디렉토리에 존재하지 않을때, vpath 지시어 안의 pattern이 종속물 파일의 이름과 매치된다면, 그 지시어 안의 directoriesVPATH 변수안의 디렉토리와 동일하게(그리고 그 이전에) 검색된다.

예를 들어서

vpath %.h ../headers

이것은 make`.h'로 끝나는 이름의 종속물이 현재 디렉토리에 없으면 `../headers' 디렉토리에서 찾도록 말한다.

몇가지 vpath 패턴들이 종속물 파일의 이름과 매치된다면 make는 각 매치되는 vpath 지시어를 하나씩 처리하면서 각 지시어 내에서 언급된 모든 디렉토리들을 검색한다. make는 다수의 vpath 지시어들을 그들이 makefile에 나타난 순서대로 처리한다; 동일한 패턴을 갖는 다수의 지시어들은 각각 다른 것에 대해서 독립적이다.

그래서

vpath %.c foo
vpath %   blish
vpath %.c bar

이것은 `foo'에서 `.c'로 끝나는 파일을 찾을 것이고 그 다음에는 `blish', 그 다음에는 `bar'를 찾을 것이다. 반면에 다음

vpath %.c foo:bar
vpath %   blish

`foo'에서 `.c'로 끝나는 파일을 찾을 것이다. 그 다음은 `bar', 그리고 `blish'를 찾을 것이다.

디렉토리 검색이 수행되는 방법(How Directory Searches are Performed)

어떤 종속물이 디렉토리 검색에서 찾아질 때 타입(general 또는 selective)에 상관없이 찾아진 패스이름은 make가 실제로 종속물 리스트에서 제공한 것들 중의 하나가 아닐 수 있다. 간혹 디렉토리 검색을 통해서 찾아진 패스는 버려진다.

make가 디렉토리 검색을 통해서 찾은 패스를 간직하는가 아니면 버리는가를 결정하는 데 사용하는 알고리즘은 다음과 같다:

  1. 타겟 파일이 makefile에서 지정한 패스에 존재하지 않으면 디렉토리 검색이 수행된다.
  2. 디렉토리 검색이 성공적이면 그 패스는 간직되고 이 파일은 시험적으로 타겟으로 저장된다.
  3. 이 타겟의 모든 종속물들은 이런 동일한 방법을 사용해서 시험된다.
  4. 종속물들을 처리한 후, 타겟은 재빌드가 될 필요가 있거나 그렇지 않다:
    1. 타겟이 재빌드될 필요가 없다면, 디렉토리 검색 동안 찾아진 파일에 대한 경로는, 이런 타겟을 포함하는 임의의 종속물 리스트에 사용된다. 간단히 말해서 make가 타겟을 재빌드할 필요가 없다면 여러분은 디렉토리 검색을 통해서 찾아진 패스를 사용한다.
    2. 타겟이 재빌드될 필요가 있으면 (out-of-date이면), 디렉토리 검색동안 찾아진 경로명은 버려지고, 타겟은 makefile에서 지정된 파일 이름을 사용하여 재빌드된다. 간단히 말하면 make가 반드시 재빌드해야 한다면 타겟은 로컬로 재빌드도기ㅗ 디렉토리 검색을 통해서 찾아진 디렉토리에서는 재빌드되지 않는다.

이 알고리즘은 복잡하게 보일수 있지만 실제로 이것은 여러분이 원하는 것과 완전히 똑같은 경우가 많다.

다른 make 버전들은 좀 더 단순한 알고리즘을 사용한다: 파일이 존재하지 않고 디렉토리 검색을 통해서 찾아지면 그 경로명은 항상, 타겟이 빌드되어야 하는가 또는 하지 않아도 되는가에 따라서 사용된다. 그래서 타겟이 재빌드되면 이것은 디렉토리 검색 동안 발견된 경로명에서 생성된다.

사실, 이것이 여러분이 어떤 또는 모든 디렉토리들에 대해서 원하는 행동이라면, 여러분은 GPATH 변수를 사용해서 이것을 maek에게 지정할 수 있다.

GPATHVPATH와 동일한 문법과 포멧을 가진다 (즉, 경로명들의 공백 또는 콜론으로 구분된 리스트). out-of-date 타겟이 디렉토리 검색을 통해서 GPATH에 있는 어떤 디렉토리에서 찾아진 것이라면 그 경로명은 버려지지 않는다. 타겟은 확장된 경로를 사용해서 재빌드된다.

디렉토리 검색 쉘 명령 작성(Writing Shell Commands with Directory Search)

종속물(dependency)이 디렉토리 검색을 통해서 다른 디렉토리에서 찾아질 때, 이것은 그 규칙의 명령들ㅇ르 변경할 수 없다; 그들은 작성된 대로 실행된다. 그러므로 여러분은 반드시 명령들이 make가 그것을 찾는 디렉토리에서 종속물들을 찾도록, 조심스럽게 작성해야 한다.

이것은 `$^'와 같은 자동 변수와 함께 이루어진다 (see section 자동 변수들(Automatic Variables)). 예를 들어서 `$^'의 값은 그 규칙의 모든 종속물들의 리스트이다. 이것은 그들이 찾아지는 디렉토리의 이름들을 포함하고 `$@'의 값은 타겟이다. 그래서:

foo.o : foo.c
        cc -c $(CFLAGS) $^ -o $@

(변수 CFLAGS는 여러분이 C 컴파일에 대해서 묵시적 규칙으로 플래그 값들을 지정할 수 있도록 존재한다; 우리는 이것을 일관성 때문에 사용했고 그래서 이것은 모든 C 컴파일에 공통으로 영향을 미칠 것이다; see section 묵시적 규칙에 의해 사용되는 변수(Variables Used by Implicit Rules).)

종종 종속물들은 헤더 파일들을 같이 포함한다. 이들은 명령안에서 언급하고 싶지 않은 것이다. 자동 변수 `$<'는 단지 첫번째 종속물을 가리킨다:

VPATH = src:../headers
foo.o : foo.c defs.h hack.h
        cc -c $(CFLAGS) $< -o $@

디렉토리 검색과 묵시적 규칙들(Directory Search and Implicit Rules)

$code{VPATH}나 vpath로 지정된 디렉토리들에 대한 검색은 묵시적 규칙을 생각할 때에도 또한 일어난다 (see section 묵시적 규칙(Using Implicit Rules)).

예를 들어서 파일 `foo.o'가 어떤 명시적인 규칙도 가지지 않으면, `foo.c'가 존재하지 않으면 이것을 컴파일하는 내장 규칙과 같은, 묵시적 규칙들을 생각한다. 그런 파일이 현재 디렉토리에 없으면 적절한 디렉토리들이 검색된다. `foo.c'가 어떤 디렉토리들 중 하나에 존재하면 (또는 makefile에 언급되었다면), C 컴파일을 위한 묵시적 규칙이 적용된다.

묵시적 규칙들의 명령은 일반적으로 필요해서 자동 변수들을 사용한다; 결과적으로 그들은 어떤 여분의 노력없이도 디렉토리 검색에 의해서 찾아지는 파일 이름들을 사용할 것이다.

링크 라이브러리 디렉토리 검색(Directory Search for Link Libraries)

디렉토리 검색은 링커와 함께 사용되는 라이브러리들에 특별한 방식으로 적용된다. 이 특별한 기능은 여러분이 종속물의 이름이 `-lname'과 같은 형태를 지니도록 작성할 때 동작한다. (여러분은 이상한 어떤 것이 여기서 진행중이다라고 말할 수도 있다. 왜냐면 종속물은 일반적으로 파일의 이름이고 라이브러리의 파일 이름`-lname'가 아니라 `libname.a' 처럼 보이기 때문이다.)

어떤 종속물의 이름이 `-lname'의 형태를 가지면 make는 그것을 현재 디렉토리, vpath 검색 경로, VPATH 검색 경로와 매치되도록 지정된 디렉토리들 안에서, 그리고 나서 `/lib', `/usr/lib', 그리고 `prefix/lib' (일반적으로 `/usr/local/lib', 그러나 MS-DOS/MS-Windows 버전의 makeprefix가 DJGPP 설치 트리의 루트로 정의된 것처럼 작동한다)에서 `libname.a' 파일을 검색함으로써, 특별하게 처리한다.

예를 들어서,

foo : foo.c -lcurses
        cc $^ -o $@

`cc foo.c /usr/lib/libcurses.a -o foo'가, `foo'`foo.c'보다 또는 `/usr/lib/libcurses.a'보다 더 오래된 것이라면, 실행되도록 한다.

가짜 목적물(Phony Targets)

가짜 목적물은 실제로 파일의 이름이 아닌 것이다. 이것은 여러분이 명시적인 요구를 할 때 실행되는 어떤 명령들에 대한 이름이다. 가짜 목적물을 사용하는 데는 두 가지 이유가 있다: 동일한 이름을 가진 파일과 충돌을 피하기 위해서가 하나이고 퍼포먼스를 개선하기 위한 것이 하나이다.

그것의 명령들이 목적 파일을 생성하지 않을 규칙을 만든다면, 그 명령들은 목적물이 다시만들어야 하는 것으로 나타날 때마다 실행될 것이다. 다음은 하나의 예제이다:

clean:
        rm *.o temp

rm 명령이 `clean'이라는 이름의 파일을 생성하지 않기 때문에, 아마도 그런 파일은 앞으로 절대 존재하지 않을 것이다. 그러므로, rm 명령은 여러분이 `make clean'이라고 말할 때마다 실행될 것이다.

가짜 목적물은 이 디렉토리에서 `clean'이라는 이름의 파일을 무엇인가가 생성한다면 작업을 멈출 것이다. 그것은 종속물을 갖지 않기 때문에 `clean'이라는 파일은 무조건 가장 최근 것으로 생각될 것이고 그것의 명령들은 절대 수행되지 않을 것이다. 이런 문제를 피하기 위해서 여러분은 명시적으로 가짜가 될 목적물을, 특수한 목적물 .PHONY(see section 특수 내장 타겟 이름(Special Built-in Target Names))를 써서 다음과 같이, 선언할 수 있다:

.PHONY : clean

일단 이렇게 설정하면 `make clean'`clean'이라는 이름의 파일의 존재를 신경쓰지 않고서 그 명령들을 실행할 것이다.

가짜 목적물들은 다른 파일들로부터 실제 리메이크될 수 있는 실제 파일을 지칭하는 것이 아니란 것을 알기 때문에, make은 가짜 목적들을 검색하는 묵시적인 규칙을 스킵한다(see section 묵시적 규칙(Using Implicit Rules)). 비록 실제 파일의 존재 여부를 신경쓰지 않더라도, 이것이 바로 가짜 목적물이 퍼포먼스에 좋다고 한 이유이다.

그래서 다음과 같이 여러분은 먼저 clean이 가짜 목적물이다라고 말하는 라인을 쓰고, 규칙을 써야 한다:

.PHONY: clean
clean:
        rm *.o temp

포니 타겟은 실제 타겟 파일의 종속물이 되어서는 안된다; 만일 그렇다면, 그것의 명령들이, make가 그 파일을 업데이트할 때마다, 실행될 것이다. 포니 타겟이 실제 타겟의 종속물이 절대로 아닌 한, 포니 타겟 명령들은 포니 타겟이 특수한 goal일 때만 실행될 것이다 (see section goal을 지정하는 매개변수(Arguments to Specify the Goals)).

포니 타겟들은 종속물들을 가질 수 있다. 한 디렉토리가 다수의 프로그램들을 포함하고 있을 때, 이런 프로그램 모두를 하나의 makefile `./Makefile' 안서 기술하는 것이 가장 편하다. 디폴트로 만들어진 타겟이 makefile에서 첫번째가 될 것이기 때문에 이것이 `all'라는 이름의 포니 타겟이 되도록 하고 그것의 종속물로써 모든 개별 프로그램들로 설정하는 것이 일반적이다. 예를 들어서:

all : prog1 prog2 prog3
.PHONY : all

prog1 : prog1.o utils.o
        cc -o prog1 prog1.o utils.o

prog2 : prog2.o
        cc -o prog2 prog2.o

prog3 : prog3.o sort.o utils.o
        cc -o prog3 prog3.o sort.o utils.o

이제 여러분은 `make'가 모든 세개의 프로그램들을 다시 만들도록 할 수 있거나 매개변수로써, 다시 만들 하나를 지정할 수 있다 (`make prog1 prog3'와 같이).

하나의 포니 타겟이 다른 것의 종속물이라면 이것은 다른 것의 서브루틴으로 작동된다. 예를 들어서 다음 `make cleanall' 는 오브젝트 파일들, 차이 파일들, 그리고 `program' 파일을 모두 지울 것이다:

.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
        rm program

cleanobj :
        rm *.o

cleandiff :
        rm *.diff

명령과 종속물이 없는 규칙(Rules without Commands or Dependencies)

어떤 규칙이 종속물이나 명령이 없고 그 규칙의 타겟이 존재하지 않는 파일이라면 make는 이 타겟을 그것의 규칙이 실행될 때마다 업데이트되어야 할 것으로 생각한다. 그래서 결과적으로 이것에 종속적인 모든 타겟들의 명령은 항상 실행된다.

다음 예제는 이것을 예시한다:

clean: FORCE
        rm $(objects)
FORCE:

여기서 타겟 `FORCE'는 특별한 조건을 만족하고 있기 때문에 이것에 종속적인 타겟 `clean'이 그것의 명령을 무조건 실행한다. `FORCE'이라는 이름 자체에는 특별한 것이 없지만 이런 스타일로 사용되는 이름으로 일반적으로 사용된다.

여러분이 볼 수 있는 것처럼 이런 식으로 `FORCE'를 사용하는 것은 `.PHONY: clean'를 사용하는 것과 동일한 결과를 낸다.

`.PHONY'를 사용하는 것은 좀 더 명시적이고 좀 더 효과적이다. 그러나 make의 다른 버전들은 `.PHONY'를 지원하지 않는다; 그래서 `FORCE'는 많은 makefile에서 나타난다. See section 가짜 목적물(Phony Targets).

이벤트를 기록하기 위한 빈 타겟 파일(Empty Target Files to Record Events)

empty target이란 포니 타겟의 변종이다; 이것은 여러분이 때때로 명시적으로 요구하는 액션에 대한 명령을 갖고 있는데 사용된다. 포니 타겟과는 다르게 이런 타겟 파일은 실재 존재할 수 있다; 그러나 그 파일의 내용은 상관이 없다. 그리고 보통 이것은 비어 있다.

빈 타겟의 목적은 이것의 마지막-변경 시간과 함께 그 규칙의 명령들이 마지막으로 수행된 시간을 기록하고자 하는 것이다. 이것은 명령들 중의 하나가 타겟 파일을 업데이트하는 touch 명령이기 때문에 그렇게 한다.

빈 타겟 파일은 반드시 어떤 종속물을 가져야 한다. 여러분이 빈 타겟을 만들라고 요구할 때 명령들은 그 종속물 중의 하나라도 타겟보다 더 최근의 것이어야만 실행된다; 다른말로 하면 종속물이 여러분이 타겟을 만든 이후 변경되었어야만 실행된다. 다음 예제를 보자:

print: foo.c bar.c
        lpr -p $?
        touch print

이 규칙을 가지고 `make print'하면 소스 파일이 마지막으로 `make print'한 후 변경되었다면, lpr 명령을 실행할 것이다. 자동 변수 `$?'는 변경된 파일들만 인쇄할 때 사용된다 (see section 자동 변수들(Automatic Variables)).

특수 내장 타겟 이름(Special Built-in Target Names)

어떤 이름들은 그들이 타겟으로 나타날 때 특수한 의미를 갖는다.

.PHONY
특수 타겟 .PHONY의 종속물들은 포니 타겟들로 생각된다. 그런 타겟을 생각할 때 make는 그 이름의 파일이 존재하는지 아니면 그것의 최종-변경 시간이 무엇인지 생각하지 않고서 그것의 명령들을 무조건 실행할 것이다.
.SUFFIXES
특수 타겟 .SUFFIXES의 종속물들은 확장자 규칙(suffix rule)을 검사하는 데 사용되는 확장자들의 리스트이다. See section 구닥다리 접미사 규칙(Old-Fashioned Suffix Rules).
.DEFAULT
.DEFAULT로 지정된 명령들이 어떤 규칙도 찾을 수 없는 임의의 타겟들에 대해서 사용된다(명시적 규칙이나 묵시적 규칙들). See section 최후의 디폴트 규칙 정의(Defining Last-Resort Default Rules). .DEFAULT 명령들이 지정되면 종속물로 업급된 모든 파일들, 그러나 어떤 규칙의 타겟이 아닌 파일들은 이런 명령들을 실행할 것이다. See section 묵시적 규칙 검색 알고리즘(Implicit Rule Search Algorithm).
.PRECIOUS
.PRECIOUS가 의존하는 타겟들은 다음과 같은 특별한 취급을 받는다: make가 명령 실행 중에 죽거나 인터럽트를 받으면, 그 타겟은 삭제되지 않는다. See section make를 인터럽트 또는 죽이기(Interrupting or Killing make). 또한, 그 타겟이 중간 파일이라면, 더이상 필요하지 않을 때, 일반적인 경우처럼, 삭제되지 않을 것이다. See section 묵시적 규칙의 연쇄(Chains of Implicit Rules). 여러분은 또한 묵시적 규칙의 타겟 패턴(`%.o'와 같은)을 특별한 타겟 .PRECIOUS의 종속 파일로 지정해서 그 파일의 이름과 매치하는 타겟 패턴 매치의 규칙ㅇ 의해서 생성된 중간 파일들을 보존할 수 있다.
.INTERMEDIATE
.INTERMEDIATE가 의존하는 타겟들은 중간 파일들로 취급된다. See section 묵시적 규칙의 연쇄(Chains of Implicit Rules). 종속물이 없는 .INTERMEDIATE는 makefile에서 언급된 모든 타겟들을 중간 파일들로 마킹한다.
.SECONDARY
.SECONDARY가 의존하는 타겟들은 중간 파일들로 취급된다. 단 그들은 자동으로 삭제되지 않는다. See section 묵시적 규칙의 연쇄(Chains of Implicit Rules). 종속물이 없는 .SECONDARY는 makefile에서 언급된 모든 타겟을 secondary로 마킹한다.
.IGNORE
.IGNORE에 대해서 종속물들을 지정하면 make는 그런 특수한 파일들에 대해서 실행한 명령들의 실행에서 발생한 에러들을 무시한다. .IGNORE에 대한 명령들은 의미가 없다. 종속물이 없이 타겟으로써 언급되면 .IGNORE는 모든 파일들에 대한 명령들의 실행에서 발생하는 에러들을 무시하라고 말하는 것이다. 이런 `.IGNORE'의 사용은 역사적인 호환성만을 위해서 지원된다. 이것이 makefile에 있는 모든 명령에 영향을 미치기 때문에 이것은 아주 유용한 것이 아니다; 우리는 여러분이 특정한 명령들에서 에러들을 무시하는 선택적인 방법을 좀 더 사용하기를 권한다. See section 명령에서 에러(Errors in Commands).
.SILENT
.SILENT에 대한 종속물들을 지정한다면 make는 이런 특정 파일들을 다시 만드는 명령들을 실행하기 전에 이들을 디스플레이하지 않을 것이다. .SILENT에 대한 명령들은 의미가 없다. 종속물이 없는 타겟으로써 언급된다면 .SILENT는 그것들을 실행하기 전에 모든 명령들을 디스플레이하지 않도록 말하는 것이다. 이런 `.SILENT'의 사용법은 역사적 호환성만을 위해서 지원되는 것이다. 특정 명령들이 침묵하게 하도록 하기 위해서 좀 더 선택적인 방법을 사용하기를 권장한다. See section 명령 에코(Command Echoing). make의 특정한 실행에 대해서 모든 명령들을 잠잠하게 하기를 원한다면 `-s'`--silent' 옵션을 사용하라 (see section 옵션들의 요약(Summary of Options)).
.EXPORT_ALL_VARIABLES
타겟으로써 언급됨으로써 이것은 make가 모든 변수들을, 디폴트로 차일드 프로세스들에게 익스포트하도록 한다. See section 서브-make에 대한 통신 변수(Communicating Variables to a Sub-make).

정의된 묵시적 규칙 접시사가 타겟으로써 나타난다면 이것도 또한 특수 타겟으로 여겨진다. 그래서 `.c.o'와 같은 두 접미사들도 마찬가지이다. 이런 타겟들은 접미사 규칙이다. 이것은 묵시적 규칙들을 정의하는 구식 방법이다(그러나 아직 여전히 널리 사용되고 있는 방법이다). 원칙적으로 어떤 타겟이름이라도 여러분이 이것을 두개로 쪼개서 그 두 부분을 접미사 리스트에다 추가하면, 이런 식으로 특수한 것이 될 수 있다. 실제로, 접미사들은 보통 `.'로 시작하기 때문에 이런 특수 타겟 이름들 또한 `.'로 시작한다. See section 구닥다리 접미사 규칙(Old-Fashioned Suffix Rules).

하나의 규칙안의 다수의 타겟들(Multiple Targets in a Rule)

다수 타겟을 가지는 규칙은 하나의 타겟을 가지는(그리고 나머진ㄴ 모두 동일한) 다수의 규칙들을 작성하는 것과 동일하다. 동일한 명령들이 모든 타겟들에 적용되지만 그들의 효과는, 여러분이 명령에다 `$@'를 사용하여 실제 타겟 이름을 대체할 수 있기 때문에, 다양할 수 있다. 규칙은 모든 타겟들에 대해서 동일한 종속물들을 적용한다.

이것은 다음 두가지 경우에 유용하다.

여러분이, 변수 `$@'가 여러분에게 명령들을 변하게 하는 것과 비슷하게, 타겟에 따라서 종속물들을 다르게 하고자 한다고 해보자. 여러분은 하나의 일반적인 규칙안에다 다수의 타겟들을 써서 이렇게 할 수 없다. 그러나 여러분은 이것을 static pattern rule를 사용해서 할 수 있다. See section 정적 패턴 규칙(Static Pattern Rules).

타겟 하나에 대한 여러 규칙(Multiple Rules for One Target)

하나의 파일이 여러 규칙들의 타겟이 될 수 있다. 모든 규칙에서 언급된 모든 종속물들은 그 타겟에 대한 종속물 리스트 하나로 합쳐진다. 타겟이 한 규칙의 임의의 종속물보다 더 오래된 것이라면 그 명령이 실행된다.

하나의 파일에 대해서 실행될 명령들 집합은 하나만 존재할 수 있다. 규칙 하나 이상이 동일한 파일에 대한 명령들을 제공한다면 make는 마지막으로 주어진 명령 집합을 사용하고 에러 메시지를 출력할 것이다. (특별한 경우로써 그 파일의 이름이 점으로 시작하면 에러메시지는 출력되지 않는다. 이런 이상한 행동은 다른 make의 구현과 호환을 이루기 위해서이다.) 여러분의 makefile들을 이런식으로 작성하는 이유는 없다; 그것이 왜 make가 여러분에게 에러 메시지를 주는 이유이다.

종속물만 있는 여분의 규칙이 동시에 많은 파일들에게 여분의 종속물들 제공하는 데 사용될 수 있다. 예를 들어서 만들어지고 있는 모든 컴파일러 결과 파일들의 리스트를 담고 있는 objects라는 이름의 변수를 보통 가진다. 이들중 모두가 `config.h' 파일이 변경되면 반드시 컴파일되어야 한다는 것을 말하는 쉬운 방법은 다음과 같이 작성하는 것이다:

objects = foo.o bar.o
foo.o : defs.h
bar.o : defs.h test.h
$(objects) : config.h

이것은, 실제로 오브젝트 파일들을 만드는 방법을 지정하는 규칙들을 변경하지 않고서 삽입되거나 제거될 수 있다. 또한 추가의 종속물을 간헐적으로 추가하고자 한다면 이것은 사용하기 편리한 폼이 될 것이다.

추가된 종속물들은 make에 대한 명령 매개변수로 여러분이 설정한 변수로 지정될 수 있다는 것이 다른 좋은 좋은 점이다. (see section 변수 겹쳐쓰기(Overriding Variables)). 예를 들어서,

extradeps=
$(objects) : $(extradeps)

이것은 명령 `make extradeps=foo.h'`foo.h'를 각 오브젝트 파일에 대해서 종속물로써 생각할 것이지만 이런 매개변수가 없는 평범한 `make'는 그렇지 않을것이라는 것을 의미한다.

하나의 타겟에 대한 명시된 규칙들 중의 어떤 것도 명령들을 갖지 않는다면 make는 어떤 명령들을 찾기 위해서 적용가능한 묵시적 규칙을 검색한다 see section 묵시적 규칙(Using Implicit Rules)).

정적 패턴 규칙(Static Pattern Rules)

정적 패턴 규칙(Static pattern rules)은 다수의 타겟을 지정하고 타겟의 이름에 기반해서 각 타겟에 대한 종속물 이름들을 구축하는 규칙이다. 이것은 다수의 규칙을 가지는 하나의 일반 규칙보다 좀 더 일반적이다. 왜냐면 타겟들이 동일한 종속물들을 가질 필요가 없기 때문이다. 그들의 종속물들은 반드시 비슷(analogous)해야 하지만 반드시 동일(identical)할 필요는 없다.

정적 패턴 규칙의 문법(Syntax of Static Pattern Rules)

다음은 정적 패턴 규칙의 문법이다.

targets ...: target-pattern: dep-patterns ...
        commands
        ...

여기서 targets 리스트는 이 규칙이 적용될 대상 타겟들을 지정한다. 타겟들은 일반 규칙의 타겟과 마찬가지로 와일드카드 문자들을 가질 수 있다 (see section 파일 이름에 와일드카드 사용(Using Wildcard Characters in File Names)).

target-patterndep-patterns은 각 타겟에 대한 종속물들을 계산하는 방법을 말하는 것이다. 각 타겟은 target-pattern에 대해서, 줄기(stem)이라고 불리는, 타겟 이름 부분을 추출하기 위해서 비교된다. 이 줄기는 종속물 이름들을 만들기 위해서 dep-patterns 각각에 대입된다. (각 dep-pattern으로부터 하나씩)

각 패턴은 보통 하나의 `%' 문자를 담고 있다. target-pattern가 타겟 하나와 비교될 때, `%'는 타겟 이름의 임의의 부분과 매치될 수 있다; 이런 부분은 줄기(stem)라고 불린다. 이 패턴의 나머지 부분들은 정확하게 매치되어야 한다. 예를 들엇 타겟 `foo.o'가 패턴 `%.o'와 매치된다. 이 때 `foo'가 줄기이다. `foo.c'`foo.out'은 그 패턴과 매치되지 않는다.

각 타겟에 대한 종속물 이름들은 각 종속물 패턴에 있는 `%'에 대한 줄기를 대치함으로써 만들어진다. 예를 들어서 한 종속물 패턴이 `%.c'이라면 줄기 `foo'의 대치는 종속물 이름 `foo.c'를 제공한다. `%'를 갖지 않는 종속물 패턴을 작성하는 것도 합법적이다; (이렇게 쓰는 경우) 이 종속물은 모든 타겟들과 동일하다.

패턴 규칙에 있는 `%' 문자들은 앞에다 역슬래쉬 (`\')로 인용될 수 있다. 딴 방법으로 `%'를 인용할 역슬래쉬들은 좀 더 많은 역슬레쉬들로 인용될 수 있다. `%' 문자들이나 다른 역슬래쉬들을 인용하는 역슬래쉬들은 패턴에서, 이것이 파일이름들에 비교되거나 그것으로 줄기가 대치되기 전에, 제거된다. `%' 문자들을 인용할 위험에 있지 않는 역슬래쉬들은 간섭받지 않는다. 에를 들ㅇ서 `the\%weird\\%pattern\\' 패턴은 앞에 `%' 문자를 가진 `the%weird\'를 가지며, `pattern\\' 가 그 뒤에 온다. 마지막에 있는 두개의 역슬래쉬들은 그들이 `%' 문자에 영향을 미치지 않으므로 혼자 남게 된다.

다음은, `foo.o'`bar.o' 각각을 대응하는 `.c' 파일로부터 컴파일하는, 예제이다:

objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@

여기서 `$<'는 종속물의 이름을 갖고 이는 자동 변수이고 `$@'는 타겟의 이름을 갖고 있는 장동 변수이다; see section 자동 변수들(Automatic Variables).

지정된 각 타겟은 타겟 패턴과 반드시 일치해야 한다; 그렇지 않은 각 타겟에 대해서는 경고가 출력될 것이다. 여러분이 파일들의 리스트를 가진다면 이들중 어떤 것들만이 그 패턴과 일치할 것이고 여러분은 filter 함수를 써서 일치하지 않는 파일 이름들을 사용할 수 있다 (see section 문자 대입과 분석을 위한 함수들(Functions for String Substitution and Analysis)):

files = foo.elc bar.o lose.o

$(filter %.o,$(files)): %.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
        emacs -f batch-byte-compile $<

이 예제에서 `$(filter %.o,$(files))'의 결과는 `bar.o lose.o'이고, 첫번째 정적 패턴 규칙은 이런 오브젝트 파일들 각각이 대응하는 C 소스 파일을 컴파일해서 업데이트되도록 한다. `$(filter %.elc,$(files))' 의 결과는 `foo.elc'이다. 그래서 그 파일은 `foo.el'로부터 만들어진다.

다른 예제는 $*를 정적 패턴 규칙안에서 사용하는 방법을 보여준다:

bigoutput littleoutput : %output : text.g
        generate text.g -$* > $@

generate 명령이 실행될 때 *는 줄기인 `big'`little'로 확장될 것이다.

정적 패턴 규칙 대(對) 묵시적 규칙(Static Pattern Rules versus Implicit Rules)

정적 패턴 규칙은 패턴 규칙으로써 정의된 묵시적 규칙과 많은 면에서 비슷하다 (see section 패턴 규칙을 정의하고 재정하기(Defining and Redefining Pattern Rules)). 둘다 타겟에 대한 패턴을 가지고 종속물 이름들을 구축하는 패턴을 가진다. 차이는 make가 규칙이 적용될 를 결정하는 방법이다.

묵시적 규칙은 그것의 패턴과 일치하는 어떤 타겟에도 적용될 수 있다. 그러나 이것은 그 타겟이 지정된 어떤 명령도 가지지 않을 때, 그리고 종속물들이 찾아질 수 있을 때에만, 적용된다. 하나의 묵시적 규칙보다 많은 것이 적용가능으로 나타난다면 단지 하나만 적용된다; 이 때 그 선택은 규칙들의 순서에 종속적이다.

이에 반해서 정적 패턴 규칙은 여러분이 규칙안에 지정한 정확한 타겟들 리스트에만 적용된다. 이것은 다른 타겟들에는 적용될 수 없으며 지정된 각 타겟에 일정하게 적요된다. 두개의 서로 상충하는 규칙들이 적용되고 이 두개가 명령들을 가진다면 에러이다.

정적 패턴 규칙은 다음과 같은 이유들 때문에 묵시적 규칙보다 더 좋을 수 있다:

더블-콜론 규칙(Double-Colon Rules)

더블-콜론(Double-colon) 규칙은 타겟 이름 뒤에 `:' 대신에 `::'를 사용하여 작성된 규칙을 말한다. 이들은 동일한 타겟이 여러 규칙에서 나타날 때 일반 규칙들과는 다르게 처리된다.

하나의 타겟이 다수의 규칙에서 나타날 때 이런 모든 규칙들은 동일한 타입을 가져야만 한다: 즉, 모두 일반 규칙이거나 모두 더블-콜론 규칙이어야만 한다. 각 더블-콜론 규칙의 명령들은 타겟이 그 규칙의 임의의 종속물보다 더 오래된 것이라면 실행된다. 그래서 더블 콜론 규칙의 모든 것, 또는 임의의 것을 실행하거나, 또는 아무것도 실행시키지 않을 수 있다.

동일한 타겟의 더블-콜론 규칙들은 실제로 완전히 다른 것과 분리된 것이다. 각 더블-콜론 규칙은, 다른 타겟들이 처리되는 것처럼, 개별적으로 처리된다.

하나의 타겟에 대한 더블-콜론 규칙들은 그들이 makefile에 나타난 순서대로 실행된다. 그러나 더블-콜론 규칙들이 실제 의미가 있는 경우는 명령들을 실행하는 순서가 의미가 없는 경우이다.

더블-콜론 규칙들은 어떤면에서는 불명료하고 그렇게 자주 유용한 것이 아니다; 그들은 타겟을 업데이트하는 사용되는 방법이 업데이트를 유발하는 데 사용되는 종속물 파일들에 따라서 다른 경우를 위한 메카니즘을 제공한다. 그리고 그런 경우는 드물다.

각 더블-콜론 규칙은 명령들을 반드시 지정해야 한다; 그렇지 않으면 묵시적 규칙이 사용될 것이다. See section 묵시적 규칙(Using Implicit Rules).

종속물들을 자동으로 생성하기(Generating Dependencies Automatically)

어떤 프로그램을 위한 makefile에서 여러분이 작성하고자 하는 많은 규칙들은 종종 어떤 오브젝트 파일이 다른 헤더 파일에 의존한다는 것만을 말한다. 예를 들엇 `main.c'#include를 통해서 `defs.h'를 사용한다면 여러분은 다음과 같이 쓸 것이다:

main.o: defs.h

여러분은 make가, `defs.h'가 변할 때마다 `main.o'를 반드시 다시 만들어야 한다는 것을 알게 하기 위해서 이 규칙이 필요하다. 어떤 커다란 프로그램에 대해서는 makefile안에 그런 규칙들 수십개를 작성해야 할 것이다. 그리고, 여러분은 항상 makefile을, #include를 더하거나 제거할 때마다, 조심스럽게 ㄷ업데이트해야 한다.

이런 고전분트를 피하기 위해서 대부분의 현대 C 컴파일러들은 여러분의 소스 파일에서 #include들을 찾아서, 여러분을 위해서 이런 규칙들 작성할 수 있다. 대개 컴파일러에게 `-M' 옵션을 주어서 이런 일을 할 수 있다. 예를 들어서 다음 명령은:

cc -M main.c

다음과 같은 출력을 생성한다:

main.o : main.c defs.h

그래서 여러분은 더이상 모든 이런 규칙들을 여러분 스스로 작성할 필요가 없다. 컴파일러는 여러분을 위해서 이런 것을 할 것이다.

그런 종속물이 makefile에서 `main.o'를 언급하는 것을 구성한다. 그래서 이것은 묵시적 규칙 검색에 의해서 중간 파일로 절대 생각되어질 수 없다. 이것은 make는 절대 그 파일을 사용한 후에 지우지 않는다는 것을 의미한다.; see section 묵시적 규칙의 연쇄(Chains of Implicit Rules).

구식 make 프로그램들로, 이런 컴파일러 기능을 사용해서 `make depend'과 같은 명령으로 요구에 따른 종속물들을 생성하는 것은 전통적인 현실이었다. 그런 명려은 모든 자동으로-생성된 종속물들을 담고 있는 파일 `depend'를 생성할 것이다; 그리고 나서 makefile은 include를 사용해서 (생성된) 그것을 읽어들인다 (see section 다른 makefile 삽입(Including Other Makefiles)).

GNU make에서는, makefile들을 다시 만드는 기능이, 이런 현실을 구식으로 만든다--여러분은 make에게 명시적으로 종속물들을 다시 생성하도록 말할 필요가 없다. 왜냐면 이것은 항상 out of date인 임의의 makefile을 다시 만들기 때문이다. See section Makefiles가 다시 만들어지는 과정(How Makefiles Are Remade).

우리가 자동 종속물 생성에 대해서 추천하는 방법은 각 소스 파일에 대해서 대응하는 하나의 makefile을 가지는 것이다. 각 소스 파일 `name.c'에 대해서 어떤 파일이 오브젝트 파일 `name.o'인지 나타내는 makefile `name.d'이 존재한다. 이 방법에서 변경된 소스 파일들만이 새로운 종속물들을 생성하기 위해서 다시 스캔될 필요가 있다.

다음은 `name.c'라고 불리는 C 소스 파일로부터 `name.d'라고 불리는, 종속물들로 이루어진 파일 하나(즉, 하나의 makefile)를 생성하기 위한 패턴 규칙이다:

%.d: %.c
        $(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< \
                      | sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
                      [ -s $@ ] || rm -f $@'

패턴 규칙을 정의하는 데 대한 정보를 위해서는 See section 패턴 규칙을 정의하고 재정하기(Defining and Redefining Pattern Rules). 쉘에 대한 `-e' 플래그는 $(CC) 명령이 실패하면(0ㅇ 아닌 상태값으로 exit하면) 즉시 exit하도록 만든다. 보통 쉘은 파이프 라인(이 경우는 sed)에서 마지막 명령의 상태값을 가지고 exit한다. 그래서 make는 컴파일러로부터 0이 아닌 상태값을 보지 못할 것이다.

GNU C 컴파일러로 여러분은 `-M' 플래그 대신 `-MM'를 사용하기를 원할런지 모른다. 이것은 시스템 헤더 파일들에 대해서는 종속물들을 생략하도록 한다. 자세한 것은 See section `Options Controlling the Preprocessor' in Using GNU CC.

sed 명령의 목적은 다음과 같은 것을:

main.o : main.c defs.h

다음과 같은 것으로:

main.o main.d : main.c defs.h

변환하는 것이다(예를 들어서). 이것은 각 `.d'파일이 대응하는 `.o' 파일이 종속하고 있는 모든 소스와 헤더 파일들에 종속하도록 만든다. make는 그러면 소스나 헤더 파일들 중에 임의의 것이 변하면 종속물들을 재생성해야 한다는 것을 알고 있다.

일단 `.d' 파일들을 다시 만드는 규칙을 정의했다면 여러분은 그것들 모두를 읽어 들이기 위해서 include 지시어를 사용한다. See section 다른 makefile 삽입(Including Other Makefiles). 예를 들어서:

sources = foo.c bar.c

include $(sources:.c=.d)

(이 예제는 소스 파일들 `foo.c bar.c'을 종속물 makefile들 `foo.d bar.d'의 리스트로 변환하기 위해서 대치 변수 참조를 사용한다. 대입 참조에 대한 완전한 정보를 위해서는 See section 대입 참조(Substitution References).) `.d'가 다른 것들과 비슷하게 makefile들이기 때문에 make는 그것들을 여러분으로부터 어떤 추가의 작업도 필요로 할 것 없이, 필요하다면 다시 만든다. See section Makefiles가 다시 만들어지는 과정(How Makefiles Are Remade).


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