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


규칙내 명령 작성(Writing the Commands in Rules)

규칙의 명령들은 하나 하나씩 실행되는 쉘 명령 라인들로 이루어진다. 각 명령은 반드시 탭 하나로 시작해야 한다. 한 가지 예외는, 첫번째 명령은 목적물-종속물 라인에 세미콜론으로 구분되어 뒤에 붙어있을 수 있다는 것이다. 빈라인들과 주석뿐인 라인들은 명령 라인들 사이 사이에 올 수 있다; 그들은 모두 무시된다. (그러나 하나의 탭으로 시작하는 겉으로 보기에 빈 라인은 실제 빈 라인이 아니다라는 것을 주의하자! 이것은 빈 명령이다;see section 빈 명령 사용하기(Using Empty Commands).)

유저들은 많은 다른 쉘 명령들을 사용할 수 있지만 makefile에 있는 명령들은, makefile이 다른 경우를 지정하지 않았다면, 항상 `/bin/sh'에 의해서 해석된다. See section 명령 실행(Command Execution).

사용되고 있는 쉘이 주석들이 명령 라인에 쓰일 수 있는지 없는지와 그들이 사용하는 문법이 무엇인지를 결정한다. 쉘이 `/bin/sh'이라면 `#'은 라인의 마지막을 늘리는 주석을 시작한다. `#'가 라인의 맨 앞에 올 필요는 없다. `#' 앞에 있는 텍스트는 주석이 아니다.

명령 에코(Command Echoing)

일반적으로 make는 각 명령 라인을 그것이 실행되기 전에 디스플레이한다. 우리는 이것을, 여러분이 그 명령들을 직접 타이핑하는 모양이므로, echoing라고 부른다.

어떤 라인이 `@'로 시작할 때, 그 라인의 에코는 나타나지 않는다. `@'는 명령이 쉘에 전달되기 전에 버려진다. 전형적으로 여러분은 이것을, makefile을 통해서 진행되는 상황을 표시하기 위해서 echo와 같은 명령과 같은, 어떤 것을 출력하는 것이 그것의 유일한 하는 일인 명령에 대해서 사용할 것이다:

@echo About to make distribution files

make`-n' 또는 `--just-print' 플래그를 받으면 실행 없이 에코만 한다. See section 옵션들의 요약(Summary of Options). 이런 경우 그리고 이런 경우에만 `@'으로 시작하는 명령들조차도 출력된다. 이 플래그는 그것을을 실제로 수행하지 않고서, make가 생각하기에 어떤 명령들이 필요한 것인가를 찾아낼 때 유용하다.

make에 대한 `-s' 또는 `--silent' 플래그는, 마치 모든 명령들이 `@'으로 시작하는 것처럼 모든 에코를 금지시킨다. 종속물이 없는 특수 타겟 .SILENT 규칙은 이것과 동일한 효과를 가진다 (see section 특수 내장 타겟 이름(Special Built-in Target Names)). .SILENT`@'가 좀 더 플렉시블하기 때문에 기본적으로 잘 안쓴다.

명령 실행(Command Execution)

타겟을 업데이트하기 위해서 명령들을 실행할 때, 각 라인에 대한 새로운 서브쉘들을 만듬으로써 실행된다. (실제로 make는 결과에 영향을 미치지 않는 지름길을 취할런지도 모른다.)

Please note: 이것은 cd와 같이 각 프로세스에게 로컬인 변수들을 설정하는 쉘 명령들은 다음 명령 라인들에 영향을 미치지 않을 것이다. (2) cde를 사용하고 다음 명령에 영향을 미치기를 원한다면 이 두개를 단일 라인에 넣고 그 가운데 세미콜론을 사용하자. 그러면 make는 그들을 단일 명령으로 생각하고 그들을 같이 쉘에게 전달할 것이다. 예를 들어서:

foo : bar/lose
        cd bar; gobble lose > ../foo

여러분이 단일 쉘 명령을 여러 라인들로 분할하고자 한다면 여러분은 마지막 서브라인만 제외하고 모든 라인의 마지막에다 역슬래쉬를 사용해야 한다. 그런 라인들의 시퀀스는 역슬래쉬-개행 시퀀스를 제거함으로써, 그것을 쉘에게 전달하기 전에, 단일 라인으로 조합된다. 그래서 다음은 이전 예제와 동일한 것이다:

foo : bar/lose
        cd bar;  \
        gobble lose > ../foo

쉘로 사용된 프로그램은 변수 SHELL로부터 취해진다. 디폴트로 `/bin/sh'라는 프로그램이 사용된다.

MS-DOS에서 SHELL이 설정되어 있지 않으면 COMSPEC이라는 변수의 값(이것은 항상 설정된다)이 대신 사용된다.

변수 SHELL를 Makefile들에서 설정하는 라인들을 처리하는 것은 MS-DOS의 경우 다르다. 기본 쉘, `command.com', 은 이상하게 그 기능이 많은 제약이 있고 많은 make 사용자들은 대체 쉘을 설치하는 경향이 있다. 그러므로 MS-DOS에서 make는 변수 SHELL의 값을 시험하고 그것의 행동을 그것이 유닉스 스타일 쉘인가 아니면 DOS- 스타일 쉘인가에 따라서 변경한다. 이것은 SHELL`command.com'을 가리키더라도 타당성 있는 기능을 제공한다. `command.com'.

SHELL이 유닉스-스타일 쉘을 가리키면 MS_DOS상의 make는 그 쉘이 실제로 찾아질 수 있는 것인가 아닌가를 추가로 검사한다; 그렇지 않다면 이것은 SHELL을 설정한 라인을 무시한다. MS-DOS에서 GNU make는 다음과 같은 위치들에서 쉘을 검색한다:

  1. SHELL에 의해서 지정된 정확한 위치에서. 예를 들어서 makefile이 `SHELL = /bin/sh'라고 지정했다면 make는 현재 드라이브의 `/bin' 디렉토리에서 찾을 것이다.
  2. 현재 디렉토리.
  3. PATH 변수에 있는 각 디렉토리에서 순서대로 검색한다.

이것이 시험한 모든 디렉토리에서 make는 첫번째 특정한 파일(위의 예제에서는 `sh')를 찾는다. 이것이 없으면 실행 파일임을 나타내는 알려진 확장자들 중의 하나를 가지는 파일을 그 디렉토리에서 또한 찾을 것이다. 예를 들어서 `.exe', `.com', `.bat', `.btm', `.sh', 그리고 나머지.

이런 시도들중에 어ㄸ너 것이라도 성공하면 SHELL의 값은 찾아진 쉘의 풀 경로명으로 설정될 것이다. 그러나 이들중 어떤 것도 찾아지지 않으면 SHELL는 변경될 것이고 그래서 이것을 설정한 라인은 효과적으로 무시될 것이다. 이것이, make가 실행하는 시스템에서 그런 쉘이 실제로 설치되었다면, 유닉스-스타일 쉘에 종속적으로 make가 유일하게 지원하는 것이 될 것이다.

이런 쉘에 대한 확장된 검색은 SHELL이 Makefile에서 설정된 경우로 제한된다는 것에 유의하자; 이것이 환경변수로 또는 명령행에서 지정되면 여러분은 유닉스에서 하는 것과 아주 똑같이, 이것을 쉘의 완전한 경로명으로 설정할 것으로 기대된다.

위와 같은 DOS-종속적인 처리의 효과는 `SHELL = /bin/sh'(많은 유닉스 makefile들이 하는 것처럼)라고 말하는 Makefile은 여러분이 PATH의 어떤 디렉토리에 예를 들면 `sh.exe'과 같은 것을 설치해놓았을 경우, 변경없이 MS-DOS에서 사용될 것이다라는 것이다.

대부분의 변수들과는 다르게 SHELL 변수는 절대로 환경변수로부터 설정되지 않는다. 이것은 왜냐면 SHELL 환경변수가 인터렉티브한 사용을 위한 쉘 프로그램에 대한 여러분의 개인적인 선택을 지정할 때 사용되기 때문이다. 이것과 같은 개인적인 선택들이 makefile의 기능들에 영향을 미치지는 것은 아주 안좋을 수 있다. See section 환경으로부터의 변수들(Variables from the Environment). 그러나 MS-DOS와 MS-Windows에서 환경변수 SHELL의 값은 사용된다. 왜냐면 그런 시스템들에서 대부분의 사용자들은 이런 변수를 설정하지 않기 때문이다. 그러므로 make에 의해서 사용되도록 특별히 설정되는 경우가 대부분일 것이다. MS-DOS에서 SHELL의 설정이 make에 대해서 적절하지 않다면 여러분은 변수 MAKESHELLmake가 사용해야 하는 쉘에 대해서 지정할 수 있다; 이것은 SHELL의 값을 오버라이드할 것이다.

패러럴 실행(Parallel Execution)

GNU make는 여러 명령들을 동시에 실행하는 방법을 알고 있다. 일반적으로 make는 한번에 하나의 명령만을 실행하고 다음의 것을 실행하기전에 그것이 종료될 때까지 기다린다. 그러나 `-j' 또는 `--jobs' 옵션은 make 에게 많은 명령들을 동시에 실행하도록 한다.

MS-DOS에서 `-j' 옵션은 효과가 없다. 왜냐면 그 시스템은 멀티-프로세싱을 지원하지 않기 때문이다.

`-j' 옵션 뒤에 정수가 붙으면 이것은 한 번에 수행할 명령들의 개수를 말한다; 이것은 작업 슬롯(job slots) 의 개수라고 불린다. `-j' 옵션 뒤에 정수로 보이는 것이 없다면 작업 슬롯의 개수에 제한이 없어진다. 작업 슬롯의 디폴트 개수는 1이다. 이것은 순차적인 실행(한번에 하나씩)을 의미한다.

다수의 명령들을 동시에 실행하는 것의 한가지 즐겁지 않은 결과는 모든 명령들의 출력물이 명령들이 그것을 보낼 때 나타난다는 것이다. 그래서 서로 다른 명령들로부터의 메시지들이 여기저기 섞여서 나타난다.

다른 문제는 두 프로세스들이 동일한 장치로부터 입력을 동시에 취할 수 없다는 것이다; 그래서 단지 하나의 명령이 터미널로부터 한 시점에 입력을 받으려고 시도한다. 그래서 make는 하나를 제외한 모든 실행중인 명령들의 표준 입력 스트림들을 무효화할 것이다. 이것은, 여러개의 자식 프로세스들이 있을 경우 대부분의 자식 프로세스들에 대해서 표준 입력으로부터 읽으려고 시도하는 것은 보통 치명적인 에러(`Broken pipe' 시그널)를 만들것이다라는 것을 의미한다

어떤 명령이 유효한 표준 입력 스트림(터미널로부터 올, 또는 여러분이 make의 표준입력을 리다이렉트한 어떤 것이라도 이곳으로부터 올)을 가지고 있는지 예측하는 것은 거의 불가능하다. 처음 명령이 항상 첫번째를 얻을 것이다. 그리고 명령은 하나가 끝난 후 시작한 첫번째 명령이 다음 것을 얻을 것이다. 이런 식으로 계속된다.

우리가 좀 더 나은 대안을 찾는다면 make의 이런 양식이 작동하는 방법을 바꿀 것이다. 그러기 전에 여러분이 병렬 처리 기능을 사용하고 있다면 표준 입력을 사용하는 어떤 명령도 의존해서는 안된다; 그러나 이런 기능을 사용하고 있지 않다면 표준 입력은 모든 명령들에서 일반적으로 잘 작옹한다.

어떤 명령이 실패하고(시그널에 의해서 kill되거나 0이 아닌 상태값을 가지고 exit하고), 에러들이 그 명령에 대해서 무시되지 않으면 (see section 명령에서 에러(Errors in Commands)), 동일한 타겟을 다시 만드는 남은 명령 라인들은 실행되지 않을 것이다. 명령이 실패하고 `-k'`--keep-going' 옵션이 주어지지 않으면 (see section 옵션들의 요약(Summary of Options)), make는 실행을 중지한다. 어떤 이유에서건(시그널을 포함해서) 실행중인 자식 프로세스들을 가진 make가 종료하게 되면 그것은 실제로 나가기 전에 자식 프로세스들이 종료하기를 기다린다.

시스템의 부하가 아주 클때 여러분은 아마도 부하가 적을 때보다 더 적은 작업들을 실행하고자 할 것이다. 여러분은 `-l' 옵션을 써서 make에게 한번에 실행할 작업들의 개수를, 평균 부하에 기초해서 제한하도록 지시할 수 있다. `-l' 또는 `--max-load' 옵션은 그 뒤에 부동-소숫점 숫자가 붙는다. 예를 들어서,

-l 2.5

이것은 make가, 평균 부하가 2.5보다 크면 한 작업보다 더 많은 작업을 시작하지 못하도록 할 것이다. 뒤에 숫자가 없는 `-l' 옵션은, 이전에 `-l' 옵션으로 지정된 것이 있다면, 부하 제한을 제거한다.

좀 더 정확하게, make가 하나의 작업을 시작할 때, 그리고 적어도 하나의 실행중인 작업을 가지고 있을 때, 이것은 현재 평균 부하를 측정한다; `-l'로 주어진 제한보다 더 낮지 않다면 make 는 평균 부하가 그 제한보다 낮아질 때까지 혹은 모든 다른 작업들이 종료될 때까지 기다린다.

디폴트로 부하 제한은 없다.

명령에서 에러(Errors in Commands)

각 쉘 명령이 리턴한 후, make는 그것의 종료 상태값을 조사한다. 그 명령이 성공적으로 종료하면 다음 명령 라인이 새로운 쉘에서 실행된다; 마지막 명령 라인이 종료된 후 그 규칙은 종료한다.

에러가 있으면(종료 상태값이 0이 아니면), make는 현재 규칙을 그리고 아마도 모든 규칙들을, 포기한다.

때때로 어떤 명령의 실패가 문제를 가리키는 것은 아니다. 예를 들어서 여러분은 mkdir 명령을 사용해서 어떤 디렉토리의 존재 유무를 검사할 수도 있다. 그런 디렉토리가 이미 존재한다면 mkdir는 에러를 보고할 것이다. 그러나 여러분은 아마도 make가 그것을 신경쓰지 않고 계속하기를 원할 것이다.

명령 라인에서 에러들을 무시하기 위해서 그 라인 텍스트의 시작부분(초기 탭 문자 뒤에)에 `-' 하나를 넣는다. `-'는 명령이 실행을 위해서 쉘로 전달되기 전에 무시된다.

예를 들어서,

clean:
        -rm -f *.o

이것은 rm이 어떤 파일을 제거할 수 없다하더라도 계속하도록 한다.

여러분이 make`-i'`--ignore-errors' 플래그를 써서 실행할 때 에러들이 모든 규칙의 모든 명령들에서 무시된다. makefile에 있는 특수 타겟 .IGNORE에 대한 규칙은, 종속물들이 없을 때, 동일한 효과를 낸다. 에러를 무시하는 이런 방법들은 `-'가 좀 더 유연하기 때문에 구식이 되버렸다.

에러들이 무시되어야 할 때, `-'`-i' 플래그 때문에, make는 에러 리턴을 성공처럼 취급한다. 단, 여러분에 그 명령이 exit한 상태 코드를 말해주는 메시지를 출력하고 에러가 무시되었다는 것을 말하는 것외는 그렇다.

make가 무시하도록 요구받지 않은 어떤 에러가 발생하면, 이것은 현재 타겟이 정상적으로 다시 만들어질수 없다는 것을 의미하고, 이것에 직간접적으로 의존하고 있는 다른 어떤 것들도 또한 만들어질 수 없다는 것을 의미한다. 이런 타겟들에 대한 더이상의 어떤 명령들도 실행되지 않을 것이다. 왜냐면 그들의 사전조건(precondition)들이 이루어지지 않았기 때문이다.

일반적으로 make는 이런 상황에서 즉각 포기하여 0이 아닌 상태값을 리턴한다. 그러나 `-k'`--keep-going' 플래그가 지정되면 포기하고 0이 아닌 상태값을 리턴하기 전에, make는 계류중인 타겟들의 다른 종속물들을 생각하기 시작하고, 그것들을 필요하다면 다시 만든다. 예를 들어서 한가지 오브젝트 파일을 컴파일할 때 에러가 생긴 후에 `make -k'는 이미 다른 오브젝트 파일들을 링크가하는 것이 불가능할 것이라는 것을 안다하더라도 다른 이런 오브젝트 파일들을 게속 컴파일할 것이다. See section 옵션들의 요약(Summary of Options).

일반적인 행동은 여러분의 목적이 특정한 타겟이 갱신되도록 하는 것이라고 가정한다; 일단 make가 이것이 불가능한 것을 배우게 되면 이것은 그 실패를 즉각 보고할 것이다. `-k' 옵션은, 실제 목적이 프로그램 내에서 만들어진 가능한 많은 변화를 테스트하는 것이라고, 그리고 아마도 몇가지 독립적인 문제들을 찾아서 여러분이 그것들을 다음 컴파일 시도 이전에 교정할 수 있도록 하는 것이라고 말하는 것이다. 이것이 바로 왜 이맥스의 compile 명령이 디폴트로 `-k' 플래그를 전달하는가에 대한 이유이다. @cindex Emacs (M-x compile)

일반적으로 어떤 명령이 실패할 때, 이것이 타겟 타일을 변경하여 버렸다면, 그 파일은 오염된 것이고 사용될 수 없는 것이다---아니면 적어도 이것은 완전히 갱신된 것이 아니다. 그러나 그 파일의 타임스탬프는 이것이 이제 갱신된 것이라고 말한다. 그래서 다음번 make가 실행할 때 이것은 그 파일을 갱신하려고 시도하지 않을 것이다. 이런 상황은 명령이 시그널에 의해서 kill되었을 때와 동일하다; see section make를 인터럽트 또는 죽이기(Interrupting or Killing make). 그래서 일반적으로 해야 할 올바른 일은 그 명령이 그 파일을 변경 시작한 후 실패했다면 그 타겟 파일을 지우는 것이다. .DELETE_ON_ERROR가 타겟으로써 나타나면 make는 이런 일을 할 것이다. 이것은 대개 항상 make가 하였으면 하는 것이지만 이것은 역사적으로 현실적인 것이 아니다; 그래서 호환성을 위해서 여러분은 반드시 이것을 명시적으로 요구해야 한다.

make를 인터럽트 또는 죽이기(Interrupting or Killing make)

make가 치명적인 시그널을 어떤 명령이 실행하고 있을 때, 받는다면 이것은 그 명령이 업데이트하려고 한 타겟 파일을 삭제할 것이다. 이것은 타겟 파일의 마지막-변경 시간이 make가 맨처음 그것을 검사한 이후 변경되었다면 이루어진다.

타겟을 삭제하는 목적은 make가 다음에 실행될 때 확실히 출발선으로부터 다시 만들어지도록 하는 것이다. 왜 이런가? 여러분이 컴파일러가 실행하고 있을 때 Ctrl-c를 입력했다고 그리고 오브젝트 파일 `foo.o'을 작성하기 시작했다고 가정하자. Ctrl-c는 컴파일러를 킬하게 되어 마지막-변경 시간이 소스 파일 `foo.c'보다 더 새로운 불완전한 파일을 만들게 된다. 그러나 make도 또한 Ctrl-c 시그널을 받게 되고 이 불완전한 파일을 삭제한다. make가 이것을 하지 않는다면 다음 make 호출은 `foo.o'이 갱신이 필요한 파일이 아니라고 생각할 것이다---그래서 이것이 반쯤 부족한 오브젝트 파일을 링크하려고 할 때 링커는 이상한 에러 메시지를 내게 될 것이다.

여러분은 어떤 타겟에 의존하는 특수 타겟 .PRECIOUS을 만듬으로써 이런 식의 타겟 파일의 삭제를 막을 수 있다. 타겟을 다시 만들기 전에 make는 그것이 .PRECIOUS의 종속물들 중에 있는지 없는지를 검사하고 그것에 의해서 그 타겟이 시그널이 발생되었을 때 삭제되어야 하는지 그러지 않는지를 결정한다. 여러분이 이렇게 해야 할 몇가지 이유는 다음과 같다. 타겟은 어떤 소규모 형식으로 갱신된다. 또는 타겟은 변경-시간을 기록하기 위해서만 존재한다(그것의 내용은 상관이 없다). 또는 타겟은 다른 종류의 문제를 막기 위해서 모든 시점에 존재해야만 한다.

make의 재귀적 사용(Recursive Use of make)

make의 재귀적 사용이란 make를 makefile에서 하나의 명령으로 사용한다는 것이다. 이 테크닉은 여러분이 더 큰 시스템을 만드는 여러 서브시스템들을 위한 여러 분리된 makefile들을 원할 때 유용하다. 예를 들어서 여러분이 자신의 makefile을 가지고 있는 `subdir' 서브디렉토리를 가지고 있고 상위 디렉토리의 makefile을 사용해서 그 서브 디렉토리에 대해서 make를 실행하고자 한다고 가정하자. 여러분은 다음과 같이 작성해서 이렇게 할 수 있다:

subsystem:
        cd subdir && $(MAKE)

또는 동일하게 다음과 같이 할 수도 있다 (see section 옵션들의 요약(Summary of Options)):

subsystem:
        $(MAKE) -C subdir

여러분은 이 예제를 그대로 복사해서 재귀적 make 명령을 작성할 수도 있지만 그들이 작동하는 방식과 이유, 그리고 서브-make가 톱-레벨 make에 어떻게 연결되어 있는가에 대해서 알아야 할 것들이 많이 있다.

여러분의 편의를 위해서 GNU make는 변수 CURDIR를 현재 작업 디렉토리의 경로명으로 설정한다. -C가 쓰였다면 오리지널 디렉토리가 아니라 새로운 디렉토리의 경로를 포함할 것이다. 그값은(CURDIR의 값 ?) 이것이 makefile안에서 설정되었다면 가질 우선순위와 동일하다(디폴트로 환경 변수 CURDIR는 이 값을 오버라이드하지 않을 것이다). 이 변수를 설정하는 것은 make의 작동에 영향을 미치지 않는다.

MAKE 변수가 작동하는 방법(How the MAKE Variable Works)

재귀적인 make 명령들은, 다음에서 볼 수 있듯이 `make' 명령 이름을 명시적으로 쓰지 않고, 항상 MAKE변수를 사용하는 것이 좋다.

subsystem:
        cd subdir && $(MAKE)

이 변수의 값은 make가 호출되는 파일 이름이다. 이 파일 이름이 `/bin/make'이라면 실행될 명령은 `cd subdir && /bin/make'일 것이다. 톱-레벨 makefile을 실행하기 위해서 특수한 버전의 make를 사용한다면 동일한 특수한 버전이 재귀적 호출에도 사용될 것이다.

특수한 기능으로써, MAKE를 규칙의 명령에서 사용한다는 것은 `-t' (`--touch'), `-n' (`--just-print'), 또는 `-q' (`--question')옵션의 효과를 변경한다. MAKE변수를 사용하는 것은 명령 라인의 처음에 `+'문자를 사용하는 것과 동일한 효과가 있다.See section 명령 실행 대신에...(Instead of Executing the Commands).

위의 예제에서 `make -t' 라는 명령을 생각해보자. (`-t'옵션은 실제 아무런 명령도 실행하지 않고서도 목적물을 가장 최근의 타임 스탬프를 가지는 것으로 마킹한다; section 명령 실행 대신에...(Instead of Executing the Commands).) `-t'의 일반적인 정의를 따라서, 예제에서 `make -t' 명령은 `subsystem'라는 이름을 가진 파일ㅇ르 하나 생성하고 아무것도 안할 것이다. 여러분이 실제로 원하는 것은 `cd subdir &&' make -t 이다; 그러나 이것은 현존하는 명령을 요구한다. 그래서 `-t'가 명령을 실행하지 말라고 한 것이다.

특수한 기능이 이것을 여러분이 원하는 것으로 만든다: 어떤 규칙의 명령이 변수 MAKE을 담고 있을 때마다 플래그 `-t', `-n' 그리고 `-q'는 그 라인을 적용하지 않는다. MAKE를 담고 있는 명령 라인들은 대부분의 명령이 실행하지 않도록 하는 플래그의 존재에도 불구하고 보통 실행된다. 일반적인 MAKEFLAGS 메카니즘은 플래그들을 서브-make (see section 서브-make에 대한 통신 옵션(Communicating Options to a Sub-make)) 에게 전달하여, 파일을 터치하라는 또는 명령들을 인쇄하라는 여러분의 요구가 서브시스템에 보급된다.

서브-make에 대한 통신 변수(Communicating Variables to a Sub-make)

톱-레벨 make의 변수 값들은 명시적 요구에 의해서 환경을 통해서 서브-make로 전달될 수 있다. 이런 변수들은 서브-make에서 디폴트로 정의되지만 서브-make makefiel에 의해서 사용되는, makefile에서 지정된 것을, `-e' 스위치 (see section 옵션들의 요약(Summary of Options))를 사용하지 않으면, 오버라이드하지 않는다.

변수를 전달해주기 위해서 또는 익스포트(export)하기 위해서 make는 각 명령을 실행하기 위해서 환경에다 그 변수와 값을 더한다. 그러면 서브-make는 환경을 사용해서 그의 변수값들의 테이블을 초기화한다. See section 환경으로부터의 변수들(Variables from the Environment).

명시적인 요구를 제외하고, make는 이것이 환경에서 초기에 정의되거나 명령 라인에서 설정된 경우에만, 그리고 그것의 이름이 영문자, 숫자 그리고 밑줄로 이루어졌다면, 익스포트한다. 어떤 쉘들은 영문자, 숫자, 그리고 밑줄이 아닌 문자로 이루어진 환경변수 이름들을 대처하지 못한다.

특수 변수 SHELLMAKEFLAGS들은 항상 익스포트된다(그것들을 unexport하지 않았다면). MAKEFILES는 그것을 어떤 것으로 설정하면 익스포트된다.

make는 명령 라인에서 정의된 변수 값들을, MAKEFLAGS 변수에 그들을 넣어서, 자동으로 아래로 전달한다. 전달한다. 다음 섹션을 보자.

변수들이 make에 의해서 디폴트로 생성되었다면 이들은 보통 아래로 전달되지 않는다 (see section 묵시적 규칙에 의해 사용되는 변수(Variables Used by Implicit Rules)). 서브-make는 자신을 위해서 이들을 정의할 것이다.

여러분이 특정 변수가 서브-make에 익스포트되기를 원한다면 다음과 같이 export 지시어를 사용하라:

export variable ...

어떤 변수가 익스포트되는 것을 금지하고자 한다면 다음과 같이 unexport 디렉티브를 사용한다:

unexport variable ...

편리하게 여러분은 어떤 변수를 정의하면서 동시에 그것을 익스포트할 수 있다:

export variable = value

이것은 다음과 같은 결과를 가진다:

variable = value
export variable

그리고

export variable := value

는 다음과 같은 결과를 가진다:

variable := value
export variable

비슷하게

export variable += value

는 다음과 동일하다:

variable += value
export variable

See section 변수에 텍스트를 덧붙이기(Appending More Text to Variables).

여러분은 exportunexport 지시어들이 그들이 쉘에서 작동하는 것과 동일한 방식으로 make에서 작동한다는 것을 알았을 수도 있다.

모든 변수들이 디폴트로 익스포트되는 것을 원한다면 여러분은 export을 다음과 같이 홀로 쓰면 된다:

export

이것은 make에게 exportunexport 지시어에서 명시적으로 언급되지 않은 변수들은 모두 익스포트되어야 한다는 것을 말한다. unexport 지시어에서 주어진 임의의 변수는 여전히 익스포트되지 않을 것이다. 여러분이 홀로 export만 사용하여 변수들을 디폴트로 익스포트한다면 그것의 이름이 알파벳과 숫자 그리고 밑줄이 아닌 것을 담고 있을 때, 명시적으로 export 지시어에서 언급하지 않는 한, 익스포트되지 않을 것이다.

export 지시어를 홀로 써서 얻어낸 행동은 GNU make의 더 오래된 버전들에서 디폴트이었다. 여러분의 makefile들이 이런 행동에 의존하고 여러분이 make의 예전 버전들과의 호환성을 얻고자 한다면 여려분은 특수한 타겟 .EXPORT_ALL_VARIABLESexport 지시어를 사용하는 대신 쓸 수 있다. 이것은 오래된 make들에 의해서 무시될 것이다. 반면에 export 지시어는 문법 에러를 유발할 것이다.

비슷하게 여러분은 unexport를 홀로 써서 make가 디폴트로, 변수들을 모두 익스포트하지 않도록 지시할 수 있다. 이것은 디폴트 행동이기 때문에 export가 홀로 이전에(아마 include된 makefile에서) 사용되었을 때에만, 이것을 사용할 필요가 있을 것이다. exportunexport를 둘다 홀로 써서 어떤 명령들에 대해서 변수들이 익스포트되고 다른 것들에 대해서는 익스포트되지 않도록 할 수 없다. 홀로 사용된 exportunexport 지시어 중에서 마지막으로 사용된 것만이 make의 전체 실행 행동양식을 결정한다.

특수한 기능으로써, 변수 MAKELEVEL는, 이것이 윗레벨에서 아래레벨로 전달될 때, 변경된다. 이 변수의 값은 레벨의 깊이를 십진수로 표현한 문자열이다. 그 값은 톱-레벨 make에 대해서 `0'이다; 서브-make에 대해서는 `1'이고, 서브-서브-make에 대해서는 `2'이다. 이런 식으로 계속된다. 증가는 make가 어떤 명령에 대한 환경을 셋업할 때 발생한다.

MAKELEVEL의 주요 사용은 조건 지시어 (see section Makefile의 조건 부분(Conditional Parts of Makefiles)) 안에서 그것을 테스트할 때이다; 재귀적으로 실행된다면 한가지 방식으로 작동하고 직접 실행한다면 다른 방식으로 작동하는 makefile을 작성할 수 있다.

변수 MAKEFILES를 사용해서 모든 서브-make 명령들이 추가의 makefile들을 사용하도록 할 수 있다. MAKEFILES의 값은 공백으로 분리된 파일 이름들의 리스트이다. 이 변수는, 외부-레벨 makefile안에서 정의되었다면, 환경을 통해서 아래로 전달된다; 그리고 나서 이것은 서브-make에 대해서, 보통의 또는 지정된 makefile들을 읽도록, 외부 makefile들의 리스트로 취급된다. See section MAKEFILES 변수(The Variable MAKEFILES).

서브-make에 대한 통신 옵션(Communicating Options to a Sub-make)

`-s'`-k' 같은 플래그들은 자동으로 변수 MAKEFLAGS를 통해서 서브-make에게 전달된다. 이 변수는 make에 의해서 make가 받는 플래그 문자들을 담고 있도록 자동으로 셋업된다. 그래서 `make -ks'라고 하면 MAKEFLAGS는 값 `ks'를 가진다.

결과적으로 모든 서브-make는 그 환경안에서 MAKEFLAGS에 대한 값을 가진다. 이에 대한 대응으로 그것은 그 값으로부터 플래그들을 취해서 그들이 매개변수로써 전달된 것처럼 이들을 처리한다. See section 옵션들의 요약(Summary of Options).

명령행에서 정의된 변수들과 비슷하게 MAKEFLAGS를 통해서 서브-make에게 전달된다. `='를 담고 있는 MAKEFLAGS의 값의 워드들을 make는 그들이 명령행에 나타난 것처럼, 변수 정의로 취급한다. See section 변수 겹쳐쓰기(Overriding Variables).

`-C', `-f', `-o', 그리고 `-W' 옵션들은 MAKEFLAGS에 들어가지 않는다; 이들 옵션들은 아래로 전달되지 않는다.

`-j' 옵션은 특수한 경우이다 (see section 패러럴 실행(Parallel Execution)). 이것을 어떤 숫자값으로 설정하면 `-j 1'가 항상 지정한 값 대신에 MAKEFLAGS에 들어간다. 이것은 왜냐면, `-j' 옵션이 서브-make들에 들어간다면 요구한 것보다 더 많은 작업들을 병렬로 실행하도록 할 것이기 때문이다. `-j'를 숫자 매개변수 없이 주면 이것은 아래로 전달된다. 왜냐면 다수 무한(multiple infinities)란 1값에 지나지 않기 때문이다.

다른 플래그들은 아래로 전달하고자 하지 않는다면 반드시 다음과 같이 MAKEFLAGS의 값을 변경해야 한다:

subsystem:
        cd subdir && $(MAKE) MAKEFLAGS=

명령 라인 변수 정의들은 실제로 MAKEOVERRIDES라는 변수에 나타나고 MAKEFLAGS는 이 변수에 대한 참조를 담고 있다. 플래그들을 정상적으로 아래로 전달하고자 하지만 명령행 변수 정의들은 아래로 전달하고자 하지 않는다면 다음과 같이 MAKEOVERRIDES를 빈 것으로 리셋할 수 있다:

MAKEOVERRIDES =

이렇게 하는 것이 항상 유용한 것은 아니다. 그러나 어떤 시스템들은 환경의 크기가 작게 제한되어 있을 수 있고 많은 정보들을 MAKEFLAGS의 값으로 넣는 것은 이 제한을 넘을수도 있다. `Arg list too long'와 같은 에러 메시지를 본다면 이것이 그런 문제이다. (POSIX.2와의 엄격한 호환을 위해서 MAKEOVERRIDES를 변경하는 것은, 특수 타겟 `.POSIX'이 makefile에 있다면, MAKEFLAGS에는 영향을 미치지 않는다. 여러분은 아마도 이것에 대해서 신경쓰지 않을 것이다.)

비슷한 변수 MFLAGS도 역사적인 호환을 위해서 존재한다. 이것은 명령행 변수 정의들을 담고 있지 않다는 점과, 이것이 빈것이 아니라면 항상 시작한다(MAKEFLAGS는 이것이 such as `--warn-undefined-variables'과 같은 단일-문자 버전이 아닌 옵션으로 시작할 때에만 하이픈으로 시작한다)는 점을 제외하고 MAKEFLAGS과 동일한 값을 가진다. MFLAGS는 전통적으로 재귀적인 make 명령안에서 다음과 같이 명시적으로 사용된다:

subsystem:
        cd subdir && $(MAKE) $(MFLAGS)

그러나 이제 MAKEFLAGS는 이런 사용을 여분의 것으로 만들었다. makefile들이 오래된 make 프로그램들에 대해서 호환이 되도록 하기를 원한다면, 이런 테크닉을 사용하자; 이것은 좀 더 현대적인 make 버전들에서도 잘 작동할 것이다.

MAKEFLAGS 변수는, make를 실행할 때마다 설정되는, `-k' (see section 옵션들의 요약(Summary of Options))와 같은 어떤 옵션들을 가지기를 원한다면 유용할 수 있다. makefile안에서, 이 makefile에 대해서 영향을 미쳐야 하는 추가의 프래그들을 지정하기 위해서, MAKEFLAGS를 설정할 수도 있다. (MFLAGS는 이런식으로 사용될 수 없다. 이 변수는 호환성을 위해서만 설정된다; make는 여러분이 이것을 위해서 설정한 값을 어떤식으로든 해석하지 않는다.)

makeMAKEFLAGS의 값을 해석할 때(환경이나 makefile로부터), 이것은 그 값이 하이픈으로 시작하지 않는다면, 하이픈 하나를 앞에다 먼저 단다. 그리고 나서 그 값을 공백으로 분리된 워드들로 자르고 이들 워드들이 명령행에서 주어진 옵션들인것처럼 이런 워드들을 파싱한다(`-C', `-f', `-h', `-o', `-W', 그리고 긴-이름 버전들은 무시되는 것은 제외; 그리고 무효한 옵션에 대해서 에러는 발생하지 않는다).

MAKEFLAGS를 환경에 넣는다면 make의 행동에 맹렬하게 영향을 미칠, make 자신과 makefile의 목적을 해치는 어떤 옵션들도 넣지 않도록 주의해야 한다. 예를 들어서 `-t', `-n', 그리고 `-q' 옵션들은, 이런 변수들 중의 하나에 넣는다면, 위험한 결과들을 낼 것이고 분명히 적어도 놀라운 아마도 성질내게 만드는 결과들을 얻을 것이다.

`--print-directory' 옵션

재귀적 make 호출의 여러 레벨들을 가진다면 `-w'`--print-directory' 옵션은 make가 각 디렉토리를 처리하기 시작할 때와 make가 이것의 처리를 종료할 때 이것을 보여줌으로써 좀 더 이해하기 쉬운 출력을 한다. 예를 들어서 `make -w'`/u/gnu/make' 디렉토리안에서 실행되면 make는 다음과 같은 형태의 라인을 출력할 것이다:

make: Entering directory `/u/gnu/make'.

그리고 처리가 완료되면 다른 것을 하기 전에, 다음과 같은 라인을:

make: Leaving directory `/u/gnu/make'.

출력한다.

일반적으로 이 옵션을 지정할 필요가 없다. 왜냐면 `make'가 이것을 대신 하기 때문이다: `-w'`-C' 옵션을 사용할 때, 그리고 서브-make들 안에서 자동으로 켜진다. make`-s'도 또한 사용한다면 `-w'를 자동으로 켜지 않을 것이다. 이것은 조용히 하라는 옵션이다. 또는 `--no-print-directory' 라는 옵션을 사용해서 명시적으로 그렇게 하는 것을 하지 못하도록 할 수 있다.

명령들을 묶어서 정의하기(Defining Canned Command Sequences)

동일한 명령 시퀀스가 다양한 타겟들을 만드는데 유용할 때, 그것을 define라는 지시어로 묶인 시퀀스(canned sequence)로 정의할 수 있고 그 묶인 시퀀스를 그런 타겟들에 대한 규칙들로부터 참조할 수 잇다. 묶인 시퀀스는 실제로 하나의 변수이다. 그래서 그 이름은 다른 변수 이름들과 같아서는 안된다.

다음은 명령들의 묶인 시퀀스 하나를 정의하는 예제이다:

define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

여기서 run-yacc는 정의되고 있는 변수의 이름이다; endef는 정의의 마지막을 표시한다; 이들 사이의 라인들이 명령들이다. define 지시어는 묶인 시퀀스안에서 변수 참조와 함수 호출들을 확장하지 않는다; `$' 문자들, 괄호들, 변수 이름들, 기타 등등 모두는 정의하고 있는 변수의 값의 일부가 된다. define의 완전한 설명에 대해서, See section 축어 변수 정의(Defining Variables Verbatim).

이 예제의 첫번째 명령은 Yacc를, 이 묶인 시퀀스를 사용하는 규칙의 첫번째 종속물이면 무엇이든지 이것에 대해서, 실행시킨다. Yacc의 결과 파일은 항상 `y.tab.c'라는 이름이다. 두번째 명령은 그 규칙의 타겟 파일 이름으로 이 결과를 덮어쓴다.

묶인 시퀀스를 사용하려면 그 변수를 어떤 규칙의 명령들안에 대입하면 된다. 이것을 다른 변수(see section 변수 참조의 기본(Basics of Variable References)) 들 처럼 대입할 수 있다. define에 의해서 정의된 변수들은 재귀적으로 확장되는 변수들이기 때문에 define안에서 작성하는 모든 변수 참조들은 이때 확장된다. 예를 들어서:

foo.c : foo.y
        $(run-yacc)

`foo.y'는 이것이 run-yacc의 값안에 나타날 때, `$^' 변수에 대입되며 `foo.c'`$@'에 대해서 대입된다.

이것은 현실적인 예제이지만 이 구체적인 것은 실제의 경우 별로 필요가 없는 것이다. 왜냐면 make는 포함된 파일이름들에 기반해서 이런 명령들을 추측해내는 묵시적 규칙을 갖고 있기 때문이다 (see section 묵시적 규칙(Using Implicit Rules)).

명령 실행에서 묶인 시퀀스이 각 라인은 그 라인이 규칙에 홀로 나타난 것처럼, 앞에 탭 문자를 달고 있는 것처럼, 취급된다. 특별히 make는 각 라인에 대해서 분리된 서브쉘을 호출한다. 여러분은 묶인 시퀀스에 잇는 각 라인의 앞에다 명령 라인들에 영향을 미치는 특수 접두 문자(`@', `-', and `+')들을 사용할 수 있다. See section 규칙내 명령 작성(Writing the Commands in Rules). 예를 들어서 다음과 같은 묶인 시퀀스를 사용해서:

define frobnicate
@echo "frobnicating target $@"
frob-step-1 $< -o $@-step-1
frob-step-2 $@-step-1 -o $@
endef

make는 첫번째 라인, echo 명령 자체를 에코하지 않을 것이다. 그러나 다음 두 라인들은 에코할 것이다.

한편 묶인 시퀀스를 참조하는 명령 라인에 붙은 접두 문자들은 그 시퀀스에 있는 각 라인에 대해서 적용된다. 그래서 다음 라인은:

frob.out: frob.in
	@$(frobnicate)

어떤 명령도 에코하지 않는다. (`@'에 대한 완전한 설명에 대해서, See section 명령 에코(Command Echoing).)

빈 명령 사용하기(Using Empty Commands)

아무것도 하지 않는 명령들을 정의하는 것이 때때로 유용하다. 이것은 공백외에 아무것도 없는 명령을 줌으로써 정의될 수 있다. 예를 들어서:

target: ;

이것은 `target'에 대해서 빈 명령 문자열을 정의한다. 또는 빈 명령 문자열을 정의하기 위해서 탭문자로 시작하는 한 라인을 사용할수도 있지만 이것은 그런 라인이 빈것처럼 보이지 않기 때문에 혼동을 일으킬 수 있다.

아무것도 하지 않는 명령을 왜 정의해야 할까에 대해서 의아해 할런지도 모르겠다. 어떤 타겟이 묵시적 명령들(묵시적 규칙들로부터 또는 .DEFAULT 특수 타겟으로부터; see section 묵시적 규칙(Using Implicit Rules) 그리고 see section 최후의 디폴트 규칙 정의(Defining Last-Resort Default Rules))을 얻지 못하도록 하는 것이 그 유일한 이유이다.

실제 파일이 아니지만 그들의 종속물들이 다시 만들어질 수 있도록하기 위해서만 존재하는 타겟들에 대해서 빈 명령 문자열을 곧잘 정의할 수도 있다. 그러나 이것은 그렇게 하기 위한 가장 좋은 방법이 아니다. 왜냐면 종속물들이, 타겟 파일이 실제로 존재한다면, 제대로 다시 만들어지지 않을 것이기 대문이다. 이렇게 하기 위한 좀 더 나은 방법을 찾는다면 See section 가짜 목적물(Phony Targets).


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