GNU make

freejack·2021년 8월 26일
1

GNU make

원본링크: https://www.gnu.org/software/make/manual/make.html

1. Overview of make (make 개요)

make 유틸리티는 재 컴파일 해야하는 대형 프로그램 부분을 자동으로 판별하고 이를 재 컴파일하는 명령을 실행합니다. 이 매뉴얼은 Richard Stallman과 Roland McGrath가 구현한 GNU make에 대해 설명합니다. 버전 3.76 이후의 개발은 Paul D. Smith가 맡았습니다.

GNU make는 IEEE 표준 1003.2-1992 (POSIX.2)의 섹션 6.2를 준수합니다.

우리의 예제는 가장 일반적인 C 프로그램으로 보여 주지만 컴파일러가 쉘 명령으로 실행될 수 있는 모든 프로그래밍 언어로 make를 사용할 수 있습니다. 실제로 make는 프로그램에만 국한되지 않습니다. 다른 파일이 변경될 때마다 일부 파일을 다른 파일에서 자동으로 업데이트 해야하는 모든 작업을 설명하는데 사용할 수 있습니다.

Preparing and Running Make (Make 준비 및 실행)

make 사용을 준비하려면 프로그램에 있는 파일간의 관계를 설명하고 각 파일을 업데이트하는 명령을 제공하는 makefile이라는 파일을 작성해야합니다. 일반적으로 프로그램에서 실행 파일은 소스 파일을 컴파일하여 생성되는 개체 파일에서 업데이트됩니다.

적절한 메이크 파일이 존재하면 소스 파일을 변경할 때마다 다음과 같은 간단한 쉘 명령이 있습니다:

make

필요한 모든 재 컴파일을 수행하는 것으로 충분합니다. make 프로그램은 makefile 데이터베이스와 파일의 마지막 수정 시간을 사용하여 업데이트 해야할 파일을 결정합니다. 각 파일에 대해 데이터베이스에 기록된 레시피를 실행합니다.

재 컴파일해야하는 파일 또는 방법을 제어하기 위해 만들 명령줄 인수를 제공할 수 있습니다. make 실행 방법을 참조하십시오.

1.1 How to Read This Manual (이 설명서를 읽는 방법)

처음 만들거나 일반적인 소개를 찾고 있다면 각 장의 처음 몇 절을 읽고 이후 절은 건너 뛰십시오. 각 장에서 처음 몇 개의 섹션에는 소개 또는 일반 정보가 포함되고 이후 섹션에는 전문 또는 기술 정보가 포함됩니다. 두 번째 장인 Makefile 소개는 예외이며, 모두 입문입니다.

다른 make 프로그램에 익숙하다면 GNU make의 향상된 기능을 나열하는 Features of GNU make와 다른 사람들이 가지고 있는 GNU가 부족한 몇 가지 사항을 설명하는 비 호환성 및 누락된 기능을 참조하십시오.

빠른 요약은 옵션 요약, 빠른 참조 및 특수 대상을 참조하십시오.

1.2 Problems and Bugs (문제와 버그)

GNU make에 문제가 있거나 버그를 발견했다고 생각되면 개발자에게 보고하십시오. 우리는 아무것도 할 것이라고 약속할 수 없지만 그것을 고치고 싶을 것입니다.

버그를 신고하기 전에 실제 버그를 발견했는지 확인하세요. 문서를 주의 깊게 다시 읽고 실제로 수행하려는 작업을 수행할 수 있는지 확인합니다. 어떤 일을 할 수 있어야 하는지 여부가 명확하지 않은 경우에도 신고하십시오. 문서의 버그입니다!

버그를 보고하거나 직접 수정하기 전에 문제를 재현할 수 있는 가장 작은 메이크 파일로 격리하십시오. 그런 다음 오류 또는 경고 메시지를 포함하여 makefile과 정확한 결과를 보내주십시오. 이 메시지들을 다른 말로 바꾸지 마세요: 잘라내어 보고서에 붙여 넣는 것이 가장 좋습니다. 이 작은 메이크 파일을 생성할 때 레시피에서 자유롭지 않거나 특이한 도구를 사용하지 마십시오: 이러한 도구가 간단한 쉘 명령으로 수행하는 작업을 거의 항상 에뮬레이션 할 수 있습니다. 마지막으로 예상한 일을 설명하십시오. 이것은 문제가 실제로 문서에 있는지 결정하는데 도움이 됩니다.

정확한 문제가 있으면 두 가지 방법 중 하나로 보고할 수 있습니다. 다음 주소로 전자 메일을 보내십시오:

    bug-make@gnu.org

또는 다음 웹 기반 프로젝트 관리 도구를 사용하십시오:

    http://savannah.gnu.org/projects/make/

위의 정보 외에도 사용중인 'make'의 버전 번호를 포함하도록 해주시기 바랍니다. 이 정보는 'make --version'명령으로 얻을 수 있습니다. 사용중인 시스템 및 운영 체제 유형도 포함해야 합니다. 이 정보를 얻는 한 가지 방법은 'make --help' 명령에서 출력의 마지막 줄을 보는 것입니다.


2. An Introduction to Makefiles (Makefile 소개)

make에게 무엇을해야하는지 알려주려면 'Makefile'이라는 파일이 필요합니다. 대부분의 경우 Makefile은 make가 프로그램을 컴파일하고 링크하는 방법을 알려줍니다.

이 장에서는 8개의 C 소스 파일과 3개의 헤더 파일로 구성된 텍스트 편집기를 컴파일하고 링크하는 방법을 설명하는 간단한 makefile에 대해 설명합니다. makefile은 명시적으로 요청될 때 기타 명령을 실행하는 방법을 make에 알려줄 수도 있습니다 (예를 들어, 정리 작업으로 특정 파일을 제거하려는 경우). 더 복잡한 Makefile의 예를 보려면 [복잡한 메이크 파일]을 참조하십시오.

make가 편집기를 다시 컴파일 할 때 변경된 각 C 소스 파일을 다시 컴파일 해야합니다. 헤더 파일이 변경된 경우 헤더 파일을 포함하는 각 C 소스 파일을 안전하게 다시 컴파일 해야합니다. 각 컴파일은 소스 파일에 해당하는 개체 파일을 생성합니다. 마지막으로 재 컴파일된 소스가 있다면 새로 만들어 지거나 이전 컴파일에서 생성됬던 모든 개체 파일을 함께 링크하여 새 실행 파일을 생성해야합니다.

2.1 What a Rule Looks Like (규칙(Rule)의 모양)

간단한 메이크 파일은 다음과 같은 형태의 "규칙"으로 구성됩니다.

target ... : prerequisites ...
        recipe
        ...
        ...

대상(Target)은 일반적으로 프로그램에 의해 생성된 파일의 이름입니다. 대상의 예로는 실행 파일 또는 개체 파일이 있습니다. 대상은 'clean'과 같이 수행할 작업의 이름일 수도 있습니다 (가짜 대상(Phony Targets) 참조).

전제 조건(prerequisites)은 대상을 작성하기 위한 입력으로 사용되는 파일입니다. 대상은 종종 여러 파일에 의존합니다.

레시피(recipe)는 수행하는 작업입니다. 레시피는 같은 줄에 또는 각각 자체 줄에 둘 이상의 명령을 가질 수 있습니다. 참고: 모든 레시피 라인의 시작 부분에 탭 문자를 넣어야합니다! 이것은 부주의한 사람들을 사로 잡는 모호함입니다. 레시피에 탭 이외의 문자를 접두사로 사용하려면 .RECIPEPREFIX 변수를 대체 문자로 설정할 수 있습니다 (특수 변수(Special Variables) 참조).

일반적으로 레시피는 전제 조건이 있는 규칙에 있으며 전제 조건이 변경되면 대상 파일을 작성하는 역할을 합니다. 그러나 대상에 대한 레시피를 지정하는 규칙에는 전제 조건이 필요하지 않습니다. 예를 들어, 'clean' 대상과 연관된 delete 명령이 포함된 규칙에는 전제 조건이 없습니다.

그런 다음 규칙(rule)은 특정 규칙의 대상인 특정 파일을 다시 만드는 방법과 시기를 설명합니다. make는 대상을 생성하거나 업데이트 하기위한 전제 조건에 대한 레시피를 수행합니다. 규칙은 조치를 수행하는 방법과 시기를 설명할 수도 있습니다. 쓰기 규칙(Writing Rules) 을 참조하십시오.

makefile은 규칙 외에 다른 텍스트를 포함할 수 있지만 간단한 makefile에는 규칙만 포함하면됩니다. 규칙은 이 템플릿에 표시된 것보다 다소 복잡해 보일 수 있지만 모두 패턴에 어느 정도 맞습니다.

2.2 A Simple Makefile (간단한 메이크파일)

다음은 edit라고하는 실행 파일이 8 개의 C 소스와 3 개의 헤더 파일에 의존하는 8 개의 오브젝트 파일에 의존하는 방식을 설명하는 간단한 메이크 파일입니다.

이 예에서 모든 C 파일에는 defs.h가 포함되지만 편집 명령을 정의하는 파일에만 command.h가 포함되고 편집기 버퍼를 변경하는 하위 수준 파일에만 buffer.h가 포함됩니다.

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

백슬래시와 개행을 사용하여 긴 줄을 두 줄로 나눕니다. 이것은 하나의 긴 줄을 사용하는 것과 같지만 읽기가 더 쉽습니다. 긴 줄 분할(Splitting Long Lines)을 참조하십시오.

이 makefile을 사용하여 edit라는 실행 파일을 만들려면 다음을 입력하십시오:

make

이 메이크 파일을 사용하여 실행 파일과 디렉터리에서 모든 개체 파일을 삭제하려면 다음을 입력합니다:

make clean

예제 makefile에서 대상에는 실행 파일 'edit'와 개체 파일 'main.o'및 'kbd.o'가 포함됩니다. 필수 구성 요소는 'main.c' 및 'defs.h'와 같은 파일입니다. 실제로 각 '.o' 파일은 대상이자 전제 조건입니다. 레시피에는 'cc -c main.c' 및 'cc -c kbd.c'가 포함됩니다.

대상이 파일인 경우 전제 조건이 변경되면 다시 컴파일하거나 다시 링크해야 합니다. 또한 자동으로 생성되는 모든 필수 구성 요소를 먼저 업데이트해야 합니다. 이 예에서 edit는 8 개의 개체 파일 각각에 따라 달라집니다. 오브젝트 파일 main.o는 소스 파일 main.c와 헤더 파일 defs에 의존합니다.

레시피는 대상(target)과 전제 조건(prerequisites)이 포함된 각 줄을 따를 수 있습니다. 이 레시피는 대상 파일을 업데이트하는 방법을 알려줍니다. 레시피를 메이크 파일의 다른 행과 구별하려면 탭 문자 (또는 .RECIPEPREFIX 변수에 의해 지정된 모든 문자; 특수 변수(Special Variables) 참조)가 레시피의 모든 행 시작 부분에 와야합니다. (make는 레시피가 어떻게 작동하는지에 대해 알지 못합니다. 타겟 파일을 올바르게 업데이트할 레시피를 제공하는 것은 사용자의 몫입니다. 모든 make는 타겟 파일을 업데이트 해야할 때 지정한 레시피를 실행하는 것입니다.)

'clean' 대상은 파일이 아니라 단순히 작업의 이름입니다. 일반적으로 이 규칙의 작업을 수행하지 않기 때문에 'clean'은 다른 규칙의 전제 조건이 아닙니다. 따라서 make는 구체적으로 말하지 않는 한 아무것도하지 않습니다. 이 규칙은 전제 조건이 아닐뿐만 아니라 전제 조건도 없으므로 규칙의 유일한 목적은 지정된 레시피를 실행하는 것입니다. 파일을 참조하지 않고 작업에 불과한 대상을 가짜 대상(phony targets)이라고 합니다. 이러한 종류의 대상에 대한 정보는 가짜 대상(Phony Targets) 을 참조하십시오. make가 rm 또는 기타 명령의 오류를 무시하도록하는 방법은 레시피의 오류(Errors in Recipes) 을 참조하십시오.

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

기본적으로 make는 첫 번째 대상으로 시작합니다 (이름이 '.' 로 시작하는 대상이 아님). 이를 기본 목표(default goal)라고합니다. (목표(Goals)는 궁극적으로 업데이트하려고 노력하는 대상입니다. 명령줄 (목표 지정 인수(Arguments to Specify the Goals) 참조) 또는 .DEFAULT_GOAL 특수 변수 (기타 특수 변수(Other Special Variables) 참조)를 사용하여 이 동작을 재정의 할 수 있습니다.

이전 섹션의 간단한 예에서 기본 목표는 실행 가능한 프로그램 'edit'를 업데이트하는 것입니다. 따라서 우리는 그 규칙을 우선시합니다.

따라서 다음 명령을 내릴 때:

make

make는 현재 디렉토리의 makefile을 읽고 첫 번째 규칙을 처리하여 시작합니다. 예에서 이 규칙은 'edit'를 다시 링크(relinking) 하기위한 것입니다. 그러나 make가 이 규칙을 완전히 처리하기 전에 'edit'이 종속된 파일에 대한 규칙을 처리해야 합니다. 이 경우에는 객체(object) 파일입니다. 이러한 각 파일은 자체 규칙에 따라 처리됩니다. 이러한 규칙은 소스 파일을 컴파일하여 각 '.o' 파일을 업데이트하도록 합니다. 소스 파일 또는 전제 조건으로 명명된 헤더 파일이 오브젝트 파일보다 최신이거나 오브젝트 파일이 없는 경우 재 컴파일(recompilation)을 수행해야합니다.

다른 규칙(rules)은 해당 대상이 목표의 전제 조건으로 나타나기 때문에 처리됩니다. 다른 규칙이 목표 (또는 그에 의존하는 모든것 등)에 의존하지 않는 경우 make에게 그렇게 하도록 지시하지 않는한 해당 규칙은 처리되지 않습니다 (make clean과 같은 명령 사용).

오브젝트 파일을 다시 컴파일하기 전에 make는 전제 조건, 소스 파일 및 헤더 파일 업데이트를 고려하십시오. 이 makefile은 수행할 작업을 지정하지 않습니다. '.c' 및 '.h' 파일은 규칙의 대상이 아니므로 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'를 링크합니다.

2.4 Variables Make Makefiles Simpler (변수는 Makefile을 더 단순하게 만듭니다.)

인용된 예시에서는 '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

이러한 복제는 오류가 발생하기 쉽습니다. 새 개체 파일이 시스템에 추가되면 한 목록에 추가하고 다른 목록은 잊어 버릴 수 있습니다. 변수를 사용하여 위험을 제거하고 메이크 파일을 단순화 할 수 있습니다. 변수를 사용하면 텍스트 문자열을 한 번 정의하고 나중에 여러 위치에서 대체 할 수 있습니다 (변수 사용 방법(How to Use Variables) 참조).

모든 메이크 파일이 모든 오브젝트 파일 이름 목록인 objects, OBJECTS, objs, OBJS, obj 또는 OBJ라는 변수를 갖는 것이 일반적인 관행입니다. makefile에서 다음과 같은 줄로 이러한 변수 개체를 정의합니다.

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

그런 다음 각 위치에 개체 파일 이름 목록을 넣고 '$(objects)' 를 작성하여 변수 값을 대체할 수 있습니다 (변수 사용 방법 (How to Use Variables) 참조).

다음은 오브젝트 파일에 변수를 사용할 때 완전한 단순 메이크 파일의 모습입니다:

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)

2.5 Letting make Deduce the Recipes (make가 레시피를 추론하게 하기)

make가 알아낼 수 있기 때문에 개별 C 소스 파일을 컴파일 하기위한 레시피를 타이핑할 필요가 없습니다: 'cc -c' 명령을 사용하여 해당 이름의 '.c' 파일에서 '.o' 파일을 업데이트하는 암시적 규칙이 있습니다. 예를 들어, 'cc -c main.c -o main.o' 레시피를 사용하여 main.c 를 main.o 로 컴파일합니다. 따라서 객체 파일에 대한 규칙에서 레시피를 생략할 수 있습니다. 암시적 규칙 사용(Using Implicit Rules)을 참조하십시오.

이러한 방식으로 '.c' 파일이 자동으로 사용되면 필수 구성 요소 목록에도 자동으로 추가됩니다. 따라서 레시피를 생략하면 전제 조건에서 '.c' 파일을 생략할 수 있습니다.

다음은 이러한 변경 사항과 위에서 제안한 변수 개체가 포함된 전체 예제입니다:

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'과 관련된 문제점들은 다른 곳에 설명되어 있습니다. 가짜 타겟(Phony Targets) 및 레시피의 오류(Errors in Recipes)을 참조하세요.)

암시적 규칙은 매우 편리하기 때문에 중요합니다. 자주 사용되는 것을 볼 수 있습니다.

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

묵시적 규칙에 의해서만 메이크 파일의 객체가 생성될 때, 메이크 파일의 대체 스타일이 가능합니다. 이 스타일의 makefile에서는 대상이 아니라 전제 조건에 따라 항목을 그룹화합니다. 그게 어떻게 생겼는지는 다음과 같습니다:

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 는 모든 오브젝트 파일의 전제 조건으로 제공됩니다. command.h 및 buffer.h는 이에 대해 나열된 특정 오브젝트 파일의 전제 조건입니다.

이것이 더 좋은지 여부는 취향의 문제입니다. 더 간결하지만 일부 사람들은 각 대상에 대한 모든 정보를 한 곳에 두는 것이 더 명확하기 때문에 싫어합니다.

2.7 Rules for Cleaning the Directory (디렉토리 정리 규칙)

프로그램을 컴파일하는 것이 규칙을 작성하려는 유일한 것은 아닙니다. Makefile은 일반적으로 프로그램을 컴파일하는 것 외에 몇 가지 다른 작업을 수행하는 방법을 알려줍니다. 예를 들어 모든 개체 파일과 실행 파일을 삭제하여 디렉토리가 '정리(clean)' 되도록하는 방법이 있습니다.

예제 'edit'를 정리하기위한 make 규칙을 작성하는 방법은 다음과 같습니다:

clean:
        rm edit $(objects)

실제로는 예상치 못한 상황을 처리하기 위해 다소 복잡한 방식으로 규칙을 작성하고자 할 수 있습니다. 우리는 이것을 해볼것 입니다:

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

이렇게하면 make가 clean 이라는 실제 파일과 혼동되는 것을 방지하고 rm의 오류에도 불구하고 계속 진행됩니다. (가짜 대상 (Phony Targets)및 레시피의 오류(Errors in Recipes)을 참조하십시오.)

이와 같은 규칙은 기본적으로 실행되는 것을 원하지 않기 때문에 makefile의 시작 부분에 배치해서는 안됩니다! 따라서 예제 makefile에서 'edit'를 다시 컴파일하는 'edit'에 대한 규칙이 기본 목표로 유지되기를 원합니다.

clean은 'edit'의 전제 조건이 아니므로 인수없이 'make' 명령을 제공하면 이 규칙이 전혀 실행되지 않습니다. 규칙을 실행하려면 'make clean'을 입력해야 합니다. make 실행 방법(How to Run make)을 참조하십시오.


3. Writing Makefiles (메이크파일 작성)

make에게 시스템을 재컴파일하는 방법을 알려주는 정보는 makefile이라는 데이터베이스를 읽는 것에서 나옵니다.

3.1 What Makefiles Contain (메이크파일에 포함된 내용)

Makefile에는 명시적 규칙, 암시적 규칙, 변수 정의, 지시문 및 주석의 5가지 종류가 있습니다. 규칙, 변수 및 지시문은 이후 장에서 자세히 설명합니다.

  • 명시적 규칙은 규칙의 '대상' 이라고 하는 하나 이상의 파일을 언제 어떻게 다시 만들지 알려줍니다. 대상의 '전제 조건'이라고 하는 대상이 의존하는 다른 파일을 나열하고 대상을 생성하거나 업데이트하는데 사용할 '레시피'를 제공할 수도 있습니다. 작성 규칙(Writing Rules)을 참조하십시오.

  • '암시적 규칙'은 이름을 기반으로 파일 클래스를 언제 어떻게 다시 만들지 알려줍니다. 대상이 대상과 유사한 이름을 가진 파일에 어떻게 의존하는지 설명하고 그러한 대상을 생성하거나 업데이트하기 위한 레시피를 제공합니다. 암시적 규칙 사용(Using Implicit Rules)을 참조하십시오.

  • '변수' 정의는 나중에 텍스트로 대체될 수 있는 변수에 대한 텍스트 문자열 값을 지정하는 행입니다. 간단한 makefile 예제는 모든 객체 파일의 목록으로 객체에 대한 변수 정의를 보여줍니다 (변수로 Makefile을 더 단순하게 만들기(Variables Make Makefiles Simpler) 참조).

  • '지시문'은 make 파일을 읽는 동안 특별한 작업을 수행하도록 만드는 명령입니다. 여기에는 다음이 포함됩니다:

    • 다른 메이크파일 읽기 (다른 메이크파일 포함(Including Other Makefiles) 참조).
    • (변수 값에 따라) makefile의 일부를 사용할지 무시할지 결정 (Makefile의 조건 부분(Conditional Parts of Makefiles) 참조).
    • 여러 줄을 포함하는 축어적(verbatim) 문자열에서 변수 정의(여러줄 변수 정의(Defining Multi-Line Variables) 참조).
  • makefile 줄의 '#'은 주석을 시작합니다. 다른 백슬래시로 이스케이프되지 않은 마지막에 오는 백슬래시가 여러 줄에 걸쳐 주석을 계속한다는 점을 제외하고 이 줄과 나머지 줄은 무시됩니다. 주석(앞에 공백이 있을 수 있음)만 포함하는 행은 사실상 공백이며 무시됩니다. 리터럴 # 을 원하면 백슬래시 (예: #)로 이스케이프 하십시오. 주석은 특정 상황에서 특별히 취급되기는 하지만 makefile의 모든 행에 나타날 수 있습니다.
    변수 참조 또는 함수 호출 내에서 주석을 사용할 수 없습니다: # 의 모든 인스턴스는 변수 참조 또는 함수 호출 내에서 (주석의 시작이 아닌) 문자 그대로 처리됩니다.

    레시피 내의 주석은 다른 레시피 텍스트와 마찬가지로 셸로 전달됩니다. 쉘은 그것을 해석하는 방법을 결정합니다: 이것이 주석인지 아닌지는 쉘에 달려 있습니다.

    정의 지시문 내에서 주석은 변수를 정의하는 동안 무시되지 않고 변수 값에 그대로 유지됩니다. 변수가 확장되면 변수가 평가되는 컨텍스트에 따라 주석 작성 또는 레시피 텍스트로 처리됩니다.

3.1.1 Splitting Long Lines (긴 줄 나누기)

Makefile은 줄 바꿈 문자가 특수하고 명령문의 끝을 표시되는 "줄 기반" 구문을 사용합니다. GNU make는 명령문 행의 길이에 제한이 없으며 컴퓨터의 메모리 양까지 제한이 없습니다.

그러나 줄바꿈이나 스크롤 없이 표시하기에는 너무 긴 줄을 읽기가 어렵습니다. 따라서 명령문 중간에 줄 바꿈을 추가하여 가독성을 위해 메이크 파일 형식을 지정할 수 있습니다: 내부 줄 바꿈을 백슬래시() 문자로 이스케이프 처리하면 됩니다. 구분을 해야 하는 경우 "물리적 줄"을 줄 바꿈으로 끝나는 단일 줄(이스케이프 처리 여부에 관계 없이)과 "논리적 줄"은 첫 번째 비-이스케이프된 개행까지 이스케이프된 줄 바꿈을 모두 포함하는 완전한 문장으로 참조할 것입니다.

백슬래시/개행 문자 조합이 처리되는 방식은 명령문이 레시피 라인인지 비레시피 라인인지에 따라 다릅니다. 레시피 라인에서 백슬래시/개행의 처리는 나중에 논의됩니다(레시피 라인 분할(Splitting Recipe Lines) 참조).

레시피 행 외부에서 백슬래시/개행 문자는 단일 공백 문자로 변환됩니다. 완료되면 백슬래시/개행 문자 주변의 모든 공백이 단일 공백으로 압축됩니다. 여기에는 백슬래시 앞의 모든 공백, 백슬래시/개행 문자 뒤의 줄 시작 부분에 있는 모든 공백 및 연속적인 백슬래시/개행 조합이 포함됩니다.

.POSIX 특수 대상이 정의되면 백슬래시/개행 처리가 POSIX.2 를 준수하도록 약간 수정됩니다: 첫째, 백슬래시 앞의 공백이 제거되지 않고 두 번째, 연속적인 백슬래시/개행 문자가 압축되지 않습니다.

Splitting Without Adding Whitespace (공백을 추가하지 않고 분할하기)

줄을 분할해야 하지만 공백을 추가하지 않으려면 미묘한 트릭을 사용할 수 있습니다. 백슬래시/개행 문자쌍을 달러 기호/백슬래시/개행 3문자로 교체합니다:

var := one$\
       word

make가 백슬래시/개행 문자를 제거하고 다음 줄을 단일 공백으로 압축하면 다음과 같습니다:

var := one$ word

그런 다음 make는 변수 확장을 수행합니다. 변수 참조 '$ '는 존재하지 않는 한 문자 이름 " "(공백)을 가진 변수를 참조하므로 빈 문자열로 확장되어 다음과 같은 최종 할당을 제공합니다:

var := oneword

3.2 What Name to Give Your Makefile (Makefile에 어떤 이름을 지정할 것인가)

기본적으로 make는 makefile을 찾을 때 다음 이름을 순서대로 시도합니다: GNUmakefile, makefile 및 Makefile.

일반적으로 makefile을 makefile 또는 Makefile로 호출해야 합니다. (Makefile은 디렉토리 목록의 시작 부분, README와 같은 다른 중요한 파일 바로 옆에 눈에 띄게 나타나기 때문에 이걸 권장합니다) 확인된 이름인 GNUmakefile은 대부분의 makefile에 권장되지 않습니다. GNU make에 특정한 makefile이 있고 다른 make 버전에서는 이해할 수 없는 경우 이 이름을 사용해야 합니다. 다른 make 프로그램은 makefile과 Makefile을 찾지만 GNUmakefile은 찾지 않습니다.

make가 이러한 이름을 찾지 못하면 makefile을 사용하지 않습니다. 그런 다음 명령 인수로 목표를 지정해야 하며 make는 기본 제공되는 암시적 규칙만 사용하여 목표를 다시 만드는 방법을 알아 내려고 시도합니다. 암시적 규칙 사용(Using Implicit Rules)을 참조하십시오.

메이크파일에 비표준 이름을 사용하려면 '-f' 또는 '--file' 옵션을 사용하여 메이크파일 이름을 지정할 수 있습니다. 인수 '-f name' 또는 '--file=name'은 make에게 파일 이름을 makefile로 읽도록 지시합니다. 하나 이상의 '-f' 또는 '--file' 옵션을 사용하는 경우 여러 makefile을 지정할 수 있습니다. 모든 메이크파일은 지정된 순서대로 효과적으로 연결됩니다. 기본 makefile 이름 GNUmakefile, makefile 및 Makefile은 '-f' 또는 '--file'을 지정하면 자동으로 확인되지 않습니다.

3.3 Including Other Makefiles (다른 Makefile 포함하기)

include 지시문은 make에게 현재 makefile 읽기를 중단하고 계속하기 전에 하나 이상의 다른 makefile을 읽도록 지시합니다. 지시문은 다음과 같은 makefile의 한 줄입니다:

include filenames...

파일 이름에는 셸에서의 파일 이름 패턴이 포함될 수 있습니다. 파일 이름이 비어 있으면 아무 것도 포함되지 않고 오류가 인쇄되지 않습니다.

추가 공백은 줄 시작 부분에서 허용 및 무시되지만 첫 번째 문자는 탭(또는 .RECIPEPREFIX 값)이 아니어야 합니다. 줄이 탭으로 시작하는 경우 레시피 줄로 간주됩니다. 'include' 지시문과 파일 이름 사이, 파일 이름 사이에는 공백이 필요합니다. 추가 공백은 지시문(directive) 끝에서 무시됩니다. 줄 끝에 '#'으로 시작하는 주석이 허용됩니다. 파일 이름에 변수 또는 함수 참조가 포함되어 있으면 확장됩니다. 변수 사용 방법(How to Use Variables)을 참조하십시오.

예를 들어, 세 개의 .mk 파일(a.mk, b.mk 및 c.mk)이 있고 $(bar)가 bish bash로 확장되는 경우 다음 표현식은

include foo *.mk $(bar)

다음과 동등합니다

include foo a.mk b.mk c.mk bish bash

make가 'include' 지시문을 처리할때 포함하는(include가 표시된) makefile의 읽기를 일시 중단하고 나열된(include로 지정된) 각 파일에서 차례로 읽습니다. 이 작업이 완료되면 make는 지시문이 나타나는 makefile 읽기를 재개합니다.

include 지시문을 사용하는 한 가지 사례로는 다양한 디렉토리의 개별 makefile에 의해 처리되는 여러 프로그램이 공통 변수 정의 세트(변수 설정(Setting Variables) 참조) 또는 패턴 규칙(패턴 규칙 정의 및 재정의(Defining and Redefining Pattern Rules) 참조)을 사용해야 하는 경우입니다.

또 다른 경우는 소스 파일에서 전제 조건을 자동으로 생성하려는 경우입니다. 필수 구성 요소는 기본 makefile에 포함된 파일에 넣을 수 있습니다. 이 방법은 일반적으로 다른 버전의 make에서 수행되었던 것처럼 기본 makefile 끝에 전제 조건을 추가하는 것보다 일반적으로 더 깔끔합니다. 자동 전제 조건(Automatic Prerequisites)을 참조하십시오.

지정된 이름이 슬래시로 시작하지 않고 파일이 현재 디렉토리에 없으면 다른 여러 디렉토리가 검색됩니다. 먼저 '-I' 또는 '--include-dir' 옵션으로 지정한 모든 디렉토리가 검색됩니다(옵션 요약(Summary of Options) 참조). 그런 다음 접두사/포함(일반적으로 /usr/local/include) /usr/gnu/include, /usr/local/include, /usr/include의 순서로 (존재하는 경우) 디렉토리가 검색됩니다.

포함된 메이크파일을 이러한 디렉토리에서 찾을 수 없으면 경고 메시지가 생성되지만 즉시적 치명적인 오류는 아닙니다. 'include'를 포함하는 메이크파일의 처리가 계속됩니다. makefile 읽기가 끝나면 make는 오래되었거나 존재하지 않는 것을 다시 만들려고 시도합니다. Makefile을 다시 만드는 방법(How Makefiles Are Remade)을 참조하십시오. makefile을 다시 만드는 방법을 찾으려고 시도했지만 실패한 후에만 make는 누락된 makefile을 치명적인 오류로 진단합니다.

make가 존재하지 않거나 다시 만들 수 없는 makefile을 오류 메시지 없이 단순히 무시하도록 하려면 다음과 같이 'include' 대신 '-include' 지시문을 사용하십시오:

-include filenames...

이것은 파일 이름(또는 파일 이름의 전제 조건)이 존재하지 않거나 다시 만들 수 없는 경우 오류(경고도 아님)가 없다는 점을 제외하고는 모든 면에서 'include'처럼 작동합니다.

일부 다른 make 구현과의 호환성을 위해 'sinclude'는 '-include'의 다른 이름으로 사용됩니다.

3.4 The Variable MAKEFILES (변수 MAKEFILES)

환경 변수 MAKEFILES이 정의되면 make는 그 값을 다른 makefile보다 먼저 읽을 추가 makefile의 이름 목록(공백으로 구분)으로 간주합니다. 이것은 include 지시어와 매우 유사하게 작동합니다. 다양한 디렉토리에서 해당 파일을 검색합니다(다른 Makefile 포함(Including Other Makefiles) 참조). 또한 기본 목표(default goal)는 이러한 메이크파일중 하나(또는 여기에 포함된 모든 메이크파일)에서 가져오지 않으며 MAKEFILES에 나열된 파일을 찾을 수 없는 경우 오류가 아닙니다.

MAKEFILES의 주요 용도는 make의 재귀 호출간의 통신입니다(make의 재귀 사용(Recursive Use of make) 참조). 일반적으로 외부에서 makefile을 엉망으로 만들지 않는 것이 좋기 때문에 make의 최상위 호출 전에 환경 변수를 설정하는 것은 바람직하지 않습니다. 그러나 특정 makefile 없이 make를 실행하는 경우 MAKEFILES의 makefile은 검색 경로 정의(디렉토리 검색(Directory Search) 참조)와 같이 기본 제공(built-in) 암시적 규칙이 더 잘 작동하는데 도움이 되는 유용한 작업을 수행할 수 있습니다.

일부 사용자는 로그인시 환경에서 MAKEFILES를 자동으로 설정하고 makefiles가 이것이 완료되기를 기대하도록 프로그램을 설정하려는 유혹을 받습니다. 다른 사람이 실행하면 그러한 makefile이 작동하지 않기 때문에 이것은 매우 나쁜 생각입니다. makefile에 명시적 include 지시문을 작성하는 것이 훨씬 좋습니다. 다른 Makefile 포함(Including Other Makefiles)을 참조하십시오.

3.5 How Makefiles Are Remade (Makefile을 다시 만드는 방법)

때때로 makefile은 RCS 또는 SCCS 파일과 같은 다른 파일에서 다시 만들어질 수 있습니다. makefile이 다른 파일에서 다시 만들어질 수 있다면 make가 읽을 수 있는 makefile의 최신 버전을 얻기를 원할 것입니다.

이를 위해 모든 makefile을 읽은 후 make는 각각을 목표 대상으로 간주하고 업데이트를 시도합니다. makefile에 업데이트 방법을 알려주는 규칙이 있거나(바로 그 makefile 또는 다른 makefile에 있음) 암시적 규칙이 적용되는 경우(암시적 규칙 사용(Using Implicit Rules) 참조) 필요한 경우 업데이트됩니다. 모든 메이크파일을 확인한 후 실제로 변경된 사항이 있으면 make는 깨끗한 상태로 시작하여 모든 메이크파일을 다시 읽습니다. (또한 각각을 다시 업데이트하려고 시도하지만 일반적으로 이미 최신 상태이므로 다시 변경하지 않습니다.) 다시 시작할 때마다 특수 변수 MAKE_RESTARTS가 업데이트됩니다(특수 변수(Special Variables) 참조).

하나 이상의 makefile을 다시 만들 수 없다는 것을 알고 있고 make가 이에 대한 암시적 규칙 검색을 수행하지 못하도록 하려면 아마도 효율성을 위해 암시적 규칙 조회를 방지하는 일반적인 방법을 사용하여 그렇게 할 수 있습니다. 예를 들어 makefile을 대상으로 하고 빈 레시피를 사용하여 명시적 규칙을 작성할 수 있습니다(빈 레시피 사용(Using Empty Recipes) 참조).

makefiles이 레시피가 있지만 전제 조건이 없는 파일을 다시 만들기 위해 이중 콜론 규칙을 지정하는 경우 해당 파일은 항상 다시 만들어집니다(이중 콜론(Double-Colon) 참조). makefiles의 경우, 레시피가 포함된 이중 콜론 규칙이 있지만 전제 조건이 없는 메이크 파일은 make가 실행될 때마다 다시 만들어지고, make가 다시 시작된 후 다시 만들어지고 메이크 파일을 다시 읽습니다. 이것은 무한 루프를 일으킬 것입니다: make는 계속해서 makefile을 리메이크할 것이고, 다른 어떤 것도 하지 않을 것입니다. 따라서 이것을 피하기 위해 make는 이중 콜론 규칙의 대상으로 지정된 makefile을 레시피는 있지만 전제 조건 없이 리메이크하려고 시도하지 않습니다.

'-f' 또는 '--file' 옵션으로 읽을 makefiles을 지정하지 않으면 make는 기본 makefiles 이름을 읽으려 시도합니다. Makefile에 부여할 이름(What Name to Give Your Makefile)을 참조하십시오. '-f' 또는 '--file' 옵션으로 명시적으로 요청된 makefiles과 달리 make는 이러한 makefiles이 존재해야 하는지 확신하지 못합니다. 그러나 기본 makefile이 존재하지 않지만 make 규칙을 실행하여 만들 수 있는 경우 makefile을 사용할 수 있도록 규칙이 실행되기를 원할 것입니다.

따라서 기본 makefile이 존재하지 않는 경우 make는 성공적으로 만들거나 시도할 이름이 없을때까지 검색된 순서와 동일한 순서로 각 makefile을 만들려고 시도합니다 (Makefile에 부여할 이름(What Name to Give Your Makefile) 참조). make가 makefile을 찾거나 만들 수 없는 경우에는 오류가 아닙니다. makefile이 항상 필요한 것은 아닙니다.

'-t' 또는 '--touch' 옵션을 사용할 때(레시피 실행 대신(Instead of Executing Recipes) 참조) 터치할 대상을 결정하기 위해 오래된 makefile을 사용하고 싶지 않을 것입니다. 따라서 '-t' 옵션은 makefile 업데이트에 영향을 미치지 않습니다. '-t'가 지정된 경우에도 실제로 업데이트됩니다. 마찬가지로, '-q'(또는 '--question') 및 '-n'(또는 '--just-print')은 오래된 makefile로 인하여 잘못된 출력을 초래하기 때문에 makefile의 업데이트를 방지하지 않습니다. 따라서 'make -f mfile -n foo'는 mfile을 업데이트하고 읽어들인 다음 실행하지 않고 foo와 전제 조건을 업데이트하는 레시피를 인쇄합니다. foo에 대해 인쇄된 레시피는 mfile의 업데이트된 내용에 지정된 레시피가 됩니다.

그러나 때때로 실제로 makefile의 업데이트를 막고 싶을 수도 있습니다. 명령줄에서 makefile을 목표로 지정하고 makefile로 지정하여 이를 수행할 수 있습니다. makefile 이름이 목표로 명시적으로 지정되면 옵션 '-t' 등이 적용됩니다.

따라서 'make -f mfile -n mfile foo'는 makefile mfile을 읽고 실제로 실행하지 않고 업데이트에 필요한 레시피를 인쇄한 다음 실행하지 않고 foo를 업데이트하는데 필요한 레시피를 인쇄합니다. foo의 레시피는 mfile의 기존 내용으로 지정된 레시피입니다.

3.6 Overriding Part of Another Makefile (다른 Makefile의 일부 재정의)

때때로 다른 makefile과 거의 같은 makefile을 갖는 것이 유용합니다. 종종 'include' 지시문을 사용하여 하나를 다른 하나에 포함하고 더 많은 대상 또는 변수 정의를 추가할 수 있습니다. 그러나 두 메이크파일이 동일한 대상에 대해 서로 다른 레시피를 제공하는 것은 유효하지 않습니다. 그러나 다른 방법이 있습니다.

포함하는 메이크파일(다른 것을 포함하려는 것)에서, 포함하는 메이크파일의 정보에서 만들 수 없는 모든 대상을 리메이크하려면 make가 다른 메이크파일을 찾아야 한다고 말하는 모든 일치 패턴 규칙을 사용할 수 있습니다. 패턴 규칙에 대한 자세한 내용은 패턴 규칙(Pattern Rules)을 참조하세요.

예를 들어, 타겟 'foo'(및 다른 타겟)를 만드는 방법을 알려주는 Makefile이라는 메이크파일이 있다면 다음을 포함하는 GNUmakefile이라는 메이크파일을 작성할 수 있습니다:

foo:
        frobnicate > foo

%: force
        @$(MAKE) -f Makefile $@
force: ;

'make foo'라고 말하면 make는 GNUmakefile을 찾아서 읽고 foo를 만들기 위해 'frobnicate > foo' 레시피를 실행해야 합니다. 'make bar'라고 말하면 make는 GNUmakefile에서 bar를 만들 방법을 찾지 못하므로 'make -f Makefile bar' 패턴 규칙의 레시피를 사용합니다. Makefile이 bar 업데이트 규칙을 제공하면 make는 규칙을 적용합니다. 그리고 GNUmakefile이 만드는 방법을 알려주지 않는 다른 대상에 대해서도 마찬가지입니다.

이것이 작동하는 방식은 패턴 규칙이 '%'의 패턴을 가지므로 모든 대상과 일치한다는 것입니다. 규칙은 대상 파일이 이미 있는 경우에도 레시피가 실행되도록 보장하기 위해 전제 조건을 지정합니다. make가 그것을 빌드하기 위해 묵시적 규칙을 검색하는 것을 방지하기 위해 force target에 빈 레시피를 제공합니다. 그렇지 않으면 동일한 일치 규칙을 적용하여 강제로 실행하고 전제 조건 루프를 만듭니다!

3.7 How make Reads a Makefile (make가 Makefile을 읽는 방법)

GNU make는 두 가지 별개의 단계로 작업을 수행합니다. 첫 번째 단계에서 모든 makefile, 포함된 makefile 등을 읽고 모든 변수와 해당 값, 암시적 및 명시적 규칙을 내부화하고 모든 대상과 전제 조건의 종속성 그래프를 작성합니다. 두 번째 단계에서 make는 이 내부화된 데이터를 사용하여 업데이트해야 할 대상을 결정하고 업데이트에 필요한 레시피를 실행합니다.

변수 및 기능 확장이 발생하는 방식에 직접적인 영향을 미치기 때문에 이 2단계 접근 방식을 이해하는 것이 중요합니다. 이것은 종종 makefile을 작성할 때 혼란의 원인이 됩니다. 다음은 makefile에서 찾을 수 있는 다양한 구성과 구성의 각 부분에 대해 확장이 발생하는 단계에 대한 요약입니다.

확장이 첫 번째 단계에서 발생하면 즉시 발생한다고 말합니다: make는 makefile이 구문 분석될때 구성의 해당 부분을 확장합니다. 우리는 그것이 즉각적이지 않다면 확장이 연기된다고 말합니다. 지연된 구성 부분의 확장은 확장이 사용될 때까지 지연됩니다: 즉각적인 컨텍스트에서 참조되거나 두 번째 단계에서 필요할 때입니다.

이러한 구성중 일부는 아직 익숙하지 않을 수 있습니다. 나중에 익숙해지면 이 섹션을 참조할 수 있습니다.

Variable Assignment (변수 할당)

변수 정의는 다음과 같이 구문 분석됩니다:

immediate = deferred
immediate ?= deferred
immediate := immediate
immediate ::= immediate
immediate += deferred or immediate
immediate != immediate

define immediate
  deferred
endef

define immediate =
  deferred
endef

define immediate ?=
  deferred
endef

define immediate :=
  immediate
endef

define immediate ::=
  immediate
endef

define immediate +=
  deferred or immediate
endef

define immediate !=
  immediate
endef

추가 연산자 '+='의 경우, 변수가 이전에 단순 변수(':=' 또는 '::=')로 설정되어 있으면 오른쪽이 즉시로 간주되고, 그렇지 않으면 지연됩니다.

쉘 할당 연산자 '!='의 경우 오른쪽이 즉시 평가되어 쉘로 전달됩니다. 결과는 왼쪽에 이름이 지정된 변수에 저장되고 해당 변수는 단순 변수가 됩니다(따라서 각 참조에서 재평가됩니다).

Conditional Directives (조건부 지시문)

조건부 지시문은 즉시 구문 분석됩니다. 예를 들어, 자동 변수는 해당 규칙에 대한 레시피가 호출될 때까지 자동 변수가 설정되지 않기 때문에 조건부 지시문에서 사용할 수 없음을 의미합니다. 조건부 지시문에서 자동 변수를 사용해야 하는 경우 조건을 레시피로 이동하고 쉘 조건부 구문을 대신 사용해야 합니다.

Rule Definition (규칙 정의)

규칙은 형식(form)에 관계없이 항상 같은 방식으로 확장됩니다:

immediate : immediate ; deferred
        deferred

즉, 대상 및 전제 조건 섹션은 즉시 확장되고 대상을 빌드하는데 사용되는 레시피는 항상 지연됩니다. 이는 명시적 규칙, 패턴 규칙, 접미사 규칙, 정적 패턴 규칙 및 단순 전제조건 정의에 해당됩니다.

3.8 How Makefiles Are Parsed (Makefile이 구문 분석되는 방법)

GNU make는 makefile을 한 줄씩 구문 분석합니다. 구문 분석은 다음 단계를 사용하여 진행됩니다:

  1. 백슬래시 이스케이프된 줄을 포함하여 전체 논리 줄을 읽습니다(긴줄 분할(Splitting Long Lines) 참조).

  2. 주석을 제거합니다(Makefile에 포함된 내용(What Makefiles Contain) 참조).

  3. 라인이 레시피 접두사 문자로 시작하고 우리가 규칙(rule) 컨텍스트에 있는 경우 현재 레시피에 라인을 추가하고 다음 라인을 읽으십시오(레시피 구문(Recipe Syntax) 참조).

  4. 즉각적인 확장 컨텍스트에 나타나는 줄의 요소를 확장합니다(make가 Makefile을 읽는 방법(How make Reads a Makefile) 참조).

  5. ':' 또는 '='와 같은 구분 문자가 있는지 행을 스캔하여 행이 매크로 할당인지 규칙인지 확인합니다(레시피 구문(Recipe Syntax) 참조).

  6. 결과 연산을 내부화하고 다음 줄을 읽습니다.

이것의 중요한 결과는 한 줄 길이인 경우 매크로가 전체 규칙으로 확장될 수 있다는 것입니다. 이것은 작동합니다:

myrule = target : ; echo built

$(myrule)

그러나 make는 라인을 확장한후 다시 분할하지 않기 때문에 이것은 작동하지 않습니다:

define myrule
target:
        echo built
endef

$(myrule)

위의 makefile은 마치 makefile에 레시피가 있는 규칙이 아니라 target: echo built가 포함된 것처럼 전제 조건 'echo' 및 'built'를 사용하여 대상 'target'을 정의합니다. 확장이 완료된 후에도 줄에 계속 존재하는 줄 바꿈은 일반 공백으로 무시됩니다.

여러 줄 매크로를 적절하게 확장하려면 eval 함수를 사용해야 합니다: 이렇게 하면 확장된 매크로의 결과에 대해 make 구문 분석기가 실행됩니다(Eval 함수(Eval Function) 참조).

3.9 Secondary Expansion (2차 확장)

이전에 우리는 GNU make가 두 가지 별개의 단계에서 작동한다는 것을 배웠습니다: 읽기 단계와 대상 업데이트 단계 (make가 Makefile을 읽는 방법(How make Reads a Makefile) 참조). GNU make는 또한 makefile에 정의된 일부 또는 모든 대상에 대한 전제조건(만)의 두 번째 확장을 가능하게하는 기능이 있습니다. 이 두 번째 확장이 발생하려면 이 기능을 사용하는 첫 번째 전제 조건 목록보다 먼저 특수 대상 .SECONDEXPANSION을 정의해야 합니다.

그 특수 대상이 정의되면 위에서 언급한 두 단계 사이, 즉 읽기 단계가 끝날때 특수 대상 이후에 정의된 대상의 모든 전제 조건이 두 번째로 확장됩니다. 대부분의 경우 이 2차 확장은 효과가 없습니다. 모든 변수 및 함수 참조가 메이크파일의 초기 구문 분석 중에 확장되기 때문입니다. 파서의 2차 확장 단계를 활용하려면 makefile에서 변수 또는 함수 참조를 이스케이프해야 합니다. 이 경우 첫 번째 확장은 참조를 이스케이프 해제만 하고 확장하지 않으며 확장은 두 번째 확장 단계에 남습니다. 예를 들어 다음 makefile을 고려하십시오:

.SECONDEXPANSION:
ONEVAR = onefile
TWOVAR = twofile
myfile: $(ONEVAR) $$(TWOVAR)

첫 번째 확장 단계 후에 myfile 대상의 전제 조건 목록은 onefile 및 $(TWOVAR)입니다. ONEVAR에 대한 첫 번째(이스케이프 처리되지 않은) 변수 참조가 확장되는 반면 두 번째(이스케이프 처리된) 변수 참조는 변수 참조로 인식되지 않고 단순히 이스케이프 처리되지 않습니다. 이제 두 번째 확장 중에 첫 번째 단어가 다시 확장되지만 변수나 함수 참조가 포함되어 있지 않기 때문에 값 onefile로 유지되는 반면 두 번째 단어는 이제 값 twofile로 확장되는 변수 TWOVAR에 대한 일반 참조입니다. 최종 결과는 onefile과 twofile이라는 두 가지 전제 조건이 있다는 것입니다.

분명히 이것은 두 변수가 전제 조건 목록에 이스케이프 처리되지 않은 상태로 나타나도록 하면 동일한 결과를 더 쉽게 얻을 수 있기 때문에 그다지 흥미로운 사례가 아닙니다. 변수가 재설정되면 한 가지 차이점이 분명해집니다. 이 예를 고려하십시오:

.SECONDEXPANSION:
AVAR = top
onefile: $(AVAR)
twofile: $$(AVAR)
AVAR = bottom

여기에서 onefile의 전제 조건은 즉시 확장되고 값 top으로 해결되는 반면 twofile의 전제 조건은 두 번째 확장이 될 때까지 완전히 확장되지 않고 bottom 값을 생성합니다.

이것은 약간 더 흥미롭지만 이 기능의 진정한 힘은 2차 확장이 항상 해당 대상에 대한 자동 변수 범위 내에서 발생한다는 것을 발견했을 때만 분명해집니다. 즉, 두 번째 확장 중에 $@, $* 등과 같은 변수를 사용할 수 있으며 레시피에서와 같이 예상 값을 갖게 됩니다. $를 이스케이프하여 확장을 연기하기만 하면 됩니다. 또한 명시적 및 암시적(패턴) 규칙 모두에 대해 2차 확장이 발생합니다. 이를 알면 이 기능의 가능한 사용이 극적으로 증가합니다. 예를 들어:

.SECONDEXPANSION:
main_OBJS := main.o try.o test.o
lib_OBJS := lib.o api.o

main lib: $$($$@_OBJS)

여기서 초기 확장후 main 및 lib 대상 모두의 전제 조건은 $($@_OBJS)가 됩니다. 2차 확장 동안 $@ 변수는 대상의 이름으로 설정되므로 기본 대상에 대한 확장은 $(main_OBJS) 또는 main.o try.o test.o를 생성하는 반면 lib에 대한 2차 확장은 대상은 $(lib_OBJS) 또는 lib.o api.o를 생성합니다.

적절하게 이스케이프 처리되는한 여기에서 함수를 혼합할 수도 있습니다:

main_SRCS := main.c try.c test.c
lib_SRCS := lib.c api.c

.SECONDEXPANSION:
main lib: $$(patsubst %.c,%.o,$$($$@_SRCS))

이 버전에서는 사용자가 개체 파일 대신 소스 파일을 지정할 수 있지만 이전 예제와 동일한 결과 전제 조건 목록을 제공합니다.

특히 대상 이름 변수 $$@의 2차 확장 단계 중 자동 변수 평가는 레시피내 평가와 유사하게 작동합니다. 그러나 이해를 돕는 여러 유형의 규칙 정의에 적용되는 몇 가지 미묘한 차이점과 "모퉁이의 경우(corner cases)"가 있습니다. 다양한 자동 변수 사용의 미묘함은 아래에 설명되어 있습니다.

Secondary Expansion of Explicit Rules (명시적 규칙의 2차 확장)

명시적 규칙의 2차 확장 동안 $$@ 및 $$%는 각각 대상의 파일 이름을 평가하고 대상이 아카이브 구성원인 경우 대상 구성원 이름을 평가합니다. $$< 변수는 이 대상에 대한 첫 번째 규칙의 첫 번째 전제 조건으로 평가됩니다. $$^ 및 $$+는 동일한 대상(반복이 있는 $$+ 및 포함하지 않는 $$^)에 대해 이미 나타난 규칙의 모든 전제 조건 목록으로 평가됩니다. 다음 예는 이러한 동작을 설명하는데 도움이 됩니다:

.SECONDEXPANSION:

foo: foo.1 bar.1 $$< $$^ $$+    # line #1

foo: foo.2 bar.2 $$< $$^ $$+    # line #2

foo: foo.3 bar.3 $$< $$^ $$+    # line #3

첫 번째 전제 조건 목록에서 세 변수($$<, $$^ 및 $$+)는 모두 빈 문자열로 확장됩니다. 두 번째에서는 각각 foo.1, foo.1 bar.1 및 foo.1 bar.1 값을 갖습니다. 세 번째에서는 foo.1, foo.1 bar.1 foo.2 bar.2 및 foo.1 bar.1 foo.2 bar.2 foo.1 foo.1 bar.1 foo.1 bar.1 값을 각각 갖습니다.

규칙은 레시피가 있는 규칙이 항상 마지막으로 평가된다는 점을 제외하고는 메이크파일 순서로 2차 확장을 거칩니다.

변수 $$? 및 $$*는 사용할 수 없으며 빈 문자열로 확장됩니다.

Secondary Expansion of Static Pattern Rules (정적 패턴 규칙의 2차 확장)

정적 패턴 규칙의 2차 확장에 대한 규칙은 한 가지 예외를 제외하고 위의 명시적 규칙에 대한 규칙과 동일합니다. 정적 패턴 규칙의 경우 $$* 변수가 패턴 어간으로 설정됩니다. 명시적 규칙과 마찬가지로 $$? 사용할 수 없으며 빈 문자열로 확장됩니다.

Secondary Expansion of Implicit Rules (암시적 규칙의 2차 확장)

As make searches for an implicit rule, it substitutes the stem and then performs secondary expansion for every rule with a matching target pattern. The value of the automatic variables is derived in the same fashion as for static pattern rules. As an example:
make는 암시적 규칙을 검색할때 어간을 대체한 다음 일치하는 대상 패턴이 있는 모든 규칙에 대해 2차 확장을 수행합니다. 자동 변수의 값은 정적 패턴 규칙과 동일한 방식으로 파생됩니다. 예를들면:

.SECONDEXPANSION:

foo: bar

foo foz: fo%: bo%

%oo: $$< $$^ $$+ $$*

대상 foo에 대해 암시적 규칙이 시도되면 $$<는 bar로 확장되고 $$^는 bar boo로 확장되고 $$+도 bar boo로 확장되고 $$*는 f로 확장됩니다.

암시적 규칙 검색 알고리즘에 설명된대로 디렉터리 접두사(D)가 전제 조건 목록의 모든 패턴에 추가됩니다(확장 후). 예를들면:

.SECONDEXPANSION:

/tmp/foo.o:

%.o: $$(addsuffix /%.c,foo bar) foo.h
        @echo $^

2차 확장 및 디렉토리 접두사 재구성후 인쇄된 전제 조건 목록은 /tmp/foo/foo.c /tmp/bar/foo.c foo.h가 됩니다. 이 재구성에 관심이 없으면 전제 조건 목록에서 % 대신 $$*를 사용할 수 있습니다.


4. Writing Rules (작성 규칙)

규칙은 makefile에 나타나며 규칙의 대상이라고 하는 특정 파일을 언제 어떻게 다시 만들지 알려줍니다 (대부분 규칙당 하나만). 여기에는 대상의 전제 조건인 다른 파일과 대상을 만들거나 업데이트하는데 사용할 레시피가 나열됩니다.

규칙의 순서는 기본 목표를 결정하는 것을 제외하고는 중요하지 않습니다: 기본 목표는 첫 번째 메이크파일에 있는 첫 번째 규칙의 대상입니다. 첫 번째 규칙에 여러 대상이 있는 경우 첫 번째 대상만 기본값으로 사용됩니다. 두 가지 예외가 있습니다. 마침표로 시작하는 대상은 하나 이상의 슬래시 '/'도 포함하지 않는한 기본값이 아닙니다. 패턴 규칙을 정의하는 대상은 기본 목표에 영향을 미치지 않습니다. (패턴 규칙 정의 및 재정의(Defining and Redefining Pattern Rules)을 참조하십시오)

따라서 우리는 일반적으로 첫 번째 규칙이 전체 프로그램 또는 makefile에 의해 설명된 모든 프로그램 (종종 'all'이라고 하는 대상을 가짐)을 컴파일하는 규칙이 되도록 makefile을 작성합니다. 목표를 지정하는 인수(Arguments to Specify the Goals)을 참조하십시오.

4.1 Rule Example (규칙 예시)

다음은 규칙의 예입니다:

foo.o : foo.c defs.h       # module for twiddling the frobs
        cc -c -g foo.c

대상은 foo.o 이고 전제 조건은 foo.c 및 defs.h 입니다. 레시피에는 'cc -c -g foo.c'라는 명령이 하나 있습니다. 레시피는 레시피로 식별할 수 있는 탭으로 시작합니다.

이 규칙은 두 가지를 말합니다:

  • foo.o가 구식인지 여부를 결정하는 방법: 존재하지 않거나 foo.c 또는 def.h가 그것보다 최신이면 구식입니다.

  • foo.o 파일을 업데이트하는 방법: 명시된 대로 cc를 실행합니다. 레시피에는 def.h가 명시적으로 언급되어 있지 않지만 foo.c에 포함되어 있다고 가정하고 defs.h가 전제 조건에 추가되었습니다.

4.2 Rule Syntax (규칙 구문)

일반적으로 규칙은 다음과 같습니다:

targets : prerequisites
        recipe
        ...

또는 다음과 같이:

targets : prerequisites ; recipe
        recipe
        ...

대상은 공백으로 구분된 파일 이름입니다. 와일드카드 문자를 사용할 수 있으며(파일 이름에 와일드카드 문자 사용(Using Wildcard Characters in File Names) 참조) a(m) 형식의 이름은 아카이브 파일 a의 멤버 m을 나타냅니다(대상에서의 아카이브 멤버(Archive Members as Targets) 참조). 일반적으로 규칙당 하나의 대상만 있지만 경우에따라 더 많은 이유가 있습니다(규칙의 여러 대상(Multiple Targets in a Rule) 참조).

레시피 라인은 탭 문자(또는 .RECIPEPREFIX 변수 값의 첫 번째 문자; 특수 변수(Special Variables) 참조)로 시작합니다. 첫 번째 레시피 행은 전제 조건 뒤의 행에 탭 문자로 나타나거나 같은 행에 세미콜론으로 나타날 수 있습니다. 어느 쪽이든 효과는 동일합니다. 레시피의 구문에는 다른 차이점이 있습니다. 규칙에 레시피 작성(Writing Recipes in Rules)을 참조하십시오.

달러 기호는 변수 참조 만들기를 시작하는데 사용되기 때문에 대상 또는 전제 조건에 달러 기호를 정말로 원하면 '$$'(변수 사용 방법(How to Use Variables) 참조)를 작성해야 합니다. 2차 확장(2차 확장(Secondary Expansion) 참조)을 활성화하고 전제 조건 목록에 리터럴 달러 기호를 원하는 경우 실제로 4개의 달러 기호('$$$$')를 작성해야 합니다.

백슬래시 다음에 줄 바꿈을 삽입하여 긴 줄을 분할할 수 있지만 make는 makefile의 줄 길이에 제한이 없기 때문에 필수 사항은 아닙니다.

규칙은 make에게 두 가지 사항을 알려줍니다. 대상이 오래된 경우와 필요할 때 업데이트하는 방법입니다.

구식이라는 기준은 공백으로 구분된 파일 이름으로 구성된 전제 조건에 따라 지정됩니다. (와일드카드 및 아카이브 구성원(아카이브(Archives) 참조)도 여기에서 허용됩니다.) 대상이 존재하지 않거나 전제 조건보다 오래된 경우(마지막 수정 시간 비교) 대상이 오래된 것입니다. 아이디어는 대상 파일의 내용이 전제 조건의 정보를 기반으로 계산되므로 전제 조건중 하나라도 변경되면 기존 대상 파일의 내용이 더 이상 유효하지 않다는 것입니다.

업데이트 방법은 레시피로 지정됩니다. 이것은 쉘(일반적으로 'sh')에 의해 실행되는 하나 이상의 행이지만 몇 가지 추가 기능이 있습니다(규칙에서 레시피 작성(Writing Recipes in Rules) 참조).

4.3 Types of Prerequisites (전제 조건 유형)

실제로 GNU make가 이해하는 두 가지 다른 유형의 전제 조건이 있습니다: 이전 섹션에서 설명한 것과 같은 일반 전제 조건과 주문 전용(order-only) 전제 조건입니다. 일반적인 전제 조건은 두 가지 명령문을 작성합니다: 첫째, 레시피가 호출되는 순서를 부과합니다: 대상의 모든 전제 조건에 대한 레시피는 대상에 대한 레시피가 실행되기 전에 완료됩니다. 둘째, 종속 관계를 부과합니다: 전제 조건이 대상보다 새로운 경우 대상은 오래된 것으로 간주되어 다시 빌드해야 합니다.

일반적으로 이것이 바로 원하는 것입니다: 대상의 전제 조건이 업데이트되면 대상도 업데이트되어야 합니다.

그러나 때때로 이러한 규칙중 하나가 실행되는 경우 대상을 업데이트하지 않고 호출할 규칙에 특정 순서를 적용하려는 상황이 있습니다. 이 경우 주문 전용 전제조건을 정의하려고 합니다. 주문 전용 전제조건은 전제조건 목록에 파이프 기호(|)를 배치하여 지정할 수 있습니다: 파이프 기호 왼쪽에 있는 전제조건은 정상입니다. 오른쪽에 대한 모든 전제 조건은 주문 전용입니다.

targets : normal-prerequisites | order-only-prerequisites

정상적인 전제 조건 섹션은 물론 비어 있을 수 있습니다. 또한 동일한 대상에 대해 여러 줄의 선행 조건을 선언할 수 있습니다: 적절하게 추가됩니다(일반 선행 조건은 일반 선행 조건 목록에 추가되고 주문 전용 선행 조건은 주문 전용 선행 조건 목록에 추가됨). 동일한 파일을 일반 및 주문 전용 선행 조건으로 선언하면 일반 선행 조건이 우선합니다(주문 전용 선행 조건 동작의 엄격한 상위 집합이 있기 때문에).

대상이 별도의 디렉토리에 배치되고 make가 실행되기 전에 해당 디렉토리가 존재하지 않을 수 있는 예를 고려하십시오. 이 상황에서 대상이 배치되기 전에 디렉토리가 생성되기를 원하지만 파일이 추가, 제거 또는 이름이 변경될 때마다 디렉토리의 타임스탬프가 변경되기 때문에 그때마다 모든 대상을 다시 빌드하고 싶지는 않습니다. 이것을 관리하는 한 가지 방법은 주문 전용 전제 조건을 사용하는 것입니다. 모든 대상에서 디렉토리를 주문 전용 전제 조건으로 만듭니다:

OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)

$(OBJDIR)/%.o : %.c
        $(COMPILE.c) $(OUTPUT_OPTION) $<

all: $(OBJS)

$(OBJS): | $(OBJDIR)

$(OBJDIR):
        mkdir $(OBJDIR)

이제 objdir 디렉토리를 만드는 규칙은 '.o'가 빌드되기 전에 필요한 경우 실행되지만 objdir 디렉토리 타임스탬프가 변경되었기 때문에 '.o'는 빌드되지 않습니다.

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

단일 파일 이름은 와일드카드 문자를 사용하여 여러 파일을 지정할 수 있습니다. make의 와일드카드 문자는 Bourne 셸과 동일한 '*', '?' 및 '[...]'입니다. 예를 들어, *.c는 이름이 '.c'로 끝나는 모든 파일(작업 디렉토리에 있음)의 목록을 지정합니다.

파일 이름의 시작 부분에 있는 '~' 문자도 특별한 의미를 갖습니다. 단독이거나 슬래시가 뒤에 오는 경우 홈 디렉토리를 나타냅니다. 예를 들어 ~/bin은 /home/you/bin으로 확장됩니다. '~' 뒤에 단어가 오는 경우 문자열은 해당 단어로 명명된 사용자의 홈 디렉토리를 나타냅니다. 예를 들어 ~john/bin은 /home/john/bin으로 확장됩니다. 각 사용자에 대한 홈 디렉토리가 없는 시스템(예: MS-DOS 또는 MS-Windows)에서는 환경 변수 HOME을 설정하여 이 기능을 시뮬레이션할 수 있습니다.

와일드카드 확장은 대상 및 전제 조건에서 자동으로 make에 의해 수행됩니다. 레시피에서 셸은 와일드카드 확장을 담당합니다. 다른 컨텍스트에서 와일드카드 확장은 와일드카드 함수를 사용하여 명시적으로 요청한 경우에만 발생합니다.

The special significance of a wildcard character can be turned off by preceding it with a backslash. Thus, foo*bar would refer to a specific file whose name consists of 'foo', an asterisk, and 'bar'.
와일드카드 문자의 특별한 의미는 앞에 백슬래시를 추가하여 끌 수 있습니다. 따라서 foo*bar는 이름이 'foo', 별표 및 'bar'로 구성된 특정 파일을 참조합니다.

4.4.1 Wildcard Examples (와일드카드 예시)

와일드카드는 쉘에 의해 확장되는 규칙의 레시피에서 사용할 수 있습니다. 예를 들어 다음은 모든 개체 파일을 삭제하는 규칙입니다:

clean:
        rm -f *.o

와일드카드는 규칙의 전제 조건에서도 유용합니다. makefile의 다음 규칙에 따라 'make print'는 마지막으로 인쇄한 이후 변경된 모든 '.c' 파일을 인쇄합니다:

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

이 규칙은 인쇄를 빈 대상 파일로 사용합니다; 이벤트를 기록하기 위한 빈 대상 파일(Empty Target Files to Record Events을 참조하십시오. (자동 변수 '$?'는 변경된 파일만 인쇄하는 데 사용됩니다; 자동 변수(Automatic Variables)을 참조하십시오.)

변수를 정의할 때 와일드카드 확장은 발생하지 않습니다. 따라서 다음과 같이 작성하면:

objects = *.o

변수 객체의 값은 실제 문자열 '*.o'입니다. 그러나 대상 또는 전제 조건에서 개체 값을 사용하는 경우 와일드카드 확장이 해당 위치에서 발생합니다. 레시피에서 개체 값을 사용하는 경우 레시피가 실행될때 셸에서 와일드카드 확장을 수행할 수 있습니다. 개체를 확장으로 설정하려면 대신 다음을 사용하세요:

objects := $(wildcard *.o)

와일드카드 기능(Wildcard Function)을 참조하십시오.

4.4.2 Pitfalls of Using Wildcards (와일드카드 사용의 함정)

이제 여기에 와일드카드 확장을 사용하는 순진한 방법의 예가 있습니다. 이는 의도한 대로 수행되지 않습니다. 실행 파일 foo가 디렉토리의 모든 개체 파일로 만들어졌다고 가정하고 다음과 같이 작성합니다:

objects = *.o

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

객체의 값은 실제 문자열 '*.o'입니다. 와일드카드 확장은 foo에 대한 규칙에서 발생하므로 각각의 기존 '.o' 파일은 foo의 전제 조건이 되며 필요한 경우 다시 컴파일됩니다.

그러나 모든 '.o'파일을 삭제하면 어떻게 될까요? 와일드카드가 파일과 일치하지 않으면 그대로 남아 있으므로 foo는 이름이 이상한 *.o 파일에 종속됩니다. 그러한 파일이 존재하지 않을 가능성이 높기 때문에 make는 *.o를 만드는 방법을 알 수 없다는 오류를 표시합니다. 이것은 당신이 원하는 것이 아닙니다!

실제로는 와일드카드 확장을 통해 원하는 결과를 얻을 수 있지만 와일드카드 기능 및 문자열 대체를 비롯한 보다 정교한 기술이 필요합니다. 함수 와일드카드(The Function wildcard)을 참조하세요.

Microsoft 운영 체제(MS-DOS 및 MS-Windows)는 다음과 같이 백슬래시를 사용하여 경로 이름에서 디렉토리를 구분합니다:

  c:\foo\bar\baz.c

이것은 Unix 스타일의 c:/foo/bar/baz.c와 동일합니다(c: 부분은 소위 드라이브 문자입니다). make가 이러한 시스템에서 실행될때 경로 이름에서 백슬래시와 Unix 스타일의 슬래시를 지원합니다. 그러나 이 지원에는 백슬래시가 따옴표 문자인 와일드카드 확장이 포함되지 않습니다. 따라서 이러한 경우에는 Unix 스타일의 슬래시를 사용해야 합니다.

4.4.3 The Function wildcard (wildcard 함수)

와일드카드 확장은 규칙에서 자동으로 발생합니다. 그러나 와일드카드 확장은 일반적으로 변수가 설정되거나 함수의 인수 내부에서 발생하지 않습니다. 이러한 위치에서 와일드카드 확장을 수행하려면 다음과 같이 와일드카드 함수를 사용해야 합니다:

$(wildcard pattern...)

makefile의 어느 곳에서나 사용되는 이 문자열은 주어진 파일 이름 패턴중 하나와 일치하는 기존 파일 이름의 공백으로 구분된 목록으로 대체됩니다. 기존 파일 이름이 패턴과 일치하지 않으면 해당 패턴이 와일드카드 함수의 출력에서 생략됩니다. 이것은 일치하지 않는 와일드카드가 무시되는 것이 아니라 그대로 사용되는 규칙에서 작동하는 방식과 다릅니다(와일드 카드 함정(Wildcard Pitfall) 참조).

와일드카드 함수의 한 가지 용도는 다음과 같이 디렉토리에 있는 모든 C 소스 파일의 목록을 가져오는 것입니다:

$(wildcard *.c)

다음과 같이 결과에서 '.c' 접미사를 '.o'로 대체하여 C 소스 파일 목록을 개체 파일 목록으로 변경할 수 있습니다:

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

(여기서 우리는 patsubst라는 또 다른 함수를 사용했습니다. 문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)을 참조하십시오)

따라서 디렉토리에 있는 모든 C 소스 파일을 컴파일하고 함께 링크하는 메이크파일은 다음과 같이 작성할 수 있습니다:

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

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

(이는 C 프로그램 컴파일을 위한 암시적 규칙을 활용하므로 파일 컴파일을 위한 명시적 규칙을 작성할 필요가 없습니다. '='의 변형인 ':='에 대한 설명은 변수의 두가지 맛(The Two Flavors of Variables)을 참조하십시오.)

4.5 Searching Directories for Prerequisites (전제 조건에 대한 디렉토리 검색)

대규모 시스템의 경우 소스를 바이너리와 별도의 디렉토리에 두는 것이 종종 바람직합니다. make의 디렉토리 검색 기능은 전제 조건을 찾기 위해 자동으로 여러 디렉토리를 검색하여 이를 용이하게 합니다. 디렉토리 간에 파일을 재배포할 때 개별 규칙을 변경할 필요가 없으며 검색 경로만 변경할 수 있습니다.

4.5.1 VPATH: Search Path for All Prerequisites (VPATH: 모든 전제 조건에 대한 검색 경로)

make 변수 VPATH의 값은 make가 검색해야 하는 디렉토리 목록을 지정합니다. 대부분의 경우 디렉토리에는 현재 디렉토리에 없는 전제조건 파일이 포함될 것으로 예상됩니다. 그러나 make는 규칙의 전제 조건과 대상 모두에 대한 검색 목록으로 VPATH를 사용합니다.

따라서 대상 또는 전제조건으로 나열된 파일이 현재 디렉토리에 없으면 make는 VPATH에 나열된 디렉토리에서 해당 이름을 가진 파일을 검색합니다. 그 중 하나에서 파일이 발견되면 해당 파일이 전제 조건이 될 수 있습니다(아래 참조). 그런 다음 규칙은 현재 디렉토리에 모두 존재하는 것처럼 전제 조건 목록의 파일 이름을 지정할 수 있습니다. 디렉토리 검색으로 레시피 작성(Writing Recipes with Directory Search)을 참조하십시오.

VPATH 변수에서 디렉토리 이름은 콜론이나 공백으로 구분됩니다. 디렉토리가 나열되는 순서는 검색에서 make 다음에 오는 순서입니다. (MS-DOS 및 MS-Windows에서는 드라이브 문자 뒤의 경로 이름 자체에서 콜론을 사용할 수 있기 때문에 세미콜론이 VPATH에서 디렉토리 이름의 구분 기호로 사용됩니다)

예를 들어,

VPATH = src:../headers

specifies a path containing two directories, src and ../headers, which make searches in that order.
src 및 ../headers의 두 디렉토리가 포함된 경로를 지정하면 make는 그 순서대로 검색합니다.

이 VPATH 값을 사용하면 다음 규칙이 적용됩니다.

foo.o : foo.c

다음과 같이 작성된 것으로 해석됩니다:

foo.o : src/foo.c

foo.c 파일이 현재 디렉토리에 존재하지 않지만 src 디렉토리에 있다고 가정합니다.

4.5.2 The vpath Directive (vpath 지시문)

VPATH 변수와 유사하지만 더 선택적인 것은 vpath 지시문(소문자)으로, 이는 특정 패턴과 일치하는 파일 이름의 특정 클래스에 대한 검색 경로를 지정할 수 있도록 합니다. 따라서 한 클래스의 파일 이름에 대해 특정 검색 디렉토리를 제공하고 다른 파일 이름에 대해 다른 디렉토리(또는 없음)를 제공할 수 있습니다.

vpath 지시문에는 세 가지 형식이 있습니다:

vpath pattern directories
패턴과 일치하는 파일 이름에 대한 검색 경로 디렉토리를 지정하십시오.

검색 경로 디렉토리는 VPATH 변수에 사용된 검색 경로와 마찬가지로 콜론(MS-DOS 및 MS-Windows의 경우 세미콜론) 또는 공백으로 구분된 검색할 디렉토리 목록입니다.

vpath pattern
패턴과 관련된 검색 경로를 지웁니다.

vpath
이전에 vpath 지시문으로 지정된 모든 검색 경로를 지웁니다.

vpath 패턴은 '%' 문자를 포함하는 문자열입니다. 문자열은 검색 중인 전제조건의 파일 이름과 일치해야 하며, '%' 문자는 0개 이상의 문자 시퀀스와 일치해야 합니다(패턴 규칙에서와 같이, 패턴 규칙 정의 및 재정의(Defining and Redefining Pattern Rules) 참조). 예를 들어, %.h는 .h로 끝나는 파일과 일치합니다. ('%'가 없으면 패턴이 전제 조건과 정확히 일치해야하므로 자주 유용하지 않습니다.)

vpath 지시문 패턴의 '%' 문자는 앞에 백슬래시('\')를 사용하여 인용할 수 있습니다. 그렇지 않으면 '%' 문자를 인용하는 백슬래시가 더 많은 백슬래시로 인용될 수 있습니다. '%' 문자를 인용하는 백슬래시 또는 기타 백슬래시는 파일 이름과 비교되기 전에 패턴에서 제거됩니다. '%' 문자를 인용할 위험이 없는 백슬래시는 문제가 되지 않습니다.

현재 디렉토리에 전제조건이 존재하지 않을때 vpath 지시문의 패턴이 전제조건 파일의 이름과 일치하면 해당 지시문의 디렉토리는 VPATH 변수의 디렉토리와 마찬가지로(그리고 그 이전) 검색됩니다.

예를 들어,

vpath %.h ../headers

현재 디렉토리에서 파일을 찾을 수 없는 경우 ../headers 디렉토리에서 이름이 .h로 끝나는 전제조건을 찾도록 make에 지시합니다.

여러 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, bar, blish에서 '.c'로 끝나는 파일을 찾습니다.

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

디렉토리 검색을 통해 전제 조건이 발견되면 유형(일반 또는 선택)에 관계없이 찾은 경로 이름이 실제로 전제 조건 목록에서 제공하는 경로 이름이 아닐 수 있습니다. 디렉토리 검색을 통해 발견한 경로가 버려지는 경우가 있습니다.

디렉토리 검색을 통해 찾은 경로를 유지할지 포기할지 결정하는 알고리즘은 다음과 같습니다:

  1. makefile에 지정된 경로에 대상 파일이 없으면 디렉터리 검색을 수행합니다.

  2. 디렉터리 검색이 성공하면 해당 경로를 유지하고 이 파일을 대상으로 잠정 저장합니다.

  3. 이 대상의 모든 전제 조건은 이와 동일한 방법을 사용하여 검사됩니다.

  4. 전제 조건을 처리한 후 대상을 다시 빌드해야 할 수도 있고 그렇지 않을 수도 있습니다:

  5. 대상을 다시 빌드할 필요가 없는 경우 디렉터리 검색 중에 찾은 파일의 경로는 이 대상이 포함된 전제 조건 목록에 사용됩니다. 요컨대, make가 대상을 다시 빌드할 필요가 없으면 디렉토리 검색을 통해 찾은 경로를 사용합니다.

  6. 대상을 다시 빌드해야 하는 경우(오래된 경우) 디렉터리 검색 중에 찾은 경로 이름은 폐기되고 대상은 makefile에 지정된 파일 이름을 사용하여 다시 빌드됩니다. 간단히 말해서 make가 다시 빌드해야 하는 경우 대상은 디렉토리 검색을 통해 찾은 디렉토리가 아니라 로컬로 재빌드됩니다.

이 알고리즘은 복잡해 보일 수 있지만 실제로는 원하는 대로 정확히 일치하는 경우가 많습니다.

다른 버전의 make는 더 간단한 알고리즘을 사용합니다. 파일이 존재하지 않고 디렉토리 검색을 통해 찾은 경우 대상을 빌드해야 하는지 여부에 관계없이 해당 경로 이름이 항상 사용됩니다. 따라서 대상이 재구축되면 디렉터리 검색 중에 발견된 경로 이름에 생성됩니다.

실제로 이것이 디렉토리의 일부 또는 전체에 대해 원하는 동작인 경우 GPATH 변수를 사용하여 이를 표시할 수 있습니다.

GPATH는 VPATH와 동일한 구문 및 형식을 갖습니다(즉, 공백 또는 콜론으로 구분된 경로 이름 목록). GPATH에도 표시되는 디렉토리에서 디렉토리 검색을 통해 오래된 대상을 찾은 경우 해당 경로 이름은 삭제되지 않습니다. 대상은 확장된 경로를 사용하여 다시 작성됩니다.

4.5.4 Writing Recipes with Directory Search (디렉토리 검색으로 레시피 작성하기)

디렉토리 검색을 통해 다른 디렉토리에서 전제 조건이 발견되면 규칙의 레시피를 변경할 수 없습니다. 쓰여진대로 실행될겁니다. 따라서 make가 찾는 디렉토리에서 전제조건을 찾을 수 있도록 주의해서 레시피를 작성해야 합니다.

이것은 '$^'와 같은 자동 변수로 수행됩니다(자동 변수(Automatic Variables) 참조). 예를 들어, '$^'의 값은 발견된 디렉토리의 이름을 포함하여 규칙의 모든 전제 조건의 목록이고 '$@'의 값은 대상입니다. 따라서:

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

(CFLAGS 변수가 존재하므로 암시적 규칙에 따라 C 컴파일에 대한 플래그를 지정할 수 있습니다. 여기서는 일관성을 위해 이 변수를 사용하므로 모든 C 컴파일에 균일하게 영향을 미칩니다; 암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules)을 참조하십시오.)

종종 전제 조건에는 레시피에서 언급하고 싶지 않은 헤더 파일도 포함됩니다. 자동 변수 '$<'는 첫 번째 전제 조건일 뿐입니다:

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

4.5.5 Directory Search and Implicit Rules (디렉토리 검색 및 암시적 규칙)

VPATH 또는 vpath에 지정된 디렉토리를 통한 검색은 암시적 규칙을 고려하는 동안에도 발생합니다(암시적 규칙 사용(Using Implicit Rules) 참조).

예를 들어 foo.o 파일에 명시적 규칙이 없는 경우 make는 해당 파일이 존재하는 경우 foo.c를 컴파일하는 내장 규칙과 같은 암시적 규칙을 고려합니다. 이러한 파일이 현재 디렉토리에 없으면 적절한 디렉토리에서 해당 파일을 검색합니다. foo.c가 디렉토리에 존재하는 경우(또는 makefile에 언급된 경우) C 컴파일에 대한 암시적 규칙이 적용됩니다.

암시적 규칙의 레시피는 일반적으로 필요에 따라 자동 변수를 사용합니다. 결과적으로 추가 노력 없이 디렉토리 검색에서 찾은 파일 이름을 사용합니다.

디렉토리 검색은 링커와 함께 사용되는 라이브러리에 특별한 방식으로 적용됩니다. 이 특별한 기능은 이름이 '-lname' 형식인 전제조건을 작성할 때 작동합니다. (필수 조건은 일반적으로 파일의 이름이고 라이브러리의 파일 이름은 일반적으로 '-lname'이 아닌 libname.a처럼 보이기 때문에 여기서 이상한 일이 진행되고 있음을 알 수 있습니다.)

전제 조건의 이름이 '-lname' 형식을 가질 때 make는 libname.so 파일을 검색하여 특별히 처리하고, 찾지 못하면 현재 디렉토리의 libname.a 파일에 대해 vpath 일치에 의해 지정된 디렉토리에서 처리합니다. 검색 경로 및 VPATH 검색 경로를 찾은 다음 /lib, /usr/lib 및 prefix/lib 디렉토리(일반적으로 /usr/local/lib, 그러나 make의 MS-DOS/MS-Windows 버전은 prefix가 DJGPP 설치 트리의 루트로 정의됨).

예를 들어 시스템에 /usr/lib/libcurses.a 라이브러리가 있고 /usr/lib/libcurses.so 파일이 없는 경우

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

foo가 foo.c 또는 /usr/lib/libcurses.a보다 오래된 경우 'cc foo.c /usr/lib/libcurses.a -o foo' 명령이 실행됩니다.

검색할 기본 파일 세트는 libname.so 및 libname.a이지만 .LIBPATTERNS 변수를 통해 사용자 정의할 수 있습니다. 이 변수 값의 각 단어는 패턴 문자열입니다. '-lname'과 같은 전제 조건이 표시되면 make는 목록의 각 패턴에 있는 백분율을 이름으로 바꾸고 각 라이브러리 파일 이름을 사용하여 위의 디렉토리 검색을 수행합니다.

.LIBPATTERNS의 기본값은 위에서 설명한 기본 동작을 제공하는 'lib%.so lib%.a'입니다.

이 변수를 빈 값으로 설정하여 링크 라이브러리 확장을 완전히 끌 수 있습니다.

4.6 Phony Targets (가짜 대상)

가짜 대상은 실제로 파일 이름이 아닌 대상입니다. 오히려 명시적 요청을 할 때 실행될 레시피의 이름일 뿐입니다. 가짜 대상을 사용하는 두 가지 이유는 같은 이름의 파일과의 충돌을 피하고 성능을 향상시키기 위해서 입니다.

레시피가 대상 파일을 생성하지 않는 규칙을 작성하면 대상이 재작성될 때마다 레시피가 실행됩니다. 다음은 예입니다:

clean:
        rm *.o temp

rm 명령은 clean이라는 파일을 생성하지 않기 때문에 아마도 그러한 파일은 존재하지 않을 것입니다. 따라서 'make clean'을 말할 때마다 rm 명령이 실행됩니다.

이 예에서 clean이라는 파일이 이 디렉토리에 생성된 경우 clean 대상이 제대로 작동하지 않습니다. 전제 조건이 없기 때문에 clean은 항상 최신 상태로 간주되고 해당 레시피는 실행되지 않습니다. 이 문제를 방지하려면 다음과 같이 특수 대상 .PHONY(특수 내장 대상 이름 참조)의 전제 조건으로 만들어 대상을 가짜 대상으로 명시적으로 선언할 수 있습니다:

.PHONY: clean
clean:
        rm *.o temp

이 작업이 완료되면 clean이라는 파일이 있는지 여부에 관계없이 'make clean'이 레시피를 실행합니다.

가짜 대상은 make의 재귀 호출과 함께 유용합니다(make의 재귀 사용(Recursive Use of make) 참조). 이 상황에서 makefile은 종종 빌드될 서브디렉토리의 숫자를 나열하는 변수를 포함할 것입니다. 이것을 처리하는 간단한 방법은 다음과 같이 하위 디렉토리를 반복하는 레시피로 하나의 규칙을 정의하는 것입니다:

SUBDIRS = foo bar baz

subdirs:
        for dir in $(SUBDIRS); do \
          $(MAKE) -C $$dir; \
        done

그러나 이 방법에는 문제가 있습니다. 첫째, sub-make에서 감지된 모든 오류는 이 규칙에 의해 무시되므로 하나가 실패하더라도 나머지 디렉토리를 계속 빌드합니다. 이것은 오류를 기록하고 종료하는 쉘 명령을 추가하여 극복할 수 있지만, make가 -k 옵션과 함께 호출되더라도 불행히도 그렇게 할 것입니다. 두 번째, 그리고 아마도 더 중요한 것은 make의 타겟을 병렬로 빌드하는 기능을 활용할 수 없다는 것입니다(병렬 실행(Parallel Execution) 참조). 규칙이 하나만 있기 때문입니다.

하위 디렉토리를 .PHONY 타겟으로 선언함으로써 (하위 디렉토리는 분명히 항상 존재하므로 이를 수행해야 합니다. 그렇지 않으면 빌드되지 않습니다) 다음 문제를 제거할 수 있습니다:

SUBDIRS = foo bar baz

.PHONY: subdirs $(SUBDIRS)

subdirs: $(SUBDIRS)

$(SUBDIRS):
        $(MAKE) -C $@

foo: baz

여기서 우리는 baz 서브디렉토리가 완성될 때까지 foo 서브디렉토리를 만들 수 없다고 선언했습니다. 이러한 종류의 관계 선언은 병렬 빌드를 시도할 때 특히 중요합니다.

암시적 규칙 검색(암시적 규칙(Implicit Rules) 참조)은 .PHONY 대상에 대해 건너뜁니다. 이것이 대상을 .PHONY로 선언하는 것이 실제 존재하는 파일에 대해 걱정하지 않아도 성능에 좋은 이유입니다.

가짜 대상은 실제 대상 파일의 전제 조건이 되어서는 안 됩니다. 그렇다면 make 가 해당 파일을 업데이트할 때마다 레시피가 실행됩니다. 가짜 대상이 실제 대상의 전제 조건이 아닌한 가짜 대상 레시피는 가짜 대상이 지정된 목표일 때만 실행됩니다(목표를 지정하는 인수(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'은 개체(object) 파일, 차이점(diff) 파일 및 'program' 파일을 삭제합니다:

.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
        rm program

cleanobj :
        rm *.o

cleandiff :
        rm *.diff

4.7 Rules without Recipes or Prerequisites (레시피 또는 전제 조건이 없는 규칙)

규칙에 전제 조건이나 레시피가 없고 규칙의 대상이 존재하지 않는 파일인 경우 make는 규칙이 실행될 때마다 이 대상이 업데이트되었다고 상상합니다. 이것은 이것에 의존하는 모든 대상이 항상 레시피를 실행함을 의미합니다.

이걸 예로 들면 다음과 같습니다:

clean: FORCE
        rm $(objects)
FORCE:

Here the target 'FORCE' satisfies the special conditions, so the target clean that depends on it is forced to run its recipe. There is nothing special about the name 'FORCE', but that is one name commonly used this way.
여기서 타겟 'FORCE'는 특수 조건을 만족하므로 이에 의존하는 타겟 clean은 강제로 레시피를 실행합니다. 'FORCE'라는 이름이 특별한 것은 아니지만, 일반적으로 이런 식으로 사용되는 이름중 하나입니다.

보시다시피 'FORCE'를 이런 식으로 사용하면 '.PHONY: clean'을 사용하는 것과 동일한 결과를 얻을 수 있습니다.

'.PHONY'를 사용하는 것이 더 명확하고 효율적입니다. 그러나 다른 버전의 make는 '.PHONY'를 지원하지 않습니다. 따라서 'FORCE'는 많은 메이크파일에 나타납니다. 가짜 대상(Phony Targets)을 참조하십시오.

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

빈 대상은 가짜 대상의 변형입니다. 때때로 명시적으로 요청하는 작업에 대한 레시피를 보관하는데 사용됩니다. 가짜 대상과 달리 이 대상 파일은 실제로 존재할 수 있습니다. 그러나 파일의 내용은 중요하지 않으며 일반적으로 비어 있습니다.

빈 대상 파일의 목적은 규칙의 레시피가 마지막으로 실행된 시간을 마지막 수정 시간과 함께 기록하는 것입니다. 레시피의 명령 중 하나가 대상 파일을 업데이트하는 터치 명령이기 때문에 그렇게 합니다.

빈 대상 파일에는 몇 가지 전제 조건이 있어야 합니다 (그렇지 않으면 의미가 없음). 빈 대상을 다시 만들도록 요청할 때 전제 조건이 대상보다 최신인 경우 레시피가 실행됩니다. 즉, 마지막으로 대상을 다시 만든 이후 전제 조건이 변경된 경우입니다. 다음은 예입니다:

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

이 규칙을 사용하면 마지막 'make print' 이후에 소스 파일이 변경된 경우 'make print'가 lpr 명령을 실행합니다. 자동 변수 '$?'는 변경된 파일만 인쇄하는 데 사용됩니다(자동 변수(Automatic Variables) 참조).

4.9 Special Built-in Target Names (특수 내장 대상 이름)

특정 이름은 대상으로 표시되는 경우 특별한 의미를 갖습니다.

  • .PHONY

    특수 대상 .PHONY의 전제 조건은 가짜 대상으로 간주됩니다. 그러한 대상을 고려할 때 make는 해당 이름을 가진 파일이 존재하는지 여부 또는 최종 수정 시간에 관계없이 무조건 레시피를 실행합니다. 가짜 대상(Phony Targets)을 참조하십시오.

  • .SUFFIXES

    특수 대상 .SUFFIXES의 전제 조건은 접미사 규칙을 확인하는데 사용할 접미사 목록입니다. 구식 접미사 규칙(Old-Fashioned Suffix Rules)을 참조하십시오.

  • .DEFAULT

    .DEFAULT에 대해 지정된 레시피는 규칙을 찾을 수 없는 모든 대상에 사용됩니다 (명시적 규칙 또는 암시적 규칙). 최후의 수단(Last Resort)을 참조하십시오. .DEFAULT 레시피가 지정되면 규칙의 대상이 아닌 전제 조건으로 언급된 모든 파일에서 해당 레시피가 대신 실행됩니다. 암시적 규칙 검색 알고리즘(Implicit Rule Search Algorithm)을 참조하십시오.

  • .PRECIOUS

    .PRECIOUS가 의존하는 대상은 다음과 같은 특별 처리가 제공됩니다: 레시피 실행 중에 make가 종료되거나 중단되면 대상은 삭제되지 않습니다. make 중단 또는 종료(Interrupting or Killing make)를 참조하십시오. 또한 대상이 중간 파일인 경우 일반적으로 수행되는 것처럼 더 이상 필요하지 않은 후 삭제되지 않습니다. 암시적 규칙 체인(Chains of Implicit Rules)을 참조하십시오. 이 후자의 측면에서 .SECONDARY 특수 대상과 겹칩니다.

    또한 암시적 규칙의 대상 패턴('%.o'와 같은)을 특수 대상 .PRECIOUS의 전제 조건 파일로 나열하여 대상 패턴이 해당 파일의 이름과 일치하는 규칙에 의해 생성된 중간 파일을 보존할 수 있습니다.

  • .INTERMEDIATE

    .INTERMEDIATE가 의존하는 대상은 중간 파일로 처리됩니다. 암시적 규칙 체인(Chains of Implicit Rules)을 참조하십시오. 전제 조건이 없는 .INTERMEDIATE는 효과가 없습니다.

  • .SECONDARY

    .SECONDARY가 의존하는 대상은 자동으로 삭제되지 않는다는 점을 제외하고 중간 파일로 처리됩니다. 암시적 규칙 체인(Chains of Implicit Rules)을 참조하십시오.

    전제 조건이 없는 .SECONDARY는 모든 대상이 2차로 처리되도록 합니다 (즉, 중간으로 간주되기 때문에 대상이 제거되지 않음).

  • .SECONDEXPANSION

    .SECONDEXPANSION이 메이크파일의 어느 곳에서나 대상으로 언급되면, 나타난 후에 정의된 모든 전제조건 목록은 모든 메이크파일을 읽은 후 두 번째로 확장됩니다. 2차 확장(Secondary Expansion)을 참조하십시오.

  • .DELETE_ON_ERROR

    .DELETE_ON_ERROR가 makefile의 어느 곳에서나 대상으로 언급되면 make는 규칙의 대상이 변경되고 해당 레시피가 신호를 수신할 때와 마찬가지로 0이 아닌 종료 상태로 종료되는 경우 대상을 삭제합니다. 레시피의 오류(Errors in Recipes)를 참조하십시오.

  • .IGNORE

    .IGNORE에 대한 전제 조건을 지정하면 make는 해당 특정 파일에 대한 레시피 실행시 오류를 무시합니다. .IGNORE에 대한 레시피(있는 경우)는 무시됩니다.

    전제 조건이 없는 대상으로 언급된 경우 .IGNORE는 모든 파일에 대한 레시피 실행 오류를 무시한다고 말합니다. 이 '.IGNORE' 사용은 과거 호환성을 위해서만 지원됩니다. 이것은 makefile의 모든 레시피에 영향을 미치기 때문에 그다지 유용하지 않습니다. 특정 레시피의 오류를 무시하려면 보다 선별적인 방법을 사용하는 것이 좋습니다. 레시피의 오류(Errors in Recipes)를 참조하십시오.

  • .LOW_RESOLUTION_TIME

    .LOW_RESOLUTION_TIME에 대한 전제 조건을 지정하면 make는 이러한 파일이 저해상도 타임스탬프를 생성하는 명령에 의해 생성된다고 가정합니다. .LOW_RESOLUTION_TIME 대상에 대한 레시피는 무시됩니다.

    많은 최신 파일 시스템의 고해상도 파일 타임스탬프는 파일이 최신 상태라고 잘못 판단할 가능성을 줄입니다. 불행히도 일부 호스트는 고해상도 파일 타임 스탬프를 설정하는 방법을 제공하지 않으므로 파일의 타임 스탬프를 명시적으로 설정하는 'cp -p'와 같은 명령은 하위 초(second) 부분을 삭제해야 합니다. 이러한 명령에 의해 파일이 생성되면 make가 파일이 오래되었다고 잘못 결론짓지 않도록 .LOW_RESOLUTION_TIME의 전제 조건으로 나열해야 합니다. 예를 들어:

    .LOW_RESOLUTION_TIME: dst
    dst: src
            cp -p src dst

    'cp -p'는 src 타임스탬프의 1초 미만 부분을 버리기 때문에 dst는 최신 상태일지라도 일반적으로 src보다 약간 오래된 것입니다. .LOW_RESOLUTION_TIME 라인은 타임 스탬프가 src의 타임 스탬프가 있는 초의 시작 부분에 있는 경우 make가 dst를 최신것으로 간주하도록 합니다.

    아카이브 형식의 제한으로 인해 아카이브 구성원 타임스탬프는 항상 저해상도입니다. make가 자동으로 수행하므로 아카이브 멤버를 .LOW_RESOLUTION_TIME의 전제 조건으로 나열할 필요가 없습니다.

  • .SILENT

    .SILENT에 대한 전제 조건을 지정하면 make는 특정 파일을 실행하기 전에 다시 만드는데 사용되는 레시피를 인쇄하지 않습니다. .SILENT의 레시피는 무시됩니다.

    전제 조건이 없는 대상으로 언급된 경우 .SILENT는 실행하기 전에 레시피를 인쇄하지 말라고 말합니다. 특정 레시피 명령줄을 침묵시키기 위해 보다 선택적인 방법을 사용할 수도 있습니다. 레시피 반향(Recipe Echoing)을 참조하십시오. 특정 make 실행에 대한 모든 레시피를 침묵시키려면 '-s' 또는 '--silent' 옵션을 사용하십시오 (옵션 요약(Options Summary) 참조).

  • .EXPORT_ALL_VARIABLES

    단순히 대상으로 언급되어 기본적으로 모든 변수를 자식 프로세스로 내보내도록 make에 지시합니다. Sub-make에 변수 통신(Communicating Variables to a Sub-make)을 참조하십시오.

  • .NOTPARALLEL

    .NOTPARALLEL이 대상으로 언급되면 '-j' 옵션이 제공되더라도 이 make 호출은 순차적으로 실행됩니다. 재귀적으로 호출된 모든 make 명령은 여전히 병렬로 레시피를 실행합니다 (makefile에도 이 대상이 포함되어 있지 않은 경우). 이 대상에 대한 모든 전제 조건은 무시됩니다.

  • .ONESHELL

    .ONESHELL이 대상으로 언급된 경우 대상이 빌드될때 각 줄이 별도로 호출되는것이 아니라 셸의 단일 호출에 레시피의 모든 라인이 제공됩니다(레시피 실행(Recipe Execution) 참조).

  • .POSIX

    .POSIX가 대상으로 언급되면 makefile이 구문 분석되고 POSIX 준수 모드에서 실행됩니다. 이것은 POSIX 준수 makefile만 허용된다는 의미가 아닙니다. 모든 고급 GNU make 기능을 계속 사용할 수 있습니다. 오히려 이 타겟은 make의 기본 동작이 다른 영역에서 make가 POSIX에서 요구하는 대로 동작하도록 합니다.

    특히, 이 대상이 언급되면 쉘이 -e 플래그를 전달한 것처럼 레시피가 호출됩니다: 레시피에서 첫 번째 실패 명령은 레시피를 즉시 실패하게 만듭니다.

정의된 암시적 규칙 접미사는 대상으로 표시되는 경우 특수 대상으로 간주되며 '.c.o' 와 같은 두 접미사의 연결도 마찬가지입니다. 이러한 대상은 암시적 규칙을 정의하는 더 이상 사용되지 않는 방식인 접미사 규칙입니다 (그러나 여전히 널리 사용되는 방식). 원칙적으로 대상 이름을 둘로 나누고 두 조각을 접미사 목록에 추가하면 이러한 방식으로 대상 이름이 특별할 수 있습니다. 실제로 접미사는 일반적으로 '.'로 시작하므로 이러한 특수 대상 이름도 '.'로 시작합니다. 구식 접미사 규칙(Old-Fashioned Suffix Rules)을 참조하십시오.

4.10 Multiple Targets in a Rule (규칙의 여러 대상)

명시적 규칙에 여러 대상이 있는 경우 독립 대상 또는 그룹화된 대상의 두 가지 가능한 방법중 하나로 처리할 수 있습니다. 처리 방식은 대상 목록 뒤에 표시되는 구분 기호에 따라 결정됩니다.

Rules with Independent Targets (독립 대상이 있는 규칙)

표준 대상 구분 기호 ':' 를 사용하는 규칙은 독립적인 대상을 정의합니다. 이는 중복된 전제 조건 및 레시피를 사용하여 각 대상에 대해 동일한 규칙을 한 번 작성하는 것과 같습니다. 일반적으로 레시피는 빌드 중인 대상을 지정하기 위해 '$@'와 같은 자동 변수를 사용합니다.

독립 대상이 있는 규칙은 다음 두 가지 경우에 유용합니다:

  • 레시피 없이 전제 조건만 원하는 경우. 예를 들어:

    kbd.o command.o files.o: command.h

    언급된 세 가지 목적 파일 각각에 대한 추가 전제 조건을 제공합니다. 다음과 같이 쓰는 경우와 같습니다.

    kbd.o: command.h
    command.o: command.h
    files.o: command.h
  • 유사한 레시피가 모든 대상에 대해 작동합니다. 자동 변수 '$@'는 명령으로 다시 만들 특정 대상을 대체하는데 사용할 수 있습니다(자동 변수(Automatic Variables) 참조). 예를 들어:

    bigoutput littleoutput : text.g
            generate text.g -$(subst output,,$@) > $@

    는 다음과 같습니다.

    bigoutput : text.g
            generate text.g -big > bigoutput
    littleoutput : text.g
            generate text.g -little > littleoutput

    여기서 우리는 가상의 프로그램 generate가 '-big'이 주어지거나'-little'이 주어지는 두 가지 유형의 출력을 만든다고 가정합니다. subst 함수에 대한 설명은 문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오.

변수 '$@'를 사용하여 레시피를 변경할 수 있는 것처럼 대상에 따라 전제 조건을 변경하려고 한다고 가정합니다. 일반 규칙에서는 여러 대상에 대해 이 작업을 수행할 수 없지만 정적 패턴 규칙에서는 수행할 수 있습니다. 정적 패턴 규칙(Static Pattern Rules)을 참조하십시오.

Rules with Grouped Targets (그룹화된 대상이 있는 규칙)

독립 대상 대신 단일 호출에서 여러 파일을 생성하는 레시피가 있는 경우 그룹화된 대상을 사용하도록 규칙을 선언하여 해당 관계를 표현할 수 있습니다. 그룹화된 대상 규칙은 구분 기호 &:를 사용합니다 (여기서 '&'는 "모두(all)"를 의미하는 데 사용됨).

make가 그룹화된 대상중 하나를 빌드할때 그룹의 다른 모든 대상도 레시피 호출의 결과로 생성된다는 것을 이해합니다. 또한 그룹화된 대상중 일부만 오래되었거나 make가 누락된 경우 레시피를 실행하면 모든 대상이 업데이트된다는 사실을 알게 됩니다.

예를 들어 이 규칙은 그룹화된 대상을 정의합니다:

foo bar biz &: baz boz
        echo $^ > foo
        echo $^ > bar
        echo $^ > biz

그룹화된 대상의 레시피를 실행하는 동안 자동 변수 '$@'는 규칙을 트리거한 그룹의 특정 대상 이름으로 설정됩니다. 그룹화된 대상 규칙의 레시피에서 이 변수에 의존하는 경우 주의해야 합니다.

독립 대상과 달리 그룹화된 대상 규칙에는 레시피가 포함되어야 합니다. 그러나 그룹화된 대상의 구성원인 대상은 레시피가 없는 독립 대상 규칙 정의에도 나타날 수 있습니다.

각 대상에는 연결된 레시피가 하나만 있을 수 있습니다. 그룹화된 대상이 독립적인 대상 규칙이나 레시피가 있는 다른 그룹화된 대상 규칙에 나타나면 경고를 받고 후자의 레시피가 이전의 레시피를 대체합니다. 또한 대상은 이전 그룹에서 제거되고 새 그룹에만 나타납니다.

대상이 여러 그룹에 나타나도록 하려면 해당 대상을 포함하는 모든 그룹을 선언할 때 이중 콜론 그룹화된 대상 구분 기호 &::를 사용해야 합니다. 그룹화된 더블 콜론 대상은 각각 독립적으로 간주되며, 여러 대상중 하나 이상이 업데이트되어야 하는 경우 그룹화된 각 더블 콜론 규칙의 레시피가 최대 한 번 실행됩니다.

4.11 Multiple Rules for One Target (하나의 대상에 대한 여러 규칙)

하나의 파일이 여러 규칙의 대상이 될 수 있습니다. 모든 규칙에 언급된 모든 필수 구성 요소는 대상에 대한 하나의 필수 구성 요소 목록으로 병합됩니다. 대상이 규칙의 전제 조건보다 오래된 경우 레시피가 실행됩니다.

파일에 대해 하나의 레시피만 실행할 수 있습니다. 하나 이상의 규칙이 동일한 파일에 대한 레시피를 제공하는 경우 make는 마지막으로 제공된 것을 사용하고 오류 메시지를 인쇄합니다. (특별한 경우로 파일 이름이 점으로 시작하면 오류 메시지가 인쇄되지 않습니다. 이 이상한 동작은 make의 다른 구현과의 호환성을 위한 것입니다만... 이런식의 사용을 피해야 합니다.) 때때로 동일한 대상이 메이크파일의 다른 부분에 정의된 여러 레시피를 호출하도록 하는 것이 유용합니다. 이를 위해 이중 콜론 규칙(더블 콜론 참조)을 사용할 수 있습니다.

전제 조건만 있는 추가 규칙을 사용하여 한 번에 많은 파일에 몇 가지 추가 전제 조건을 제공할 수 있습니다. 예를 들어, 메이크 파일에는 생성중인 시스템의 모든 컴파일러 출력 파일 목록이 포함된 객체와 같은 변수가 있는 경우가 많습니다. config.h가 변경되면 모두 다시 컴파일해야 한다고 말하는 쉬운 방법은 다음과 같이 작성하는 것입니다:

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

이것은 실제로 개체 파일을 만드는 방법을 지정하는 규칙을 변경하지 않고 삽입하거나 빼낼 수 있으므로 간헐적으로 추가 전제 조건을 추가하려는 경우 사용하기 편리한 형식입니다.

또 다른 문제는 make 명령줄 인수로 설정한 변수로 추가 전제 조건을 지정할 수 있다는 것입니다(변수 재정의(Overriding Variables) 참조). 예를 들어,

extradeps=
$(objects) : $(extradeps)

즉, 'make extradeps=foo.h' 명령은 foo.h를 각 개체 파일의 전제 조건으로 간주하지만 일반 'make'는 그렇지 않습니다.

대상에 대한 명시적 규칙에 레시피가 없으면 적용 가능한 암시적 규칙을 검색하여 하나를 찾습니다. 암시적 규칙 사용(Using Implicit Rules) 참조).

4.12 Static Pattern Rules (정적 패턴 규칙)

정적 패턴 규칙은 여러 대상을 지정하고 대상 이름을 기반으로 각 대상에 대한 전제 조건 이름을 구성하는 규칙입니다. 대상이 동일한 전제 조건을 가질 필요가 없기 때문에 여러 대상이 있는 일반 규칙보다 더 일반적입니다. 전제 조건은 유사해야 하지만 반드시 동일하지는 않습니다.

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

다음은 정적 패턴 규칙의 구문입니다:

targets ...: target-pattern: prereq-patterns ...
        recipe
        ...

대상 목록은 규칙이 적용되는 대상을 지정합니다. 대상은 일반 규칙의 대상과 마찬가지로 와일드카드 문자를 포함할 수 있습니다 (파일 이름에 와일드카드 문자 사용(Using Wildcard Characters in File Names) 참조).

'target-pattern' 및 'prereq-patterns'는 각 대상의 전제 조건을 계산하는 방법을 말합니다. 각 대상은 대상 패턴과 일치하여 대상 이름의 일부인 어간을 추출합니다. 이 어간은 전제 조건 이름을 만들기 위해 각 prereq 패턴으로 대체됩니다(각 prereq 패턴에서 하나씩).

각 패턴에는 일반적으로 문자 '%'가 한 번만 포함됩니다. 대상 패턴이 대상과 일치하면 '%'는 대상 이름의 모든 부분과 일치할 수 있습니다. 이 부분을 어간(stem) 이라고 합니다. 나머지 패턴은 정확히 일치해야 합니다. 예를 들어 대상 foo.o는 'foo'를 어간으로 사용하여 '%.o' 패턴과 일치합니다. 대상 foo.c 및 foo.out은 해당 패턴과 일치하지 않습니다.

각 대상에 대한 전제 조건 이름은 각 전제 패턴에서 '%'를 어간으로 대체하여 만듭니다. 예를 들어, 하나의 전제 조건 패턴이 %.c인 경우 어간 'foo'를 대체하면 전제 조건 이름이 foo.c가 됩니다. '%'를 포함하지 않는 전제조건 패턴을 작성하는 것은 합법적입니다. 이 전제 조건은 모든 대상에 대해 동일합니다.

패턴 규칙의 '%' 문자는 앞에 백슬래시('\')를 사용하여 인용할 수 있습니다. 그렇지 않으면 '%' 문자를 인용하는 백슬래시가 더 많은 백슬래시로 인용될 수 있습니다. '%' 문자를 인용하는 백슬래시 또는 기타 백슬래시는 파일 이름과 비교되거나 어간이 대체되기 전에 패턴에서 제거됩니다. '%' 문자를 인용할 위험이 없는 백슬래시는 문제가 되지 않습니다. 예를 들어 the\%weird\%pattern\ 패턴은 작동하는 '%' 문자 앞에 'the%weird\'가 있고 그 뒤에는 'pattern\'이 있습니다. 마지막 두 개의 백슬래시는 '%' 문자에 영향을 줄 수 없기 때문에 그대로 둡니다.

다음은 해당 .c 파일에서 foo.o 및 bar.o를 각각 컴파일하는 예입니다:

objects = foo.o bar.o

all: $(objects)

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

여기서 '$<'는 전제 조건의 이름을 보유하는 자동 변수이고 '$@'는 대상의 이름을 보유하는 자동 변수입니다. 자동 변수(Automatic Variables)를 참조하십시오.

지정된 각 대상은 대상 패턴과 일치해야 합니다. 그렇지 않은 각 대상에 대해 경고가 발행됩니다. 파일 목록이 있고 그 중 일부만 패턴과 일치하는 경우 필터 함수를 사용하여 일치하지 않는 파일 이름을 제거할 수 있습니다 (문자열 대체 및 분석을 위한 함수(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 loss.o이고 첫 번째 정적 패턴 규칙은 해당 C 소스 파일을 컴파일하여 이러한 각 개체 파일을 업데이트하도록 합니다. '$(filter %.elc,$(files))'의 결과는 foo.elc이므로 파일은 foo.el에서 만들어집니다.

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

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

When the generate command is run, $ will expand to the stem, either 'big' or 'little'.
generate 명령이 실행되면 $
는 'big' 또는 'little' 어간으로 확장됩니다.

4.12.2 Static Pattern Rules versus Implicit Rules (정적 패턴 규칙 대 암시적 규칙)

정적 패턴 규칙은 패턴 규칙으로 정의된 암시적 규칙과 많은 공통점이 있습니다 (패턴 규칙 정의 및 재정의(Defining and Redefining Pattern Rules) 참조). 둘 다 대상에 대한 패턴과 전제 조건 이름을 구성하는 패턴이 있습니다. 차이점은 규칙이 적용되는 시점을 make가 결정하는 방법에 있습니다.

암시적 규칙은 패턴과 일치하는 모든 대상에 적용할 수 있지만 대상에 달리 지정된 레시피가 없고 전제 조건을 찾을 수 있는 경우에만 적용됩니다. 둘 이상의 암시적 규칙이 적용 가능한 것으로 나타나면 하나만 적용됩니다. 선택은 규칙의 순서에 따라 다릅니다.

대조적으로, 정적 패턴 규칙은 규칙에서 지정하는 정확한 대상 목록에 적용됩니다. 다른 대상에는 적용할 수 없으며 항상 지정된 각 대상에 적용됩니다. 두 개의 상충되는 규칙이 적용되고 둘 다 레시피가 있으면 오류입니다.

정적 패턴 규칙은 다음과 같은 이유로 암시적 규칙보다 나을 수 있습니다:

  • 이름을 구문적으로 분류할 수 없지만 명시적 목록으로 제공할 수 있는 몇 가지 파일에 대해 일반적인 암시적 규칙을 재정의할 수 있습니다.

  • 사용 중인 디렉토리의 정확한 내용을 확신할 수 없는 경우 make가 잘못된 암시적 규칙을 사용하도록 유도할 수 있는 다른 관련 없는 파일이 있는지 확신할 수 없습니다. 선택은 암시적 규칙 검색이 수행되는 순서에 따라 달라질 수 있습니다. 정적 패턴 규칙을 사용하면 불확실성이 없습니다. 각 규칙은 지정된 대상에 정확하게 적용됩니다.

4.13 Double-Colon Rules (이중 콜론 규칙)

이중 콜론 규칙은 대상 이름 뒤에 ':' 대신 '::'로 작성된 명시적 규칙입니다. 동일한 대상이 둘 이상의 규칙에 나타나는 경우 일반 규칙과 다르게 처리됩니다. 이중 콜론이 있는 패턴 규칙은 완전히 다른 의미를 갖습니다 (무엇이든 일치하는 규칙(Match-Anything Rules) 참조).

대상이 여러 규칙에 나타날 때 모든 규칙은 동일한 유형이어야 합니다: 모두 일반 유형 이거나 모두 이중 콜론 유형. 이중 콜론인 경우 각각은 서로 독립적입니다. 대상이 해당 규칙의 전제 조건보다 오래된 경우 각 이중 콜론 규칙의 레시피가 실행됩니다. 해당 규칙에 대한 전제 조건이 없으면 해당 레시피가 항상 실행됩니다 (대상이 이미 존재하더라도). 이로 인해 이중 콜론 규칙이 실행되지 않거나, 일부 또는 모두 실행될 수 있습니다.

동일한 대상에 대한 이중 콜론 규칙은 실제로 서로 완전히 별개입니다. 각 이중 콜론 규칙은 대상이 다른 규칙이 처리되는 것처럼 개별적으로 처리됩니다.

대상에 대한 이중 콜론 규칙은 makefile에 나타나는 순서대로 실행됩니다. 그러나 이중 콜론 규칙이 실제로 의미가 있는 경우는 레시피 실행 순서가 중요하지 않은 경우입니다.

이중 콜론 규칙은 다소 모호하고 그다지 유용하지 않습니다. 업데이트를 유발한 전제 조건 파일에 따라 대상 업데이트에 사용된 방법이 달라지는 경우에 대한 메커니즘을 제공하며 이러한 경우는 드뭅니다.

각 이중 콜론 규칙은 레시피를 지정해야 합니다. 그렇지 않은 경우 적용되는 경우 암시적 규칙이 사용됩니다. 암시적 규칙 사용(Using Implicit Rules)을 참조하십시오.

4.14 Generating Prerequisites Automatically (전제 조건 자동 생성)

프로그램을 위한 makefile에서 작성해야 하는 많은 규칙은 종종 일부 개체 파일이 일부 헤더 파일에 의존한다고 말합니다. 예를 들어 main.c가 #include를 통해 defs.h를 사용하는 경우 다음과 같이 작성합니다:

main.o: defs.h

defs.h가 변경될 때마다 main.o를 다시 만들어야 한다는 것을 make가 알 수 있도록 이 규칙이 필요합니다. 큰 프로그램의 경우 makefile에 수십 개의 그러한 규칙을 작성해야 한다는 것을 알 수 있습니다. 그리고 #include를 추가하거나 제거할 때마다 makefile을 업데이트하는데 항상 매우 주의해야 합니다.

이러한 번거로움을 피하기 위해 대부분의 최신 C 컴파일러는 소스 파일의 #include 행을 보고 이러한 규칙을 작성할 수 있습니다. 일반적으로 이것은 컴파일러에 대한 '-M' 옵션으로 수행됩니다. 예를 들어 다음 명령은 다음과 같습니다:

cc -M main.c

출력을 생성합니다:

main.o : main.c defs.h

따라서 더 이상 모든 규칙을 직접 작성할 필요가 없습니다. 컴파일러가 당신을 위해 그것을 할 것입니다.

이러한 규칙은 makefile에서 main.o를 언급하는 것으로 구성되므로 암시적 규칙 검색에 의해 중간 파일로 간주될 수 없습니다. 이것은 make가 파일을 사용한 후에 파일을 제거하지 않는다는 것을 의미합니다. 암시적 규칙 체인(Chains of Implicit Rules)을 참조하십시오.

이전 make 프로그램에서는 이 컴파일러 기능을 사용하여 'make depend'과 같은 명령으로 필요에 따라 필수 구성 요소를 생성하는 것이 전통적인 관행 이었습니다. 이 명령은 자동으로 생성된 모든 전제 조건을 포함하는 파일 종속을 만듭니다. 그런 다음 makefile은 포함을 사용하여 읽을 수 있습니다(Include 참조).

GNU make에서 makefile을 다시 만드는 기능은 이 관행을 쓸모없게 만듭니다. make는 항상 오래된 makefile을 재생성하기 때문에 전제 조건을 재생성하도록 명시적으로 말할 필요가 없습니다. Makefile 재작성(Remaking Makefiles)을 참조하십시오.

자동 전제조건 생성을 위해 권장하는 방법은 각 소스 파일에 해당하는 하나의 메이크파일을 갖는 것입니다. 각 소스 파일 name.c에 대해 name.o 개체 파일이 의존하는 파일을 나열하는 makefile name.d가 있습니다. 이렇게 하면 변경된 소스 파일만 다시 스캔하여 새 전제조건을 생성하면 됩니다.

다음은 name.c라는 C 소스 파일에서 name.d라는 전제 조건 파일(즉, makefile)을 생성하는 패턴 규칙입니다:

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

패턴 규칙 정의에 대한 정보는 패턴 규칙(Pattern Rules)을 참조하십시오. 쉘에 대한 '-e' 플래그는 $(CC) 명령(또는 다른 명령)이 실패하면(0이 아닌 상태로 종료) 쉘이 즉시 종료되도록 합니다.

GNU C 컴파일러를 사용하면 '-M' 대신 '-MM' 플래그를 사용할 수 있습니다. 이것은 시스템 헤더 파일에 대한 전제조건을 생략합니다. 자세한 내용은 GNU CC 사용시 전처리기를 제어하는 옵션(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 지시문을 사용하여 파일을 모두 읽어들입니다. Include를 참조하십시오. 예를 들어:

sources = foo.c bar.c

include $(sources:.c=.d)

(이 예는 소스 파일 'foo.c bar.c'의 목록을 전제 조건 makefile의 목록인 'foo.d bar.d'로 변환하기 위해 대체 변수 참조를 사용합니다. 대체 참조에 대한 전체 정보는 대체 참조(Substitution Refs)를 참조하십시오.) '.d' 파일은 다른 것과 마찬가지로 makefile이기 때문에 make는 더 이상의 작업 없이 필요에 따라 파일을 다시 만듭니다. Makefile 재작성(Remaking Makefiles)을 참조하십시오.

'.d' 파일에는 대상 정의가 포함되어 있습니다. makefile의 첫 번째 기본 목표 뒤에 include 지시문을 배치해야 합니다. 그렇지 않으면 임의의 개체 파일이 기본 목표가 되는 위험을 감수해야 합니다. Make 작동 방식(How Make Works)을 참조하십시오.


5. Writing Recipes in Rules (규칙에 레시피 작성)

규칙의 레시피는 나타나는 순서대로 한 번에 하나씩 실행할 하나 이상의 셸 명령줄로 구성됩니다. 일반적으로 이러한 명령을 실행하면 규칙의 대상이 최신 상태가 됩니다.

사용자는 다양한 쉘 프로그램을 사용하지만 makefile의 레시피는 makefile이 달리 지정하지 않는한 항상 /bin/sh에 의해 해석됩니다. 레시피 실행(Recipe Execution)을 참조하십시오.

5.1 Recipe Syntax (레시피 구문)

Makefile은 하나의 파일에 실제로 두 개의 별개의 구문이 있다는 특이한 속성을 가지고 있습니다. 대부분의 makefile은 'make 구문'을 사용합니다(Makefile 작성(Writing Makefiles) 참조). 그러나 레시피는 셸에서 해석해야 하므로 '셸 구문'을 사용하여 작성됩니다. make 프로그램은 쉘 구문을 이해하려고 시도하지 않습니다. 쉘에 전달하기 전에 레시피의 내용에 대해 매우 적은 특정 번역만 수행합니다.

첫 번째 레시피 라인은 세미콜론을 사용하여 target-and-prerequisites 라인에 첨부될 수 있다는 점을 제외하고 레시피의 각 라인은 탭(또는 .RECIPEPREFIX 변수 값의 첫 번째 문자, 특수 변수(Special Variables) 참조)으로 시작해야 합니다. 탭으로 시작하고 "규칙 컨텍스트(rule context)"(즉, 규칙이 시작된후 다른 규칙이나 변수 정의까지)에 나타나는 makefile의 모든 행은 해당 규칙에 대한 레시피의 일부로 간주됩니다. 빈 줄과 주석 줄은 레시피 줄 사이에 나타날 수 있습니다. 그들은 무시됩니다.

이러한 규칙의 결과는 다음과 같습니다:

  • 탭으로 시작하는 빈 줄은 비어 있지 않습니다: 그것은 빈 레시피입니다(빈 레시피(Empty Recipes) 참조).

  • 레시피의 코멘트는 메이크 코멘트가 아닙니다. 그대로 쉘에 전달됩니다. 쉘이 그것을 주석으로 처리하는지 여부는 쉘에 따라 다릅니다.

  • 탭에 의해 행의 첫 번째 문자로 들여쓰기된 "규칙 컨텍스트"의 변수 정의는 make 변수 정의가 아닌 레시피의 일부로 간주되어 쉘에 전달됩니다.

  • 탭에 의해 줄의 첫 번째 문자로 들여쓰기되는 "규칙 컨텍스트"의 조건식(ifdef, ifeq 등. 조건문 구문(Syntax of Conditionals) 참조)은 레시피의 일부로 간주되어 셸에 전달됩니다.

5.1.1 Splitting Recipe Lines (레시피 라인 분할)

make가 레시피를 해석하는 몇 가지 방법중 하나는 개행 직전에 백슬래시를 확인하는 것입니다. 일반 makefile 구문에서와 같이 각 개행 앞에 백슬래시를 배치하여 단일 논리적 레시피 라인을 makefile의 여러 물리적 라인으로 분할할 수 있습니다. 이와 같은 일련의 라인은 단일 레시피 라인으로 간주되며 쉘의 한 인스턴스가 이를 실행하기 위해 호출됩니다.

그러나 makefile의 다른 위치에서 처리되는 방식과 달리(긴 줄 분할(Splitting Long Lines) 참조) 백슬래시/개행 문자 쌍은 레시피에서 제거되지 않습니다. 백슬래시와 개행 문자는 모두 보존되어 쉘에 전달됩니다. 백슬래시/개행 문자가 해석되는 방식은 쉘에 따라 다릅니다. 백슬래시/개행후 다음 줄의 첫 번째 문자가 레시피 접두어 문자(기본적으로 탭; 특수 변수(Special Variables) 참조)이면 해당 문자(및 해당 문자만)가 제거됩니다. 공백은 레시피에 추가되지 않습니다.

예를 들어, 이 makefile에서 모든 대상에 대한 레시피는 다음과 같습니다:

all :
        @echo no\
space
        @echo no\
        space
        @echo one \
        space
        @echo one\
         space

출력은 다음과 같은 4개의 개별 셸 명령으로 구성됩니다:

nospace
nospace
one space
one space

이 makefile의 더 복잡한 예를 들면 다음과 같습니다:

all : ; @echo 'hello \
        world' ; echo "hello \
    world"

이것은 다음 명령으로 하나의 셸을 호출하게 됩니다:

echo 'hello \
world' ; echo "hello \
    world"

쉘 인용 규칙에 따라 다음과 같은 결과가 나옵니다:

hello \
world
hello     world

백슬래시/개행 쌍이 큰따옴표("...")로 인용된 문자열 내에서 제거되었지만 작은따옴표('...')로 인용된 문자열에서는 제거되지 않은 방법에 주목하십시오. 이것이 기본 셸(/bin/sh)이 백슬래시/개행 문자 쌍을 처리하는 방식입니다. makefile에 다른 쉘을 지정하면 다르게 취급할 수 있습니다.

때로는 작은 따옴표 안에 긴 줄을 분할하고 싶지만 인용된 내용에 백슬래시/개행 문자를 표시하고 싶지는 않습니다. 이것은 스크립트 내부의 불필요한 백슬래시가 의미를 변경하거나 구문 오류가 될 수 있는 Perl과 같은 언어에 스크립트를 전달할 때 종종 발생합니다. 이것을 처리하는 한 가지 간단한 방법은 따옴표로 묶인 문자열 또는 전체 명령을 make 변수에 넣은 다음 레시피의 변수를 사용하는 것입니다. 이 상황에서 makefile에 대한 개행 인용 규칙이 사용되며 백슬래시/개행 문자가 제거됩니다. 이 방법을 사용하여 위의 예를 다시 작성하면:

HELLO = 'hello \
world'

all : ; @echo $(HELLO)

우리는 다음과 같은 출력을 얻을 것입니다:

hello world

원한다면, 대상별 변수(대상별 변수 값(Target-specific Variable Values) 참조)를 사용하여 변수와 이를 사용하는 레시피 간의 더 긴밀한 대응 관계를 얻을 수도 있습니다.

5.1.2 Using Variables in Recipes (레시피에서 변수 사용하기)

make 프로세스 레시피의 다른 방법은 변수 참조를 확장하는 것입니다(변수 참조의 기본(Basics of Variable References) 참조). 이것은 make가 모든 makefile 읽기를 완료하고 대상이 오래된 것으로 결정된 후에 발생합니다. 따라서 재구축되지 않은 대상에 대한 레시피는 절대 확장되지 않습니다.

Variable and function references in recipes have identical syntax and semantics to references elsewhere in the makefile. They also have the same quoting rules: if you want a dollar sign to appear in your recipe, you must double it ('$$'). For shells like the default shell, that use dollar signs to introduce variables, it's important to keep clear in your mind whether the variable you want to reference is a make variable (use a single dollar sign) or a shell variable (use two dollar signs). For example:
레시피의 변수 및 함수 참조는 makefile의 다른 곳에서 참조와 동일한 구문 및 의미를 갖습니다. 또한 동일한 인용 규칙이 있습니다: 레시피에 달러 기호를 표시하려면 두개를 사용해서 표시해야 합니다('$$'). 변수를 도입하기 위해 달러 기호를 사용하는 기본 쉘과 같은 쉘의 경우 참조하려는 변수가 make 변수인지(단일 달러 기호 사용) 쉘 변수인지(두개의 달러 기호 사용) 예를 들어:

LIST = one two three
all:
        for i in $(LIST); do \
            echo $$i; \
        done

결과적으로 다음 명령이 셸에 전달됩니다:

for i in one two three; do \
    echo $i; \
done

이것은 다음과 같은 결과 생성이 예상됩니다:

one
two
three

5.2 Recipe Echoing (레시피 에코)

일반적으로 make는 실행되기 전에 레시피의 각 라인을 인쇄합니다. 우리는 이것을 반향(echoing)이라고 부릅니다. 이는 사용자가 직접 줄을 입력하는 것처럼 보이기 때문입니다.

줄이 '@'로 시작하면 해당 줄의 에코가 억제됩니다. '@'는 줄이 셸에 전달되기 전에 버려집니다. 일반적으로 echo 명령과 같이 makefile을 통한 진행 상황을 나타내는 것과 같이 무언가를 인쇄하는 것뿐인 명령에 이것을 사용합니다:

@echo About to make distribution files

make에 '-n' 또는 '--just-print' 플래그가 지정되면 실행하지 않고 대부분의 레시피만 에코합니다. 옵션 요약을 참조하십시오. 이 경우 '@'로 시작하는 레시피 라인도 인쇄됩니다. 이 플래그는 실제로 수행하지 않고도 어떤 레시피가 필요하다고 생각하는지 알아내는 데 유용합니다.

'-s' 또는 '--silent' 플래그는 모든 레시피가 '@'로 시작하는 것처럼 모든 에코를 방지합니다. 전제 조건이 없는 특수 대상 .SILENT에 대한 makefile의 규칙은 동일한 효과를 가집니다(특수 내장 대상 이름(Special Built-in Target Names) 참조).

5.3 Recipe Execution (레시피 실행)

타겟을 업데이트하기 위해 레시피를 실행할 시간이 되면 .ONESHELL 특수 타겟이 적용되지 않는 한 레시피의 각 라인에 대해 새로운 하위 쉘을 호출하여 실행됩니다(하나의 쉘 사용(Using One Shell) 참조) (실제로 make는 결과에 영향을 미치지 않는 단축키를 사용할 수 있습니다)

참고: 이것은 쉘 변수를 설정하고 각 프로세스에 로컬 컨텍스트를 설정하는 cd와 같은 쉘 명령을 호출하는 것이 레시피의 다음 행에 영향을 미치지 않는다는 것을 의미합니다. cd를 사용하여 다음 명령문에 영향을 미치려면 두 명령문을 모두 하나의 레시피 라인에 넣으십시오. 그런 다음 make는 전체 라인을 실행하기 위해 하나의 셸을 호출하고 셸은 명령문을 순서대로 실행합니다. 예를 들어:

foo : bar/lose
        cd $(<D) && gobble $(<F) > ../$@

여기서 쉘 AND 연산자(&&)를 사용하여 cd 명령이 실패하면 잘못된 디렉토리에서 gobble 명령을 호출하지 않고 스크립트가 실패하여 문제를 일으킬 수 있습니다 (이 경우 적어도 ../foo 가 잘릴것 입니다).

5.3.1 Using One Shell (하나의 셸 사용)

때때로 당신은 레시피의 모든 라인이 쉘의 단일 호출로 전달되는 것을 선호할 것입니다. 일반적으로 이것이 유용한 두 가지 상황이 있습니다. 첫째, 추가 프로세스를 피함으로써 레시피가 많은 명령줄로 구성된 makefile의 성능을 향상시킬 수 있습니다. 두 번째로, 당신은 당신의 레시피 명령에 줄바꿈을 포함하기를 원할 수 있습니다 (예를 들어 당신의 SHELL로 매우 다른 인터프리터를 사용하고 있을 수 있습니다). .ONESHELL 특수 대상이 makefile의 아무 곳에나 나타나면 각 대상에 대한 모든 레시피 행이 셸의 단일 호출에 제공됩니다. 레시피 줄 사이의 줄 바꿈은 유지됩니다. 예를 들어:

.ONESHELL:
foo : bar/lose
        cd $(@D)
        gobble $(@F) > ../$@

명령이 다른 레시피 라인에 있더라도 이제 예상대로 작동합니다.

.ONESHELL이 제공되면 특수 접두어 문자('@', '-' 및 '+')에 대해 레시피의 첫 번째 줄만 확인됩니다. 후속 라인은 SHELL이 호출될 때 레시피 라인의 특수 문자를 포함합니다. 레시피를 이러한 특수 문자중 하나로 시작하려면 주석 또는 이와 유사한 것을 추가하여 첫 번째 줄의 첫 번째 문자가 되지 않도록 정렬해야 합니다. 예를 들어, 이것은 첫 번째 '@'가 make에 의해 제거되기 때문에 Perl에서 구문 오류가 될 것입니다:

.ONESHELL:
SHELL = /usr/bin/perl
.SHELLFLAGS = -e
show :
        @f = qw(a b c);
        print "@f\n";

그러나 다음 대안중 하나가 제대로 작동합니다:

.ONESHELL:
SHELL = /usr/bin/perl
.SHELLFLAGS = -e
show :
        # Make sure "@" is not the first character on the first line
        @f = qw(a b c);
        print "@f\n";

or

.ONESHELL:
SHELL = /usr/bin/perl
.SHELLFLAGS = -e
show :
        my @f = qw(a b c);
        print "@f\n";

특별한 기능으로 SHELL이 POSIX 스타일 쉘로 결정되면 "내부" 레시피 라인의 특수 접두어 문자는 레시피가 처리되기 전에 제거됩니다. 이 기능은 기존 메이크파일이 .ONESHELL 특수 대상을 추가할 수 있도록 하고 광범위한 수정 없이 여전히 제대로 실행되도록 하기 위한 것입니다. 특수 접두어 문자는 POSIX 셸 스크립트에서 줄의 시작 부분에 올바르지 않기 때문에 기능 손실이 아닙니다. 예를 들어 다음과 같이 예상대로 작동합니다:

.ONESHELL:
foo : bar/lose
        @cd $(@D)
        @gobble $(@F) > ../$@

그러나 이 특수 기능을 사용하더라도 .ONESHELL이 있는 makefile은 눈에 띄게 다르게 작동합니다. 예를 들어, 일반적으로 레시피의 라인이 실패하면 규칙이 실패하고 더 이상 레시피 라인이 처리되지 않습니다. .ONESHELL 아래에서 최종 레시피 라인을 제외한 모든 실패는 make에 의해 감지되지 않습니다. .SHELLFLAGS를 수정하여 -e 옵션을 셸에 추가할 수 있습니다. 이렇게 하면 명령줄의 어느 곳에서나 셸이 실패하게 되지만 이로 인해 레시피가 다르게 작동할 수 있습니다. 궁극적으로 .ONESHELL과 함께 작동할 수 있도록 레시피 라인을 강화해야 할 수도 있습니다.

5.3.2 Choosing the Shell (쉘 선택)

쉘로 사용되는 프로그램은 변수 SHELL에서 가져옵니다. 이 변수가 makefile에 설정되어 있지 않으면 /bin/sh 프로그램이 쉘로 사용됩니다. 쉘에 전달된 인수는 .SHELLFLAGS 변수에서 가져옵니다. .SHELLFLAGS의 기본값은 일반적으로 -c이고 POSIX 준수 모드에서는 -ec입니다.

대부분의 변수와 달리 SHELL 변수는 환경에서 설정되지 않습니다. 이는 SHELL 환경 변수가 대화식 사용을 위한 쉘 프로그램의 개인 선택을 지정하는 데 사용되기 때문입니다. 이와 같은 개인적인 선택이 makefile의 기능에 영향을 미치는 것은 매우 나쁠 것입니다. 환경으로 부터의 변수들(Variables from the Environment)을 참조하십시오.

게다가, 당신이 makefile에서 SHELL을 설정할 때 그 값은 환경에서 make를 호출하는 recipe 라인으로 내보내지지 않습니다. 대신 사용자 환경에서 상속된 값이 있는 경우 내보냅니다. SHELL을 명시적으로 내보내서 이 동작을 재정의할 수 있으며(변수 통신을 Sub-make로 참조) 환경에서 이를 레시피 라인으로 전달하도록 강제할 수 있습니다.

그러나 MS-DOS 및 MS-Windows에서는 환경의 SHELL 값이 사용됩니다. 이러한 시스템에서는 대부분의 사용자가 이 변수를 설정하지 않으므로 make에서 사용하도록 특별히 설정될 가능성이 높기 때문입니다. MS-DOS에서 SHELL 설정이 make에 적합하지 않으면 make가 사용해야 하는 쉘로 MAKESHELL 변수를 설정할 수 있습니다. 설정하면 SHELL 값 대신 쉘로 사용됩니다.

Choosing a Shell in DOS and Windows (DOS 및 Windows에서 셸 선택)

MS-DOS와 MS-Windows에서 쉘을 선택하는 것은 다른 시스템에서보다 훨씬 더 복잡합니다.

MS-DOS에서 SHELL이 설정되지 않은 경우 변수 COMSPEC(항상 설정됨) 값이 대신 사용됩니다.

Makefiles에서 변수 SHELL을 설정하는 행의 처리는 MS-DOS에서 다릅니다. 기본 쉘인 command.com은 기능면에서 엄청나게 제한적이며 많은 make 사용자가 대체 쉘을 설치하는 경향이 있습니다. 따라서 MS-DOS에서 make는 SHELL의 값을 검사하고 Unix 스타일 또는 DOS 스타일 쉘을 가리키는지 여부에 따라 동작을 변경합니다. 이것은 SHELL이 command.com을 가리키더라도 합리적인 기능을 허용합니다.

SHELL이 Unix 스타일 셸을 가리키는 경우 MS-DOS의 make는 해당 셸을 실제로 찾을 수 있는지 여부를 추가로 확인합니다. 그렇지 않은 경우 SHELL을 설정하는 행을 무시합니다. MS-DOS에서 GNU는 다음 위치에서 쉘을 검색합니다.

  1. SHELL(환경변수)의 값이 가리키는 정확한 위치에서. 예를 들어 makefile이 'SHELL = /bin/sh'를 지정하면 make는 현재 드라이브의 /bin 디렉토리를 찾습니다.

  2. 현재 디렉토리에서.

  3. PATH 변수의 각 디렉토리에서 순서대로.

검사하는 모든 디렉토리에서 make는 먼저 특정 파일을 찾습니다 (위의 예에서 sh). 이것이 발견되지 않으면 실행 파일을 식별하는 알려진 확장자 중 하나를 가진 해당 파일을 해당 디렉토리에서 찾습니다. 예를 들어 .exe, .com, .bat, .btm, .sh 및 기타.

이러한 시도 중 하나라도 성공하면 SHELL 값은 발견된 셸의 전체 경로 이름으로 설정됩니다. 그러나 이들 중 아무 것도 발견되지 않으면 SHELL의 값은 변경되지 않으므로 이를 설정하는 행은 효과적으로 무시됩니다. 이는 make가 실행되는 시스템에 실제로 그러한 셸이 설치된 경우에만 make가 Unix 스타일 셸에 특정한 기능을 지원하기 때문입니다.

쉘에 대한 이 확장 검색은 SHELL이 Makefile에서 설정된 경우로 제한됩니다. 환경이나 명령줄에 설정되어 있으면 Unix에서와 마찬가지로 셸의 전체 경로 이름으로 설정해야 합니다.

위의 DOS 특정 처리의 효과는 'SHELL = /bin/sh'를 포함하는 Makefile (많은 Unix makefile이 하는 것처럼)이 다음과 같은 경우 MS-DOS에서 변경되지 않고 작동한다는 것입니다. sh.exe는 경로를 따라 일부 디렉토리에 설치됩니다.

5.4 Parallel Execution (병렬 실행)

GNU make는 한 번에 여러 레시피를 실행하는 방법을 알고 있습니다. 일반적으로 make는 한 번에 하나의 레시피만 실행하고 다음 레시피를 실행하기 전에 완료될 때까지 기다립니다. 그러나 '-j' 또는 '--jobs' 옵션은 make에게 동시에 많은 레시피를 실행하도록 지시합니다. .NOTPARALLEL 의사 대상을 사용하여 특정 메이크파일에서 병렬 처리를 금지할 수 있습니다(특수 내장 대상 이름(Special Built-in Target Names) 참조).

MS-DOS에서 '-j' 옵션은 해당 시스템이 다중 처리를 지원하지 않기 때문에 효과가 없습니다.

'-j' 옵션 뒤에 정수가 오면 한 번에 실행할 레시피의 수입니다. 이것을 작업 슬롯의 수라고 합니다. '-j' 옵션 뒤에 정수처럼 보이는 것이 없으면 작업 슬롯의 수에는 제한이 없습니다. 작업 슬롯의 기본 수는 직렬 실행(한 번에 하나씩)을 의미하는 1입니다.

재귀적 make 호출을 처리하면 병렬 실행에 대한 문제가 발생합니다. 이에 대한 자세한 내용은 Sub-make에 옵션 통신(Communicating Options to a Sub-make)을 참조하십시오.

레시피가 실패하고 (신호에 의해 종료되거나 0이 아닌 상태로 종료됨) 해당 레시피에 대한 오류가 무시되지 않으면 (레시피의 오류(Errors in Recipes) 참조) 동일한 대상을 다시 만들기 위한 나머지 레시피 라인은 실행되지 않습니다. 레시피가 실패하고 '-k' 또는 '--keep-going' 옵션이 제공되지 않은 경우 (옵션 요약(Summary of Options) 참조) 실행을 중단합니다. make가 어떤 이유로든(시그널 포함) 자식 프로세스가 실행 중인 상태에서 종료되면 실제로 종료되기 전에 완료될 때까지 기다립니다.

시스템 부하가 심하면 부하가 낮을 때보다 더 적은 수의 작업을 실행하고 싶을 것입니다. '-l' 옵션을 사용하여 평균 로드를 기반으로 한 번에 실행할 작업 수를 제한하도록 make에 지시할 수 있습니다. '-l' 또는 '--max-load' 옵션 뒤에 부동 소수점 숫자가 옵니다. 예를 들어,

-l 2.5

로드 평균이 2.5보다 높으면 make가 두 개 이상의 작업을 시작하도록 허용하지 않습니다. 다음 번호가 없는 '-l' 옵션은 이전 '-l' 옵션과 함께 제공된 경우 로드 제한을 제거합니다.

더 정확하게는 make가 작업을 시작하고 이미 하나 이상의 작업이 실행 중이면 현재 로드 평균을 확인합니다. 만약 그것이 '-l'로 주어진 한계보다 낮지 않다면, make는 부하 평균이 그 한계 아래로 떨어질 때까지 또는 다른 모든 작업이 끝날 때까지 기다립니다.

기본적으로 로드 제한은 없습니다.

5.4.1 Output During Parallel Execution (병렬 실행 중 출력)

여러 레시피를 병렬로 실행할 때 각 레시피의 출력은 생성되자마자 나타나며, 결과적으로 다른 레시피의 메시지가 산재되어 때로는 같은 줄에 나타나기도 합니다. 이렇게 하면 출력을 읽기가 매우 어려울 수 있습니다.

이를 피하기 위해 '--output-sync'('-O') 옵션을 사용할 수 있습니다. 이 옵션은 make가 호출한 명령의 출력을 저장하고 명령이 완료되면 모두 인쇄하도록 지시합니다. 또한 병렬로 실행되는 재귀적 make 호출이 여러 개 있는 경우 한 번에 하나만 출력을 생성하도록 통신합니다.

작업 디렉토리 인쇄가 활성화된 경우('--print-directory' 옵션 참조), 각 출력 그룹 주위에 들어가기/나가기 메시지가 인쇄됩니다. 이 메시지를 보고 싶지 않다면 MAKEFLAGS에 '--no-print-directory' 옵션을 추가하세요.

옵션에 인수를 지정하여 출력을 동기화할 때 네 가지 수준의 세분성이 있습니다(예: '-Oline' 또는 '--output-sync=recurse').

  • none

    이것이 기본값입니다: 모든 출력은 생성될 때 직접 전송되며 동기화가 수행되지 않습니다.

  • line

    레시피의 각 개별 라인의 출력은 해당 라인이 완료되는 즉시 그룹화되고 인쇄됩니다. 레시피가 여러 라인으로 구성된 경우 다른 레시피의 라인과 산재될 수 있습니다.

  • target

    각 대상에 대한 전체 레시피의 출력은 대상이 완료되면 그룹화되고 인쇄됩니다. --output-sync 또는 -O 옵션이 인수 없이 제공된 경우 이것이 기본값입니다.

  • recurse

    make의 각 재귀 호출의 출력은 재귀 호출이 완료되면 그룹화되고 인쇄됩니다.

선택한 모드에 관계없이 총 빌드 시간은 동일합니다. 유일한 차이점은 출력이 표시되는 방식입니다.

'대상(target)' 및 '재귀(recurse)' 모드는 모두 대상의 전체 레시피 출력을 수집하고 레시피가 완료될 때 중단 없이 표시합니다. 이들 사이의 차이점은 make의 재귀 호출을 포함하는 레시피가 처리되는 방식에 있습니다 (make의 재귀 사용(Recursive Use of make) 참조). 재귀 행이 없는 모든 레시피의 경우 '대상' 및 '재귀' 모드가 동일하게 작동합니다.

'recurse' 모드를 선택하면 재귀적 make 호출을 포함하는 레시피가 다른 대상과 동일하게 처리됩니다. 재귀적 make의 출력을 포함하여 레시피의 출력은 전체 레시피가 완료된 후 저장되고 인쇄됩니다. 이렇게 하면 주어진 재귀 make 인스턴스에 의해 빌드된 모든 대상의 출력이 함께 그룹화되어 출력을 더 쉽게 이해할 수 있습니다. 그러나 그것은 또한 출력이 표시되지 않는 빌드 중 오랜 시간이 지난 후 출력의 큰 분출(bursts)을 초래합니다. 빌드가 진행되는 동안 지켜보는 것이 아니라 나중에 빌드 로그를 보는 경우 이것이 최선의 선택일 수 있습니다.

출력을 보고 있다면 빌드하는 동안의 긴 침묵 간격이 답답할 수 있습니다. '대상' 출력 동기화 모드는 표준 방법을 사용하여 make가 재귀적으로 호출될 때를 감지하고 해당 라인의 출력을 동기화하지 않습니다. 재귀적 make는 대상에 대한 동기화를 수행하고 각각의 출력은 완료되면 즉시 표시됩니다. 레시피의 재귀 행의 출력은 동기화되지 않는다는 점에 유의하십시오(예를 들어 make를 실행하기 전에 재귀 행이 메시지를 인쇄하면 해당 메시지는 동기화되지 않습니다).

'라인' 모드는 레시피가 시작되고 완료되는 시점을 추적하기 위해 make의 출력을 보고 있는 프런트 엔드에 유용할 수 있습니다.

make에 의해 호출된 일부 프로그램은 출력을 터미널 대 파일에 쓰고 있다고 판단하면 다르게 동작할 수 있습니다(종종 "대화형" 모드와 "비대화형" 모드로 설명됨). 예를 들어, 컬러 출력을 표시할 수 있는 많은 프로그램은 터미널에 쓰지 않는다고 결정하면 그렇게 하지 않습니다. makefile이 이와 같은 프로그램을 호출하는 경우 출력 동기화 옵션을 사용하면 출력이 궁극적으로 터미널로 이동하더라도 프로그램이 "비대화형" 모드에서 실행 중이라고 믿게 됩니다.

5.4.2 Input During Parallel Execution (병렬 실행 중 입력)

두 프로세스가 동시에 동일한 장치에서 입력을 받을 수 없습니다. 한 번에 하나의 레시피만 터미널에서 입력을 받으려고 하는 것을 확인하기 위해 make는 실행 중인 레시피를 제외한 모든 표준 입력 스트림을 무효화합니다. 다른 레시피가 표준 입력에서 읽으려고 시도하면 일반적으로 치명적인 오류('깨진 파이프(Broken pipe)' 신호)가 발생합니다.

어떤 레시피가 유효한 표준 입력 스트림을 가질지는 예측할 수 없습니다. 첫 번째 레시피 실행은 항상 첫 번째 레시피를 가져오고 그 실행이 완료된 후 시작된 첫 번째 레시피는 다음에 가져오는 식입니다.

더 나은 대안을 찾으면 make 의 이 측면이 작동하는 방식을 변경할 것입니다. 그 동안 병렬 실행 기능을 사용하는 경우 표준 입력을 사용하는 레시피에 전혀 의존해서는 안 됩니다. 그러나 이 기능을 사용하지 않는 경우 표준 입력은 모든 레시피에서 정상적으로 작동합니다.

5.5 Errors in Recipes (레시피의 오류)

각 셸 호출이 반환된 후 make는 종료 상태를 확인합니다. 셸이 성공적으로 완료되면(종료 상태가 0임) 레시피의 다음 줄이 새 셸에서 실행됩니다. 마지막 줄이 끝나면 규칙이 완료됩니다.

오류가 있는 경우(종료 상태가 0이 아님) make는 현재 규칙을 포기하고 아마도 모든 규칙을 포기합니다.

때때로 특정 레시피 라인의 실패는 문제를 나타내지 않습니다. 예를 들어, mkdir 명령을 사용하여 디렉토리가 존재하는지 확인할 수 있습니다. 디렉토리가 이미 존재하는 경우 mkdir은 오류를 보고하지만 이에 관계없이 make를 계속하기를 원할 것입니다.

레시피 라인의 오류를 무시하려면 라인 텍스트의 시작 부분(초기 탭 뒤)에 '-'를 작성하십시오. '-'는 행이 실행을 위해 셸로 전달되기 전에 버려집니다.

예를 들어,

clean:
        -rm -f *.o

이로 인해 rm이 파일을 제거할 수 없는 경우에도 make가 계속됩니다.

'-i' 또는 '--ignore-errors' 플래그와 함께 make를 실행하면 모든 규칙의 모든 레시피에서 오류가 무시됩니다. 전제 조건이 없는 경우 특수 대상 .IGNORE에 대한 makefile의 규칙은 동일한 효과를 갖습니다. 이것은 덜 유연하지만 때로는 유용합니다.

오류가 무시되어야 하는 경우 '-' 또는 '-i' 플래그로 인해 make는 쉘이 종료된 상태 코드를 알려주는 메시지를 출력하고 오류가 무시되었다는 메시지를 출력한다는 점을 제외하고는 오류 반환을 성공과 동일하게 처리합니다.

make가 무시하도록 지시되지 않은 오류가 발생하면 현재 대상을 올바르게 다시 작성할 수 없으며 이에 의존하는 다른 대상도 직접 또는 간접적으로 할 수 없음을 의미합니다. 전제 조건이 충족되지 않았기 때문에 이러한 대상에 대해 더 이상 레시피가 실행되지 않습니다.

일반적으로 make는 이 상황에서 즉시 포기하고 0이 아닌 상태를 반환합니다. 그러나 '-k' 또는 '--keep-going' 플래그가 지정되면 make는 포기하고 0이 아닌 상태를 반환하기 전에 보류 중인 대상의 다른 전제 조건을 계속 고려하여 필요하다면 다시 만듭니다. 예를 들어, 'make -k'는 하나의 오브젝트 파일을 컴파일하는데 오류가 발생하면 링크가 불가능하다는 것을 이미 알고 있음에도 불구하고 다른 오브젝트 파일을 계속 컴파일합니다. 옵션 요약(Summary of Options)을 참조하십시오.

일반적인 동작은 사용자의 목적이 지정된 대상을 최신 상태로 유지하는 것이라고 가정합니다. make가 이것이 불가능하다는 것을 알게 되면 즉시 실패를 보고할 수도 있습니다. '-k' 옵션은 프로그램의 변경 사항을 가능한 한 많이 테스트하는 것이 실제 목적이며, 다음 컴파일을 시도하기 전에 모두 수정할 수 있도록 몇 가지 독립적인 문제를 찾는 것일 수 있습니다. 이것이 Emacs의 컴파일 명령이 기본적으로 '-k' 플래그를 전달하는 이유입니다.

일반적으로 레시피 라인이 실패할 때 대상 파일을 조금이라도 변경했다면 파일이 손상되어 사용할 수 없거나 최소한 완전히 업데이트되지 않은 것입니다. 그러나 파일의 타임 스탬프는 현재 최신 상태이므로 다음에 make가 실행될 때 해당 파일을 업데이트하려고 시도하지 않습니다. 상황은 신호에 의해 쉘이 종료될 때와 동일합니다. 인터럽트(Interrupts)를 참조하십시오. 따라서 일반적으로 올바른 방법은 파일 변경을 시작한 후 레시피가 실패하면 대상 파일을 삭제하는 것입니다. make는 .DELETE_ON_ERROR가 타겟으로 나타나면 이것을 할 것입니다. 이것은 거의 항상 당신이 하고 싶은 일이지만 역사적 관행은 아닙니다. 따라서 호환성을 위해 명시적으로 요청해야 합니다.

5.6 Interrupting or Killing make (방해하거나 죽이는 메이크)

쉘이 실행되는 동안 make가 치명적인 신호를 받으면 레시피가 업데이트되어야 했던 대상 파일을 삭제할 수 있습니다. 대상 파일의 마지막 수정 시간이 make가 처음 확인한 이후에 변경된 경우 수행됩니다.

대상을 삭제하는 목적은 다음에 make가 실행될 때 처음부터 다시 만들어지도록 하는 것입니다. 왜 이럴까요? 컴파일러가 실행되는 동안 Ctrl-c를 입력하고 개체 파일 foo.o를 작성하기 시작했다고 가정합니다. Ctrl-c는 컴파일러를 죽이고 마지막 수정 시간이 소스 파일 foo.c보다 최신인 불완전한 파일을 만듭니다. 그러나 make는 또한 Ctrl-c 신호를 수신하고 이 불완전한 파일을 삭제합니다. 만약 make가 이것을 하지 않는다면, make의 다음 호출은 foo.o가 업데이트를 필요로 하지 않는다고 생각할 것입니다. 그 결과 링커가 링크를 시도할 때 링커로부터 이상한 오류 메시지가 나타나게 됩니다.

특수 대상 .PRECIOUS가 종속되도록 하여 이러한 방식으로 대상 파일의 삭제를 방지할 수 있습니다. 대상을 다시 만들기 전에 .PRECIOUS의 전제 조건에 나타나는지 확인하여 신호가 발생하면 대상을 삭제할지 여부를 결정합니다. 이렇게 하는 몇 가지 이유는 대상이 원자적 방식으로 업데이트되거나 수정 시간을 기록하기 위해서만 존재하거나(내용은 중요하지 않음), 다른 종류의 문제를 방지하기 위해 항상 존재해야 하기 때문입니다.

make는 정리를 위해 최선을 다하지만 정리가 불가능한 특정 상황이 있습니다. 예를 들어, make는 잡을 수 없는 신호에 의해 죽임을 당할 수 있습니다. 또는 make 호출 중 하나가 종료되거나 충돌하여 최신이지만 손상된 대상 파일을 남길 수 있습니다. make는 이 실패가 대상을 정리해야 한다는 것을 인식하지 못합니다. 또는 make 자체에서 버그 및 충돌이 발생할 수 있습니다.

이러한 이유로 실패하더라도 손상된 대상을 남기지 않는 방어적인 레시피를 작성하는 것이 가장 좋습니다. 가장 일반적으로 이러한 레시피는 대상을 직접 업데이트하는 대신 임시 파일을 만든 다음 임시 파일의 이름을 최종 대상 이름으로 바꿉니다. 일부 컴파일러는 이미 이런 식으로 동작하므로 방어적인 레시피를 작성할 필요가 없습니다.

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

make의 재귀적 사용은 make를 makefile에서 명령으로 사용하는 것을 의미합니다. 이 기술은 더 큰 시스템을 구성하는 다양한 하위 시스템에 대해 별도의 메이크파일을 원할 때 유용합니다. 예를 들어, 자체 makefile이 있는 하위 디렉토리 하위 디렉토리가 있고 포함 디렉토리의 makefile이 하위 디렉토리에서 make를 실행하기를 원한다고 가정합니다. 다음과 같이 작성하면 됩니다:

subsystem:
        cd subdir && $(MAKE)

또는, 다음과 같이해도 같습니다. (옵션 요약(Summary of Options) 참조):

subsystem:
        $(MAKE) -C subdir

이 예제를 복사하는 것만으로 재귀적 make 명령을 작성할 수 있지만 작동 방식과 이유, 하위 make가 최상위 make와 어떻게 관련되는지에 대해 알아야 할 사항이 많이 있습니다. 재귀적 make 명령을 호출하는 대상을 '.PHONY'로 선언하는 것이 유용할 수도 있습니다 (이것이 유용한 경우에 대한 자세한 내용은 가짜 대상(Phony Targets) 참조).

편의를 위해 GNU make가 시작될 때 (-C 옵션을 처리한 후) CURDIR 변수를 현재 작업 디렉토리의 경로 이름으로 설정합니다. 이 값은 다시 make에 의해 건드리지 않습니다. 특히 다른 디렉토리의 파일을 포함하는 경우 CURDIR 값은 변경되지 않습니다. 값은 makefile에 설정된 경우와 동일한 우선 순위를 갖습니다 (기본적으로 환경 변수 CURDIR는 이 값을 무시하지 않습니다). 이 변수를 설정하는 것은 make 작업에 영향을 미치지 않습니다 (예를 들어 make가 작업 디렉토리를 변경하게 하지 않음).

5.7.1 How the MAKE Variable Works (MAKE 변수 작동 방식)

재귀적 make 명령은 다음과 같이 명시적 명령 이름 'make'가 아니라 항상 변수 MAKE를 사용해야 합니다:

subsystem:
        cd subdir && $(MAKE)

이 변수의 값은 make가 호출된 파일 이름입니다. 이 파일 이름이 /bin/make라면 실행되는 레시피는 'cd subdir && /bin/make'입니다. 특수 버전의 make를 사용하여 최상위 makefile을 실행하는 경우 재귀 호출에 대해 동일한 특수 버전이 실행됩니다.

특별한 기능으로 규칙의 레시피에서 변수 MAKE를 사용하면 '-t'('--touch'), '-n'('--just-print') 또는 '-q' ('--question') 옵션의 효과가 변경됩니다. MAKE 변수를 사용하면 레시피 라인의 시작 부분에 '+' 문자를 사용하는 것과 같은 효과가 있습니다. 레시피를 실행하는 대신하기(Instead of Executing the Recipes)를 참조하십시오. 이 특수 기능은 MAKE 변수가 레시피에 직접 나타나는 경우에만 활성화됩니다: MAKE 변수가 다른 변수의 확장을 통해 참조되는 경우에는 적용되지 않습니다. 후자의 경우 이러한 특수 효과를 얻으려면 '+' 토큰을 사용해야 합니다.

위의 예에서 'make -t' 명령을 고려하십시오. ('-t' 옵션은 실제로 레시피를 실행하지 않고 대상을 최신 상태로 표시합니다. 실행 대신하기(Instead of Execution) 참조) '-t'의 일반적인 정의에 따라 예제에서 'make -t' 명령은 다음과 같은 파일을 생성합니다. 다른 작업은 하지 않습니다. 정말로 원하는 것은 'cd subdir && make -t'를 실행하는 것입니다. 그러나 그것은 레시피를 실행해야 하고 '-t'는 레시피를 실행하지 말라고 말합니다.

이 특수 기능은 원하는 대로 수행하도록 합니다. 규칙의 레시피 라인에 변수 MAKE가 포함될 때마다 플래그 '-t', '-n' 및 '-q'가 해당 라인에 적용되지 않습니다. MAKE를 포함하는 레시피 라인은 대부분의 레시피가 실행되지 않도록 하는 플래그가 있음에도 불구하고 정상적으로 실행됩니다. 일반적인 MAKEFLAGS 메커니즘은 플래그를 sub-make에 전달하므로(Sub-make에 대한 옵션 통신(Communicating Options to a Sub-make) 참조) 파일을 만지거나 레시피를 인쇄하라는 요청이 하위 시스템으로 전파됩니다.

5.7.2 Communicating Variables to a Sub-make (Sub-make에 변수 통신하기)

최상위 make의 변수 값은 명시적 요청에 의해 환경을 통해 하위 make에 전달할 수 있습니다. 이러한 변수는 기본적으로 sub-make에서 정의되지만 '-e' 스위치를 사용하지 않는한 sub-make에서 사용하는 makefile에 정의된 변수를 무시하지 않습니다(옵션 요약(Summary of Options) 참조).

변수를 전달하거나 내보내기 위해 make는 레시피의 각 라인을 실행하기 위한 환경에 변수와 그 값을 추가합니다. sub-make는 차례로 환경을 사용하여 변수 값 테이블을 초기화합니다. 환경으로 부터의 변수들(Variables from the Environment)를 참조하십시오.

명시적인 요청을 제외하고 make는 변수가 처음에 환경에 정의되었거나 명령줄에 설정되어 있고 이름이 문자, 숫자 및 밑줄로만 구성된 경우에만 변수를 내보냅니다. 일부 쉘은 문자, 숫자 및 밑줄 이외의 문자로 구성된 환경 변수 이름을 처리할 수 없습니다.

make 변수 SHELL의 값은 내보내지지 않습니다. 대신, 호출 환경에서 SHELL 변수의 값이 sub-make로 전달됩니다. 아래에 설명된 내보내기 지시문을 사용하여 make가 SHELL에 대한 값을 강제로 내보내도록 할 수 있습니다. 쉘 선택(Choosing the Shell)을 참조하십시오.

특수 변수 MAKEFLAGS는 항상 내보내집니다 (내보내기를 취소하지 않는 한). MAKEFILES는 아무거나 설정하면 내보내집니다.

make는 명령줄에 정의된 변수 값을 MAKEFLAGS 변수에 넣어 자동으로 전달합니다. 옵션/재귀(Options/Recursion)를 참조하십시오.

make에 의해 기본적으로 생성된 변수는 일반적으로 전달되지 않습니다 (암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules) 참조). sub-make는 이것들을 스스로 정의할 것입니다.

특정 변수를 하위 제조사로 내보내려면 다음과 같이 내보내기 지시문을 사용하십시오:

export variable ...

변수를 내보내는 것을 방지하려면 다음과 같이 unexport 지시문을 사용하십시오:

unexport variable ...

이 두 형식 모두에서 export 및 unexport에 대한 인수가 확장되므로 내보낼(또는 내보내지 않을) 변수 이름(또는 변수 이름 목록)으로 확장되는 변수 또는 함수가 될 수 있습니다.

편의상 다음을 수행하여 변수를 정의하고 동시에 내보낼 수 있습니다:

export variable = value

이것은 다음과 같은 결과를 가집니다:

variable = value
export variable

그리고

export variable := value

이것은 다음과 같은 결과를 가집니다:

variable := value
export variable

이와 비슷하게,

export variable += value

은 다음과 같습니다:

variable += value
export variable

변수에 더 많은 텍스트 추가(Appending More Text to Variables)를 참조하십시오.

export 및 unexport 지시문이 쉘 sh에서 작동하는 것과 같은 방식으로 make에서 작동한다는 것을 알 수 있습니다.

기본적으로 모든 변수를 내보내려면 내보내기를 단독으로 사용할 수 있습니다:

export

이것은 export 또는 unexport 지시문에서 명시적으로 언급되지 않은 변수를 내보내야 한다는 것을 make에게 알려줍니다. unexport 지시문에 지정된 변수는 여전히 내보내지지 않습니다. 기본적으로 내보내기 자체를 사용하여 변수를 내보내는 경우 이름에 영숫자 및 밑줄 이외의 문자가 포함된 변수는 내보내기 지시문에서 특별히 언급하지 않는 한 내보내지 않습니다.

export 지시문 자체에 의해 유발되는 동작은 이전 버전의 GNU make에서 기본이었습니다. makefile이 이 동작에 의존하고 make의 이전 버전과 호환되기를 원한다면 export 지시자를 사용하는 대신 특수 대상 .EXPORT_ALL_VARIABLES에 대한 규칙을 작성할 수 있습니다. 이것은 이전 make에서 무시되지만 export 지시문은 구문 오류를 일으킵니다.

마찬가지로 unexport 자체를 사용하여 기본적으로 변수를 내보내지 않도록 make에 지시할 수 있습니다. 이것이 기본 동작이므로 내보내기가 더 일찍(아마도, 포함된 makefile에서) 자체적으로 사용된 경우에만 이 작업을 수행하면 됩니다. 내보내기 및 내보내기 취소를 단독으로 사용하여 일부 레시피에 대해 변수를 내보내고 다른 레시피에 대해서는 내보낼 수 없습니다. 그 자체로 나타나는 마지막 export 또는 unexport 지시문은 make의 전체 실행에 대한 동작을 결정합니다.

특별한 기능으로 MAKELEVEL 변수는 레벨에서 레벨로 전달될 때 변경됩니다. 이 변수의 값은 레벨의 깊이를 십진수로 나타내는 문자열입니다. 값은 최상위 make의 경우 '0'이고 서브메이크의 경우 '1'이며 서브의 서브메이크의 경우 '2' 등입니다. 증분은 make가 레시피에 대한 환경을 설정할 때 발생합니다.

MAKELEVEL의 주요 용도는 조건부 지시문에서 테스트하는 것입니다 (Makefile의 조건부 부분(Conditional Parts of Makefiles) 참조). 이렇게 하면 재귀적으로 실행되는 경우 한 방향으로 작동하고 사용자가 직접 실행하는 경우 다른 방식으로 작동하는 메이크파일을 작성할 수 있습니다.

MAKEFILES 변수를 사용하여 모든 하위 make 명령이 추가 makefile을 사용하도록 할 수 있습니다. MAKEFILES의 값은 공백으로 구분된 파일 이름 목록입니다. 이 변수는 외부 수준 makefile에 정의되어 있으면 환경을 통해 전달됩니다. 그런 다음 일반적이거나 지정된 파일보다 먼저 하위 make가 읽을 수 있는 추가 makefile 목록으로 사용됩니다. 변수 MAKEFILES(The Variable MAKEFILES)를 참조하십시오.

5.7.3 Communicating Options to a Sub-make (하위 make에 옵션 전달)

'-s' 및 '-k'와 같은 플래그는 MAKEFLAGS 변수를 통해 자동으로 sub-make에 전달됩니다. 이 변수는 make가 수신한 플래그 문자를 포함하도록 자동으로 설정됩니다. 따라서 'make -ks'를 수행하면 MAKEFLAGS는 'ks' 값을 얻습니다.

결과적으로 모든 하위 메이크는 해당 환경에서 MAKEFLAGS에 대한 값을 얻습니다. 응답으로 해당 값에서 플래그를 가져와 인수로 제공된 것처럼 처리합니다. 옵션 요약(Summary of Options)을 참조하십시오.

마찬가지로 명령줄에 정의된 변수는 MAKEFLAGS를 통해 하위 make에 전달됩니다. MAKEFLAGS 값에 '='가 포함된 단어는 명령줄에 나타난 것처럼 변수 정의로 취급합니다. 변수 재정의(Overriding Variables)를 참조하십시오.

옵션 '-C', '-f', '-o' 및 '-W'는 MAKEFLAGS에 넣지 않습니다. 이러한 옵션은 전달되지 않습니다.

'-j' 옵션은 특별한 경우입니다(병렬 실행(Parallel Execution) 참조). 일부 숫자 값 'N'으로 설정하고 운영 체제가 이를 지원하면 (대부분의 UNIX 시스템은 그럴 것이고 다른 시스템은 일반적으로 그렇지 않을 것입니다) 상위 제조업체와 모든 하위 제조업체가 통신하여 그들 사이에 동시에 'N' 작업만 실행되도록 합니다. 재귀로 표시된 작업(레시피 실행 대신(Instead of Executing Recipes) 참조)은 총 작업에 포함되지 않습니다 (그렇지 않으면 'N'개의 sub-makes가 실행되고 실제 작업을 위한 슬롯이 남지 않을 수 있습니다!).

운영 체제가 위의 통신을 지원하지 않으면 MAKEFLAGS에 '-j'가 추가되지 않으므로 하위 구성이 비병렬 모드에서 실행됩니다. '-j' 옵션이 하위 제작으로 전달되면 요청한 것보다 더 많은 작업을 병렬로 실행할 수 있습니다. 숫자 인수 없이 '-j'를 지정하면 가능한 한 많은 작업을 병렬로 실행하는 것을 의미합니다. 여러 무한대가 1보다 크지 않기 때문에 이것이 전달됩니다.

다른 플래그를 전달하지 않으려면 MAKEFLAGS 값을 다음과 같이 변경해야 합니다:

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

명령줄 변수 정의는 실제로 MAKEOVERRIDES 변수에 나타나며 MAKEFLAGS에는 이 변수에 대한 참조가 포함됩니다. 플래그를 정상적으로 전달하고 싶지만 명령줄 변수 정의를 전달하고 싶지 않다면 다음과 같이 MAKEOVERRIDES를 공백으로 재설정할 수 있습니다:

MAKEOVERRIDES =

이것은 일반적으로 유용하지 않습니다. 그러나 일부 시스템은 환경 크기에 작은 고정 제한이 있으며 MAKEFLAGS 값에 너무 많은 정보를 넣으면 이를 초과할 수 있습니다. 'Arg list too long' 오류 메시지가 표시되면 문제일 수 있습니다. (POSIX.2를 엄격히 준수하기 위해 MAKEOVERRIDES를 변경해도 makefile에 특수 대상 '.POSIX'가 표시되면 MAKEFLAGS에 영향을 미치지 않습니다. 당신은 아마 이것에 대해 신경 쓰지 않을 것입니다.)

역사적 호환성을 위해 유사한 변수 MFLAGS도 존재합니다. 명령줄 변수 정의를 포함하지 않는다는 점을 제외하고 MAKEFLAGS와 동일한 값을 가지며 비어 있지 않은한 항상 하이픈으로 시작합니다 (MAKEFLAGS는 단일 문자 버전이 없는 옵션으로 시작하는 경우에만 '--warn-undefined-variables'와 같이 하이픈으로 시작합니다). MFLAGS는 전통적으로 다음과 같이 재귀적 make 명령에서 명시적으로 사용되었습니다:

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

그러나 이제 MAKEFLAGS는 이 사용을 중복으로 만듭니다. 메이크파일이 예전 메이크 프로그램과 호환되기를 원한다면 이 기술을 사용하십시오. 더 현대적인 make 버전에서도 잘 작동합니다.

MAKEFLAGS 변수는 make를 실행할 때마다 '-k'(옵션 요약 참조)와 같은 특정 옵션을 설정하려는 경우에도 유용할 수 있습니다. 환경에 MAKEFLAGS 값을 입력하기만 하면 됩니다. 또한 메이크파일에 MAKEFLAGS를 설정하여 해당 메이크파일에도 적용되어야 하는 추가 플래그를 지정할 수 있습니다. (이 방법으로는 MFLAGS를 사용할 수 없습니다. 해당 변수는 호환성을 위해서만 설정되며 make는 어떤 식으로든 설정한 값을 해석하지 않습니다.)

make가 MAKEFLAGS의 값 (환경 또는 makefile에서)을 해석할 때 값이 이미 하이픈으로 시작하지 않으면 먼저 하이픈을 추가합니다. 그런 다음 값을 공백으로 구분된 단어로 자르고 명령줄에 제공된 옵션인 것처럼 이러한 단어를 구문 분석합니다(단 '-C', '-f', '-h', '-o', '- W' 및 긴 이름의 버전은 무시되며 잘못된 옵션에 대한 오류가 없습니다).

MAKEFLAGS를 환경에 배치하는 경우 make의 작업에 크게 영향을 미치고 makefile과 make 자체의 목적을 훼손하는 옵션을 포함하지 않도록 해야 합니다. 예를 들어, '-t', '-n' 및 '-q' 옵션을 이러한 변수 중 하나에 넣으면 재앙적인 결과를 초래할 수 있으며 적어도 놀랍고 아마도 성가신 영향을 미칠 것입니다.

GNU make 외에 make의 다른 구현을 실행하고 GNU make 전용 플래그를 MAKEFLAGS 변수에 추가하지 않으려면 대신 GNUMAKEFLAGS 변수에 추가할 수 있습니다. 이 변수는 MAKEFLAGS와 동일한 방식으로 MAKEFLAGS 직전에 구문 분석됩니다. make가 재귀적 make에 전달할 MAKEFLAGS를 구성하면 GNUMAKEFLAGS에서 가져온 플래그를 포함하여 모든 플래그가 포함됩니다. 결과적으로 GNUMAKEFLAGS GNU를 구문 분석한 후 make는 재귀 중에 플래그가 중복되는 것을 피하기 위해 이 변수를 빈 문자열로 설정합니다.

makefile의 동작을 실질적으로 변경하지 않는 플래그와 함께 GNUMAKEFLAGS를 사용하는 것이 가장 좋습니다. 당신의 메이크파일이 어쨌든 GNU make를 필요로 한다면, 간단히 MAKEFLAGS를 사용하십시오. '--no-print-directory' 또는 '--output-sync'와 같은 플래그는 GNUMAKEFLAGS에 적합할 수 있습니다.

5.7.4 The '--print-directory' Option

여러 수준의 재귀적 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' 옵션을 사용할 때와 서브-메이크에서 자동으로 켜집니다. 자동으로 '-s'를 사용하거나 '--no-print-directory'를 사용하여 명시적으로 비활성화하는 경우 make는 자동으로 '-w'를 켜지 않습니다.

5.8 Defining Canned Recipes (미리 준비된 레시피 정의)

동일한 명령 시퀀스가 다양한 대상을 만드는 데 유용할 때 정의 지시문을 사용하여 '미리 준비된 시퀀스'로 정의하고 해당 대상에 대한 레시피에서 미리 준비된 시퀀스를 참조할 수 있습니다. 미리 준비된 시퀀스는 실제로 변수이므로 이름이 다른 변수 이름과 충돌하지 않아야 합니다.

다음은 통조림 레시피를 정의하는 예입니다:

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

여기서 run-yacc는 정의되는 변수의 이름입니다. endef는 정의의 끝을 표시합니다. 사이에 있는 줄은 명령입니다. define 지시문은 미리 준비된 시퀀스에서 변수 참조 및 함수 호출을 확장하지 않습니다. '$' 문자, 괄호, 변수 이름 등은 모두 정의하는 변수 값의 일부가 됩니다. 정의에 대한 전체 설명은 여러 줄 변수 정의(Defining Multi-Line Variables)를 참조하십시오.

이 예의 첫 번째 명령은 미리 준비된 시퀀스를 사용하는 규칙의 첫 번째 전제 조건에서 Yacc를 실행합니다. Yacc의 출력 파일 이름은 항상 y.tab.c입니다. 두 번째 명령은 출력을 규칙의 대상 파일 이름으로 이동합니다.

미리 준비된 시퀀스를 사용하려면 변수를 규칙의 레시피로 대체하십시오. 다른 변수처럼 대체할 수 있습니다 (변수 참조의 기본(Basics of Variable References) 참조). 정의에 의해 정의된 변수는 재귀적으로 확장된 변수이기 때문에 정의 내부에 작성한 모든 변수 참조가 이제 확장됩니다. 예를 들어:

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

run-yacc의 값에서 'foo.y'는 변수 '$^'로 대체되고, '$@'는 'foo.c'로 대체됩니다.

이것은 현실적인 예이지만 make에는 관련된 파일 이름을 기반으로 이러한 명령을 알아내는 묵시적 규칙이 있기 때문에 실제로는 이 특별한 것이 필요하지 않습니다 (암시적 규칙 사용(Using Implicit Rules) 참조).

레시피 실행에서 미리 준비된 시퀀스의 각 라인은 탭이 앞에 오는 규칙에서 해당 라인이 단독으로 나타나는 것처럼 처리됩니다. 특히 make는 각 줄에 대해 별도의 하위 셸을 호출합니다. 미리 준비된 시퀀스의 각 줄에 명령줄('@', '-' 및 '+')에 영향을 주는 특수 접두사 문자를 사용할 수 있습니다. 규칙에 레시피 작성(Writing Recipes 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)

어떤 레시피 라인도 에코하지 않습니다. ('@'에 대한 자세한 설명은 레시피 반향(Recipe Echoing)을 참조하십시오.)

5.9 Using Empty Recipes (빈 레시피 사용)

아무 것도 하지 않는 레시피를 정의하는 것이 때때로 유용합니다. 이것은 공백으로만 구성된 레시피를 제공함으로써 간단히 수행됩니다. 예를 들어:

target: ;

대상에 대한 빈 레시피를 정의합니다. 또한 레시피 접두사 문자로 시작하는 라인을 사용하여 빈 레시피를 정의할 수 있지만 이러한 라인은 비어 있기 때문에 혼동될 수 있습니다.

아무 것도 하지 않는 레시피를 정의하려는 이유가 궁금할 것입니다. 이것이 유용한 한 가지 이유는 대상이 암시적 레시피(암시적 규칙 또는 .DEFAULT 특수 대상에서, 암시적 규칙(Implicit Rules) 및 최후 수단 기본 규칙 정의(Defining Last-Resort Default Rules) 참조)를 가져오지 못하도록 방지하는 것입니다.

다른 레시피의 부작용으로 생성될 타겟에 대한 오류를 피하기 위해 빈 레시피를 사용할 수도 있습니다. 타겟이 존재하지 않는 경우 빈 레시피는 make가 빌드 방법을 모른다고 불평하지 않도록 합니다. target 및 make는 대상이 오래되었다고 가정합니다.

실제 파일이 아니지만 전제 조건이 다시 만들어질 수 있도록 존재하는 대상에 대해 빈 레시피를 정의하려는 경향이 있을 수 있습니다. 그러나 대상 파일이 실제로 존재하는 경우 전제 조건이 제대로 다시 작성되지 않을 수 있기 때문에 이것이 최선의 방법은 아닙니다. 이를 수행하는 더 나은 방법은 가짜 대상(Phony Targets)을 참조하십시오.


6. How to Use Variables (변수 사용 방법)

변수는 변수 값이라고 하는 텍스트 문자열을 나타내기 위해 makefile에 정의된 이름입니다. 이러한 값은 대상, 전제 조건, 레시피 및 makefile의 기타 부분에 대한 명시적 요청으로 대체됩니다. (일부 make의 다른 버전에서는 변수를 매크로라고 합니다.)

makefile의 모든 부분에 있는 변수와 함수는 읽을 때 확장됩니다. 단, 레시피에서 '='를 사용하는 변수 정의의 오른쪽, define 지시문을 사용하는 변수 정의의 본문은 예외입니다.

변수는 파일 이름 목록, 컴파일러에 전달할 옵션, 실행할 프로그램, 소스 파일을 찾을 디렉토리, 출력을 기록할 디렉토리 또는 상상할 수 있는 모든 것을 나타낼 수 있습니다.

변수 이름은 ':', '#', '=' 또는 공백을 포함하지 않는 문자 시퀀스일 수 있습니다. 그러나 문자, 숫자 및 밑줄 이외의 문자를 포함하는 변수 이름은 신중하게 고려해야 합니다. 일부 셸에서는 환경을 통해 sub-make로 전달할 수 없기 때문입니다(Sub-make에 변수 통신(Communicating Variables to a Sub-make) 참조). '.'로 시작하는 변수 이름과 대문자는 향후 make 버전에서 특별한 의미를 가질 수 있습니다.

변수 이름은 대소문자를 구분합니다. 'foo', 'FOO', 'Foo'라는 이름은 모두 다른 변수를 나타냅니다.

변수 이름에 대문자를 사용하는 것이 일반적이지만 makefile에서 내부 목적으로 사용되는 변수 이름에는 소문자를 사용하고 암시적 규칙을 제어하는 매개변수 또는 사용자가 명령으로 재정의해야 하는 매개변수에는 대문자를 예약하는 것이 좋습니다. 옵션(변수 재정의(Overriding Variables) 참조).

일부 변수에는 단일 구두점 문자 또는 몇 개의 문자로된 이름이 있습니다. 이들은 자동 변수이며 특정 용도로 사용됩니다. 자동 변수(Automatic Variables)를 참조하십시오.

6.1 Basics of Variable References (변수 참조의 기초)

변수 값을 대체하려면 달러 기호 다음에 괄호나 중괄호 안에 변수 이름을 작성하십시오. '$(foo)' 또는 '${foo}'는 변수 foo에 대한 유효한 참조입니다. '$'의 이러한 특별한 의미는 파일 이름이나 레시피에서 단일 달러 기호의 효과를 갖기 위해 '$$'를 써야 하는 이유입니다.

변수 참조는 대상, 전제 조건, 레시피, 대부분의 지시문 및 새 변수 값과 같은 모든 컨텍스트에서 사용할 수 있습니다. 다음은 변수가 프로그램에 있는 모든 목적 파일의 이름을 보유하는 일반적인 경우의 예입니다:

objects = program.o foo.o utils.o
program : $(objects)
        cc -o program $(objects)

$(objects) : defs.h

변수 참조는 엄격한 텍스트 대체에 의해 작동합니다. 따라서 다음 규칙은

foo = c
prog.o : prog.$(foo)
        $(foo)$(foo) -$(foo) prog.$(foo)

C 프로그램 prog.c를 컴파일하는데 사용할 수 있습니다. 변수 할당에서 변수값 앞의 공백은 무시되므로 foo의 값은 정확히 'c'입니다. (실제로 이런 식으로 makefile을 작성하지 마십시오!)

달러 기호 다음에 달러 기호, 여는 괄호 또는 여는 중괄호 이외의 문자가 오는 경우 해당 단일 문자를 변수 이름으로 취급합니다. 따라서 변수 x를 '$x'로 참조할 수 있습니다. 그러나 이 방법은 혼동을 일으킬 수 있으므로 (예: '$foo'는 변수 f 다음에 문자열 oo가 오는 것을 나타냄) 모든 변수, 심지어 단일 문자 변수를 생략해도 가독성이 크게 향상되지 않는 한 모든 변수 주위에 괄호나 중괄호를 사용하는 것이 좋습니다. 가독성이 자주 향상되는 한 곳은 자동 변수입니다(자동 변수 (Automatic Variables) 참조).

6.2 The Two Flavors of Variables (변수의 두 가지 맛)

GNU make의 변수가 값을 가질 수 있는 두 가지 방법이 있습니다. 우리는 그것들을 두 가지 종류의 변수라고 부릅니다. 두 가지 특징은 정의 방법과 확장시 수행하는 작업에서 구별됩니다.

변수의 첫 번째 특징은 재귀적으로 확장된 변수입니다. 이러한 종류의 변수는 '='를 사용하는 행(변수 설정(Setting Variables) 참조) 또는 정의 지시문(다중 행 변수 정의(Defining Multi-Line Variables) 참조)으로 정의됩니다. 지정한 값은 그대로 설치됩니다. 다른 변수에 대한 참조가 포함되어 있으면 이 변수가 대체될 때마다 이러한 참조가 확장됩니다 (일부 다른 문자열을 확장하는 과정에서). 이런 경우를 재귀적 확장이라고 합니다.

예를 들어,

foo = $(bar)
bar = $(ugh)
ugh = Huh?

all:;echo $(foo)

는 'Huh?'라고 표시됩니다: '$(foo)'는 '$(bar)'로 확장되고 '$(ugh)'로 확장되고 마침내 'Huh?'로 확장됩니다.

이 유형의 변수는 대부분의 다른 make 버전에서 지원하는 유일한 정렬입니다. 장점과 단점이 있습니다. 장점(대부분의 경우)은 다음과 같습니다:

CFLAGS = $(include_dirs) -O
include_dirs = -Ifoo -Ibar

는 의도한 대로 수행됩니다. 레시피에서 'CFLAGS'가 확장되면 '-Ifoo -Ibar -O'로 확장됩니다. 주요 단점은 다음과 같이 변수 끝에 무언가를 추가할 수 없다는 것입니다.

CFLAGS = $(CFLAGS) -O

변수 확장에 무한 루프가 발생하기 때문입니다. (실제로 make는 무한 루프를 감지하고 오류를 보고합니다.)

또 다른 단점은 정의에서 참조된 모든 함수(텍스트 변환을 위한 함수(Functions for Transforming Text) 참조)가 변수가 확장될 때마다 실행된다는 것입니다. 이것은 make 실행을 느리게 만듭니다. 설상가상으로 와일드카드 및 셸 함수가 호출될 때 또는 호출 횟수를 쉽게 제어할 수 없기 때문에 예측할 수 없는 결과를 제공합니다.

To avoid all the problems and inconveniences of recursively expanded variables, there is another flavor: simply expanded variables.
재귀적으로 확장된 변수의 모든 문제와 불편함을 피하기 위해 또 다른 특징이 있습니다: 단순히 확장된 변수입니다.

단순히 확장된 변수는 ':=' 또는 '::='를 사용하여 행으로 정의됩니다(변수 설정(Setting Variables) 참조). 두 형식은 모두 GNU make에서 동일합니다. 그러나 '::=' 형식만 POSIX 표준에 의해 설명됩니다 ('::='에 대한 지원이 2012년 POSIX 표준에 추가되었으므로 이전 버전의 make에서도 이 형식을 허용하지 않습니다).

단순히 확장된 변수의 값은 한 번만 스캔되어 변수가 정의될때 다른 변수 및 함수에 대한 참조를 확장합니다. 단순히 확장된 변수의 실제 값은 작성한 텍스트를 확장한 결과입니다. 다른 변수에 대한 참조는 포함하지 않습니다. 이 변수가 정의된 시점의 값을 포함합니다. 그러므로,

x := foo
y := $(x) bar
x := later

는 다음과 같습니다.

y := foo bar
x := later

단순히 확장된 변수가 참조될때 해당 값은 그대로 대체됩니다.

다음은 쉘 기능과 함께 ':='의 사용을 보여주는 다소 복잡한 예입니다. (셸 함수(The shell Function)를 참조하십시오.) 이 예제는 또한 레벨에서 레벨로 전달될때 변경되는 변수 MAKELEVEL의 사용을 보여줍니다. (MAKELEVEL에 대한 정보는 Sub-make로의 변수 통신(Communicating Variables to a Sub-make)을 참조하십시오)

ifeq (0,${MAKELEVEL})
whoami    := $(shell whoami)
host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
endif

이 ':=' 사용의 장점은 일반적인 '디렉토리로 내려가는' 레시피가 다음과 같다는 것입니다:

${subdirs}:
        ${MAKE} -C $@ all

단순히 확장된 변수는 대부분의 프로그래밍 언어에서 변수처럼 작동하기 때문에 일반적으로 복잡한 메이크파일 프로그래밍을 더 예측 가능하게 만듭니다. 이를 통해 자체 값(또는 확장 함수중 하나에 의해 어떤 식으로든 처리된 값)을 사용하여 변수를 재정의하고 확장 함수를 훨씬 더 효율적으로 사용할 수 있습니다 (텍스트 변환을 위한 함수(Functions for Transforming Text) 참조).

제어된 선행 공백을 변수 값에 도입하는데 사용할 수도 있습니다. 선행 공백 문자는 변수 참조 및 함수 호출을 대체하기 전에 입력에서 삭제됩니다. 이것은 다음과 같이 변수 참조로 보호하여 변수 값에 선행 공백을 포함할 수 있음을 의미합니다:

nullstring :=
space := $(nullstring) # end of the line

여기서 변수 공간의 값은 정확히 한 공간입니다. '# end of the line' 주석은 명확성을 위해 여기에 포함됩니다. 후행 공백 문자는 변수 값에서 제거되지 않으므로 행 끝에 공백만 있으면 동일한 효과가 있습니다 (그러나 읽기가 다소 어렵습니다). 변수 값 끝에 공백을 넣을 경우 의도를 명확히 하기 위해 줄 끝에 이와 같은 주석을 넣는 것이 좋습니다. 반대로, 변수 값의 끝에 공백 문자를 사용하지 않으려면 다음과 같이 공백 뒤에 줄 끝에 임의의 주석을 추가하지 않도록 기억해야 합니다:

dir := /foo/bar    # directory to put the frobs in

여기서 변수 dir의 값은 '/foo/bar ' (후행 공백 4개 포함)인데, 아마도 의도하지 않았을 것입니다. (이 정의로 '$(dir)/file'과 같은 것을 상상해보십시오!)

There is another assignment operator for variables, '?='. This is called a conditional variable assignment operator, because it only has an effect if the variable is not yet defined. This statement:
변수에 대한 또 다른 할당 연산자인 '?='가 있습니다. 이것은 변수가 아직 정의되지 않은 경우에만 효과가 있기 때문에 조건부 변수 할당 연산자라고 합니다. 다음 문장은:

FOO ?= bar

정확히 다음과 같습니다 (origin 함수(The origin Function) 참조):

ifeq ($(origin FOO), undefined)
  FOO = bar
endif

빈 값으로 설정된 변수는 여전히 정의되어 있으므로 '?='는 해당 변수를 설정하지 않습니다.

6.3 Advanced Features for Reference to Variables (변수 참조를 위한 고급 기능)

이 섹션에서는 보다 유연한 방식으로 변수를 참조하는데 사용할 수 있는 몇 가지 고급 기능에 대해 설명합니다.

6.3.1 Substitution References (대체 참조)

대체 참조는 변수 값을 지정한 변경 사항으로 대체합니다. 형식은 '$(var:a=b)'(또는 '${var:a=b}')이며 그 의미는 변수 var의 값을 취하여 단어 끝에 있는 모든 a를 다음으로 대체하는 것입니다. b를 해당 값에 넣고 결과 문자열을 대체합니다.

"단어 끝에"라고 말할 때, 우리는 공백이 뒤따르거나 대체되기 위해 값의 끝에 반드시 나타나야 함을 의미합니다. 값의 다른 항목은 변경되지 않습니다. 예를 들어:

foo := a.o b.o l.a c.o
bar := $(foo:.o=.c)

'bar'를 'a.c b.c l.a c.c'로 설정합니다. 변수 설정(Setting Variables)을 참조하십시오.

대체 참조는 patsubst 확장 함수의 줄임말 입니다 (문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis) 참조): '$(var:a=b)'는 '$(patsubst %a,%b,var)'와 같습니다. make의 다른 구현과의 호환성을 위해 patsubst 뿐만 아니라 대체 참조를 제공합니다.

다른 유형의 대체 참조를 사용하면 patsubst 함수의 모든 기능을 사용할 수 있습니다. 이것은 이제 단일 '%' 문자를 포함해야 한다는 점을 제외하고는 위에서 설명한 '$(var:a=b)'와 동일한 형식을 갖습니다. 이 경우는 '$(patsubst a,b,$(var))'와 같습니다. patsubst 함수에 대한 설명은 문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오.

예를 들어:

foo := a.o b.o l.a c.o
bar := $(foo:%.o=%.c)

'bar'를 'a.c b.c l.a c.c'로 설정합니다.

6.3.2 Computed Variable Names (계산된 변수 이름)

계산된 변수 이름은 복잡한 makefile 프로그래밍에만 필요한 복잡한 개념입니다. 이름에 달러 기호가 포함된 변수를 만들면 이상한 결과가 나타날 수 있다는 점을 제외하고 대부분의 경우 이러한 변수를 고려할 필요가 없습니다. 그러나 모든 것을 이해하려는 유형이거나 실제로 그들이 하는 일에 관심이 있다면 계속 읽으십시오.

변수 이름 내에서 변수를 참조할 수 있습니다. 이것을 계산 변수 이름 또는 중첩 변수 참조라고 합니다. 예를 들어,

x = y
y = z
a := $($(x))

a를 'z'로 정의: '$($(x))' 내부의 '$(x)'는 'y'로 확장되므로 '$($(x))'는 '$(y)'로 확장되고 이거 다시 'z'로 확장됩니다. 여기서 참조할 변수의 이름은 명시적으로 지정되지 않습니다: '$(x)'의 확장으로 계산됩니다. 여기서 참조 '$(x)'는 외부 변수 참조 내에 중첩됩니다.

이전 예에서는 두 가지 수준의 중첩을 보여주지만 원하는 수의 수준이 가능합니다. 예를 들어 다음과 같은 세 가지 수준이 있습니다:

x = y
y = z
z = u
a := $($($(x)))
``` makefile

여기에서 가장 안쪽의 '\$(x)'는 'y'로 확장되므로 '\$(\$(x))'는 '\$(y)'로 확장되고 차례로 'z'로 확장됩니다. 이제 '\$(z)'가 남고 이건 다시 'u'가 됩니다.

변수 이름 내에서 재귀적으로 확장된 변수에 대한 참조는 일반적인 방식으로 다시 확장됩니다. 예를 들어:

``` makefile
x = $(y)
y = z
z = Hello
a := $($(x))

a는 'Hello'로 정의: '$($(x))'는 '$($(y))'가 되고 '$(z)'는 'Hello'가 됩니다.

중첩 변수 참조는 다른 참조와 마찬가지로 수정된 참조 및 함수 호출(텍스트 변환을 위한 함수(Functions for Transforming Text) 참조)을 포함할 수도 있습니다. 예를 들어, subst 함수를 사용하는 경우(문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis) 참조):

x = variable1
variable2 := Hello
y = $(subst 1,2,$(x))
z = y
a := $($($(z)))

결국 a는 'Hello'로 정의됩니다: 누구나 다음과 같이 복잡한 중첩 참조를 작성하고 싶어할지 의심스럽습니다. 하지만 작동합니다. '$($($(z)))'는 '$($(y))'로 확장되어 '$ ($(subst 1,2,$(x)))'가 되고 이것은 x에서 값 'variable1'을 가져와서 'variable2'로 대체하여 전체 문자열이 값이 'Hello'인 단순 변수 참조인 '$(variable2)'가 되도록 합니다.

계산된 변수 이름이 단일 변수 참조로 완전히 구성될 필요는 없습니다. 여기에는 몇 가지 불변 텍스트뿐만 아니라 여러 변수 참조가 포함될 수 있습니다. 예를 들어,

a_dirs := dira dirb
1_dirs := dir1 dir2

a_files := filea fileb
1_files := file1 file2

ifeq "$(use_a)" "yes"
a1 := a
else
a1 := 1
endif

ifeq "$(use_dirs)" "yes"
df := dirs
else
df := files
endif

dirs := $($(a1)_$(df))

use_a 및 use_dirs 설정에 따라 dirs에 a_dirs, 1_dirs, a_files 또는 1_files와 동일한 값을 제공합니다.

계산된 변수 이름은 대체 참조에서도 사용할 수 있습니다:

a_objects := a.o b.o c.o
1_objects := 1.o 2.o 3.o

sources := $($(a1)_objects:.o=.c)

a1 값에 따라 소스를 'a.c b.c c.c' 또는 '1.c 2.c 3.c'로 정의합니다.

이러한 종류의 중첩 변수 참조 사용에 대한 유일한 제한은 호출할 함수 이름의 일부를 지정할 수 없다는 것입니다. 이는 중첩 참조를 확장하기 전에 인식된 함수 이름에 대한 테스트를 수행하기 때문입니다. 예를 들어,

ifdef do_sort
func := sort
else
func := strip
endif

bar := a d b g q c

foo := $($(func) $(bar))

sort 또는 strip 함수에 대한 인수로 'a d b g q c'를 제공하는 대신 'foo' 변수 'sort a d b g q c' 또는 'strip a d b g q c'의 값을 제공하려고 시도합니다. 이 변경 사항이 좋은 아이디어로 판명되면 나중에 이 제한을 제거할 수 있습니다.

다음과 같이 변수 할당의 왼쪽이나 정의 지시문에서 계산된 변수 이름을 사용할 수도 있습니다:

dir = foo
$(dir)_sources := $(wildcard $(dir)/*.c)
define $(dir)_print =
lpr $($(dir)_sources)
endef

이 예제는 변수 'dir', 'foo_sources' 및 'foo_print'를 정의합니다.

중첩된 변수 참조는 재귀적으로 확장된 변수와 상당히 다르지만(변수의 두 가지 특징(The Two Flavors of Variables) 참조) 두 가지 모두 makefile 프로그래밍을 수행할 때 복잡한 방식으로 함께 사용됩니다.

6.4 How Variables Get Their Values (변수가 값을 가져오는 방법)

변수는 여러 가지 방법으로 값을 얻을 수 있습니다:

  • make를 실행할 때 재정의 값을 지정할 수 있습니다. 변수 재정의(Overriding Variables)를 참조하십시오.

  • 할당(변수 설정(Setting Variables) 참조) 또는 축어적(verbatim) 정의(멀티 라인 변수 정의(Defining Multi-Line Variables) 참조)를 사용하여 makefile에 값을 지정할 수 있습니다.

  • 환경의 변수는 make 변수가 됩니다. 환경으로 부터의 변수들(Variables from the Environment)를 참조하십시오.

  • 여러 자동 변수에 각 규칙에 대한 새 값이 제공됩니다. 이들 각각은 하나의 일반적인 용도를 가지고 있습니다. 자동 변수(Automatic Variables)를 참조하십시오.

  • 여러 변수는 초기값이 일정합니다. 암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules)를 참조하십시오.

6.5 Setting Variables (변수 설정)

makefile에서 변수를 설정하려면 변수 이름으로 시작하는 줄을 작성하고 그 뒤에 '=', ':=' 또는 '::='가 옵니다. 줄에서 '=', ':=' 또는 '::=' 뒤에 오는 것이 값이 됩니다. 예를 들어,

objects = main.o foo.o bar.o utils.o

'objects'라는 변수를 정의합니다. 변수 이름 주위와 '=' 바로 뒤의 공백은 무시됩니다.

'='로 정의된 변수는 재귀적으로 확장된 변수입니다. ':=' 또는 '::='로 정의된 변수는 단순히 확장된 변수입니다. 이러한 정의는 정의가 이루어지기 전에 확장될 변수 참조를 포함할 수 있습니다. 변수의 두 가지 특징(The Two Flavors of Variables)을 참조하십시오.

변수 이름에는 사용할 실제 변수 이름을 찾기 위해 행을 읽을 때 확장되는 함수 및 변수 참조가 포함될 수 있습니다.

컴퓨터의 메모리 양을 제외하고 변수 값의 길이에는 제한이 없습니다. 가독성을 위해 변수 값을 여러 물리적 줄로 분할할 수 있습니다(긴 줄 분할(Splitting Long Lines) 참조).

대부분의 변수 이름은 설정한 적이 없는 경우 빈 문자열을 값으로 갖는 것으로 간주됩니다. 여러 변수에는 비어 있지 않은 기본 제공 초기 값이 있지만 일반적인 방법으로 설정할 수 있습니다(암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules) 참조). 여러 특수 변수가 각 규칙에 대해 새 값으로 자동 설정됩니다. 이를 자동 변수라고 합니다(자동 변수(Automatic Variables) 참조).

변수가 아직 설정되지 않은 경우에만 값으로 설정하려면 '=' 대신 약식 연산자 '?='를 사용할 수 있습니다. 변수 'FOO'의 이 두 설정은 동일합니다(origin 함수(The origin Function) 참조):

FOO ?= bar

and

ifeq ($(origin FOO), undefined)
FOO = bar
endif

The shell assignment operator '!=' can be used to execute a shell script and set a variable to its output. This operator first evaluates the right-hand side, then passes that result to the shell for execution. If the result of the execution ends in a newline, that one newline is removed; all other newlines are replaced by spaces. The resulting string is then placed into the named recursively-expanded variable. For example:
셸 할당 연산자 '!='는 셸 스크립트를 실행하고 변수를 출력으로 설정하는 데 사용할 수 있습니다. 이 연산자는 먼저 우변을 평가한 다음 그 결과를 실행을 위해 셸에 전달합니다. 실행 결과가 개행으로 끝나면 하나의 개행이 제거됩니다. 다른 모든 개행은 공백으로 대체됩니다. 결과 문자열은 이름이 지정된 재귀적으로 확장된 변수에 배치됩니다. 예를 들어:

hash != printf '\043'
file_list != find . -name '*.c'

실행 결과가 $를 생성할 수 있고 그 뒤에 오는 것을 make 변수나 함수 참조로 해석하지 않으려면 실행의 일부로 모든 $를 $$로 바꿔야 합니다. 또는 쉘 함수 호출을 사용하여 프로그램을 실행한 결과에 단순 확장 변수를 설정할 수 있습니다. 쉘 함수를 참조하십시오. 예를 들어:

hash := $(shell printf '\043')
var := $(shell find . -name "*.c")

쉘 함수와 마찬가지로 방금 호출된 쉘 스크립트의 종료 상태는 .SHELLSTATUS 변수에 저장됩니다.

6.6 Appending More Text to Variables (변수에 더 많은 텍스트 추가하기)

종종 이미 정의된 변수 값에 더 많은 텍스트를 추가하는 것이 유용합니다. 다음과 같이 '+='가 포함된 줄로 이 작업을 수행합니다:

objects += another.o

이것은 변수 'objects'의 값을 취하고 여기에 'another.o'라는 텍스트를 추가합니다 (이미 값이 있는 경우 단일 공백이 앞에 옴). 따라서:

objects = main.o foo.o bar.o utils.o
objects += another.o

'objects'를 'main.o foo.o bar.o utils.o another.o'로 설정합니다.

'+='를 사용하는 것은 다음과 유사합니다:

objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o

그러나 더 복잡한 값을 사용할 때 중요해지는 방식이 다릅니다.

문제의 변수가 이전에 정의되지 않은 경우 '+='는 일반 '='처럼 작동합니다: 재귀적으로 확장된 변수를 정의합니다. 그러나 이전 정의가 있는 경우 '+='가 정확히 무엇을 하는지는 원래 정의한 변수의 풍미에 따라 다릅니다. 변수의 두 가지 특성에 대한 설명은 변수의 두 가지 특성(The Two Flavors of Variables)을 참조하십시오.

When you add to a variable's value with '+=', make acts essentially as if you had included the extra text in the initial definition of the variable. If you defined it first with ':=' or '::=', making it a simply-expanded variable, '+=' adds to that simply-expanded definition, and expands the new text before appending it to the old value just as ':=' does (see Setting Variables, for a full explanation of ':=' or '::='). In fact,
'+='로 변수 값에 추가할 때 make는 기본적으로 변수의 초기 정의에 추가 텍스트를 포함시킨 것처럼 작동합니다. ':=' 또는 '::='로 먼저 정의하고 단순 확장 변수로 만든 경우 '+='는 단순 확장 정의에 추가하고 이전 값에 추가하기 전에 새 텍스트를 확장합니다. ':='와 같이(':=' 또는 '::='에 대한 전체 설명은 변수 설정(Setting Variables) 참조).

variable := value
variable += more

사실 이것은 다음과 정확히 동일합니다:

variable := value
variable := $(variable) more

반면에 일반 '='를 사용하여 재귀적으로 확장되도록 먼저 정의한 변수와 함께 '+='를 사용하는 경우 make는 약간 다른 작업을 수행합니다. 재귀적으로 확장된 변수를 정의할 때 make는 변수 및 함수 참조에 대해 설정한 값을 즉시 확장하지 않습니다. 대신 텍스트를 그대로 저장하고 나중에 새 변수를 참조할 때 확장할 수 있도록 이러한 변수 및 함수 참조를 저장합니다(변수의 두 가지 특징(The Two Flavors of Variables) 참조). 재귀적으로 확장된 변수에 '+='를 사용하면 make가 지정한 새 텍스트를 추가하는 것은 이 확장되지 않은 텍스트입니다.

variable = value
variable += more

이것은 대략 다음과 같습니다 (물론 temp라는 변수를 정의하지 않는다는 점을 제외하고는):

temp = value
variable = $(temp) more

변수의 이전 값에 변수 참조가 포함될 때 이것이 중요합니다. 다음과 같은 일반적인 예를 들어보세요.

CFLAGS = $(includes) -O
...
CFLAGS += -pg # enable profiling

첫 번째 줄은 다른 변수에 대한 참조로 CFLAGS 변수를 정의합니다. (CFLAGS는 C 컴파일 규칙에서 사용됩니다; 기본 제공 규칙 카탈로그(Catalogue of Built-In Rules) 참조) 정의에 '='를 사용하면 CFLAGS가 재귀적으로 확장되는 변수가 됩니다. 즉, make가 CFLAGS의 정의를 처리할때 '$(includes) -O'가 확장되지 않습니다. 따라서 값을 적용하기 위해 'includes'를 아직 정의할 필요가 없습니다. CFLAGS에 대한 참조 전에만 정의하면 됩니다. '+='를 사용하지 않고 CFLAGS 값에 추가하려고 하면 다음과 같이 할 수 있습니다:

CFLAGS := $(CFLAGS) -pg # enable profiling

이것은 매우 가깝지만 우리가 원하는 것은 아닙니다. ':='를 사용하면 CFLAGS를 단순 확장 변수로 재정의합니다. 이것은 make가 변수를 설정하기 전에 텍스트 '$(CFLAGS) -pg'를 확장한다는 것을 의미합니다. 'includes'가 아직 정의되지 않은 경우 '-O -pg'가 표시되고 나중에 'includes'를 정의해도 효과가 없습니다. 반대로 '+='를 사용하여 CFLAGS를 확장되지 않은 값 '$(includes) -O -pg'로 설정합니다. 따라서 'includes'에 대한 참조가 유지되므로 해당 변수가 나중에 정의되면 '$(CFLAGS)'와 같은 참조는 여전히 해당 값을 사용합니다.

6.7 The override Directive (override 지시문)

변수가 명령 인수로 설정된 경우(변수 재정의(Overriding Variables) 참조) makefile의 일반 할당은 무시됩니다. makefile에 변수가 명령 인수로 설정되어 있어도 설정하려면 다음과 같은 행인 override 지시문을 사용할 수 있습니다:

override variable = value

or

override variable := value

명령줄에 정의된 변수에 더 많은 텍스트를 추가하려면 다음을 사용하십시오:

override variable += more text

변수에 더 많은 텍스트 추가하기(Appending More Text to Variables)를 참조하십시오.

재정의 플래그로 표시된 변수 할당은 다른 재정의를 제외하고 다른 모든 할당보다 우선 순위가 높습니다. 재정의로 표시되지 않은 이 변수에 대한 후속 할당 또는 추가는 무시됩니다.

override 지시문은 makefile과 명령 인수 간의 전쟁을 확대하기 위해 발명되지는 않았습니다. 사용자가 명령 인수로 지정하는 값을 변경하고 추가할 수 있도록 고안되었습니다.

예를 들어, C 컴파일러를 실행할 때 항상 '-g' 스위치를 원하지만 사용자가 평소와 같이 명령 인수로 다른 스위치를 지정할 수 있도록 하고 싶다고 가정합니다. 이 'override' 지시문을 사용할 수 있습니다:

override CFLAGS += -g

'define' 지시문과 함께 'override' 지시문을 사용할 수도 있습니다. 이것은 예상대로 수행됩니다:

override define foo =
bar
endef

여러 줄 변수 정의(Defining Multi-Line Variables)를 참조하십시오.

6.8 Defining Multi-Line Variables (여러줄 변수 정의)

변수 값을 설정하는 또 다른 방법은 define 지시문을 사용하는 것입니다. 이 지시문에는 값에 줄 바꿈 문자를 포함할 수 있는 특이한 구문이 있습니다. 이는 미리 준비된 명령 시퀀스(미리 준비된 레시피 정의(Defining Canned Recipes) 참조)와 eval과 함께 사용할 makefile 구문 섹션(Eval 함수(Eval Function) 참조)을 모두 정의하는 데 편리합니다.

define 지시어는 같은 줄에 정의되는 변수의 이름과 (선택적) 할당 연산자가 오고 그 이상은 없습니다. 변수에 줄 값은 다음 줄에 나타납니다. 값의 끝은 endef라는 단어만 포함하는 행으로 표시됩니다.

이러한 구문의 차이를 제외하고 define는 다른 변수 정의와 동일하게 작동합니다. 변수 이름에는 사용할 실제 변수 이름을 찾기 위해 지시문을 읽을 때 확장되는 함수 및 변수 참조가 포함될 수 있습니다.

endef 앞의 마지막 줄 바꿈은 값에 포함되지 않습니다. 값에 후행 줄 바꿈이 포함되도록 하려면 빈 줄을 포함해야 합니다. 예를 들어 개행 문자를 포함하는 변수를 정의하려면 하나가 아닌 두 개의 빈 행을 사용해야 합니다:

define newline


endef

원하는 경우 변수 할당 연산자를 생략할 수 있습니다. 생략하면 make는 이를 '='로 가정하고 재귀적으로 확장된 변수를 생성합니다(변수의 두 가지 특성(The Two Flavors of Variables) 참조). '+=' 연산자를 사용할 때 값은 다른 추가 작업과 마찬가지로 이전 값에 추가됩니다. 단일 공백으로 이전 값과 새 값을 구분합니다.

define 지시문을 중첩할 수 있습니다: make는 중첩 지시문을 추적하고 endef로 모두 제대로 닫히지 않은 경우 오류를 보고합니다. recipe 접두사 문자로 시작하는 라인은 레시피의 일부로 간주되므로 이러한 라인에 나타나는 모든 define 또는 endef 문자열은 make 지시문으로 간주되지 않습니다.

define two-lines
echo foo
echo $(bar)
endef

레시피에서 사용되는 경우 이전 예제는 다음과 기능적으로 동일합니다:

two-lines = echo foo; echo $(bar)

세미콜론으로 구분된 두 개의 명령은 두 개의 개별 쉘 명령처럼 작동하기 때문입니다. 그러나 두 개의 개별 라인을 사용한다는 것은 make가 쉘을 두 번 호출하여 각 라인에 대해 독립적인 하위 쉘을 실행한다는 것을 의미합니다. 레시피 실행(Recipe Execution)을 참조하십시오.

define으로 만든 변수 정의가 명령줄 변수 정의보다 우선하도록 하려면 define과 함께 override 지시문을 사용할 수 있습니다:

override define two-lines =
foo
$(bar)
endef

재정의 지시문(The override Directive)을 참조하십시오.

6.9 Undefining Variables (변수 정의 해제)

변수를 지우려면 일반적으로 해당 값을 공백으로 설정하면 충분합니다. 이러한 변수를 확장하면 설정 여부에 관계없이 동일한 결과(빈 문자열)가 생성됩니다. 그러나 flavor(Flavor 함수 참조) 및 Origin(Origin 함수 참조) 함수를 사용하는 경우 설정되지 않은 변수와 값이 비어 있는 변수 간에 차이가 있습니다. 이러한 상황에서 undefine 지시문을 사용하여 변수가 설정되지 않은 것처럼 보이게 할 수 있습니다. 예를 들어:

foo := foo
bar = bar

undefine foo
undefine bar

$(info $(origin foo))
$(info $(flavor bar))

이 예제는 두 변수 모두에 대해 "undefined"를 인쇄합니다.

명령줄 변수 정의를 해제하려면 변수 정의에 대해 수행하는 방법과 유사하게 override 지시문을 undefine과 함께 사용할 수 있습니다:

override undefine CFLAGS

6.10 Variables from the Environment (환경으로부터의 변수들)

make의 변수는 make가 실행되는 환경에서 올 수 있습니다. make가 시작할 때 보는 모든 환경 변수는 동일한 이름과 값을 가진 make 변수로 변환됩니다. 그러나 makefile 또는 명령 인수를 사용한 명시적 할당은 환경을 재정의합니다. ('-e' 플래그가 지정되면 환경의 값이 makefile의 할당을 무시합니다. 옵션 요약(Summary of Options)을 참조하십시오. 그러나 권장되는 방법은 아닙니다.)

따라서 환경에서 CFLAGS 변수를 설정하면 대부분의 makefile에서 모든 C 컴파일이 원하는 컴파일러 스위치를 사용하도록 할 수 있습니다. 이것은 makefile이 다른 용도로 변수를 사용하지 않는다는 것을 알고 있기 때문에 표준 또는 관습적 의미를 가진 변수에 대해 안전합니다. (완전히 신뢰할 수 있는 것은 아닙니다. 일부 메이크파일은 CFLAGS를 명시적으로 설정하므로 환경의 값에 영향을 받지 않습니다.)

make가 레시피를 실행하면 makefile에 정의된 변수가 각 쉘의 환경에 배치됩니다. 이를 통해 하위 make 호출에 값을 전달할 수 있습니다(make의 재귀 사용(Recursive Use of make) 참조). 기본적으로 환경이나 명령줄에서 가져온 변수만 재귀 호출에 전달됩니다. export 지시문을 사용하여 다른 변수를 전달할 수 있습니다. 자세한 내용은 Sub-make에 변수 통신(Communicating Variables to a Sub-make)을 참조하십시오.

환경 변수의 다른 사용은 권장되지 않습니다. 메이크파일이 자신의 제어 외부에 설정된 환경 변수에 따라 작동하는 것은 현명하지 않습니다. 이렇게 하면 다른 사용자가 동일한 메이크파일에서 다른 결과를 얻을 수 있기 때문입니다. 이것은 대부분의 makefile의 전체 목적에 위배됩니다.

이러한 문제는 사용자가 대화형 쉘을 선택하도록 지정하기 위해 일반적으로 환경에 존재하는 변수 SHELL에서 특히 발생할 수 있습니다. 이 선택이 make에 영향을 미치는 것은 매우 바람직하지 않습니다. 따라서 make는 SHELL 환경 변수를 특별한 방식으로 처리합니다. 쉘 선택(Choosing the Shell)을 참조하십시오.

6.11 Target-specific Variable Values (대상별 변수 값)

make의 변수 값은 일반적으로 전역적입니다. 즉, 평가 위치에 관계없이 동일합니다(물론 재설정되지 않는 한). 한 가지 예외는 자동 변수입니다(자동 변수(Automatic Variables) 참조).

다른 예외는 대상별 변수 값입니다. 이 기능을 사용하면 현재 빌드 중인 대상을 기반으로 동일한 변수에 대해 다른 값을 정의할 수 있습니다. 자동 변수와 마찬가지로 이러한 값은 대상의 레시피 컨텍스트 내에서만 사용할 수 있습니다(및 기타 대상별 할당).

다음과 같이 대상별 변수 값을 설정합니다:

target ... : variable-assignment

대상별 변수 할당은 export, override 또는 private 특수 키워드의 일부 또는 전부를 접두사로 사용할 수 있습니다. 이들은 변수의 이 인스턴스에만 정상적인 동작을 적용합니다.

여러 대상 값은 대상 목록의 각 구성원에 대해 개별적으로 대상별 변수 값을 생성합니다.

변수 할당은 유효한 할당 형식일 수 있습니다. 재귀('='), 단순(':=' 또는 '::='), 추가('+=') 또는 조건부('?='). 변수 할당 내에 나타나는 모든 변수는 대상 컨텍스트 내에서 평가되므로 이전에 정의된 대상별 변수 값이 적용됩니다. 이 변수는 실제로 모든 "전역(global)" 값과 구별됩니다: 두 변수는 동일한 특성을 가질 필요가 없습니다(재귀 vs 단순).

대상별 변수는 다른 makefile 변수와 동일한 우선 순위를 갖습니다. 명령줄에 제공된 변수('-e' 옵션이 적용된 환경에서)가 우선 적용됩니다. override 지시문을 지정하면 대상별 변수 값을 선호할 수 있습니다.

대상별 변수에는 한 가지 더 특별한 기능이 있습니다: 대상별 변수를 정의할 때 변수 값은 이 대상의 모든 전제조건 및 모든 전제조건 등에 대해서도 적용됩니다. (이러한 전제 조건이 해당 변수를 고유한 대상별 변수 값으로 재정의하지 않는 한). 예를 들어 다음과 같은 문장이 있습니다:

prog : CFLAGS = -g
prog : prog.o foo.o bar.o

prog에 대한 레시피에서 CFLAGS를 '-g'로 설정하지만 prog.o, foo.o 및 bar.o를 생성하는 레시피와 전제 조건을 생성하는 모든 레시피에서도 CFLAGS를 '-g'로 설정합니다.

주어진 전제 조건은 make 호출당 최대 한 번만 빌드된다는 점에 유의하십시오. 동일한 파일이 여러 대상의 전제 조건이고 해당 대상 각각이 동일한 대상 특정 변수에 대해 다른 값을 갖는 경우 빌드될 첫 번째 대상으로 인해 해당 전제 조건이 빌드되고 전제 조건이 대상을 상속합니다. 첫 번째 대상의 특정 값. 다른 모든 대상의 대상별 값은 무시합니다.

6.12 Pattern-specific Variable Values (패턴별 변수 값)

대상별 변수 값(대상별 변수 값(Target-specific Variable Values) 참조) 외에도 GNU make는 패턴별 변수 값을 지원합니다. 이 형식에서 변수는 지정된 패턴과 일치하는 대상에 대해 정의됩니다.

다음과 같이 패턴별 변수 값을 설정합니다:

pattern ... : variable-assignment

여기서 패턴은 % 패턴입니다. 대상별 변수 값과 마찬가지로 여러 패턴 값은 각 패턴에 대해 개별적으로 패턴별 변수 값을 생성합니다. 변수 할당은 모든 유효한 할당 형식이 될 수 있습니다. 재정의가 지정되지 않는 한 모든 명령줄 변수 설정이 우선합니다.

예를 들어:

%.o : CFLAGS = -O

패턴 %.o와 일치하는 모든 대상에 대해 CFLAGS 값 '-O'를 할당합니다.

If a target matches more than one pattern, the matching pattern-specific variables with longer stems are interpreted first. This results in more specific variables taking precedence over the more generic ones, for example:
대상이 둘 이상의 패턴과 일치하는 경우 더 긴 어간을 가진 일치하는 패턴별 변수가 먼저 해석됩니다. 그 결과 보다 구체적인 변수가 보다 일반적인 변수보다 우선 적용됩니다. 예를 들면 다음과 같습니다:

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

lib/%.o: CFLAGS := -fPIC -g
%.o: CFLAGS := -g

all: foo.o lib/bar.o

이 예에서 CFLAGS 변수의 첫 번째 정의는 두 번째 정의가 이 대상에도 적용되지만 lib/bar.o를 업데이트하는 데 사용됩니다. 동일한 어간 길이를 초래하는 패턴별 변수는 makefile에 정의된 순서대로 고려됩니다.

패턴별 변수는 해당 대상에 대해 명시적으로 정의된 대상별 변수 뒤와 상위 대상에 대해 정의된 대상별 변수 이전에 검색됩니다.

6.13 Suppressing Inheritance (상속 억제)

이전 섹션에서 설명한 대로 make 변수는 전제 조건에 의해 상속됩니다. 이 기능을 사용하면 재구축을 유발한 대상에 따라 필수 구성 요소의 동작을 수정할 수 있습니다. 예를 들어 debug 대상에 대상별 변수를 설정한 다음 'make debug'를 실행하면 해당 변수가 debug의 모든 전제 조건에 의해 상속되는 반면 'make all'(예를 들어)을 실행하면 해당 변수가 상속되지 않습니다.

그러나 때로는 변수가 상속되는 것을 원하지 않을 수 있습니다. 이러한 상황에서 make는 private 수정자를 제공합니다. 이 수정자는 모든 변수 할당과 함께 사용할 수 있지만 대상 및 패턴별 변수에 가장 적합합니다. private으로 표시된 모든 변수는 로컬 대상에서 볼 수 있지만 해당 대상의 전제 조건에 의해 상속되지 않습니다. private으로 표시된 전역 변수는 전역 범위에서 볼 수 있지만 대상에 의해 상속되지 않으므로 어떤 레시피에도 표시되지 않습니다.

예를 들어 다음 makefile을 고려하십시오:

EXTRA_CFLAGS =

prog: private EXTRA_CFLAGS = -L/usr/local/lib
prog: a.o b.o

private 수정자로 인해 a.o 및 b.o는 prog 대상에서 EXTRA_CFLAGS 변수 할당을 상속하지 않습니다.

6.14 Other Special Variables (기타 특수 변수)

GNU make는 특별한 속성을 가진 일부 변수를 지원합니다.

  • MAKEFILE_LIST

    구문 분석된 순서대로 make에 의해 구문 분석된 각 makefile의 이름을 포함합니다. 이름은 make가 makefile을 구문 분석하기 시작하기 직전에 추가됩니다. 따라서 makefile이 가장 먼저 하는 일은 이 변수의 마지막 단어를 검사하는 것이라면 현재 makefile의 이름이 됩니다. 그러나 현재 makefile이 include를 사용하면 마지막 단어는 방금 포함된 makefile이 됩니다.

    Makefile이라는 메이크파일에 다음 내용이 있는 경우:

    name1 := $(lastword $(MAKEFILE_LIST))
    
    include inc.mk
    
    name2 := $(lastword $(MAKEFILE_LIST))
    
    all:
            @echo name1 = $(name1)
            @echo name2 = $(name2)

    그러면 다음 출력이 표시될 것으로 예상됩니다:

    name1 = Makefile
    name2 = inc.mk
  • .DEFAULT_GOAL

    명령줄에 대상이 지정되지 않은 경우 사용할 기본 목표를 설정합니다 (목표를 지정하는 인수 참조). .DEFAULT_GOAL 변수를 사용하면 현재 기본 목표를 검색하거나, 해당 값을 지워 기본 목표 선택 알고리즘을 다시 시작하거나, 기본 목표를 명시적으로 설정할 수 있습니다. 다음 예에서는 이러한 경우를 보여줍니다:

    # Query the default goal.
    ifeq ($(.DEFAULT_GOAL),)
      $(warning no default goal is set)
    endif
    
    .PHONY: foo
    foo: ; @echo $@
    
    $(warning default goal is $(.DEFAULT_GOAL))
    
    # Reset the default goal.
    .DEFAULT_GOAL :=
    
    .PHONY: bar
    bar: ; @echo $@
    
    $(warning default goal is $(.DEFAULT_GOAL))
    
    # Set our own.
    .DEFAULT_GOAL := foo

    이 메이크 파일은 다음을 인쇄합니다:

    no default goal is set
    default goal is foo
    default goal is bar
    foo

    .DEFAULT_GOAL에 둘 이상의 대상 이름을 할당하는 것은 유효하지 않으며 오류가 발생합니다.

  • MAKE_RESTARTS

    이 변수는 이 make 인스턴스가 다시 시작된 경우에만 설정됩니다(Makefiles Remake 방법(How Makefiles Are Remade) 참조). 이 인스턴스가 다시 시작된 횟수가 포함됩니다. 이것은 재귀(MAKELEVEL 변수로 계산)와 동일하지 않습니다. 이 변수를 설정, 수정 또는 내보내면 안 됩니다.

  • MAKE_TERMOUT

  • MAKE_TERMERR

    make가 시작되면 stdout 및 stderr이 터미널에 출력을 표시할지 여부를 확인합니다. 그렇다면 MAKE_TERMOUT 및 MAKE_TERMERR를 각각 터미널 장치의 이름으로 설정합니다(또는 결정할 수 없는 경우 true). 설정하면 이러한 변수가 내보내기용으로 표시됩니다. 이러한 변수는 make에 의해 변경되지 않으며 이미 설정된 경우 수정되지 않습니다.

    이 값은 (특히 출력 동기화(병렬 실행 중 출력(Output During Parallel Execution) 참조)와 함께 사용하여 make 자체가 터미널에 쓰고 있는지 여부를 결정하는 데 사용할 수 있습니다. 예를 들어, 레시피 명령이 색상이 지정된 출력을 생성하도록 강제할지 여부를 결정하기 위해 테스트할 수 있습니다.

    하위 make를 호출하고 해당 stdout 또는 stderr을 리디렉션하는 경우 makefile이 해당 변수에 의존하는 경우 이러한 변수도 재설정하거나 내보내기를 취소하는 것은 사용자의 책임입니다.

  • .RECIPEPREFIX

    이 변수 값의 첫 번째 문자는 문자 make가 레시피 라인을 도입한다고 가정할 때 사용됩니다. 변수가 비어 있는 경우(기본값으로) 해당 문자는 표준 탭 문자입니다. 예를 들어 다음은 유효한 makefile입니다:

    .RECIPEPREFIX = >
    all:
    > @echo Hello, world

    .RECIPEPREFIX의 값은 여러 번 변경할 수 있습니다. 일단 설정되면 수정될 때까지 구문 분석된 모든 규칙에 대해 유효합니다.

  • .VARIABLES

    지금까지 정의된 모든 전역 변수의 이름 목록으로 확장합니다. 여기에는 빈 값이 있는 변수와 기본 제공 변수(암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules) 참조)가 포함되지만 대상 관련 컨텍스트에서만 정의된 변수는 포함되지 않습니다. 이 변수에 할당하는 모든 값은 무시됩니다. 항상 특별한 값을 반환합니다.

  • .FEATURES

    이 버전의 make에서 지원하는 특수 기능 목록으로 확장됩니다. 가능한 값에는 다음이 포함되지만 이에 국한되지는 않습니다:

    • 'archives'

      특수 파일 이름 구문을 사용하여 ar(아카이브) 파일을 지원합니다. make를 사용하여 아카이브 파일 업데이트를 참조하십시오.

    • 'check-symlink'

      -L(--check-symlink-times) 플래그를 지원합니다. 옵션 요약(Summary of Options)을 참조하십시오.

    • 'else-if'

      "else if" 중첩되지 않은 조건을 지원합니다. 조건문 구문(Syntax of Conditionals)을 참조하십시오.

    • 'jobserver'

      "작업 서버(job server)" 향상된 병렬 빌드를 지원합니다. 병렬 실행(Parallel Execution)을 참조하십시오.

    • 'oneshell'

      .ONESHELL 특수 대상을 지원합니다. 하나의 셸 사용(Using One Shell)을 참조하십시오.

    • 'order-only'

      주문 전용 전제 조건을 지원합니다. 전제 조건 유형(Types of Prerequisites)을 참조하십시오.

    • 'second-expansion'

      전제 조건 목록의 2차 확장을 지원합니다.

    • 'shortest-stem'

      적용 가능한 여러 옵션 중에서 사용할 패턴을 선택하는 "가장 짧은 어간" 방법을 사용합니다. 패턴 일치 방법(How Patterns Match)을 참조하십시오.

    • 'target-specific'

      대상별 및 패턴별 변수 할당을 지원합니다. 대상별 변수 값(Target-specific Variable Values)을 참조하십시오.

    • 'undefine'

      정의되지 않은 지시문을 지원합니다. 정의되지 않은 지시문(Undefine Directive)을 참조하십시오.

    • 'guile'

      내장된 확장 언어로 GNU Guile을 사용할 수 있습니다. GNU Guile 통합(GNU Guile Integration)을 참조하십시오.

    • 'load'

      사용자 지정 확장을 만들기 위해 동적으로 로드 가능한 개체를 지원합니다. 동적 개체 로드(Loading Dynamic Objects)를 참조하십시오.

  • .INCLUDE_DIRS

    포함된 메이크파일을 검색하는 디렉토리 목록으로 확장합니다(다른 메이크파일 포함(Including Other Makefiles) 참조).

  • .EXTRA_PREREQS

    이 변수의 각 단어는 설정된 대상에 추가되는 새로운 전제조건입니다. 이러한 전제 조건은 자동 변수에 나타나지 않는다는 점에서 일반 전제 조건과 다릅니다(자동 변수(Automatic Variables) 참조). 이를 통해 레시피에 영향을 주지 않는 전제 조건을 정의할 수 있습니다.

    프로그램을 링크하는 규칙을 고려하십시오:

    myprog: myprog.o file1.o file2.o
          $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)

    이제 컴파일러에 대한 업데이트로 인해 프로그램이 다시 링크되도록 이 makefile을 향상시키려고 한다고 가정합니다. 컴파일러를 전제 조건으로 추가할 수 있지만 링크 명령의 인수로 전달되지 않도록 해야 합니다. 다음과 같은 것이 필요합니다:

    myprog: myprog.o file1.o file2.o $(CC)
          $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(filter-out $(CC),$^) $(LDLIBS)

    그런 다음 여러 추가 전제 조건이 있는 것을 고려하십시오: 모두 필터링해야 합니다. .EXTRA_PREREQS 및 대상별 변수를 사용하면 더 간단한 솔루션을 제공합니다:

    myprog: myprog.o file1.o file2.o
          $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
    myprog: .EXTRA_PREREQS = $(CC)

    이 기능은 쉽게 수정할 수 없는 makefile에 전제 조건을 추가하려는 경우에도 유용할 수 있습니다. extra.mk와 같은 새 파일을 만들 수 있습니다:

    myprog: .EXTRA_PREREQS = $(CC)

    그런 다음 make -f extra.mk -f Makefile을 호출합니다.

    .EXTRA_PREREQS를 전역적으로 설정하면 이러한 전제 조건이 모든 대상에 추가됩니다(자체적으로 대상별 값으로 재정의하지 않음). 참고 make는 .EXTRA_PREREQS에 나열된 전제 조건을 전제 조건으로 추가하지 않을 만큼 충분히 똑똑합니다.


7. Conditional Parts of Makefiles (Makefile의 조건부)

조건부 지시문은 makefile의 일부가 변수 값에 따라 따르거나 무시되도록 합니다. 조건문은 한 변수의 값을 다른 변수와 비교하거나 변수 값을 상수 문자열과 비교할 수 있습니다. 조건문은 make 파일에서 실제로 "보는" 것을 제어하므로 실행 시 레시피를 제어하는 데 사용할 수 없습니다.

7.1 Example of a Conditional (조건부의 예)

조건문의 다음 예는 CC 변수가 'gcc'이면 한 세트의 라이브러리를 사용하고 그렇지 않으면 다른 라이브러리 세트를 사용하도록 make에 지시합니다. 규칙에 사용할 두 개의 레시피 라인을 제어하여 작동합니다. 결과는 'CC=gcc'를 인수로 사용하여 어떤 컴파일러를 사용하는지 뿐만 아니라 어떤 라이브러리를 링크했는지도 변경하는 것입니다.

libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
        $(CC) -o foo $(objects) $(libs_for_gcc)
else
        $(CC) -o foo $(objects) $(normal_libs)
endif

이 조건문은 세 가지 지시문을 사용합니다: 하나는 ifeq, 하나는 else, 하나는 endif입니다.

ifeq 지시문은 조건을 시작하고 조건을 지정합니다. 여기에는 쉼표로 구분되고 괄호로 묶인 두 개의 인수가 포함됩니다. 두 인수에 대해 변수 대체를 수행한 다음 비교합니다. ifeq 다음의 makefile 행은 두 인수가 일치하면 실행됩니다. 그렇지 않으면 무시됩니다.

else 지시문은 이전 조건문이 실패한 경우 다음 행을 따르도록 합니다. 위의 예에서 이는 첫 번째 대안이 사용되지 않을 때마다 두 번째 대안 연결 명령이 사용됨을 의미합니다. 조건문에 else를 포함하는 것은 선택 사항입니다.

endif 지시문은 조건문을 종료합니다. 모든 조건문은 endif로 끝나야 합니다. 무조건 makefile 텍스트가 뒤따릅니다.

이 예제에서 알 수 있듯이 조건문은 텍스트 수준에서 작동합니다: 조건문 행은 조건에 따라 makefile의 일부로 처리되거나 무시됩니다. 이것이 규칙과 같은 makefile의 더 큰 구문 단위가 조건문의 시작이나 끝을 가로지를 수 있는 이유입니다.

변수 CC가 'gcc' 값을 가질 때 위의 예는 다음과 같은 효과가 있습니다:

foo: $(objects)
        $(CC) -o foo $(objects) $(libs_for_gcc)

변수 CC에 다른 값이 있는 경우 효과는 다음과 같습니다:

foo: $(objects)
        $(CC) -o foo $(objects) $(normal_libs)

변수 할당을 조건화한 다음 무조건 변수를 사용하여 다른 방법으로 동등한 결과를 얻을 수 있습니다:

libs_for_gcc = -lgnu
normal_libs =

ifeq ($(CC),gcc)
  libs=$(libs_for_gcc)
else
  libs=$(normal_libs)
endif

foo: $(objects)
        $(CC) -o foo $(objects) $(libs)

7.2 Syntax of Conditionals (조건문의 구문)

else가 없는 단순 조건문의 구문은 다음과 같습니다:

conditional-directive
text-if-true
endif

text-if-true는 조건이 true인 경우 makefile의 일부로 간주되는 텍스트 행이 될 수 있습니다. 조건이 false이면 텍스트가 대신 사용되지 않습니다.

복합 조건문의 구문은 다음과 같습니다:

conditional-directive
text-if-true
else
text-if-false
endif

or:

conditional-directive-one
text-if-one-is-true
else conditional-directive-two
text-if-two-is-true
else
text-if-one-and-two-are-false
endif

필요한 만큼 "else 조건부 지시문" 절이 있을 수 있습니다. 주어진 조건이 true이면 text-if-true가 사용되고 다른 절은 사용되지 않습니다. 조건이 true가 아니면 text-if-false가 사용됩니다. text-if-true 및 text-if-false는 여러 줄의 텍스트가 될 수 있습니다.

조건 지시문의 구문은 조건이 단순하든 복잡하든 동일합니다; else다음이거나 아니거나. 서로 다른 조건을 테스트하는 네 가지 지시문이 있습니다. 다음은 그 표입니다:

  • ifeq (arg1, arg2)

  • ifeq 'arg1' 'arg2'

  • ifeq "arg1" "arg2"

  • ifeq "arg1" 'arg2'

  • ifeq 'arg1' "arg2"

    arg1 및 arg2의 모든 변수 참조를 확장하고 비교합니다. 동일하면 text-if-true가 유효합니다. 그렇지 않으면 text-if-false(있는 경우)가 유효합니다.

    변수에 비어 있지 않은 값이 있는지 테스트하려는 경우가 많습니다. 값이 변수 및 함수의 복잡한 확장에서 비롯된 경우 비어 있는 것으로 간주되는 확장에 실제로 공백 문자가 포함될 수 있으므로 비어 있는 것으로 표시되지 않습니다. 그러나 스트립 함수(텍스트 함수(Text Functions) 참조)를 사용하여 공백을 비어 있지 않은 값으로 해석하지 않도록 할 수 있습니다. 예를 들어:

    ifeq ($(strip $(foo)),)
    text-if-empty
    endif

    $(foo) 확장에 공백 문자가 포함된 경우에도 text-if-empty가 실행됩니다.

  • ifneq (arg1, arg2)

  • ifneq 'arg1' 'arg2'

  • ifneq "arg1" "arg2"

  • ifneq "arg1" 'arg2'

  • ifneq 'arg1' "arg2"

    arg1 및 arg2의 모든 변수 참조를 확장하고 비교합니다. 서로 다른 경우 text-if-true가 효과적입니다. 그렇지 않으면 text-if-false(있는 경우)가 유효합니다.

  • ifdef variable-name

    ifdef 형식은 변수에 대한 참조가 아니라 변수의 이름을 인수로 사용합니다. 해당 변수의 값이 비어 있지 않은 값이면 text-if-true가 유효합니다. 그렇지 않으면 text-if-false(있는 경우)가 유효합니다. 정의된 적이 없는 변수에는 빈 값이 있습니다. 변수 이름 텍스트가 확장되므로 변수 이름으로 확장되는 변수 또는 함수가 될 수 있습니다. 예를 들어:

    bar = true
    foo = bar
    ifdef $(foo)
    frobozz = yes
    endif

    변수 참조 $(foo)가 확장되어 변수 이름으로 간주되는 막대가 생성됩니다. 변수 bar는 확장되지 않지만 값이 비어 있지 않은지 확인하기 위해 검사됩니다.

    ifdef는 변수에 값이 있는지 여부만 테스트합니다. 해당 값이 비어 있지 않은지 확인하기 위해 변수를 확장하지 않습니다. 결과적으로 ifdef를 사용하는 테스트는 foo = 와 같은 정의를 제외한 모든 정의에 대해 true를 반환합니다. 빈 값을 테스트하려면 ifeq($(foo),)를 사용하십시오. 예를 들어,

    bar =
    foo = $(bar)
    ifdef foo
    frobozz = yes
    else
    frobozz = no
    endif

    이 경우는 'frobozz'를 'yes'로 설정하는 반면

    foo =
    ifdef foo
    frobozz = yes
    else
    frobozz = no
    endif

    이 경우는 'frobozz'를 'no'로 설정합니다.

  • ifndef variable-name

    변수 variable-name에 빈 값이 있으면 text-if-true가 유효합니다. 그렇지 않으면 text-if-false(있는 경우)가 유효합니다. variable-name의 확장 및 테스트 규칙은 ifdef 지시문과 동일합니다.

조건부 지시문의 시작 부분에서 추가 공백이 허용 및 무시되지만 탭은 허용되지 않습니다. (라인이 탭으로 시작하는 경우 규칙에 대한 레시피의 일부로 간주됩니다) 이 외에도 추가 공백이나 탭을 삽입해도 지시어 이름 또는 인수 내를 제외하고 아무 효과가 없습니다. 줄 끝에 '#'으로 시작하는 주석이 나타날 수 있습니다.

조건문에서 역할을 하는 다른 두 지시문은 else와 endif입니다. 이러한 지시문 각각은 인수 없이 한 단어로 작성됩니다. 줄의 시작 부분에 추가 공백이 허용되고 무시되고 끝 부분에 공백이나 탭이 있습니다. 줄 끝에 '#'으로 시작하는 주석이 나타날 수 있습니다.

조건문은 makefile이 사용하는 라인에 영향을 줍니다. 조건이 참이면 make는 makefile의 일부로 text-if-true 행을 읽습니다. 조건이 거짓이면 make는 해당 행을 완전히 무시합니다. 규칙과 같은 makefile의 구문 단위는 조건문의 시작 또는 끝에서 안전하게 분할될 수 있습니다.

make는 makefile을 읽을 때 조건문을 평가합니다. 결과적으로 자동 변수는 레시피가 실행될 때까지 정의되지 않기 때문에 조건 테스트에서 사용할 수 없습니다(자동 변수(Automatic Variables) 참조).

참을 수 없는 혼란을 방지하기 위해 한 makefile에서 조건문을 시작하고 다른 makefile에서 종료하는 것은 허용되지 않습니다. 그러나 포함된 파일 내에서 조건문을 종료하려고 시도하지 않는 한 조건문 내에서 include 지시문을 작성할 수 있습니다.

7.3 Conditionals that Test Flags (플래그를 테스트하는 조건부)

findstring 함수와 함께 변수 MAKEFLAGS를 사용하여 테스트에서 '-t'와 같은 명령 플래그를 만드는 조건문을 작성할 수 있습니다(문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis) 참조). 이것은 터치가 파일을 최신 상태로 표시하기에 충분하지 않을 때 유용합니다.

findstring 함수는 한 문자열이 다른 문자열의 하위 문자열로 나타나는지 여부를 결정합니다. '-t' 플래그를 테스트하려면 't'를 첫 번째 문자열로 사용하고 MAKEFLAGS 값을 다른 문자열로 사용합니다.

예를 들어, 아카이브 파일을 최신 상태로 표시하기 위해 'ranlib -t'를 사용하도록 정렬하는 방법은 다음과 같습니다:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

'+' 접두사는 해당 레시피 라인을 "재귀적"으로 표시하여 '-t' 플래그를 사용해도 실행되도록 합니다. make의 재귀 사용(Recursive Use of make)을 참조하십시오.


8. Functions for Transforming Text (텍스트 변환 함수)

함수를 사용하면 makefile에서 텍스트 처리를 수행하여 작업할 파일이나 레시피에서 사용할 명령을 계산할 수 있습니다. 함수 호출에서 함수를 사용합니다. 여기서 함수의 이름과 함수가 작동할 일부 텍스트(인수)를 제공합니다. 함수의 처리 결과는 변수가 대체될 수 있는 것처럼 호출 지점에서 makefile로 대체됩니다.

8.1 Function Call Syntax (함수 호출 구문)

함수 호출은 변수 참조와 유사합니다. 변수 참조가 나타날 수 있는 모든 위치에 나타날 수 있으며 변수 참조와 동일한 규칙을 사용하여 확장됩니다. 함수 호출은 다음과 같습니다:

$(function arguments)

또는 다음과 같이:

${function arguments}

Here function is a function name; one of a short list of names that are part of make. You can also essentially create your own functions by using the call built-in function.
여기서 function은 함수 이름입니다. make의 일부인 이름의 짧은 목록 중 하나입니다. 'call' 내장 함수를 사용하여 본질적으로 고유한 함수를 생성할 수도 있습니다.

인수는 함수의 인수입니다. 함수 이름과 하나 이상의 공백 또는 탭으로 구분되며 인수가 두 개 이상인 경우 쉼표로 구분됩니다. 이러한 공백과 쉼표는 인수 값의 일부가 아닙니다. 괄호 또는 중괄호와 상관없이 함수 호출을 둘러싸기 위해 사용하는 구분 기호는 일치하는 쌍으로만 인수에 나타날 수 있습니다. 다른 종류의 구분 기호는 단독으로 나타날 수 있습니다. 인수 자체에 다른 함수 호출이나 변수 참조가 포함된 경우 모든 참조에 대해 동일한 종류의 구분 기호를 사용하는 것이 가장 좋습니다. '$(subst a,b,${x})'가 아니라 '$(subst a,b,$(x))'를 작성하십시오. 더 명확하고 한 가지 유형의 구분 기호만 일치하여 참조의 끝을 찾기 때문입니다.

각 인수에 대해 작성된 텍스트는 함수가 작동하는 텍스트인 인수 값을 생성하기 위해 변수 및 함수 호출을 대체하여 처리됩니다. 대체는 인수가 나타나는 순서대로 수행됩니다.

Commas and unmatched parentheses or braces cannot appear in the text of an argument as written; leading spaces cannot appear in the text of the first argument as written. These characters can be put into the argument value by variable substitution. First define variables comma and space whose values are isolated comma and space characters, then substitute these variables where such characters are wanted, like this:
쉼표와 일치하지 않는 괄호 또는 중괄호는 작성된 인수 텍스트에 나타날 수 없습니다. 선행 공백은 작성된 첫 번째 인수의 텍스트에 나타날 수 없습니다. 이러한 문자는 변수 대체를 통해 인수 값에 넣을 수 있습니다. 먼저 값이 분리된 쉼표와 공백 문자인 변수 쉼표와 공백을 정의한 다음 이러한 문자가 필요한 곳에 다음과 같이 이러한 변수를 대체합니다:

comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
# bar is now 'a,b,c'.

여기서 subst 함수는 foo 값을 통해 각 공백을 쉼표로 바꾸고 결과를 대체합니다.

8.2 Functions for String Substitution and Analysis (문자열 대체 및 분석을 위한 함수)

다음은 문자열에서 작동하는 몇 가지 함수입니다:

  • $(subst from,to,text)

    Performs a textual replacement on the text text: each occurrence of from is replaced by to. The result is substituted for the function call. For example,
    'text' 텍스트에서 텍스트 바꾸기를 수행합니다: 'from'이 나타날 때마다 'to'로 바뀝니다. 결과는 함수 호출로 대체됩니다. 예를 들어,

    $(subst ee,EE,feet on the street)

    'fEEt on the strEEt' 값을 생성합니다.

  • $(patsubst pattern,replacement,text)

    'pattern'과 일치하는 텍스트에서 공백으로 구분된 단어를 찾아 'replacement'로 바꿉니다. 여기서 'pattern'은 와일드카드 역할을 하는 '%'를 포함할 수 있으며 단어 내 임의의 수의 문자와 일치합니다. 'replacement'에 '%'도 포함되어 있으면 '%'는 'pattern'의 '%'와 일치하는 텍스트로 대체됩니다. 'pattern' 및 'replacement'의 첫 번째 '%'만 이러한 방식으로 처리됩니다. 이후의 '%'는 변경되지 않습니다.

    patsubst 함수 호출의 '%' 문자는 앞에 백슬래시('\')를 사용하여 인용할 수 있습니다. 그렇지 않으면 '%' 문자를 인용하는 백슬래시가 더 많은 백슬래시로 인용될 수 있습니다. '%' 문자를 인용하는 백슬래시 또는 기타 백슬래시는 파일 이름을 비교하거나 스템이 대체되기 전에 패턴에서 제거됩니다. '%' 문자를 인용할 위험이 없는 백슬래시는 문제가 되지 않습니다. 예를 들어 the\%weird\%pattern\ 패턴은 작동하는 '%' 문자 앞에 'the%weird\'가 있고 그 뒤에는 'pattern\'이 있습니다. 마지막 두 개의 백슬래시는 '%' 문자에 영향을 줄 수 없기 때문에 그대로 둡니다.

    단어 사이의 공백은 단일 공백 문자로 접힙니다. 선행 및 후행 공백은 삭제됩니다.

    예를 들어,

    $(patsubst %.c,%.o,x.c.c bar.c)

    값 'x.c.o bar.o'를 생성합니다.

    대체 참조(대체 레퍼런스(Substitution References) 참조)는 patsubst 함수의 효과를 얻는 더 간단한 방법입니다:

    $(var:pattern=replacement)

    이것은 다음과 동등합니다

    $(patsubst pattern,replacement,$(var))

    두 번째 속기는 patsubst의 가장 일반적인 사용 중 하나인 파일 이름 끝에 있는 접미사를 대체하는 것을 단순화합니다.

    $(var:suffix=replacement)

    이것은 다음과 동등합니다

    $(patsubst %suffix,%replacement,$(var))

    예를 들어 다음과 같은 개체 파일 목록이 있을 수 있습니다:

    objects = foo.o bar.o baz.o

    해당 소스 파일 목록을 얻으려면 다음과 같이 작성하면 됩니다:

    $(objects:.o=.c)

    일반 형식을 사용하는 대신:

    $(patsubst %.o,%.c,$(objects))
  • $(strip string)

    문자열에서 선행 및 후행 공백을 제거하고 하나 이상의 공백 문자의 각 내부 시퀀스를 단일 공백으로 바꿉니다. 따라서 '$(strip a b c )'는 'a b c'가 됩니다.

    strip 함수는 조건문과 함께 사용할때 매우 유용할 수 있습니다. ifeq 또는 ifneq를 사용하여 빈 문자열 ''과 무언가를 비교할때 일반적으로 빈 문자열과 일치하는 공백 문자열을 원합니다(조건(Conditionals) 참조).

    따라서 다음은 원하는 결과를 얻지 못할 수 있습니다:

    .PHONY: all
    ifneq   "$(needs_made)" ""
    all: $(needs_made)
    else
    all:;@echo 'Nothing to make!'
    endif

    ifneq 지시문에서 변수 참조 '$(needs_made)'를 함수 호출 '$(strip $(needs_made))'로 바꾸면 더 강력해집니다.

  • $(findstring find,in)

    Searches in for an occurrence of find. If it occurs, the value is find; otherwise, the value is empty. You can use this function in a conditional to test for the presence of a specific substring in a given string. Thus, the two examples,
    'find'의 존재를 검색합니다. 검색되면 값은 'find'입니다. 그렇지 않으면 값이 비어 있습니다. 조건부에서 이 함수를 사용하여 주어진 문자열에 특정 하위 문자열이 있는지 테스트할 수 있습니다. 따라서 다음의 두 가지 예에서,

    $(findstring a,a b c)
    $(findstring a,b c)

    값 'a'와 ''(빈 문자열)을 각각 생성합니다. findstring의 실제 적용에 대해서는 테스트 플래그(Testing Flags)를 참조하십시오.

  • $(filter pattern...,text)

    'pattern' 단어와 일치하는 'text'의 모든 공백으로 구분된 단어를 반환하고 일치하지 않는 단어는 제거합니다. 'pattern'은 위의 patsubst 함수에서 사용된 패턴과 마찬가지로 '%'를 사용하여 작성됩니다.

    filter 함수는 변수에서 다른 유형의 문자열(예: 파일 이름)을 구분하는 데 사용할 수 있습니다. 예를 들어:

    sources := foo.c bar.c baz.s ugh.h
    foo: $(sources)
            cc $(filter %.c %.s,$(sources)) -o foo

    foo는 foo.c, bar.c, baz.s 및 ugh.h에 종속되지만 foo.c, bar.c 및 baz.s만 컴파일러에 대한 명령에 지정되어야 한다고 말합니다.

  • $(filter-out pattern...,text)

    pattern 단어와 일치하지 않는 text의 공백으로 구분된 모든 단어를 반환하고 하나 이상과 일치하는 단어를 제거합니다. 이것은 필터 기능의 정반대입니다.

    예를 들면 다음과 같습니다:

    objects=main1.o foo.o main2.o bar.o
    mains=main1.o main2.o

    다음은 'mains'에 없는 모든 개체 파일을 포함하는 목록을 생성합니다:

    $(filter-out $(mains),$(objects))
  • $(sort list)

    list의 단어를 사전순으로 정렬하여 중복 단어를 제거합니다. 출력은 단일 공백으로 구분된 단어 목록입니다. 따라서,

    $(sort foo bar lose)

    'bar foo loss' 값을 반환합니다.

    덧붙여서 sort는 중복된 단어를 제거하기 때문에 정렬 순서에 신경 쓰지 않아도 이 용도로 사용할 수 있습니다.

  • $(word n,text)

    text의 n번째 단어를 반환합니다. n의 적법한 값은 1부터 시작합니다. n이 text의 단어 수보다 크면 값이 비어 있습니다. 예를 들어,

    $(word 2, foo bar baz)

    는 'bar'를 리턴합니다.

  • $(wordlist s,e,text)

    단어 s로 시작하여 단어 e(포함)로 끝나는 텍스트의 단어 목록을 반환합니다. s의 유효한 값은 1부터 시작하고 e는 0부터 시작할 수 있습니다. s가 text의 단어 수보다 크면 값이 비어 있습니다. e가 text의 단어 수보다 크면 text 끝까지의 단어가 반환됩니다. s가 e보다 크면 아무 것도 반환되지 않습니다. 예를 들어,

    $(wordlist 2, 3, foo bar baz)

    는 'bar baz'를 반환합니다.

  • $(words text)

    텍스트의 단어 수를 반환합니다. 따라서 text의 마지막 단어는 $(word $(words text),text)입니다.

  • $(firstword names...)

    인수 names는 공백으로 구분된 일련의 이름으로 간주됩니다. 값은 시리즈의 첫번쨰 이름입니다. 나머지 이름은 무시됩니다.

    예를 들어,

    $(firstword foo bar)

    는 결과 'foo'를 생성합니다. $(firstword text)는 $(word 1,text)와 동일하지만 firstword 함수는 단순성을 위해 유지됩니다.

  • $(lastword names...)

    인수 names는 공백으로 구분된 일련의 이름으로 간주됩니다. 값은 시리즈의 마지막 이름입니다.

    예를 들어,

    $(lastword foo bar)

    는 결과 'bar'를 생성합니다. $(lastword text) 는 $(word $(words text),text) 와 동일하지만, 단순함과 더 나은 성능을 위해 lastword 함수가 추가되었습니다.

다음은 subst 및 patsubst의 실제 사용 예입니다. makefile이 VPATH 변수를 사용하여 make가 전제조건 파일을 검색해야 하는 디렉토리 목록을 지정한다고 가정합니다(모든 전제조건에 대한 VPATH 검색 경로(VPATH Search Path for All Prerequisites) 참조). 이 예제는 동일한 디렉토리 목록에서 헤더 파일을 검색하도록 C 컴파일러에 지시하는 방법을 보여줍니다.

VPATH의 값은 'src:../headers'와 같이 콜론으로 구분된 디렉토리 목록입니다. 먼저 subst 함수를 사용하여 콜론을 공백으로 변경합니다:

$(subst :, ,$(VPATH))

이것은 'src ../headers'를 생성합니다. 그런 다음 patsubst를 사용하여 각 디렉토리 이름을 '-I' 플래그로 바꿉니다. 다음과 같이 C 컴파일러에 자동으로 전달되는 변수 CFLAGS의 값에 추가할 수 있습니다:

override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))

이 결과는 '-Isrc -I../headers' 텍스트를 이전에 제공된 CFLAGS 값에 추가하는 것입니다. override 지시문은 CFLAGS의 이전 값이 명령 인수로 지정된 경우에도 새 값이 할당되도록 사용됩니다(override 지시문(The override Directive) 참조).

8.3 Functions for File Names (파일 이름에 대한 함수)

기본 제공 확장 기능중 일부는 특히 파일 이름 또는 파일 이름 목록을 분리하는 것과 관련이 있습니다.

다음 각 함수는 파일 이름에 대해 특정 변환을 수행합니다. 함수의 인수는 공백으로 구분된 일련의 파일 이름으로 간주됩니다. (선행 및 후행 공백은 무시됩니다.) 시리즈의 각 파일 이름은 동일한 방식으로 변환되고 결과는 그 사이에 단일 공백으로 연결됩니다.

  • $(dir names...)

    names에서 각 파일 이름의 디렉토리 부분을 추출합니다. 파일 이름의 디렉토리 부분은 파일의 마지막 슬래시를 포함하여 모든 것입니다. 파일 이름에 슬래시가 없으면 디렉토리 부분은 './' 문자열입니다. 예를 들어,

    $(dir src/foo.c hacks)

    는 결과 'src/ ./'를 생성합니다.

  • $(notdir names...)

    names에서 각 파일 이름의 디렉토리 부분을 제외한 모든 것을 추출합니다. 파일 이름에 슬래시가 포함되어 있지 않으면 변경되지 않은 상태로 유지됩니다. 그렇지 않으면 마지막 슬래시까지의 모든 것이 제거됩니다.

    슬래시로 끝나는 파일 이름은 빈 문자열이 됩니다. 이는 결과가 인수와 항상 동일한 수의 공백으로 구분된 파일 이름을 갖지 않는다는 것을 의미하기 때문에 불행한 일입니다. 그러나 우리는 다른 유효한 대안을 보지 못합니다.

    예를 들어,

    $(notdir src/foo.c hacks)

    는 'foo.c hacks' 결과를 생성합니다.

  • $(suffix names...)

    names에서 각 파일 이름의 접미사를 추출합니다. 파일 이름에 마침표가 포함된 경우 접미사는 마지막 마침표로 시작하는 모든 것입니다. 그렇지 않으면 접미사는 빈 문자열입니다. 이는 이름이 없는 경우 결과가 비어 있고 이름에 여러 파일 이름이 포함된 경우 결과에 더 적은 수의 파일 이름이 포함될 수 있음을 의미합니다.

    예를 들어,

    $(suffix src/foo.c src-1.0/bar.c hacks)

    는 결과 '.c.c'를 생성합니다.

  • $(basename names...)

    names에서 각 파일 이름의 접미사를 제외한 모든 것을 추출합니다. 파일 이름에 마침표가 포함된 경우 기본 이름은 마지막 마침표를 포함하지 않고 시작하는 모든 이름입니다. 디렉토리 부분의 마침표는 무시됩니다. 마침표가 없으면 기본 이름은 전체 파일 이름입니다. 예를 들어,

    $(basename src/foo.c src-1.0/bar hacks)

    는 'src/foo src-1.0/bar hacks' 결과를 생성합니다.

  • $(addsuffix suffix,names...)

    인수 names은 공백으로 구분된 일련의 이름으로 간주됩니다. suffix는 단위로 사용됩니다. suffix의 값은 각 개별 이름의 끝에 추가되고 결과적으로 더 큰 이름은 그 사이에 단일 공백으로 연결됩니다. 예를 들어,

    $(addsuffix .c,foo bar)

    는 결과 'foo.c bar.c'를 생성합니다.

  • $(addprefix prefix,names...)

    인수 names은 공백으로 구분된 일련의 이름으로 간주됩니다. prefix는 단위로 사용됩니다. prefix의 값은 각 개별 이름 앞에 추가되고 결과적으로 더 큰 이름은 그 사이에 단일 공백으로 연결됩니다. 예를 들어,

    $(addprefix src/,foo bar)

    는 결과 'src/foo src/bar'를 생성합니다.

  • $(join list1,list2)

    두 개의 인수를 단어별로 연결합니다: 첫 번째 두 단어(각 인수에서 하나씩)는 결과의 첫 번째 단어를 형성하고 두 번째 두 단어는 결과의 두 번째 단어를 형성하는 식입니다. 따라서 결과의 n번째 단어는 각 인수의 n번째 단어에서 나옵니다. 한 인수에 다른 인수보다 더 많은 단어가 있으면 추가 단어가 변경되지 않고 결과에 복사됩니다.

    예를 들어 '$(join a b,.c .o)'는 'a.c b.o'를 생성합니다.

    목록에 있는 단어 사이의 공백은 유지되지 않습니다. 하나의 공백으로 대체됩니다.

    이 함수는 dir 및 notdir 함수의 결과를 병합하여 두 함수에 제공된 원래 파일 목록을 생성할 수 있습니다.

  • $(wildcard pattern)

    인수 pattern은 일반적으로 와일드카드 문자를 포함하는 파일 이름 패턴입니다(셸 파일 이름 패턴에서와 같이). wildcard의 결과는 pattern과 일치하는 기존 파일 이름의 공백으로 구분된 목록입니다. 파일 이름에 와일드카드 문자 사용(Using Wildcard Characters in File Names)을 참조하십시오.

  • $(realpath names...)

    names의 각 파일 이름에 대해 정식의 절대 이름을 반환합니다. 정식 이름에는 . 또는 .. 구성 요소, 반복되는 경로 구분 기호(/) 또는 심볼릭 링크가 포함되지 않습니다. 실패의 경우 빈 문자열이 반환됩니다. 가능한 실패 원인 목록은 realpath(3) 문서를 참조하십시오.

  • $(abspath names...)

    names의 각 파일 이름에 대해 . 또는 .. 구성 요소, 반복되는 경로 구분 기호(/)가 포함되지 않은 절대 이름을 반환합니다. realpath 함수와 달리 abspath는 심볼릭 링크를 확인하지 않으며 기존 파일이나 디렉토리를 참조하는 파일 이름을 요구하지 않습니다. 와일드카드 기능을 사용하여 존재 여부를 테스트합니다.

8.4 Functions for Conditionals (조건부 함수)

조건부 확장을 제공하는 세 가지 기능이 있습니다. 이러한 함수의 주요 측면은 모든 인수가 처음에 확장되지 않는다는 것입니다. 확장해야 하는 인수만 확장됩니다.

  • $(if condition,then-part[,else-part])

    if 함수는 기능적 컨텍스트에서 조건부 확장에 대한 지원을 제공합니다 (ifeq와 같은 GNU makefile 조건부(조건부 구문(Syntax of Conditionals) 참조)).

    첫 번째 인수인 condition은 먼저 선행 및 후행 공백을 모두 제거한 다음 확장합니다. 비어 있지 않은 문자열로 확장되면 조건이 참으로 간주됩니다. 빈 문자열로 확장되면 조건이 거짓으로 간주됩니다.

    'condition'이 참이면 두 번째 인수인 then-part가 평가되고 이는 전체 if 함수의 평가 결과로 사용됩니다.

    'condition'이 거짓이면 세 번째 인수인 else-part가 평가되고 이것이 if 함수의 결과입니다. 세 번째 인수가 없으면 if 함수는 아무 것도 평가하지 않습니다(빈 문자열).

    then-part 또는 else-part 중 하나만 평가되고 둘 다 평가되지는 않습니다. 따라서 둘 중 하나에는 부작용(예: 쉘 함수 호출 등)이 포함될 수 있습니다.

  • $(or condition1[,condition2[,condition3...]])

    'or' 함수는 "단락" OR 연산을 제공합니다. 각 인수는 순서대로 확장됩니다. 인수가 비어 있지 않은 문자열로 확장되면 처리가 중지되고 확장 결과는 해당 문자열입니다. 모든 인수가 확장된 후 모든 인수가 거짓(비어 있음)이면 확장 결과는 빈 문자열입니다.

  • $(and condition1[,condition2[,condition3...]])

    and 함수는 "단락" AND 연산을 제공합니다. 각 인수는 순서대로 확장됩니다. 인수가 빈 문자열로 확장되면 처리가 중지되고 확장의 결과는 빈 문자열입니다. 모든 인수가 비어 있지 않은 문자열로 확장되면 확장 결과는 마지막 인수의 확장입니다.

8.5 The foreach Function (foreach 함수)

foreach 함수는 다른 함수와 매우 다릅니다. 이로 인해 한 텍스트 조각이 반복적으로 사용되며 매번 다른 대체 작업이 수행됩니다. sh 쉘의 for 명령과 C 쉘 csh의 foreach 명령과 유사합니다.

foreach 함수의 구문은 다음과 같습니다:

$(foreach var,list,text)

처음 두 인수 var 및 list는 다른 작업이 수행되기 전에 확장됩니다. 마지막 인수인 text는 동시에 확장되지 않습니다. 그런 다음 확장된 목록 값의 각 단어에 대해 var의 확장된 값으로 명명된 변수가 해당 단어로 설정되고 텍스트가 확장됩니다. 아마도 text에는 해당 변수에 대한 참조가 포함되어 있으므로 확장은 매번 다를 것입니다.

그 결과 목록에 공백으로 구분된 단어가 있는 만큼 텍스트가 확장됩니다. 텍스트의 다중 확장은 연결되어 그 사이에 공백이 있어 foreach의 결과를 만듭니다.

이 간단한 예는 'files' 변수를 'dirs' 목록의 디렉토리에 있는 모든 파일 목록으로 설정합니다:

dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))

여기서 텍스트는 '$(wildcard $(dir)/*)'입니다. 첫 번째 반복은 dir에 대해 값 'a'를 찾으므로 '$(wildcard a/*)'와 동일한 결과를 생성합니다. 두 번째 반복은 '$(wildcard b/*)'의 결과를 생성합니다. 세 번째는 '$(wildcard c/*)'입니다.

이 예는 다음 예와 동일한 결과('dirs' 설정 제외)를 갖습니다:

files := $(wildcard a/* b/* c/* d/*)

텍스트가 복잡하면 추가 변수를 사용하여 이름을 지정하여 가독성을 높일 수 있습니다:

find_files = $(wildcard $(dir)/*)
dirs := a b c d
files := $(foreach dir,$(dirs),$(find_files))

여기에서 우리는 이런 방식으로 find_files 변수를 사용합니다. 일반 '='를 사용하여 재귀적으로 확장되는 변수를 정의하여 해당 값에 foreach의 제어 하에 다시 확장될 실제 함수 호출이 포함되도록 합니다. 와일드카드는 find_files를 정의할 때 한 번만 호출되기 때문에 단순히 확장된 변수는 그렇지 않습니다.

foreach 함수는 변수 var에 영구적인 영향을 미치지 않습니다. foreach 함수 호출 후의 값과 특성은 이전과 동일합니다. 목록에서 가져온 다른 값은 foreach를 실행하는 동안 일시적으로만 유효합니다. var 변수는 foreach 실행중 단순 확장 변수입니다. foreach 함수 호출 전에 var가 정의되지 않은 경우 호출 후에 정의되지 않습니다. 변수의 두 가지 특징(The Two Flavors of Variables)을 참조하십시오.

많은 이상한 것들이 유효한 변수 이름이지만 의도한 것이 아닐 수 있기 때문에 변수 이름을 초래하는 복잡한 변수 표현식을 사용할 때 주의해야 합니다. 예를 들어,

files := $(foreach Esta-escrito-en-espanol!,b c ch,$(find_files))

find_files 값이 이름이 'Esta-escrito-en-espanol!'(es un nombre bastante largo, no?(이름이 꽤 길죠?))인 변수를 참조하는 경우 유용할 수 있지만 실수할 가능성이 더 큽니다.

8.6 The file Function (file 함수)

파일 기능을 사용하면 makefile이 파일에 쓰거나 파일을 읽을 수 있습니다. 두 가지 쓰기 모드가 지원됩니다: 텍스트가 파일의 시작 부분에 쓰여지고 기존 내용이 손실되는 덮어쓰기와 기존 내용을 유지하면서 텍스트가 파일 끝에 기록되는 추가입니다. 두 경우 모두 파일이 존재하지 않으면 생성됩니다. 파일을 쓰기 위해 열 수 없거나 쓰기 작업이 실패하면 치명적인 오류입니다. 파일 함수는 파일에 쓸 때 빈 문자열로 확장됩니다.

파일에서 읽을 때 파일 함수는 파일의 내용을 그대로 확장합니다. 단, 마지막 줄 바꿈(있는 경우)이 제거됩니다. 존재하지 않는 파일에서 읽으려고 하면 빈 문자열로 확장됩니다.

파일 함수의 구문은 다음과 같습니다:

$(file op filename[,text])

파일 함수가 평가될 때 모든 인수가 먼저 확장되고 filename으로 표시된 파일은 op에서 설명하는 모드에서 열립니다.

연산자 op는 파일이 새 내용으로 덮어쓰임을 나타내기 위해 >, 파일의 현재 내용이 추가될 것을 나타내기 위해 >> 또는 파일 내용을 읽을 것임을 나타내기 위해 < 일 수 있습니다. 'filename'은 쓰거나 읽을 파일을 지정합니다. 선택적으로 연산자와 파일 이름 사이에 공백이 있을 수 있습니다.

파일을 읽을 때 텍스트 값을 제공하는 것은 오류입니다.

파일을 쓸 때 텍스트가 파일에 기록됩니다. 텍스트가 줄 바꿈으로 끝나지 않으면 마지막 줄 바꿈이 작성됩니다 (텍스트가 빈 문자열인 경우에도). text 인수가 전혀 주어지지 않으면 아무 것도 기록되지 않습니다.

예를 들어, file 함수는 빌드 시스템에 제한된 명령줄 크기가 있고 레시피가 파일의 인수도 수락할 수 있는 명령을 실행하는 경우에 유용할 수 있습니다. 많은 명령은 @ 접두사가 있는 인수가 더 많은 인수를 포함하는 파일을 지정하는 규칙을 사용합니다. 그런 다음 다음과 같이 레시피를 작성할 수 있습니다:

program: $(OBJECTS)
        $(file >$@.in,$^)
        $(CMD) $(CMDFLAGS) @$@.in
        @rm $@.in

명령에서 각 인수가 입력 파일의 별도 행에 있어야 하는 경우 다음과 같이 레시피를 작성할 수 있습니다:

program: $(OBJECTS)
        $(file >$@.in) $(foreach O,$^,$(file >>$@.in,$O))
        $(CMD) $(CMDFLAGS) @$@.in
        @rm $@.in

8.7 The call Function (call 함수)

호출 함수는 새로운 매개변수화된 함수를 생성하는 데 사용할 수 있다는 점에서 고유합니다. 복잡한 표현식을 변수 값으로 작성한 다음 호출을 사용하여 다른 값으로 확장할 수 있습니다.

호출 함수의 구문은 다음과 같습니다:

$(call variable,param,param,...)

make가 이 기능을 확장할 때 각 매개변수를 임시 변수 $(1), $(2) 등에 할당합니다. 변수 $(0)에는 변수가 포함됩니다. 매개변수 인수의 최대 개수는 없습니다. 최소값도 없지만 매개변수 없이 호출을 사용하는 것은 의미가 없습니다.

그런 다음 변수는 이러한 임시 할당 컨텍스트에서 make 변수로 확장됩니다. 따라서 변수 값에서 $(1)에 대한 참조는 호출 호출의 첫 번째 매개변수로 해석됩니다.

'variable'는 해당 변수에 대한 참조가 아니라 변수의 이름입니다. 따라서 일반적으로 작성할 때 '$'나 괄호를 사용하지 않습니다. (그러나 이름이 상수가 되지 않도록 하려면 이름에 변수 참조를 사용할 수 있습니다.)

변수가 내장 함수의 이름이면 내장 함수가 항상 호출됩니다(해당 이름의 make 변수도 존재하더라도).

call 함수는 param 인수를 임시 변수에 할당하기 전에 확장합니다. 이는 foreach 또는 if와 같은 특수 확장 규칙이 있는 내장 함수에 대한 참조를 포함하는 변수 값이 예상대로 작동하지 않을 수 있음을 의미합니다.

몇 가지 예를 보면 이를 더 명확하게 알 수 있습니다.

이 매크로는 단순히 인수를 뒤집습니다:

reverse = $(2) $(1)

foo = $(call reverse,a,b)

여기서 foo는 'b a'를 포함합니다.

이것은 약간 더 흥미롭습니다: PATH에서 프로그램의 첫 번째 인스턴스를 검색하는 매크로를 정의합니다:

pathsearch = $(firstword $(wildcard $(addsuffix /$(1),$(subst :, ,$(PATH)))))

LS := $(call pathsearch,ls)

이제 변수 LS에는 /bin/ls 또는 이와 유사한 항목이 포함됩니다.

호출 함수는 중첩될 수 있습니다. 각 재귀 호출은 상위 수준 호출의 값을 마스킹하는 $(1) 등에 대한 자체 로컬 값을 가져옵니다. 예를 들어 다음은 지도 함수의 구현입니다:

map = $(foreach a,$(2),$(call $(1),$(a)))

Now you can map a function that normally takes only one argument, such as origin, to multiple values in one step:
이제 origin과 같이 일반적으로 하나의 인수만 사용하는 함수를 한 단계에서 여러 값에 매핑할 수 있습니다:

o = $(call map,origin,o map MAKE)

'file file default'와 같은 것을 포함하는 o로 끝납니다.

마지막 주의사항: 호출할 인수에 공백을 추가할 때 주의하십시오. 다른 함수와 마찬가지로 두 번째 및 후속 인수에 포함된 공백은 유지됩니다. 이것은 이상한 효과를 일으킬 수 있습니다. 호출할 매개변수를 제공할 때 모든 관련 없는 공백을 제거하는 것이 일반적으로 가장 안전합니다.

8.8 The value Function (value 함수)

value 함수는 변수의 값을 확장하지 않고 사용할 수 있는 방법을 제공합니다. 이것은 이미 발생한 확장을 취소하지 않는다는 점에 유의하십시오. 예를 들어 단순히 확장된 변수를 생성하는 경우 해당 값은 정의 중에 확장됩니다. 이 경우 값 함수는 변수를 직접 사용하는 것과 동일한 결과를 반환합니다.

값 함수의 구문은 다음과 같습니다:

$(value variable)

Note that variable is the name of a variable, not a reference to that variable. Therefore you would not normally use a '$' or parentheses when writing it. (You can, however, use a variable reference in the name if you want the name not to be a constant.)
variable는 해당 변수에 대한 참조가 아니라 변수의 이름입니다. 따라서 일반적으로 작성할 때 '$'나 괄호를 사용하지 않습니다. (그러나 이름이 상수가 되지 않도록 하려면 이름에 변수 참조를 사용할 수 있습니다.)

이 함수의 결과는 확장이 발생하지 않고 변수 값을 포함하는 문자열입니다. 예를 들어, 이 메이크파일에서:

FOO = $PATH

all:
        @echo $(FOO)
        @echo $(value FOO)

첫 번째 출력 라인은 "$P"가 make 변수로 확장되기 때문에 ATH가 될 것이고 두 번째 출력 라인은 $PATH 환경 변수의 현재 값이 될 것입니다. 값 함수는 확장을 피했기 때문입니다.

value 함수는 평가 함수와 함께 가장 자주 사용됩니다(Eval 함수(Eval Function) 참조).

8.9 The eval Function (eval 함수)

eval 함수는 매우 특별합니다: 일정하지 않은 새로운 makefile 구성을 정의할 수 있습니다. 다른 변수와 기능을 평가한 결과입니다. eval 함수에 대한 인수가 확장되면 해당 확장의 결과가 makefile 구문으로 구문 분석됩니다. 확장된 결과는 새로운 make 변수, 대상, 암시적 또는 명시적 규칙 등을 정의할 수 있습니다.

eval 함수의 결과는 항상 빈 문자열입니다: 따라서 구문 오류를 일으키지 않고 makefile의 거의 모든 위치에 배치할 수 있습니다.

eval 인수가 두 번 확장된다는 것을 깨닫는 것이 중요합니다: 먼저 eval 함수에 의해 확장된 다음 makefile 구문으로 구문 분석될 때 해당 확장의 결과가 다시 확장됩니다. 이것은 eval을 사용할 때 "$" 문자에 대해 추가 수준의 이스케이프를 제공해야 할 수도 있음을 의미합니다. value 함수(값 함수(Value Function) 참조)는 때때로 이러한 상황에서 원치 않는 확장을 방지하는 데 유용할 수 있습니다.

다음은 eval을 사용하는 방법의 예입니다. 이 예는 여러 개념과 기타 기능을 결합합니다. 이 예제에서 eval을 사용하는 것이 지나치게 복잡해 보일 수 있지만 규칙을 작성하는 것보다 두 가지를 고려하십시오. 첫째, 템플릿 정의(PROGRAM_template에서)가 여기보다 훨씬 더 복잡해야 할 수 있습니다. 둘째, 이 예제의 복잡한 "일반적인(generic)" 부분을 다른 메이크파일에 넣은 다음 모든 개별 메이크파일에 포함할 수 있습니다. 이제 개별 makefile은 매우 간단합니다.

PROGRAMS    = server client

server_OBJS = server.o server_priv.o server_access.o
server_LIBS = priv protocol

client_OBJS = client.o client_api.o client_mem.o
client_LIBS = protocol

# Everything after this is generic

.PHONY: all
all: $(PROGRAMS)

define PROGRAM_template =
 $(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
 ALL_OBJS   += $$($(1)_OBJS)
endef

$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))

$(PROGRAMS):
        $(LINK.o) $^ $(LDLIBS) -o $@

clean:
        rm -f $(ALL_OBJS) $(PROGRAMS)

8.10 The origin Function (origin 함수)

Origin 함수는 변수 값에 대해 작동하지 않는다는 점에서 대부분의 다른 함수와 다릅니다. 변수에 대해 알려줍니다. 특히, 그것은 그것이 어디에서 왔는지 알려줍니다.

Origin 함수의 구문은 다음과 같습니다:

$(origin variable)

variable는 해당 변수에 대한 참조가 아니라 조회할 변수의 이름입니다. 따라서 일반적으로 작성할 때 '$'나 괄호를 사용하지 않습니다. (그러나 이름이 상수가 되지 않도록 하려면 이름에 변수 참조를 사용할 수 있습니다.)

The result of this function is a string telling you how the variable variable was defined:
이 함수의 결과는 variable 변수가 어떻게 정의되었는지 알려주는 문자열입니다:

  • 'undefined'

    변수가 정의되지 않은 경우.

  • 'default'

    if variable has a default definition, as is usual with CC and so on. See Variables Used by Implicit Rules. Note that if you have redefined a default variable, the origin function will return the origin of the later definition.
    변수에 기본 정의가 있는 경우 CC 등의 경우와 같이 일반적입니다. 암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules)를 참조하십시오. 기본 변수(default variable)를 재정의한 경우 origin 함수는 이후 정의의 원점을 반환합니다.

  • 'environment'

    변수가 make에 제공된 환경에서 상속된 경우.

  • 'environment override'

    변수가 make에 제공된 환경에서 상속되었고 '-e' 옵션의 결과로 makefile의 변수 설정을 재정의하는 경우(옵션 요약(Summary of Option) 참조).

  • 'file'

    makefile에 변수가 정의된 경우.

  • 'command line'

    변수가 명령줄에 정의된 경우.

  • 'override'

    변수가 makefile에서 override 지시문으로 정의된 경우(override 지시문(The override Directive) 참조).

  • 'automatic'

    변수가 각 규칙에 대한 레시피 실행을 위해 정의된 자동 변수인 경우(자동 변수(Automatic Variables) 참조).

이 정보는 변수 값을 믿고 싶은지 여부를 결정하는 데 주로 유용합니다(호기심 제외). 예를 들어, 다른 makefile bar를 포함하는 makefile foo가 있다고 가정합니다. 환경에 Bletch의 정의가 포함되어 있더라도 'make -f bar' 명령을 실행하면 변수 Bletch가 bar에 정의되기를 원합니다. 그러나 foo가 bar를 포함하기 전에 Bletch를 정의했다면 해당 정의를 재정의하고 싶지 않습니다. 이것은 foo에서 재정의 지시문을 사용하여 수행할 수 있으며, bar의 이후 정의보다 해당 정의에 우선 순위를 부여합니다. 불행히도 override 지시문은 모든 명령줄 정의도 무시합니다. 따라서 bar에는 다음이 포함될 수 있습니다:

ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc.
endif
endif

Bletch가 환경에서 정의된 경우 이를 재정의합니다.

환경에서 온 경우 Bletch의 이전 정의를 재정의하려면 '-e' 아래에서도 대신 다음과 같이 작성할 수 있습니다:

ifneq "$(findstring environment,$(origin bletch))" ""
bletch = barf, gag, etc.
endif

여기서 재정의는 '$(origin bletch)'가 '환경' 또는 '환경 재정의'를 반환하는 경우 발생합니다. 문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오.

8.11 The flavor Function (flavor 함수)

flavor 함수는 origin 함수와 마찬가지로 변수 값에 대해 작동하지 않고 오히려 변수에 대해 알려줍니다. 특히 변수의 특징을 알려줍니다(변수의 두 가지 특징(The Two Flavors of Variables) 참조).

flavor 함수의 구문은 다음과 같습니다:

$(flavor variable)

variable는 해당 변수에 대한 참조가 아니라 조회할 변수의 이름입니다. 따라서 일반적으로 작성할 때 '$'나 괄호를 사용하지 않습니다. (그러나 이름이 상수가 되지 않도록 하려면 이름에 변수 참조를 사용할 수 있습니다.)

이 함수의 결과는 variable 변수의 특징을 식별하는 문자열입니다:

  • 'undefined'

    변수가 정의되지 않은 경우.

  • 'recursive'

    변수가 재귀적으로 확장된 변수인 경우.

  • 'simple'

    변수가 단순히 확장된 변수인 경우.

8.12 Functions That Control Make (Make를 제어하는 기능)

이 함수는 make 실행 방식을 제어합니다. 일반적으로 makefile의 사용자에게 정보를 제공하거나 일종의 환경 오류가 감지되면 make가 중지되도록 하는데 사용됩니다.

  • $(error text...)

    메시지가 text인 경우 치명적인 오류를 생성합니다. 이 함수가 평가될 때마다 오류가 생성됩니다. 따라서 레시피 내부나 재귀 변수 할당의 오른쪽에 넣으면 나중에까지 평가되지 않습니다. 오류가 생성되기 전에 텍스트가 확장됩니다.

    예를 들어,

    ifdef ERROR1
    $(error error is $(ERROR1))
    endif

    make 변수 ERROR1이 정의되어 있으면 makefile을 읽는 동안 치명적인 오류가 발생합니다. 또는,

    ERR = $(error found an error!)
    
    .PHONY: err
    err: ; $(ERR)

    err 대상이 호출되면 make가 실행되는 동안 치명적인 오류를 생성합니다.

  • $(warning text...)

    이 함수는 make가 종료되지 않는다는 점을 제외하고는 위의 error 함수와 유사하게 작동합니다. 대신 텍스트가 확장되고 결과 메시지가 표시되지만 makefile 처리는 계속됩니다.

    이 함수의 확장 결과는 빈 문자열입니다.

  • $(info text...)

    이 함수는 (확장된) 인수를 표준 출력으로 인쇄하는 것 외에는 아무 것도 하지 않습니다. 메이크파일 이름이나 줄 번호가 추가되지 않습니다. 이 함수의 확장 결과는 빈 문자열입니다.

8.13 The shell Function (shell 함수)

shell 함수는 make 외부의 세계와 통신한다는 점에서 와일드카드 함수(와일드카드 함수(The Function wildcard) 참조) 이외의 다른 함수와 다릅니다.

shell 함수는 역따옴표('`')가 대부분의 쉘에서 수행하는 것과 동일한 기능을 수행합니다: 명령 확장을 수행합니다. 이것은 쉘 명령을 인수로 취하고 명령의 출력으로 평가됨을 의미합니다. make가 결과에 대해 수행하는 유일한 처리는 각 개행(또는 캐리지 리턴/개행 쌍)을 단일 공백으로 변환하는 것입니다. 후행(carriage-return 및) 개행이 있으면 간단히 제거됩니다.

shell 함수에 대한 호출에 의해 실행되는 명령은 함수 호출이 확장될 때 실행됩니다(make가 Makefile을 읽는 방법(How make Reads a Makefile) 참조). 이 함수는 새 쉘을 생성하는 것과 관련이 있기 때문에 재귀적으로 확장된 변수와 단순히 확장된 변수 내에서 shell 함수를 사용할 때의 성능 영향을 주의 깊게 고려해야 합니다(변수의 두 가지 맛(The Two Flavors of Variables) 참조).

shell 함수 또는 '!=' 할당 연산자가 사용된 후 종료 상태는 .SHELLSTATUS 변수에 배치됩니다.

다음은 shell 기능을 사용하는 몇 가지 예입니다:

contents := $(shell cat foo)

내용을 foo 파일의 내용으로 설정하고 각 줄을 구분하는 공백(개행 대신)을 사용합니다.

files := $(shell echo *.c)

파일을 '.c' 확장자로 설정합니다. make가 매우 이상한 쉘을 사용하지 않는 한, 이것은 '$(wildcard .c)'와 같은 결과를 가집니다(최소한 하나의 '.c' 파일이 존재하는 한).

8.14 The guile Function (guile 함수)

GNU make가 내장된 확장 언어로 GNU Guile을 지원하도록 빌드되면 guile 기능을 사용할 수 있습니다. guile 함수는 먼저 일반적인 방식으로 make에 의해 확장된 다음 GNU Guile 평가자에게 전달되는 하나의 인수를 취합니다. 평가자의 결과는 문자열로 변환되어 makefile에서 guile 함수의 확장으로 사용됩니다. Guile에서 만들 확장 프로그램 작성에 대한 자세한 내용은 GNU Guile 통합(GNU Guile Integration)을 참조하십시오.

guile이라는 단어에 대한 .FEATURES 변수를 확인하여 GNU Guile 지원을 사용할 수 있는지 여부를 결정할 수 있습니다.


9. How to Run make (make를 실행하는 방법)

프로그램을 재컴파일하는 방법을 알려주는 메이크파일은 여러 가지 방법으로 사용할 수 있습니다. 가장 간단한 사용법은 오래된 모든 파일을 다시 컴파일하는 것입니다. 일반적으로 makefile은 인수 없이 make를 실행하면 그대로 수행되도록 작성됩니다.

그러나 일부 파일만 업데이트할 수 있습니다. 다른 컴파일러나 다른 컴파일러 옵션을 사용하고 싶을 수도 있습니다. 파일을 변경하지 않고 오래된 파일을 찾고 싶을 수도 있습니다.

make를 실행할 때 인수를 지정하면 이러한 작업과 다른 많은 작업을 수행할 수 있습니다.

make의 종료 상태는 항상 다음 세 가지 값 중 하나입니다.

  • 0

    make가 성공하면 종료 상태는 0입니다.

  • 2

    make에서 오류가 발생하면 종료 상태는 2입니다. 특정 오류를 설명하는 메시지를 인쇄합니다.

  • 1

    '-q' 플래그를 사용하고 make가 일부 대상이 아직 최신 상태가 아니라고 판단하는 경우 종료 상태는 1입니다. 레시피 실행 대신(Instead of Executing Recipes)을 참조하십시오.

9.1 Arguments to Specify the Makefile (Makefile을 지정하는 인수)

makefile의 이름을 지정하는 방법은 '-f' 또는 '--file' 옵션을 사용하는 것입니다('--makefile'도 작동합니다). 예를 들어 '-f altmake'는 altmake 파일을 makefile로 사용하도록 지시합니다.

'-f' 플래그를 여러 번 사용하고 각 '-f' 뒤에 인수가 있으면 지정된 모든 파일이 makefile로 공동으로 사용됩니다.

'-f' 또는 '--file' 플래그를 사용하지 않는 경우 기본적으로 GNUmakefile, makefile 및 Makefile을 순서대로 시도하고 이 세 가지 중 존재하거나 만들 수 있는 첫 번째 항목을 사용합니다 (Makefile작성하기(Writing Makefiles) 참조).

9.2 Arguments to Specify the Goals (목표를 지정하기 위한 인수)

목표는 make가 궁극적으로 업데이트를 위해 노력해야 하는 대상입니다. 다른 대상은 목표의 전제 조건 또는 목표 전제 조건의 전제 조건 등으로 나타나는 경우 업데이트됩니다.

기본적으로 목표는 makefile의 첫 번째 대상입니다(마침표로 시작하는 대상은 계산하지 않음). 따라서 makefile은 일반적으로 첫 번째 대상이 설명하는 전체 프로그램 또는 프로그램을 컴파일하기 위해 작성됩니다. makefile의 첫 번째 규칙에 여러 대상이 있는 경우 전체 목록이 아니라 규칙의 첫 번째 대상만 기본 목표가 됩니다. .DEFAULT_GOAL 변수를 사용하여 makefile 내에서 기본 목표 선택을 관리할 수 있습니다 (기타 특수 변수(Other Special Variables) 참조).

만들 명령줄 인수를 사용하여 다른 목표를 지정할 수도 있습니다. 목표의 이름을 인수로 사용하십시오. 여러 목표를 지정하는 경우 이름을 지정한 순서대로 각각의 목표를 차례로 처리합니다.

makefile의 모든 대상은 목표로 지정할 수 있습니다('-'로 시작하거나 '='를 포함하지 않는 한, 이 경우 각각 스위치 또는 변수 정의로 구문 분석됩니다). make 파일에 없는 대상도 지정될 수 있습니다. make가 대상을 만드는 방법을 알려주는 암시적 규칙을 찾을 수 있는 경우입니다.

Make는 특수 변수 MAKECMDGOALS를 명령줄에서 지정한 목표 목록으로 설정합니다. 명령줄에 목표가 지정되지 않은 경우 이 변수는 비어 있습니다. 이 변수는 특별한 상황에서만 사용해야 합니다.

An example of appropriate use is to avoid including .d files during clean rules (see Automatic Prerequisites), so make won't create them only to immediately remove them again:
적절한 사용의 예는 clean 규칙 중에 .d 파일을 포함하지 않도록 하는 것입니다(자동 전제 조건(Automatic Prerequisites) 참조). 따라서 make는 즉시 다시 제거하기 위해 파일을 생성하지 않습니다.

sources = foo.c bar.c

ifneq ($(MAKECMDGOALS),clean)
include $(sources:.c=.d)
endif

목표를 지정하는 한 가지 용도는 프로그램의 일부만 컴파일하거나 여러 프로그램 중 하나만 컴파일하려는 경우입니다. 리메이크할 각 파일을 목표로 지정하십시오. 예를 들어, 다음과 같이 시작하는 메이크파일이 있는 여러 프로그램을 포함하는 디렉토리를 고려하십시오:

.PHONY: all
all: size nm ld ar as

프로그램 size에 대해 작업하는 경우 해당 프로그램의 파일만 다시 컴파일되도록 'make size'라고 말할 수 있습니다.

목표를 지정하는 또 다른 용도는 일반적으로 만들지 않는 파일을 만드는 것입니다. 예를 들어, 디버깅 출력 파일이나 테스트를 위해 특별히 컴파일된 프로그램 버전이 있을 수 있습니다. 이 버전은 makefile에 규칙이 있지만 기본 목표의 전제 조건은 아닙니다.

목표를 지정하는 또 다른 용도는 가짜 대상(가짜 대상(Phony Targets) 참조) 또는 빈 대상(이벤트를 기록하기 위한 빈 대상 파일(Empty Target Files to Record Events) 참조)과 관련된 레시피를 실행하는 것입니다. 많은 makefile에는 소스 파일을 제외한 모든 것을 삭제하는 clean이라는 가짜 대상이 있습니다. 당연히 'make clean'으로 명시적으로 요청한 경우에만 수행됩니다. 다음은 일반적인 가짜 및 빈 대상 이름 목록입니다. GNU 소프트웨어 패키지가 사용하는 모든 표준 대상 이름의 자세한 목록은 표준 대상을 참조하십시오.

  • all

    makefile이 알고 있는 모든 최상위 대상을 만듭니다.

  • clean

    make를 실행하여 정상적으로 생성된 모든 파일을 삭제합니다.

  • mostlyclean

    'clean'과 비슷하지만 일반적으로 사람들이 다시 컴파일하고 싶지 않은 몇 가지 파일을 삭제하지 않을 수 있습니다. 예를 들어, GCC의 'mostlyclean' 대상은 libgcc.a를 삭제하지 않습니다. 재컴파일이 거의 필요하지 않고 시간이 많이 걸리기 때문입니다.

  • distclean

  • realclean

  • clobber

    이러한 대상 중 하나는 'clean'보다 더 많은 파일을 삭제하도록 정의될 수 있습니다. 예를 들어, makefile 자체에서 이러한 파일을 만들 수 없는 경우에도 일반적으로 컴파일 준비로 만드는 구성 파일이나 링크가 삭제됩니다.

  • install

    사용자가 일반적으로 명령을 검색하는 디렉토리에 실행 파일을 복사합니다. 실행 파일이 사용하는 모든 보조 파일을 찾을 디렉토리에 복사합니다.

  • print

    변경된 소스 파일 목록을 인쇄합니다.

  • tar

    소스 파일의 tar 파일을 만듭니다.

  • shar

    소스 파일의 쉘 아카이브(shar 파일)를 작성하십시오.

  • dist

    소스 파일의 배포 파일을 만듭니다. 이것은 tar 파일, shar 파일, 위의 것 중 하나의 압축된 버전 또는 위의 것 중 하나 이상일 수 있습니다.

  • TAGS

    이 프로그램에 대한 태그 테이블을 업데이트하십시오.

  • check

  • test

    이 메이크파일이 빌드하는 프로그램에 대해 자체 테스트를 수행합니다.

9.3 Instead of Executing Recipes (레시피를 실행하는 대신)

makefile은 대상이 최신 상태인지 여부와 각 대상을 업데이트하는 방법을 make에 알려줍니다. 그러나 목표를 업데이트하는 것이 항상 원하는 것은 아닙니다. 특정 옵션은 make에 대한 다른 활동을 지정합니다.

  • '-n'

  • '--just-print'

  • '--dry-run'

  • '--recon'

    "No-op". make 는 대상을 최신 상태로 만드는 데 필요한 레시피를 인쇄하지만 실제로 실행하지는 않습니다. 일부 레시피는 이 플래그가 있어도 여전히 실행됩니다(MAKE Variable 작동 방식(How the MAKE Variable Works) 참조). 또한 포함된 makefile을 업데이트하는데 필요한 모든 레시피는 여전히 실행됩니다(Makefiles Remake 방법(How Makefiles Are Remade) 참조).

  • '-t'

  • '--touch'

    "Touch". 대상을 실제로 변경하지 않고 최신으로 표시합니다. 즉, make는 대상을 업데이트하는 척하지만 실제로 내용을 변경하지는 않습니다. 대신 수정된 시간만 업데이트됩니다.

  • '-q'

  • '--question'

    "Question". 대상이 최신 상태인지 조용히 확인하되 레시피를 실행하지는 마십시오. 종료 코드는 업데이트가 필요한지 여부를 보여줍니다.

  • '-W file'

  • '--what-if=file'

  • '--assume-new=file'

  • '--new-file=file'

    "What if". 각 '-W' 플래그 뒤에는 파일 이름이 옵니다. 주어진 파일의 수정 시간은 make에 의해 현재 시간으로 기록되지만 실제 수정 시간은 동일하게 유지됩니다. '-n' 플래그와 함께 '-W' 플래그를 사용하여 특정 파일을 수정하는 경우 어떤 일이 발생하는지 확인할 수 있습니다.

make는 '-n' 플래그를 사용하여 실행은 하지않으면서 일반적으로 실행할 레시피를 인쇄합니다.

'-t' 플래그를 사용하면 make는 규칙의 레시피를 무시하고 다시 만들어야 하는 각 대상에 대해 (사실상) 명령 터치를 사용합니다. '-s' 또는 .SILENT가 사용되지 않는한 터치 명령도 인쇄됩니다. 속도를 위해 make는 실제로 프로그램 터치를 호출하지 않습니다. 작업을 직접 수행합니다.

'-q' 플래그를 사용하면 make는 아무 것도 인쇄하지 않고 레시피를 실행하지 않지만, 고려할 대상이 이미 최신 상태인 경우에만 반환되는 종료 상태 코드는 0입니다. 종료 상태가 1인 경우 일부 업데이트를 수행해야 합니다. make에서 오류가 발생하면 종료 상태가 2이므로 최신이 아닌 대상과 오류를 구별할 수 있습니다.

동일한 make 호출에서 이 세 가지 플래그 중 하나 이상을 사용하는 것은 오류입니다.

'-n', '-t' 및 '-q' 옵션은 '+' 문자로 시작하거나 '$(MAKE)' 또는 '${MAKE}' 문자열을 포함하는 레시피 라인에 영향을 미치지 않습니다. 이러한 옵션에 관계 없이 '+' 문자 또는 '$(MAKE)' 또는 '${MAKE}' 문자열이 포함된 행만 실행됩니다. 동일한 규칙의 다른 행도 '+'로 시작하거나 '$(MAKE)' 또는 '${MAKE}'를 포함하지 않는한 실행되지 않습니다(MAKE 변수 작동 방식(How the MAKE Variable Works) 참조).

'-t' 플래그는 '+'로 시작하거나 '$(MAKE)' 또는 '${MAKE}'를 포함하는 레시피 라인이 없는한 가짜 타겟(가짜 타겟(Phony Targets) 참조)이 업데이트되는 것을 방지합니다.

'-W' 플래그는 두 가지 기능을 제공합니다:

  • 만약 이미 '-n' 또는 '-q' 플래그를 사용한다면 일부 파일이 수정되는 경우 make가 수행하는 작업을 볼 수 있습니다.

  • '-n' 또는 '-q' 플래그가 없으면 make가 실제로 레시피를 실행할 때 '-W' 플래그는 make가 해당 파일에 대한 레시피를 실제로 실행하지 않고 일부 파일이 수정된 것처럼 작동하도록 지시할 수 있습니다.
    '-p' 및 '-v' 옵션을 사용하면 make 또는 사용 중인 makefile에 대한 기타 정보를 얻을 수 있습니다(옵션 요약(Summary of Options) 참조).

9.4 Avoiding Recompilation of Some Files (일부 파일의 재컴파일 방지)

때로는 소스 파일을 변경했지만 이에 종속된 모든 파일을 다시 컴파일하고 싶지는 않을 수 있습니다. 예를 들어, 다른 많은 파일이 의존하는 헤더 파일에 매크로나 선언을 추가한다고 가정합니다. 보수적으로 make는 헤더 파일의 변경 사항이 모든 종속 파일을 다시 컴파일해야 한다고 가정하지만 파일을 다시 컴파일할 필요가 없으며 컴파일을 기다리는 시간을 낭비하지 않는 것이 좋습니다.

헤더 파일을 변경하기 전에 문제가 예상되는 경우 '-t' 플래그를 사용할 수 있습니다. 이 플래그는 make에게 규칙의 레시피를 실행하지 말고 마지막 수정 날짜를 변경하여 대상을 최신 상태로 표시하도록 지시합니다. 다음 절차를 따르십시오:

  1. 'make' 명령을 사용하여 실제로 재컴파일이 필요한 소스 파일을 다시 컴파일하고 시작하기 전에 개체 파일이 최신 상태인지 확인하십시오.

  2. 헤더 파일을 변경합니다.

  3. 모든 개체 파일을 최신 상태로 표시하려면 'make -t' 명령을 사용하십시오. 다음에 make를 실행할 때 헤더 파일의 변경 사항으로 인해 재컴파일이 발생하지 않습니다.

If you have already changed the header file at a time when some files do need recompilation, it is too late to do this. Instead, you can use the '-o file' flag, which marks a specified file as "old" (see Summary of Options). This means that the file itself will not be remade, and nothing else will be remade on its account. Follow this procedure:
일부 파일을 재컴파일해야 할 때 이미 헤더 파일을 변경했다면 너무 늦었습니다. 대신 지정된 파일을 "old"로 표시하는 '-o file' 플래그를 사용할 수 있습니다(옵션 요약(Summary of Options) 참조). 이는 파일 자체가 다시 만들어지지 않고 해당 계정에서 다른 어떤 것도 다시 만들어지지 않음을 의미합니다. 다음 절차를 따르십시오.

  1. 특정 헤더 파일과 무관한 이유로 컴파일이 필요한 소스 파일을 'make -o headerfile'로 재컴파일하십시오. 여러 헤더 파일이 관련된 경우 각 헤더 파일에 대해 별도의 '-o' 옵션을 사용합니다.

  2. 모든 오브젝트 파일을 'make -t'로 터치합니다.

9.5 Overriding Variables (변수 재정의)

'='가 포함된 인수는 변수의 값을 지정합니다. 'v=x'는 변수 v의 값을 x로 설정합니다. 이러한 방식으로 값을 지정하면 makefile에서 동일한 변수의 모든 일반 할당이 무시됩니다. 우리는 그것들이 명령줄 인수에 의해 재정의되었다고 말합니다.

이 기능을 사용하는 가장 일반적인 방법은 추가 플래그를 컴파일러에 전달하는 것입니다. 예를 들어, 제대로 작성된 makefile에서 변수 CFLAGS는 C 컴파일러를 실행하는 각 레시피에 포함되어 있으므로 foo.c 파일은 다음과 같이 컴파일됩니다:

cc -c $(CFLAGS) foo.c

따라서 CFLAGS에 설정한 값은 발생하는 각 컴파일에 영향을 줍니다. makefile은 아마도 다음과 같이 CFLAGS에 대한 일반적인 값을 지정합니다:

CFLAGS=-g

make를 실행할 때마다 원하는 경우 이 값을 재정의할 수 있습니다. 예를 들어 'make CFLAGS='-g -O''라고 말하면 각 C 컴파일은 'cc -c -g -O'로 수행됩니다. (이는 또한 변수를 재정의할때 변수 값에 공백 및 기타 특수 문자를 묶기 위해 셸에서 따옴표를 사용하는 방법을 보여줍니다.)

CFLAGS 변수는 이러한 방식으로 변경할 수 있도록 존재하는 많은 표준 변수중 하나일 뿐입니다. 전체 목록은 암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules)를 참조하십시오.

또한 사용자가 변수를 변경하여 makefile이 작동하는 방식의 다른 측면을 제어할 수 있는 기능을 제공하여 사용자 자신의 추가 변수를 보도록 makefile을 프로그래밍할 수 있습니다.

명령줄 인수로 변수를 재정의할 때 재귀 확장 변수 또는 단순 확장 변수를 정의할 수 있습니다. 위에 표시된 예는 재귀적으로 확장된 변수를 만듭니다. 단순 확장 변수를 만들려면 '='대신 ':='또는 '::='를 쓰십시오. 그러나 지정한 값에 변수 참조 또는 함수 호출을 포함하려는 경우가 아니면 어떤 종류의 변수를 생성하든 상관 없습니다.

makefile이 재정의한 변수를 변경할 수 있는 한 가지 방법이 있습니다. 이것은 다음과 같은 라인인 override 지시문을 사용하기 위한 것입니다. 'override variable = value'(override 지시문(The override Directive) 참조).

9.6 Testing the Compilation of a Program (프로그램 컴파일 테스트)

일반적으로 쉘 명령을 실행할때 오류가 발생하면 make는 즉시 포기하고 0이 아닌 상태를 반환합니다. 대상에 대해 더 이상 레시피가 실행되지 않습니다. 오류는 목표를 올바르게 다시 만들 수 없음을 의미하며, 이를 알게 되는 즉시 보고합니다.

방금 변경한 프로그램을 컴파일할 때 이것은 원하는 것이 아닙니다. 대신 가능한 한 많은 컴파일 오류를 표시하기 위해 시도할 수 있는 모든 파일을 컴파일하는 것이 좋습니다.

이러한 경우에는 '-k' 또는 '--keep-going' 플래그를 사용해야 합니다. 이는 make가 포기하고 0이 아닌 상태를 반환하기 전에 보류 중인 대상의 다른 전제 조건을 계속 고려하도록 지시하고, 필요한 경우 다시 만듭니다. 예를 들어, 'make -k'는 하나의 오브젝트 파일을 컴파일하는데 오류가 발생하면 링크가 불가능하다는 것을 이미 알고 있음에도 불구하고 다른 오브젝트 파일을 계속 컴파일합니다. 쉘 명령이 실패한 후에도 계속하는것 외에도 'make -k'는 대상 또는 전제 조건 파일을 만드는 방법을 모른다는 것을 발견한 후에도 가능한 한 계속됩니다. 이것은 항상 오류 메시지를 유발하지만 '-k'가 없으면 치명적인 오류입니다(옵션 요약(Summary of Options) 참조).

make 의 일반적인 동작은 목표를 최신 상태로 유지하는 것이 목적이라고 가정합니다. make가 이것이 불가능하다는 것을 알게 되면 즉시 실패를 보고할 수도 있습니다. '-k' 플래그는 실제 목적이 프로그램의 변경 사항을 가능한 한 많이 테스트하는 것이며, 다음 컴파일을 시도하기 전에 모두 수정할 수 있도록 몇 가지 독립적인 문제를 찾는것일 수 있습니다. 이것이 Emacs의 M-x 컴파일 명령이 기본적으로 '-k' 플래그를 전달하는 이유입니다.

9.7 Summary of Options (옵션 요약)

다음은 make가 이해하는 모든 옵션에 대한 표입니다:

  • '-b'

  • '-m'

    이러한 옵션은 make의 다른 버전과의 호환성을 위해 무시됩니다.

  • '-B'

  • '--always-make'

    모든 대상을 오래된 것으로 간주합니다. GNU는 일반 알고리즘을 사용하여 대상과 전제 조건을 고려합니다. 그러나 그렇게 고려된 모든 대상은 전제 조건의 상태에 관계없이 항상 다시 작성됩니다. 무한 재귀를 피하기 위해 MAKE_RESTARTS(기타 특수 변수(Other Special Variables) 참조)가 0보다 큰 숫자로 설정되어 있으면 메이크 파일을 다시 만들지 여부를 고려할 때 이 옵션이 비활성화됩니다(Makefile을 다시 만드는 방법(How Makefiles Are Remade) 참조).

  • '-C dir'

  • '--directory=dir'

    makefile을 읽기 전에 디렉토리 dir로 변경하십시오. 여러 '-C' 옵션이 지정되면 각각은 이전 옵션에 상대적으로 해석됩니다. '-C / -C etc'는 '-C /etc'와 동일합니다. 이것은 일반적으로 make의 재귀 호출과 함께 사용됩니다(make의 재귀 사용(Recursive Use of make) 참조).

  • '-d'

    일반 처리 외에 디버깅 정보를 인쇄합니다. 디버깅 정보는 어떤 파일이 재작성을 위해 고려되고 있는지, 어떤 파일 시간 및 어떤 결과와 비교되는지, 어떤 파일이 실제로 재작성 되어야 하는지, 어떤 암시적 규칙이 고려되고 어떤 것이 적용되는지와 같은 make가 무엇을 할지 결정하는 방법에 관한 모든 흥미로운 것들을 알려줍니다. -d 옵션은 '--debug=a'와 동일합니다(아래 참조).

  • '--debug[=options]'

    일반 처리 외에 디버깅 정보를 인쇄합니다. 다양한 레벨과 출력 유형을 선택할 수 있습니다. 인수 없이 디버깅의 "기본(basic)" 수준을 인쇄합니다. 가능한 인수는 다음과 같습니다. 첫 번째 문자만 고려되며 값은 쉼표 또는 공백으로 구분해야 합니다.

    • a (all)

      모든 유형의 디버깅 출력이 활성화됩니다. 이것은 '-d'를 사용하는 것과 같습니다.

    • b (basic)

      기본 디버깅은 오래된 것으로 발견된 각 대상과 빌드 성공 여부를 인쇄합니다.

    • v (verbose)

      '기본(basic)'보다 높은 수준; 어떤 makefile이 구문 분석되었는지, 재구축할 필요가 없는 전제 조건 등에 대한 메시지를 포함합니다. 이 옵션은 또한 '기본' 메시지를 활성화합니다.

    • i (implicit)

      각 대상에 대한 암시적 규칙 검색을 설명하는 메시지를 인쇄합니다. 이 옵션은 '기본' 메시지도 활성화합니다.

    • j (jobs)

      특정 하위 명령 호출에 대한 세부 정보를 제공하는 메시지를 인쇄합니다.

    • m (makefile)

      기본적으로 위의 메시지는 makefile을 다시 만드는 동안 활성화되지 않습니다. 이 옵션은 메이크파일을 재구축하는 동안에도 메시지를 활성화합니다. 'all' 옵션은 이 옵션을 활성화합니다. 이 옵션은 '기본' 메시지도 활성화합니다.

    • n (none)

      현재 활성화된 모든 디버깅을 비활성화합니다. 이 후에 추가 디버깅 플래그가 발생하면 여전히 적용됩니다.

  • '-e'

  • '--environment-overrides'

    환경에서 가져온 변수를 makefile의 변수보다 우선시하십시오. 환경으로부터의 변수들(Variables from the Environment)를 참조하십시오.

  • '-E string'

  • '--eval=string'

    문자열을 makefile 구문으로 평가합니다. 이것은 eval 함수의 명령줄 버전입니다(Eval 함수(Eval Function) 참조). 평가는 기본 규칙과 변수가 정의된 후에 수행되지만 makefile을 읽기 전에 수행됩니다.

  • '-f file'

  • '--file=file'

  • '--makefile=file'

    file이라는 파일을 makefile로 읽습니다. Makefile 작성(Writing Makefiles)을 참조하십시오.

  • '-h'

  • '--help'

    make가 이해하는 옵션을 상기시키고 종료됩니다.

  • '-i'

  • '--ignore-errors'

    파일을 다시 만들기 위해 실행된 레시피의 모든 오류를 무시합니다. 레시피의 오류(Errors in Recipes)를 참조하십시오.

  • '-I dir'

  • '--include-dir=dir'

    포함된 메이크파일을 검색할 디렉토리 dir를 지정합니다. 다른 Makefile 포함(Including Other Makefiles)을 참조하십시오. 여러 디렉토리를 지정하기 위해 여러 '-I' 옵션을 사용하는 경우 지정된 순서대로 디렉토리를 검색합니다.

  • '-j [jobs]'

  • '--jobs[=jobs]'

    동시에 실행할 레시피(작업)의 수를 지정합니다. 인수가 없는 경우 make는 가능한 한 많은 레시피를 동시에 실행합니다. 하나 이상의 '-j' 옵션이 있는 경우 마지막 옵션이 유효합니다. 레시피 실행 방법에 대한 자세한 내용은 병렬 실행(Parallel Execution)을 참조하십시오. 이 옵션은 MS-DOS에서 무시됩니다.

  • '-k'

  • '--keep-going'

    오류후 가능한 한 계속하십시오. 실패한 대상과 이에 종속된 대상은 다시 만들 수 없지만 이러한 대상의 다른 전제 조건은 모두 동일하게 처리할 수 있습니다. 프로그램 컴파일 테스트(Testing the Compilation of a Program)를 참조하십시오.

  • '-l [load]'

  • '--load-average[=load]'

  • '--max-load[=load]'

    실행 중인 다른 레시피가 있고 로드 평균이 load(부동 소수점 수) 이상인 경우 새 레시피가 시작되지 않도록 지정합니다. 인수가 없으면 이전 로드 제한을 제거합니다. 병렬 실행(Parallel Execution)을 참조하십시오.

  • '-L'

  • '--check-symlink-times'

    심볼릭 링크를 지원하는 시스템에서 이 옵션을 사용하면 make가 해당 링크에서 참조하는 파일의 타임스탬프 외에 심볼릭 링크의 타임스탬프도 고려하게 됩니다. 이 옵션이 제공되면 파일과 심볼릭 링크중 가장 최근 타임스탬프가 이 대상 파일의 수정 시간으로 간주됩니다.

  • '-n'

  • '--just-print'

  • '--dry-run'

  • '--recon'

    실행될 레시피를 인쇄하지만 실행하지 마십시오(특정 상황 제외). 레시피 실행 대신(Instead of Executing Recipes)을 참조하십시오.

  • '-o file'

  • '--old-file=file'

  • '--assume-old=file'

    file 파일이 전제 조건보다 오래 되었더라도 다시 만들지 말고 파일 변경으로 인해 아무것도 다시 만들지 마십시오. 기본적으로 파일은 매우 오래된 것으로 처리되고 해당 규칙은 무시됩니다. 일부 파일의 재컴파일 방지(Avoiding Recompilation of Some Files)를 참조하십시오.

  • '-O[type]'

  • '--output-sync[=type]'

    Ensure that the complete output from each recipe is printed in one uninterrupted sequence. This option is only useful when using the --jobs option to run multiple recipes simultaneously (see Parallel Execution) Without this option output will be displayed as it is generated by the recipes.
    각 레시피의 전체 출력이 중단되지 않은 하나의 순서로 인쇄되는지 확인합니다. 이 옵션은 --jobs 옵션을 사용하여 여러 레시피를 동시에 실행할 때만 유용합니다(병렬 실행 참조) 이 옵션이 없으면 출력은 레시피에서 생성된 대로 표시됩니다.

    유형이 없거나 '대상' 유형이 없으면 각 대상의 전체 레시피 출력이 함께 그룹화됩니다. 'line' 유형을 사용하면 레시피의 각 라인에서 출력이 함께 그룹화됩니다. 'recurse' 유형을 사용하면 전체 재귀 make의 출력이 함께 그룹화됩니다. '없음' 유형을 사용하면 출력 동기화가 수행되지 않습니다. 병렬 실행 중 출력(Output During Parallel Execution)을 참조하십시오.

  • '-p'

  • '--print-data-base'

    makefile을 읽은 결과 데이터베이스(규칙 및 변수 값)를 인쇄합니다. 그런 다음 평소와 같이 또는 달리 지정된 대로 실행합니다. 이것은 또한 '-v' 스위치에 의해 주어진 버전 정보를 인쇄합니다(아래 참조). 파일을 다시 만들지 않고 데이터베이스를 인쇄하려면 'make -qp'를 사용하십시오. 미리 정의된 규칙 및 변수의 데이터베이스를 인쇄하려면 'make -p -f /dev/null'을 사용합니다. 데이터베이스 출력에는 레시피 및 변수 정의에 대한 파일 이름 및 줄 번호 정보가 포함되어 있으므로 복잡한 환경에서 유용한 디버깅 도구가 될 수 있습니다.

  • '-q'

  • '--question'

    "Question mode". 레시피를 실행하거나 아무 것도 인쇄하지 마십시오. 지정된 대상이 이미 최신 상태이면 0인 종료 상태를 반환하고, 다시 작성해야 하는 경우 1개, 오류가 발생한 경우 2인 종료 상태를 반환합니다. 레시피 실행 대신(Instead of Executing Recipes)을 참조하십시오.

  • '-r'

  • '--no-builtin-rules'

    내장된 암시적 규칙의 사용을 제거합니다(암시적 규칙 사용(Using Implicit Rules) 참조). 패턴 규칙을 작성하여 자신만의 규칙을 정의할 수 있습니다(패턴 규칙 정의 및 재정의(Defining and Redefining Pattern Rules) 참조). '-r' 옵션은 또한 접미사 규칙에 대한 기본 접미사 목록을 지웁니다(구식 접미사 규칙(Old-Fashioned Suffix Rules) 참조). 그러나 .SUFFIXES에 대한 규칙을 사용하여 고유한 접미사를 정의한 다음 고유한 접미사 규칙을 정의할 수 있습니다. 규칙만 -r 옵션의 영향을 받습니다. 기본 변수는 그대로 유지됩니다(암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules) 참조). 아래의 '-R' 옵션을 참조하십시오.

  • '-R'

  • '--no-builtin-variables'

    기본 제공 규칙별 변수의 사용을 제거합니다 (암시적 규칙에서 사용하는 변수(Variables Used by Implicit Rules) 참조). 물론 여전히 자신을 정의할 수 있습니다. 또한 '-R' 옵션은 '-r' 옵션을 자동으로 활성화합니다(위 참조). 사용하는 변수에 대한 정의 없이 암시적 규칙을 갖는 것은 의미가 없기 때문입니다.

  • '-s'

  • '--silent'

  • '--quiet'

    조용한 작동; 실행되는 대로 레시피를 인쇄하지 마십시오. 레시피 반향(Recipe Echoing)을 참조하십시오.

  • '-S'

  • '--no-keep-going'

  • '--stop'

    '-k' 옵션의 효과를 취소합니다. MAKEFLAGS를 통해 최상위 make에서 '-k'가 상속될 수 있는 재귀 make에서 또는 환경의 MAKEFLAGS에서 '-k'를 설정한 경우(make의 재귀 사용(Recursive Use of make) 참조)를 제외하고는 절대 필요하지 않습니다.

  • '-t'

  • '--touch'
    레시피를 실행하는 대신 파일을 터치합니다(실제로 변경하지 않고 파일을 최신 상태로 표시). 이것은 미래의 make 호출을 속이기 위해 레시피가 완료된 척하는 데 사용됩니다. 레시피 실행 대신(Instead of Executing Recipes)을 참조하십시오.

  • '--trace'

    make 실행에 대한 추적 정보를 표시합니다. (.SILENT 또는 '@'로 인해) 일반적으로 무음인 레시피의 경우에도 실행할 전체 레시피를 인쇄합니다. 또한 레시피가 정의된 메이크파일 이름과 줄 번호, 대상이 다시 빌드되는 이유에 대한 정보도 인쇄합니다.

  • '-v'

  • '--version'

    make 프로그램의 버전과 저작권, 저자 목록 및 보증이 없다는 고지를 인쇄하십시오. 그런 다음 종료합니다.

  • '-w'

  • '--print-directory'

    makefile 실행 전후에 작업 디렉토리를 포함하는 메시지를 인쇄하십시오. 이것은 재귀 make 명령의 복잡한 중첩에서 오류를 추적하는 데 유용할 수 있습니다. make의 재귀 사용(Recursive Use of make)을 참조하십시오. (실제로는 'make'가 알아서 해주기 때문에 이 옵션을 지정할 필요가 거의 없습니다. '--print-directory' 옵션을 참조하세요.)

  • '--no-print-directory'

    -w에서 작업 디렉토리의 인쇄를 비활성화합니다. 이 옵션은 -w가 자동으로 켜져 있지만 추가 메시지를 보고 싶지 않을 때 유용합니다. '--print-directory' 옵션을 참조하십시오.

  • '-W file'

  • '--what-if=file'

  • '--new-file=file'

  • '--assume-new=file'

    대상 파일이 방금 수정되었다고 가정하십시오. '-n' 플래그와 함께 사용하면 해당 파일을 수정하면 어떻게 되는지 보여줍니다. '-n'이 없으면 수정 시간이 make의 상상 속에서만 변경된다는 점을 제외하고는 make를 실행하기 전에 주어진 파일에 터치 명령을 실행하는 것과 거의 같습니다. 레시피 실행 대신(Instead of Executing Recipes)을 참조하십시오.

  • '--warn-undefined-variables'

    make가 정의되지 않은 변수에 대한 참조를 볼 때마다 경고 메시지를 발행합니다. 이것은 복잡한 방식으로 변수를 사용하는 메이크파일을 디버그하려고 할 때 도움이 될 수 있습니다.


10. Using Implicit Rules (암시적 규칙 사용)

대상 파일을 다시 만드는 특정 표준 방법은 매우 자주 사용됩니다. 예를 들어, 개체 파일을 만드는 한 가지 일반적인 방법은 C 컴파일러인 cc를 사용하여 C 소스 파일에서 가져오는 것입니다.

암시적 규칙은 make에게 관습적인 기술을 사용하는 방법을 알려주므로 그것을 사용하고 싶을 때 그것을 자세히 지정할 필요가 없습니다. 예를 들어, C 컴파일에 대한 암시적 규칙이 있습니다. 파일 이름은 실행되는 암시적 규칙을 결정합니다. 예를 들어, C 컴파일은 일반적으로 .c 파일을 가져와서 .o 파일을 만듭니다. 따라서 make는 이러한 파일 확장자 조합을 통해 C 컴파일에 대한 암시적 규칙을 적용합니다.

암시적 규칙 체인은 순서대로 적용될 수 있습니다. 예를 들어, make는 .c 파일을 통해 .y 파일에서 .o 파일을 다시 만듭니다.

기본 제공 암시적 규칙은 레시피에서 여러 변수를 사용하므로 변수 값을 변경하여 암시적 규칙이 작동하는 방식을 변경할 수 있습니다. 예를 들어, CFLAGS 변수는 C 컴파일에 대한 암시적 규칙에 의해 C 컴파일러에 제공된 플래그를 제어합니다.

패턴 규칙을 작성하여 고유한 암시적 규칙을 정의할 수 있습니다.

접미사 규칙은 암시적 규칙을 정의하는 보다 제한된 방법입니다. 패턴 규칙은 더 일반적이고 명확하지만 호환성을 위해 접미사 규칙이 유지됩니다.

10.1 Using Implicit Rules (암시적 규칙 사용)

make가 대상 파일을 업데이트하는 일반적인 방법을 찾도록 하려면 레시피를 직접 지정하지 않기만 하면 됩니다. 레시피가 없는 규칙을 작성하거나 전혀 작성하지 마십시오. 그런 다음 make는 어떤 종류의 소스 파일이 존재하거나 만들 수 있는지에 따라 사용할 암시적 규칙을 알아냅니다.

예를 들어 makefile이 다음과 같다고 가정합니다:

foo : foo.o bar.o
        cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)

foo.o에 대해 언급했지만 규칙을 제공하지 않았기 때문에 make는 자동으로 업데이트 방법을 알려주는 암시적 규칙을 찾습니다. 이것은 foo.o 파일이 현재 존재하는지 여부에 관계없이 발생합니다.

암시적 규칙이 발견되면 레시피와 하나 이상의 전제 조건(소스 파일)을 모두 제공할 수 있습니다. 암시적 규칙이 제공할 수 없는 헤더 파일과 같은 추가 전제 조건을 지정해야 하는 경우 레시피 없이 foo.o에 대한 규칙을 작성하고 싶을 것입니다.

각 암시적 규칙에는 대상 패턴과 전제 조건 패턴이 있습니다. 동일한 대상 패턴을 가진 많은 암시적 규칙이 있을 수 있습니다. 예를 들어, 수많은 규칙이 '.o' 파일을 만듭니다. 하나는 C 컴파일러가 있는 '.c' 파일에서, 다른 하나는 Pascal 컴파일러가 있는 '.p' 파일에서 가져온 것입니다. 등등. 실제로 적용되는 규칙은 전제 조건이 존재하거나 만들 수 있는 규칙입니다. 따라서 foo.c 파일이 있는 경우 make는 C 컴파일러를 실행합니다. 그렇지 않고 foo.p 파일이 있으면 make는 Pascal 컴파일러를 실행합니다. 등등.

물론, makefile을 작성할때 어떤 암시적 규칙을 사용하고 싶은지 알고 있고 어떤 가능한 전제 조건 파일이 존재해야 하는지 알고 있기 때문에 make가 그 규칙을 선택할 것임을 압니다. 미리 정의된 모든 암시적 규칙의 카탈로그는 기본 제공 규칙 카탈로그를 참조하세요.

위에서 우리는 필수 전제 조건이 "존재하거나 만들 수 있는" 경우 묵시적 규칙이 적용된다고 말했습니다. 파일이 대상 또는 전제 조건으로 makefile에서 명시적으로 언급되거나 파일을 만드는 방법에 대한 암시적 규칙을 재귀적으로 찾을 수 있는 경우 파일을 "만들 수 있습니다". 묵시적 전제 조건이 다른 묵시적 규칙의 결과일때 우리는 연결이 발생하고 있다고 말합니다. 암시적 규칙 체인(Chains of Implicit Rules)을 참조하십시오.

일반적으로 make는 각 대상에 대한 암시적 규칙과 레시피가 없는 각 이중 콜론 규칙에 대해 검색합니다. 전제 조건으로만 언급된 파일은 규칙이 아무 것도 지정하지 않는 대상으로 간주되므로 암시적 규칙 검색이 발생합니다. 검색이 수행되는 방법에 대한 자세한 내용은 암시적 규칙 검색 알고리즘(Implicit Rule Search Algorithm)을 참조하세요.

명시적 전제 조건은 암시적 규칙 검색에 영향을 미치지 않습니다. 예를 들어 다음과 같은 명시적 규칙을 고려하십시오:

foo.o: foo.p

foo.p의 전제 조건은 반드시 make가 파스칼 소스 파일인 .p 파일에서 목적 파일인 .o 파일을 만들기 위한 묵시적 규칙에 따라 foo.o를 리메이크한다는 것을 의미하지는 않습니다. 예를 들어 foo.c도 존재한다면 C 소스 파일에서 오브젝트 파일을 만드는 묵시적 규칙이 대신 사용됩니다. 미리 정의된 묵시적 규칙 목록에서 Pascal 규칙 앞에 나타나기 때문입니다(내장 규칙 카탈로그(Catalogue of Built-In Rules) 참조).

레시피가 없는 대상에 대해 암시적 규칙을 사용하지 않으려면 세미콜론을 작성하여 해당 대상에 빈 레시피를 제공할 수 있습니다(빈 레시피 정의(Defining Empty Recipes) 참조).

10.2 Catalogue of Built-In Rules (기본 제공 규칙 카탈로그)

다음은 makefile이 명시적으로 재정의하거나 취소하지 않는한 항상 사용할 수 있는 미리 정의된 암시적 규칙 목록입니다. 암시적 규칙 취소 또는 재정의에 대한 정보는 암시적 규칙 취소(Canceling Implicit Rules)를 참조하십시오. '-r' 또는 '--no-builtin-rules' 옵션은 미리 정의된 모든 규칙을 취소합니다.

이 설명서는 POSIX 기반 운영 체제에서 사용할 수 있는 기본 규칙만 설명합니다. VMS, Windows, OS/2 등과 같은 다른 운영 체제에는 기본 규칙 집합이 다를 수 있습니다. GNU make 버전에서 사용할 수 있는 기본 규칙 및 변수의 전체 목록을 보려면 makefile이 없는 디렉토리에서 'make -p'를 실행하십시오.

'-r' 옵션이 지정되지 않은 경우에도 이러한 모든 규칙이 항상 정의되는 것은 아닙니다. 미리 정의된 암시적 규칙의 대부분은 make에서 접미사 규칙으로 구현되므로 정의할 규칙은 접미사 목록(특수 대상 .SUFFIXES의 전제 조건 목록)에 따라 다릅니다. 기본 접미사 목록은 .out, .a, .ln, .o, .c, .cc, .C, .cpp, .p, .f, .F, .m, .r, .y, .l입니다. , .ym, .lm, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch .web , .sh, .elc, .el. 전제 조건에 이러한 접미사 중 하나가 있는 아래 설명된 모든 암시적 규칙은 실제로 접미사 규칙입니다. 접미사 목록을 수정하는 경우 사전 정의된 접미사 규칙은 지정한 목록에 있는 하나 또는 두 개의 접미사로 명명된 규칙만 적용됩니다. 접미사가 목록에 없는 규칙은 비활성화됩니다. 접미사 규칙에 대한 자세한 내용은 구식 접미사 규칙(Old-Fashioned Suffix Rules)을 참조하세요.

  • Compiling C programs

    n.o는 '$(CC) $(CPPFLAGS) $(CFLAGS) -c' 형식의 레시피를 사용하여 n.c에서 자동으로 만들어집니다.

  • Compiling C++ programs

    n.o는 '$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c' 형식의 레시피를 사용하여 n.cc, n.cpp 또는 n.C에서 자동으로 만들어집니다. C++ 소스 파일에 '.C' 대신 접미사 '.cc'를 사용하는 것이 좋습니다.

  • Compiling Pascal programs

    n.o는 '$(PC) $(PFLAGS) -c' 레시피를 사용하여 n.p에서 자동으로 만들어집니다.

  • Compiling Fortran and Ratfor programs

    n.o는 Fortran 컴파일러를 실행하여 n.r, n.F 또는 n.f에서 자동으로 만들어집니다. 사용된 정확한 레시피는 다음과 같습니다:

    • '.f'

      '$(FC) $(FFLAGS) -c'.

    • '.F'

      '$(FC) $(FFLAGS) $(CPPFLAGS) -c'.

    • '.r'

      '$(FC) $(FFLAGS) $(RFLAGS) -c'.

  • Preprocessing Fortran and Ratfor programs

    n.f는 n.r 또는 n.F에서 자동으로 만들어집니다. 이 규칙은 전처리기만 실행하여 Ratfor 또는 전처리 가능한 Fortran 프로그램을 엄격한 Fortran 프로그램으로 변환합니다. 사용된 정확한 레시피는 다음과 같습니다:

    • '.F'

      '$(FC) $(CPPFLAGS) $(FFLAGS) -F'.

    • '.r'

      '$(FC) $(FFLAGS) $(RFLAGS) -F'.

  • Compiling Modula-2 programs

    n.sym은 '$(M2C) $(M2FLAGS) $(DEFFLAGS)' 형식의 레시피로 n.def에서 만들어집니다. n.o는 n.mod에서 만들어집니다. 형식은 '$(M2C) $(M2FLAGS) $(MODFLAGS)'입니다.

  • Assembling and preprocessing assembler programs

    n.o는 as에서 어셈블러를 실행하여 n.s에서 자동으로 만들어집니다. 정확한 레시피는 '$(AS) $(ASFLAGS)'입니다.

    n.s는 C 전처리기 cpp를 실행하여 n.S에서 자동으로 만들어집니다. 정확한 레시피는 '$(CPP) $(CPPFLAGS)'입니다.

  • Linking a single object file

    n은 C 컴파일러를 통해 링커(보통 ld라고 함)를 실행하여 n.o에서 자동으로 만들어집니다. 사용된 정확한 레시피는 '$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)'입니다.

    이 규칙은 소스 파일이 하나만 있는 간단한 프로그램에 적합합니다. 여러 개의 개체 파일(아마도 다양한 다른 소스 파일에서 가져온 것)이 있는 경우에도 올바른 작업을 수행하며, 그 중 하나는 실행 파일의 이름과 일치합니다. 따라서,

    x: y.o z.o

    x.c, y.c 및 z.c가 모두 존재하면 다음이 실행됩니다:

    cc -c x.c -o x.o
    cc -c y.c -o y.o
    cc -c z.c -o z.o
    cc x.o y.o z.o -o x
    rm -f x.o
    rm -f y.o
    rm -f z.o

    실행 파일 이름에서 이름이 파생된 개체 파일이 없는 경우와 같이 더 복잡한 경우에는 링크를 위한 명시적 레시피를 작성해야 합니다.

    자동으로 '.o' 오브젝트 파일로 만들어진 각 파일은 컴파일러('$(CC)', '$(FC)' 또는 '$(PC)'; C 컴파일러 '$(CC)'를 사용하여 자동으로 링크됩니다. )'는 '-c' 옵션 없이 '.s' 파일을 조합하는 데 사용됩니다. 이것은 '.o' 오브젝트 파일을 중간으로 사용하여 수행할 수 있지만 컴파일과 링크를 한 단계로 수행하는 것이 더 빠르므로 그렇게 합니다.

  • Yacc for C programs

    n.c는 '$(YACC) $(YFLAGS)' 레시피로 Yacc를 실행하여 n.y에서 자동으로 만들어집니다.

  • Lex for C programs

    n.c는 Lex를 실행하여 n.l에서 자동으로 만들어집니다. 실제 레시피는 '$(LEX) $(LFLAGS)'입니다.

  • Lex for Ratfor programs

    n.r은 Lex를 실행하여 n.l에서 자동으로 만들어집니다. 실제 레시피는 '$(LEX) $(LFLAGS)'입니다.

    C 코드 또는 Ratfor 코드를 생성하는지 여부에 관계없이 모든 Lex 파일에 대해 동일한 접미사 '.l'을 사용하는 규칙으로 인해 특정 경우에 두 언어중 어떤 언어를 사용하고 있는지 make가 자동으로 결정할 수 없습니다. '.l' 파일에서 오브젝트 파일을 다시 만들기 위해 make가 호출되면 사용할 컴파일러를 추측해야 합니다. 더 일반적이기 때문에 C 컴파일러를 추측합니다. Ratfor를 사용하는 경우 makefile에서 n.r을 언급하여 make가 이것을 알고 있는지 확인하십시오. 또는 C 파일 없이 Ratfor를 독점적으로 사용하는 경우 다음을 사용하여 암시적 규칙 접미사 목록에서 '.c'를 제거합니다:

    .SUFFIXES:
    .SUFFIXES: .o .r .f .l ...
  • Making Lint Libraries from C, Yacc, or Lex programs

    n.ln은 lint를 실행하여 n.c에서 만들어집니다. 정확한 레시피는 '$(LINT) $(LINTFLAGS) $(CPPFLAGS) -i'입니다. 동일한 레시피가 n.y 또는 n.l에서 생성된 C 코드에 사용됩니다.

  • TeX and Web

    n.dvi는 n.tex에서 '$(TEX)' 레시피로 만들어집니다. n.tex는 n.web에서 '$(WEAVE)'로 만들어지거나 n.w에서(존재하거나 만들 수 있는 경우 n.ch에서) '$(CWEAVE)'로 만들어집니다. n.p는 n.web에서 '$(TANGLE)'으로 만들어지고 n.c는 n.w에서 만들어지며(존재하거나 만들 수 있는 경우 n.ch에서) '$(CTANGLE)'으로 만들어집니다.

  • Texinfo and Info

    n.dvi는 n.texinfo, n.texi 또는 n.txinfo에서 '$(TEXI2DVI) $(TEXI2DVI_FLAGS)' 레시피로 만들어집니다. n.info는 n.texinfo, n.texi 또는 n.txinfo에서 '$(MAKEINFO) $(MAKEINFO_FLAGS)' 레시피로 만들어집니다.

  • RCS

    파일 n은 필요한 경우 n,v 또는 RCS/n,v라는 RCS 파일에서 추출됩니다. 사용된 정확한 레시피는 '$(CO) $(COFLAGS)'입니다. n은 RCS 파일이 최신 버전이더라도 이미 존재하는 경우 RCS에서 추출되지 않습니다. RCS에 대한 규칙은 터미널이므로(모든 항목 일치 패턴 규칙 참조) RCS 파일은 다른 소스에서 생성할 수 없습니다. 그들은 실제로 존재해야합니다.

  • SCCS

    모든 파일 n은 필요한 경우 s.n 또는 SCCS/s.n이라는 SCCS 파일에서 추출됩니다. 사용된 정확한 레시피는 '$(GET) $(GFLAGS)'입니다. SCCS에 대한 규칙은 터미널이므로(모든 항목 일치 패턴 규칙 참조) SCCS 파일은 다른 소스에서 생성할 수 없습니다. 그들은 실제로 존재해야합니다.

    SCCS의 이점을 위해 파일 n은 n.sh에서 복사되어 (모든 사람이) 실행할 수 있습니다. 이것은 SCCS에 체크인된 쉘 스크립트를 위한 것입니다. RCS는 파일의 실행 권한을 유지하므로 이 기능을 RCS와 함께 사용할 필요가 없습니다.

    SCCS 사용을 피하는 것이 좋습니다. RCS는 널리 알려져 있으며 무료입니다. 비교 가능한(또는 열등한) 독점 소프트웨어 대신 자유 소프트웨어를 선택함으로써 자유 소프트웨어 운동을 지원합니다.

Usually, you want to change only the variables listed in the table above, which are documented in the following section.
다음 섹션에 설명되었지만, 일반적으로 여러분들은 위의 표에서 나열된 변수만 변경하려고 합니다.

그러나 내장된 암시적 규칙의 레시피는 실제로 COMPILE.c, LINK.p 및 PREPROCESS.S와 같은 변수를 사용하며, 그 값에는 위에 나열된 레시피가 포함됩니다.

make는 .x 소스 파일을 컴파일하는 규칙이 변수 COMPILE.x를 사용한다는 규칙을 따릅니다. 마찬가지로 .x 파일에서 실행 파일을 생성하는 규칙은 LINK.x를 사용합니다. .x 파일을 사전 처리하는 규칙은 PREPROCESS.x를 사용합니다.

개체 파일을 생성하는 모든 규칙은 OUTPUT_OPTION 변수를 사용합니다. make는 컴파일 시간 옵션에 따라 이 변수를 '-o $@'를 포함하거나 비어 있도록 정의합니다. VPATH를 사용할 때와 같이 소스 파일이 다른 디렉토리에 있을 때 출력이 올바른 파일로 이동하도록 하려면 '-o' 옵션이 필요합니다(디렉토리 검색 참조). 그러나 일부 시스템의 컴파일러는 개체 파일에 대해 '-o' 스위치를 허용하지 않습니다. 이러한 시스템을 사용하고 VPATH를 사용하는 경우 일부 컴파일은 출력을 잘못된 위치에 배치합니다. 이 문제에 대한 가능한 해결 방법은 OUTPUT_OPTION에 '; mv $*.o $@' 값을 주는것 입니다.

10.3 Variables Used by Implicit Rules (암시적 규칙에서 사용하는 변수)

내장된 암시적 규칙의 레시피는 미리 정의된 특정 변수를 자유롭게 사용합니다. makefile에서 이러한 변수의 값을 변경하거나 make에 대한 인수를 사용하거나 환경에서 규칙 자체를 재정의하지 않고 암시적 규칙이 작동하는 방식을 변경할 수 있습니다. '-R' 또는 '--no-builtin-variables' 옵션을 사용하여 암시적 규칙에서 사용하는 모든 변수를 취소할 수 있습니다.

예를 들어, C 소스 파일을 컴파일하는 데 사용된 레시피는 실제로 '$(CC) -c $(CFLAGS) $(CPPFLAGS)'라고 말합니다. 사용된 변수의 기본값은 'cc'이고 아무것도 없으므로 'cc -c' 명령이 생성됩니다. 'CC'를 'ncc'로 재정의하면 암시적 규칙에 의해 수행되는 모든 C 컴파일에 'ncc'가 사용되도록 할 수 있습니다. 'CFLAGS'를 '-g'로 재정의하면 각 컴파일에 '-g' 옵션을 전달할 수 있습니다. C 컴파일을 수행하는 모든 묵시적 규칙은 '$(CC)'를 사용하여 컴파일러의 프로그램 이름을 가져오며 모두 컴파일러에 제공된 인수 중 '$(CFLAGS)'를 포함합니다.

암시적 규칙에 사용되는 변수는 프로그램의 이름인 클래스(예: CC)와 프로그램에 대한 인수를 포함하는 클래스(예: CFLAGS)로 나뉩니다. ("프로그램 이름"에도 일부 명령 인수가 포함될 수 있지만 실제 실행 가능한 프로그램 이름으로 시작해야 합니다.) 변수 값에 둘 이상의 인수가 포함되어 있으면 공백으로 구분하십시오.

다음 표에서는 보다 일반적으로 사용되는 미리 정의된 변수에 대해 설명합니다. 이 목록은 전체가 아니며 여기에 표시된 기본값은 환경에 맞게 선택하지 않을 수 있습니다. GNU make 인스턴스에 대한 사전 정의된 변수의 전체 목록을 보려면 makefile이 없는 디렉토리에서 'make -p'를 실행할 수 있습니다.

다음은 기본 제공 규칙에서 프로그램 이름으로 사용되는 몇 가지 일반적인 변수에 대한 표입니다:

  • AR

    아카이브 유지 프로그램; 기본값 'ar'.

  • AS

    어셈블리 파일을 컴파일하는 프로그램; 기본값 'as'.

  • CC

    C 프로그램을 컴파일하기 위한 프로그램; 기본값 'cc'.

  • CXX

    C++ 프로그램을 컴파일하기 위한 프로그램; 기본값 'g++'.

  • CPP

    표준 출력에 대한 결과와 함께 C 전처리기를 실행하기 위한 프로그램. 기본값 '$(CC) -E'.

  • FC

    Fortran 및 Ratfor 프로그램을 컴파일하거나 전처리하기 위한 프로그램; 기본값 'f77'.

  • M2C

    Modula-2 소스 코드를 컴파일하는 데 사용할 프로그램. 기본값 'm2c'.

  • PC

    파스칼 프로그램을 컴파일하기 위한 프로그램; 기본값 'pc'.

  • CO

    RCS에서 파일을 추출하는 프로그램. 기본값 'co'.

  • GET

    SCCS에서 파일을 추출하는 프로그램. 기본값 'get'.

  • LEX

    Lex 문법을 소스 코드로 바꾸는 데 사용하는 프로그램. 기본값 'lex'.

  • YACC

    Yacc 문법을 소스 코드로 변환하는 데 사용하는 프로그램. 기본값 'yacc'.

  • LINT

    소스 코드에서 린트를 실행하는 데 사용할 프로그램. 기본값 'lint'.

  • MAKEINFO

    Texinfo 소스 파일을 Info 파일로 변환하는 프로그램. 기본값 'makeinfo'.

  • TEX

    TeX 소스에서 TeX DVI 파일을 만드는 프로그램; 기본값 'tex'.

  • TEXI2DVI

    Texinfo 소스에서 TeX DVI 파일을 만드는 프로그램; 기본값 'texi2dvi'.

  • WEAVE

    웹을 TeX로 번역하는 프로그램; 기본값 'weave'.

  • CWEAVE

    C Web을 TeX로 번역하는 프로그램; 기본값 'cweave'.

  • TANGLE

    웹을 파스칼로 번역하는 프로그램; 기본값 'tangle'.

  • CTANGLE

    C 웹을 C로 번역하는 프로그램; 기본값 'ctangle'.

  • RM

    파일을 제거하는 명령; 기본값 'rm -f'.

다음은 위의 프로그램에 대한 추가 인수 값이 있는 변수 테이블입니다. 이 모든 것에 대한 기본값은 달리 명시되지 않는 한 빈 문자열입니다.

  • ARFLAGS

    아카이브 유지 프로그램을 제공하는 플래그입니다. 기본값 'rv'.

  • ASFLAGS

    어셈블러에 제공할 추가 플래그('.s' 또는 '.S' 파일에서 명시적으로 호출되는 경우).

  • CFLAGS

    C 컴파일러에 제공할 추가 플래그입니다.

  • CXXFLAGS

    C++ 컴파일러에 제공할 추가 플래그입니다.

  • COFLAGS

    RCS 공동 프로그램에 제공할 추가 플래그입니다.

  • CPPFLAGS

    C 전처리기 및 이를 사용하는 프로그램(C 및 Fortran 컴파일러)에 제공할 추가 플래그입니다.

  • FFLAGS

    Fortran 컴파일러에 제공할 추가 플래그입니다.

  • GFLAGS

    SCCS get 프로그램에 제공할 추가 플래그입니다.

  • LDFLAGS

    -L과 같은 링커 'ld'를 호출해야 할 때 컴파일러에 제공할 추가 플래그입니다. 대신 라이브러리(-lfoo)를 LDLIBS 변수에 추가해야 합니다.

  • LDLIBS

    컴파일러가 링커 'ld'를 호출해야 할 때 컴파일러에 제공되는 라이브러리 플래그 또는 이름입니다. LOADLIBES는 LDLIBS에 대한 더 이상 사용되지 않지만 여전히 지원되는 대안입니다. -L과 같은 라이브러리가 아닌 링커 플래그는 LDFLAGS 변수에 있어야 합니다.

  • LFLAGS

    Lex에게 줄 추가 플래그입니다.

  • YFLAGS

    Yacc에게 줄 추가 플래그.

  • PFLAGS

    Pascal 컴파일러에 제공할 추가 플래그입니다.

  • RFLAGS

    Ratfor 프로그램용 Fortran 컴파일러에 제공할 추가 플래그입니다.

  • LINTFLAGS

    린트에 제공할 추가 플래그입니다.

10.4 Chains of Implicit Rules (암시적 규칙 체인)

때때로 파일은 일련의 암시적 규칙에 의해 만들어질 수 있습니다. 예를 들어, 파일 n.o는 먼저 Yacc를 실행한 다음 cc를 실행하여 n.y에서 만들 수 있습니다. 이러한 시퀀스를 체인이라고 합니다.

n.c 파일이 존재하거나 makefile에 언급되어 있으면 특별한 검색이 필요하지 않습니다. make는 n.c에서 C 컴파일로 개체 파일을 만들 수 있음을 찾습니다. 나중에 n.c를 어떻게 만들지 고민할 때 Yacc를 실행하는 규칙을 사용합니다. 궁극적으로 n.c와 n.o가 모두 업데이트됩니다.

그러나 n.c가 존재하지 않고 언급되지 않더라도 make는 이를 n.o와 n.y 사이의 누락된 링크로 상상하는 방법을 알고 있습니다! 이 경우 n.c를 중간 파일이라고 합니다. make가 중간 파일을 사용하기로 결정하면, 그것을 생성하는 방법을 알려주는 묵시적 규칙과 함께 makefile에 언급된 것처럼 데이터베이스에 입력됩니다.

중간 파일은 다른 모든 파일과 마찬가지로 규칙을 사용하여 다시 만들어집니다. 그러나 중간 파일은 두 가지 방식으로 다르게 처리됩니다.

첫 번째 차이점은 중간 파일이 존재하지 않는 경우 발생합니다. 일반 파일 b가 존재하지 않고 make가 b에 종속된 대상을 고려하면 항상 b를 생성한 다음 b에서 대상을 업데이트합니다. 그러나 b가 중간 파일인 경우 make는 충분히 혼자 남겨둘 수 있습니다. b의 일부 전제 조건이 해당 대상보다 최신이거나 해당 대상을 업데이트해야 하는 다른 이유가 있지 않는한 b 또는 최종 대상을 업데이트하는데 방해가 되지 않습니다.

두 번째 차이점은 make가 다른 것을 업데이트하기 위해 b를 생성하는 경우 더 이상 필요하지 않으면 나중에 b를 삭제한다는 것입니다. 따라서 make 이전에 존재하지 않았던 중간 파일도 make 이후에 존재하지 않습니다. make는 삭제 중인 파일을 보여주는 'rm -f' 명령을 인쇄하여 삭제를 보고합니다.

일반적으로 makefile에서 대상 또는 전제 조건으로 언급된 파일은 중간 파일이 될 수 없습니다. 그러나 파일을 특수 대상 .INTERMEDIATE의 전제 조건으로 나열하여 명시적으로 중간 파일로 표시할 수 있습니다. 이는 파일이 다른 방식으로 명시적으로 언급된 경우에도 적용됩니다.

중간 파일을 보조 파일로 표시하여 자동 삭제를 방지할 수 있습니다. 이렇게 하려면 특수 대상 .SECONDARY의 전제 조건으로 나열합니다. 파일이 2차 파일일 때 make는 파일이 이미 존재하지 않는다는 이유만으로 파일을 생성하지 않지만 make는 파일을 자동으로 삭제하지 않습니다. 파일을 보조로 표시하면 중간 파일로도 표시됩니다.

암시적 규칙의 대상 패턴(예: '%.o')을 특수 대상 .PRECIOUS의 전제 조건으로 나열하여 대상 패턴이 해당 파일 이름과 일치하는 암시적 규칙으로 만든 중간 파일을 보존할 수 있습니다. 인터럽트(Interrupts)를 참조하십시오.

체인에는 두 개 이상의 암시적 규칙이 포함될 수 있습니다. 예를 들어, RCS, Yacc 및 cc를 실행하여 RCS/foo.y,v에서 foo 파일을 만드는 것이 가능합니다. 그러면 foo.y와 foo.c는 모두 마지막에 삭제되는 중간 파일입니다.

단일 암시적 규칙은 체인에서 두 번 이상 나타날 수 없습니다. 이것은 make가 링커를 두 번 실행하여 foo.o.o에서 foo를 만드는 것과 같은 어리석은 일조차 고려하지 않는다는 것을 의미합니다. 이 제약 조건은 암시적 규칙 체인을 검색할 때 무한 루프를 방지하는 추가 이점이 있습니다.

그렇지 않으면 규칙 체인에 의해 처리될 특정 경우를 최적화하기 위한 몇 가지 특별한 암시적 규칙이 있습니다. 예를 들어 foo.c에서 foo를 만드는 것은 foo.o를 중간 파일로 사용하여 별도의 연결 규칙으로 컴파일하고 연결하여 처리할 수 있습니다. 그러나 실제로 일어나는 일은 이 경우에 대한 특별한 규칙이 단일 cc 명령으로 컴파일 및 링크를 수행한다는 것입니다. 최적화된 규칙은 규칙 순서보다 먼저 나오기 때문에 단계별 체인보다 우선적으로 사용됩니다.

마지막으로, 성능상의 이유로 make는 묵시적 규칙의 전제 조건을 구축하기 위한 규칙을 검색할 때 터미널이 아닌 모든 일치 규칙(즉, '%:')을 고려하지 않습니다(모든 항목 일치 규칙(Match-Anything Rules) 참조).

10.5 Defining and Redefining Pattern Rules (패턴 규칙 정의 및 재정의)

패턴 규칙을 작성하여 암시적 규칙을 정의합니다. 패턴 규칙은 대상에 문자 '%'(정확히 그 중 하나)가 포함되어 있다는 점을 제외하면 일반 규칙처럼 보입니다. 대상은 일치하는 파일 이름의 패턴으로 간주됩니다. '%'는 비어 있지 않은 모든 하위 문자열과 일치할 수 있지만 다른 문자는 자기 자신과만 일치합니다. 전제 조건은 마찬가지로 '%'를 사용하여 이름이 대상 이름과 어떻게 관련되는지 보여줍니다.

따라서 패턴 규칙 '%.o : %.c'는 다른 파일 stem.c에서 파일 stem.o를 만드는 방법을 알려줍니다.

패턴 규칙에서 '%'를 사용한 확장은 makefile을 읽을 때 발생하는 변수 또는 함수 확장 후에 발생합니다. 텍스트 변환을 위한 변수 및 함수 사용 방법(How to Use Variables, and Functions for Transforming Text)을 참조하십시오.

10.5.1 Introduction to Pattern Rules (패턴 규칙 소개)

패턴 규칙은 대상에 문자 '%'(정확히 그 중 하나)를 포함합니다. 그렇지 않으면 일반 규칙처럼 보입니다. 대상은 일치하는 파일 이름에 대한 패턴입니다. '%'는 비어 있지 않은 하위 문자열과 일치하지만 다른 문자는 자신과만 일치합니다.

예를 들어 패턴으로 '%.c'는 '.c'로 끝나는 파일 이름과 일치합니다. 패턴으로서의 's.%.c'는 's.'로 시작하고 '.c'로 끝나며 길이가 5자 이상인 모든 파일 이름과 일치합니다. ('%'와 일치하려면 적어도 하나의 문자가 있어야 합니다.) '%'가 일치하는 부분 문자열을 스템이라고 합니다.

패턴 규칙의 전제 조건에서 '%'는 대상의 '%'와 일치하는 동일한 어간을 나타냅니다. 패턴 규칙이 적용되려면 대상 패턴이 고려 중인 파일 이름과 일치해야 하고 모든 전제 조건(패턴 대체 후)은 존재하거나 만들 수 있는 파일의 이름을 지정해야 합니다. 이러한 파일은 대상의 전제 조건이 됩니다.

따라서 형식의 규칙은

%.o : %.c ; recipe...

n.c가 존재하거나 만들 수 있는 경우 전제 조건으로 다른 파일 n.c를 사용하여 파일 n.o를 만드는 방법을 지정합니다.

'%'를 사용하지 않는 전제 조건도 있을 수 있습니다. 이러한 전제 조건은 이 패턴 규칙에 의해 만들어진 모든 파일에 첨부됩니다. 이러한 변하지 않는 전제 조건은 때때로 유용합니다.

패턴 규칙에는 '%'가 포함된 전제 조건이 필요하지 않으며 실제로 전제 조건이 전혀 필요하지 않습니다. 이러한 규칙은 사실상 일반 와일드카드입니다. 대상 패턴과 일치하는 파일을 만드는 방법을 제공합니다. 최후의 조치(Last Resort)를 참조하십시오.

둘 이상의 패턴 규칙이 대상과 일치할 수 있습니다. 이 경우 make는 "가장 적합한" 규칙을 선택합니다. 패턴 일치 방법(How Patterns Match)을 참조하십시오.

패턴 규칙에는 둘 이상의 대상이 있을 수 있습니다. 그러나 모든 대상에는 % 문자가 포함되어야 합니다. 패턴 규칙은 : 또는 &: 구분 기호를 사용하는지 여부에 관계없이 항상 그룹화된 대상으로 처리됩니다(규칙의 다중 대상(Multiple Targets in a Rule) 참조).

10.5.2 Pattern Rule Examples (패턴 규칙 예)

다음은 make에서 실제로 미리 정의된 패턴 규칙의 몇 가지 예입니다. 먼저 '.c' 파일을 '.o' 파일로 컴파일하는 규칙:

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

x.c에서 모든 파일 x.o를 만들 수 있는 규칙을 정의합니다. 레시피는 규칙이 적용되는 각 경우에 대상 파일과 소스 파일의 이름을 대체하기 위해 자동 변수 '$@' 및 '$<'를 사용합니다(자동 변수(Automatic Variables) 참조).

다음은 두 번째 기본 제공 규칙입니다:

% :: RCS/%,v
        $(CO) $(COFLAGS) $<

하위 디렉토리 RCS의 해당 파일 x,v에서 모든 파일 x를 만들 수 있는 규칙을 정의합니다. 대상은 '%'이므로 적절한 전제 조건 파일이 존재하는한 이 규칙은 모든 파일에 적용됩니다. 이중 콜론은 규칙 터미널을 만들며, 이는 전제 조건이 중간 파일이 아닐 수 있음을 의미합니다(모든 항목 일치 패턴 규칙(Match-Anything Pattern Rules) 참조).

이 패턴 규칙에는 두 가지 대상이 있습니다:

%.tab.c %.tab.h: %.y
        bison -d $<

이것은 make에게 'bison -d x.y' 레시피가 x.tab.c와 x.tab.h를 모두 만들 것이라고 알려줍니다. foo 파일이 parse.tab.o 및 scan.o 파일에 종속되고 scan.o 파일이 parse.tab.h 파일에 종속되는 경우 parse.y가 변경될 때 레시피 'bison -d parse.y' 한 번만 실행되며 parse.tab.o와 scan.o의 전제 조건이 모두 충족됩니다. (아마도 parse.tab.o 파일은 parse.tab.c에서 다시 컴파일되고 scan.o 파일은 scan.c에서 다시 컴파일되는 반면 foo는 parse.tab.o, scan.o 및 기타 전제 조건에서 연결됩니다. 그것은 영원히 행복하게 실행될 것입니다.)

10.5.3 Automatic Variables (자동 변수)

'.c' 파일을 '.o' 파일로 컴파일하는 패턴 규칙을 작성한다고 가정합니다. 올바른 소스 파일 이름에서 작동하도록 'cc' 명령을 어떻게 작성합니까? 암시적 규칙이 적용될 때마다 이름이 다르기 때문에 레시피에 이름을 쓸 수 없습니다.

당신이 하는 일은 자동 변수인 make의 특별한 기능을 사용하는 것입니다. 이러한 변수에는 규칙의 대상 및 전제 조건을 기반으로 실행되는 각 규칙에 대해 새로 계산된 값이 있습니다. 이 예에서는 개체 파일 이름으로 '$@'를 사용하고 소스 파일 이름으로 '$<'를 사용합니다.

자동 변수 값을 사용할 수 있는 제한된 범위를 인식하는 것이 매우 중요합니다. 해당 값은 레시피 내에서만 값을 갖습니다. 특히, 규칙의 대상 목록내 어디에서나 사용할 수 없습니다. 값이 없으며 빈 문자열로 확장됩니다. 또한 규칙의 전제 조건 목록 내에서 직접 액세스할 수 없습니다. 일반적인 실수는 전제 조건 목록 내에서 $@를 사용하려고 시도하는 것입니다. 이것은 작동하지 않습니다. 그러나 GNU make의 특별한 기능인 이차 확장(Secondary Expansion 참조)이 있어 전제 조건 목록에서 자동 변수 값을 사용할 수 있습니다.

다음은 자동 변수 테이블입니다:

  • $@

    규칙의 대상(target) 파일 이름입니다. 대상이 아카이브 구성원인 경우 '$@'는 아카이브 파일의 이름입니다. 여러 대상이 있는 패턴 규칙에서(패턴 규칙 소개(Introduction to Pattern Rules) 참조) '$@'는 규칙의 레시피를 실행하게 한 대상의 이름입니다.

  • $%

    대상이 아카이브 구성원인 경우 대상 구성원 이름입니다. 아카이브(Archives)를 참조하십시오. 예를 들어 대상이 foo.a(bar.o)이면 '$%'는 bar.o이고 '$@'는 foo.a입니다. 대상이 아카이브 구성원이 아닌 경우 '$%'는 비어 있습니다.

  • $<

    첫 번째 전제 조건의 이름입니다. 대상이 암시적 규칙에서 레시피를 얻은 경우 암시적 규칙에 의해 추가된 첫 번째 전제 조건이 됩니다(암시적 규칙(Implicit Rules) 참조).

  • $?

    대상보다 최신인 모든 필수 구성 요소의 이름(공백 포함). 대상이 없으면 모든 전제 조건이 포함됩니다. 아카이브 구성원인 전제 조건의 경우 명명된 구성원만 사용됩니다(아카이브(Archives) 참조).

  • $^

    모든 필수 구성 요소의 이름(공백 포함). 아카이브 구성원인 전제 조건의 경우 명명된 구성원만 사용됩니다(아카이브(Archives) 참조). 대상은 각 파일이 전제 조건으로 나열되는 횟수와 상관없이 종속되는 서로에 대해 하나의 전제 조건만 갖습니다. 따라서 대상에 대한 전제 조건을 두 번 이상 나열하는 경우 $^ 값에는 이름의 복사본이 하나만 포함됩니다. 이 목록에는 주문 전용 전제 조건이 포함되어 있지 않습니다. 아래의 '$|' 변수를 참조하세요.

  • $+

    이것은 '$^'와 비슷하지만 두 번 이상 나열된 전제 조건은 makefile에 나열된 순서대로 복제됩니다. 이것은 특정 순서로 라이브러리 파일 이름을 반복하는것이 의미 있는 링크 명령에 주로 유용합니다.

  • $|

    모든 주문 전용 전제조건의 이름(공백 포함).

  • $*

    암시적 규칙이 일치하는 어간입니다(패턴 일치 방법(How Patterns Match) 참조). 대상이 dir/a.foo.b이고 대상 패턴이 a.%.b이면 어간은 dir/foo입니다. 어간(stem)은 관련 파일의 이름을 구성하는 데 유용합니다.

    정적 패턴 규칙에서 어간은 대상 패턴의 '%'와 일치하는 파일 이름의 일부입니다.

    명시적 규칙에는 어간이 없습니다. 따라서 '$*'는 그런 식으로 결정할 수 없습니다. 대신 대상 이름이 인식된 접미사로 끝나는 경우(구식 접미사 규칙 참조) '$*'는 대상 이름에서 접미사를 뺀 값으로 설정됩니다. 예를 들어 대상 이름이 'foo.c'이면 '.c'가 접미사이므로 '$*'가 'foo'로 설정됩니다. GNU make는 make의 다른 구현과의 호환성을 위해서만 이 기이한 일을 합니다. 암시적 규칙이나 정적 패턴 규칙을 제외하고 일반적으로 '$*' 사용을 피해야 합니다.

    명시적 규칙의 대상 이름이 인식된 접미사로 끝나지 않으면 '$*'가 해당 규칙에 대한 빈 문자열로 설정됩니다.

'$?'는 변경된 전제 조건에 대해서만 작업하려는 명시적 규칙에서도 유용합니다. 예를 들어 lib라는 아카이브에 여러 개체 파일의 복사본이 포함되어 있다고 가정합니다. 이 규칙은 변경된 개체 파일만 아카이브에 복사합니다:

lib: foo.o bar.o lose.o win.o
        ar r lib $?

위에 나열된 변수중 4개에는 단일 파일 이름 값이 있고 3개에는 파일 이름 목록 값이 있습니다. 이 7개에는 파일의 디렉터리 이름만 가져오거나 디렉터리 내의 파일 이름만 가져오는 변형이 있습니다. 변형 변수의 이름은 각각 'D' 또는 'F'를 추가하여 구성됩니다. dir 및 notdir 함수를 사용하여 유사한 효과를 얻을 수 있습니다(파일 이름에 대한 함수(Functions for File Names) 참조). 그러나 'D' 변형은 모두 dir 함수의 출력에 항상 나타나는 후행 슬래시를 생략합니다. 다음은 변형 표입니다:

  • '$(@D)'

    후행 슬래시가 제거된 대상 파일 이름의 디렉토리 부분입니다. '$@'의 값이 dir/foo.o이면 '$(@D)'는 dir입니다. 이 값은 입니다. '$@'에 슬래시가 포함되지 않은 경우.

  • '$(@F)'

    대상 파일 이름의 디렉토리 내 파일 부분입니다. '$@'의 값이 dir/foo.o이면 '$(@F)'는 foo.o입니다. '$(@F)'는 '$(notdir $@)'와 동일합니다.

  • '$(*D)'

  • '$(*F)'

    어간의 디렉토리 부분과 디렉토리 내 파일 부분; 이 예에서는 dir 및 foo입니다.

  • '$(%D)'

  • '$(%F)'

    대상 아카이브 구성원 이름의 디렉토리 부분 및 디렉토리 내 파일 부분. 이는 archive(member) 형식의 아카이브 구성원 대상에만 의미가 있으며 구성원에 디렉토리 이름이 포함될 때만 유용합니다. (구성원을 대상으로 보관(Archive Members as Targets)을 참조하십시오.)

  • '$(<D)'

  • '$(<F)'

    첫 번째 전제조건의 디렉토리 부분 및 디렉토리 내 파일 부분.

  • '$(^D)'

  • '$(^F)'

    모든 전제 조건의 디렉토리 부분 및 디렉토리 내 파일 부분의 목록입니다.

  • '$(+D)'

  • '$(+F)'

    중복된 필수 구성 요소의 여러 인스턴스를 포함하여 모든 필수 구성 요소의 디렉토리 부분 및 디렉토리 내 파일 부분의 목록입니다.

  • '$(?D)'

  • '$(?F)'

    대상보다 최신인 모든 전제조건의 디렉토리 부분 및 디렉토리 내 파일 부분의 목록입니다.

이러한 자동 변수에 대해 이야기할때 특별한 문체 규칙을 사용한다는 점에 유의하십시오. 객체 및 CFLAGS와 같은 일반 변수에 대해 작성하는 것처럼 "변수 <"가 아닌 "'$<'의 값"을 작성합니다. 우리는 이 특별한 경우에 이 규칙이 더 자연스러워 보인다고 생각합니다. 깊은 의미가 있다고 생각하지 마십시오. '$<'는 '$(CFLAGS)'가 CFLAGS라는 변수를 참조하는 것처럼 <라는 변수를 참조합니다. '$<' 대신 '$(<)'를 사용할 수도 있습니다.

10.5.4 How Patterns Match (패턴이 일치하는 방법)

대상 패턴은 접두사와 접미사 사이에 '%'로 구성되며 둘 중 하나 또는 둘 다 비어 있을 수 있습니다. 패턴은 파일 이름이 겹치지 않고 접두사로 시작하고 접미사로 끝나는 경우에만 파일 이름과 일치합니다. 접두사와 접미사 사이의 텍스트를 어간이라고 합니다. 따라서 패턴 '%.o'가 파일 이름 test.o와 일치할 때 어간은 'test'입니다. 패턴 규칙 전제 조건은 문자 '%'를 어간으로 대체하여 실제 파일 이름으로 변환됩니다. 따라서 동일한 예에서 전제 조건 중 하나가 '%.c'로 작성되면 'test.c'로 확장됩니다.

대상 패턴에 슬래시가 포함되지 않은 경우(일반적으로 포함하지 않음) 파일 이름의 디렉토리 이름은 대상 접두사 및 접미사와 비교되기 전에 파일 이름에서 제거됩니다. 파일 이름을 대상 패턴과 비교한 후 패턴 규칙의 전제조건 패턴 및 파일 이름에서 생성된 전제조건 파일 이름에 디렉토리 이름과 이를 종료하는 슬래시가 추가됩니다. 디렉토리는 사용할 묵시적 규칙을 찾기 위한 목적으로만 무시되며 해당 규칙을 적용할 때는 무시됩니다. 따라서 'e%t'는 'src/a'를 어간으로 하여 파일 이름 src/eat와 일치합니다. 전제 조건이 파일 이름으로 바뀌면 어간의 디렉토리가 맨 앞에 추가되고 나머지 어간은 '%'로 대체됩니다. 전제 조건 패턴 'c%r'이 있는 어간 'src/a'는 파일 이름 src/car를 제공합니다.

패턴 규칙은 파일 이름과 일치하는 대상 패턴이 있고 해당 규칙의 모든 전제 조건이 존재하거나 빌드할 수 있는 경우에만 지정된 파일을 빌드하는 데 사용할 수 있습니다. 작성한 규칙은 기본 제공 규칙보다 우선합니다. 그러나 전제 조건이 실제로 존재하거나 언급된 규칙은 항상 다른 암시적 규칙을 연결하여 만들어야 하는 전제 조건이 있는 규칙보다 우선합니다.

둘 이상의 패턴 규칙이 이러한 기준을 충족할 수 있습니다. 이 경우 make는 가장 짧은 어간(즉, 가장 구체적으로 일치하는 패턴)가 있는 규칙을 선택합니다. 둘 이상의 패턴 규칙에 가장 짧은 어간이 있는 경우 make는 makefile에서 찾은 첫 번째 규칙을 선택합니다.

이 알고리즘은 보다 일반적인 규칙보다 더 구체적인 규칙을 선호합니다. 예를 들어:

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

%.o : %.f
        $(COMPILE.F) $(OUTPUT_OPTION) $<

lib/%.o: lib/%.c
        $(CC) -fPIC -c $(CFLAGS) $(CPPFLAGS) $< -o $@

이러한 규칙이 주어지고 bar.c와 bar.f가 모두 있는 곳에 bar.o를 빌드하도록 요청하면 make는 첫 번째 규칙을 선택하고 bar.c를 bar.o로 컴파일합니다. bar.c가 존재하지 않는 동일한 상황에서 make는 두 번째 규칙을 선택하고 bar.f를 bar.o로 컴파일합니다.

make가 lib/bar.o를 빌드하도록 요청받고 lib/bar.c와 lib/bar.f가 모두 존재하는 경우 이 규칙의 어간('bar')이 첫 번째 규칙('lib/bar')의 어간보다 짧기 때문에 세 번째 규칙이 선택됩니다. lib/bar.c가 존재하지 않으면 세 번째 규칙은 적합하지 않으며 어간이 더 길더라도 두 번째 규칙이 사용됩니다.

10.5.5 Match-Anything Pattern Rules (모든 것이 일치하는 패턴 규칙)

패턴 규칙의 대상이 '%'일 경우 모든 파일 이름과 일치합니다. 우리는 이러한 규칙을 '모든 것과 일치하는 규칙'이라고 부릅니다. 그것들은 매우 유용하지만 make가 그것들에 대해 생각하는데 많은 시간이 걸릴 수 있습니다. 왜냐하면 타겟이나 전제 조건으로 나열된 각 파일 이름에 대한 모든 규칙을 고려해야 하기 때문입니다.

makefile이 foo.c를 언급한다고 가정합니다. 이 타겟의 경우, make는 foo.co 개체 파일을 링크하거나 foo.cc에서 한 단계로 C 컴파일 및 링크하거나 또는 foo.cp에서 Pascal 컴파일 및 링크를 통해 만드는 것과 다른 많은 가능성을 고려해야 합니다.

foo.c는 실행 파일이 아니라 C 소스 파일이기 때문에 이러한 가능성이 터무니없다는 것을 알고 있습니다. make가 이러한 가능성을 고려했다면 foo.c.o 및 foo.c.p와 같은 파일이 존재하지 않기 때문에 궁극적으로 이를 거부합니다. 그러나 이러한 가능성은 너무 많아 make가 고려해야 한다면 매우 느리게 실행될 것입니다.

속도를 높이기 위해 make가 모든 일치 규칙을 고려하는 방식에 다양한 제약 조건을 적용했습니다. 적용할 수 있는 두 가지 제약 조건이 있으며 모든 항목 일치 규칙을 정의할 때마다 해당 규칙에 대해 둘 중 하나를 선택해야 합니다.

한 가지 선택은 일치 항목 규칙을 이중 콜론으로 정의하여 터미널로 표시하는 것입니다. 규칙이 터미널인 경우 전제 조건이 실제로 존재하지 않는한 적용되지 않습니다. 다른 암시적 규칙으로 만들 수 있는 전제 조건은 충분하지 않습니다. 즉, 터미널 규칙을 넘어서는 더 이상의 연결은 허용되지 않습니다.

예를 들어, RCS 및 SCCS 파일에서 소스를 추출하기 위한 기본 제공 묵시적 규칙은 터미널입니다. 결과적으로 foo.c,v 파일이 존재하지 않으면 make는 foo.c,v.o 또는 RCS/SCCS/s.foo.c,v에서 중간 파일로 만들려는 시도조차 하지 않습니다. RCS 및 SCCS 파일은 일반적으로 궁극적인 소스 파일이며 다른 파일에서 다시 만들면 안 됩니다. 따라서 make는 다시 만들 방법을 찾지 않음으로써 시간을 절약할 수 있습니다.

모든 항목 일치 규칙을 터미널로 표시하지 않으면 비 터미널입니다. 비 터미널 모든 항목 일치 규칙 규칙은 암시적 규칙의 전제 조건이나 특정 유형의 데이터를 나타내는 파일 이름에 적용할 수 없습니다. 일치하지 않는 암시적 규칙 대상이 일치하는 경우 파일 이름은 특정 유형의 데이터를 나타냅니다.

예를 들어 파일 이름 foo.c는 패턴 규칙 '%.c : %.y'(Yacc를 실행하는 규칙)의 대상과 일치합니다. 이 규칙이 실제로 적용 가능한지 여부와 상관없이(foo.y 파일이 있는 경우에만 발생), 대상이 일치한다는 사실만으로도 foo.c 파일에 대한 모든 비터미널 일치 규칙의 고려를 방지하기에 충분합니다. 따라서 make는 foo.c를 foo.c.o, foo.c.c, foo.c.p 등의 실행 파일로 만들려는 시도조차 하지 않습니다.

이 제약 조건의 동기는 특정 유형의 데이터(예: 실행 파일)를 포함하는 파일을 만드는데 비터미널 모든 항목 일치 규칙이 사용되며 인식된 접미사가 있는 파일 이름은 다른 특정 유형의 데이터(예: C 소스 파일)를 나타냅니다.

특정 파일 이름을 인식하기 위해 특별한 내장 더미 패턴 규칙이 제공되어 비터미널 일치 규칙은 고려되지 않습니다. 이러한 더미 규칙에는 전제 조건과 레시피가 없으며 다른 모든 목적에서는 무시됩니다. 예를 들어 다음과 같은 내장된 암시적 규칙은

%.p :

foo.p와 같은 파스칼 소스 파일이 특정 대상 패턴과 일치하는지 확인하고 foo.p.o 또는 foo.p.c를 찾는 데 시간이 낭비되는 것을 방지하기 위해 존재합니다.

'%.p'에 대한 것과 같은 더미 패턴 규칙은 접미사 규칙에서 사용하기에 유효한 것으로 나열된 모든 접미사에 대해 만들어집니다(구식 접미사 규칙(Old-Fashioned Suffix Rules) 참조).

10.5.6 Canceling Implicit Rules (암시적 규칙 취소)

동일한 대상과 전제 조건을 사용하지만 레시피는 다른 새 패턴 규칙을 정의하여 기본 제공 암시적 규칙(또는 직접 정의한 규칙)을 재정의할 수 있습니다. 새 규칙이 정의되면 기본 제공 규칙이 대체됩니다. 암시적 규칙 시퀀스에서 새 규칙의 위치는 새 규칙을 작성하는 위치에 따라 결정됩니다.

동일한 대상 및 전제조건을 포함하지만 레시피는 없는 패턴 규칙을 정의하여 내장된 암시적 규칙을 취소할 수 있습니다. 예를 들어 다음은 어셈블러를 실행하는 규칙을 취소합니다:

%.o : %.s

10.6 Defining Last-Resort Default Rules (최후 수단 기본 규칙 정의)

전제 조건 없이 터미널 일치 패턴 규칙을 작성하여 최후 수단 암시적 규칙을 정의할 수 있습니다(모든 일치 규칙(Match-Anything Rules) 참조). 이것은 다른 패턴 규칙과 같습니다. 특별한 점은 모든 대상과 일치한다는 것입니다. 따라서 이러한 규칙의 레시피는 자체 레시피가 없고 다른 묵시적 규칙이 적용되지 않는 모든 대상 및 전제 조건에 사용됩니다.

예를 들어, 메이크파일을 테스트할 때 소스 파일에 실제 데이터가 포함되어 있는지 여부는 신경 쓰지 않고 존재한다는 사실만 알 수 있습니다. 그러면 다음과 같이 할 수 있습니다:

%::
        touch $@

이를 통해 필요한 모든 소스 파일(필수 조건)이 자동으로 생성되도록 합니다.

대신 규칙이 전혀 없는 대상에 사용할 레시피를 정의할 수 있습니다. 심지어 레시피를 지정하지 않는 경우에도 마찬가지입니다. .DEFAULT 대상에 대한 규칙을 작성하여 이를 수행합니다. 이러한 규칙의 레시피는 명시적 규칙에서 대상으로 나타나지 않고 묵시적 규칙이 적용되지 않는 모든 전제 조건에 사용됩니다. 당연히 작성하지 않는한 .DEFAULT 규칙은 없습니다.

레시피나 전제 조건 없이 .DEFAULT를 사용하는 경우:

.DEFAULT:

.DEFAULT에 대해 이전에 저장된 레시피가 지워집니다. 그런 다음 make는 .DEFAULT를 전혀 정의하지 않은 것처럼 작동합니다.

대상이 모든 일치 패턴 규칙 또는 .DEFAULT에서 레시피를 가져오는 것을 원하지 않지만 대상에 대해 레시피를 실행하지 않으려는 경우 빈 레시피를 제공할 수 있습니다(빈 레시피 정의(Defining Empty Recipes) 참조). .

최후의 수단 규칙을 사용하여 다른 메이크파일의 일부를 재정의할 수 있습니다. 다른 Makefile의 일부 재정의(Overriding Part of Another Makefile)를 참조하십시오.

10.7 Old-Fashioned Suffix Rules (구식 접미사 규칙)

접미사 규칙은 make에 대한 암시적 규칙을 정의하는 구식 방법입니다. 패턴 규칙이 더 일반적이고 명확하기 때문에 접미사 규칙은 더 이상 사용되지 않습니다. 이전 makefile과의 호환성을 위해 GNU make에서 지원됩니다: 이중 접미사와 단일 접미사의 두 가지 종류가 있습니다.

이중 접미사 규칙은 한 쌍의 접미사, 즉 대상 접미사와 소스 접미사로 정의됩니다. 이름이 대상 접미사로 끝나는 모든 파일과 일치합니다. 해당 암시적 전제 조건은 대상 접미사를 파일 이름의 소스 접미사로 대체하여 만들어집니다. 두 개의 접미사 규칙 '.c.o'(대상 및 소스 접미사가 '.o' 및 '.c'임)는 패턴 규칙 '%.o : %.c'와 동일합니다.

단일 접미사 규칙은 소스 접미사인 단일 접미사로 정의됩니다. 모든 파일 이름과 일치하며 해당 암시적 전제 조건 이름은 소스 접미사를 추가하여 만들어집니다. 소스 접미사가 '.c'인 단일 접미사 규칙은 패턴 규칙 '% : %.c'와 동일합니다.

접미사 규칙 정의는 각 규칙의 대상을 알려진 접미사의 정의된 목록과 비교하여 인식됩니다. make가 대상이 알려진 접미사인 규칙을 볼 때 이 규칙은 단일 접미사 규칙으로 간주됩니다. make가 연결된 두 개의 알려진 접미사를 대상으로 하는 규칙을 볼 때 이 규칙은 이중 접미사 규칙으로 간주됩니다.

예를 들어, '.c'와 '.o'는 모두 알려진 접미사의 기본 목록에 있습니다. 따라서 대상이 '.c.o'인 규칙을 정의하면 make는 소스 접미사 '.c'와 대상 접미사 '.o'가 있는 이중 접미사 규칙으로 간주합니다. 다음은 C 소스 파일을 컴파일하기 위한 규칙을 정의하는 구식 방법입니다:

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

접미사 규칙에는 자체 전제 조건이 있을 수 없습니다. 파일이 있는 경우 접미사 규칙이 아닌 재미있는 이름을 가진 일반 파일로 처리됩니다. 따라서 다음과 같은 규칙은:

.c.o: foo.h
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

전제 조건 파일 foo.h에서 파일 .c.o를 만드는 방법을 알려주며 패턴 규칙과 전혀 다릅니다:

%.o: %.c foo.h
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

'.c' 파일에서 '.o' 파일을 만드는 방법을 알려주고 이 패턴 규칙을 사용하는 모든 '.o' 파일도 foo.h에 의존하게 만듭니다.

레시피가 없는 접미사 규칙도 의미가 없습니다. 레시피가 없는 패턴 규칙처럼 이전 규칙을 제거하지 않습니다(암시적 규칙 취소(Canceling Implicit Rules) 참조). 그들은 단순히 데이터베이스의 대상으로 연결된 접미사 또는 접미사 쌍을 입력합니다.

알려진 접미사는 단순히 특수 대상 .SUFFIXES의 전제 조건 이름입니다. 다음과 같이 더 많은 전제 조건을 추가하는 .SUFFIXES에 대한 규칙을 작성하여 고유한 접미사를 추가할 수 있습니다:

.SUFFIXES: .hack .win

접미사 목록 끝에 '.hack'과 '.win'을 추가합니다.

알려진 기본 접미사를 추가하는 대신 제거하려면 전제 조건 없이 .SUFFIXES에 대한 규칙을 작성하십시오. 특별한 경륜으로 이것은 .SUFFIXES의 모든 기존 전제 조건을 제거합니다. 그런 다음 다른 규칙을 작성하여 원하는 접미사를 추가할 수 있습니다. 예를 들어,

.SUFFIXES:            # Delete the default suffixes
.SUFFIXES: .c .o .h   # Define our suffix list

'-r' 또는 '--no-builtin-rules' 플래그는 기본 접미사 목록을 비게 만듭니다.

SUFFIXES 변수는 make가 makefile을 읽기 전에 기본 접미사 목록에 정의됩니다. 특수 대상 .SUFFIXES에 대한 규칙을 사용하여 접미사 목록을 변경할 수 있지만 이 변수는 변경되지 않습니다.

10.8 Implicit Rule Search Algorithm (암시적 규칙 검색 알고리즘)

다음은 대상 t에 대한 암시적 규칙을 검색하기 위한 절차입니다. 이 절차는 레시피가 없는 각 이중 콜론 규칙, 레시피가 없는 일반 규칙의 각 대상 및 규칙의 대상이 아닌 각 전제조건에 대해 수행됩니다. 또한 규칙 체인을 검색할때 암시적 규칙에서 오는 전제 조건에 대해 재귀적으로 따릅니다.

접미사 규칙은 makefile이 읽혀지면 접미사 규칙이 동등한 패턴 규칙으로 변환되기 때문에 이 알고리즘에서 언급되지 않습니다.

'archive(member)' 형식의 아카이브 구성원 대상의 경우 다음 알고리즘이 두 번 실행됩니다. 첫 번째는 전체 대상 이름 t를 사용하고 두 번째는 첫 번째 실행에서 규칙을 찾지 못한 경우 대상 t로 '(구성원)'을 사용합니다.

  1. t를 d라고 하는 디렉토리 부분과 n이라고 하는 나머지 부분으로 나눕니다. 예를 들어, t가 'src/foo.o'이면 d는 'src/'이고 n은 'foo.o'입니다.

  2. 대상중 하나가 t 또는 n과 일치하는 모든 패턴 규칙의 목록을 만듭니다. 대상 패턴에 슬래시가 포함되어 있으면 t와 일치합니다. 그렇지 않으면 n에 대해.

  3. 해당 목록의 규칙이 모든 항목 일치 규칙이 아니거나 t가 암시적 규칙의 전제 조건인 경우 목록에서 모든 비터미널 일치 항목 규칙을 제거합니다.

  4. 레시피가 없는 모든 규칙을 목록에서 제거합니다.

  5. 목록의 각 패턴 규칙에 대해:

    • 대상 패턴에서 '%'와 일치하는 t 또는 n의 비어 있지 않은 부분인 어간 s를 찾습니다.

    • '%'를 s로 대체하여 전제 조건 이름을 계산합니다. 대상 패턴에 슬래시가 포함되지 않은 경우 각 전제조건 이름 앞에 d를 추가하십시오.

    • 모든 전제 조건이 존재하는지 또는 존재해야 하는지 여부를 테스트합니다. (만약 파일 이름이 makefile에서 타겟이나 명시적 전제 조건으로 언급된다면, 우리는 그것이 존재해야 한다고 말합니다.)
      모든 전제 조건이 존재하거나 존재해야 하는 경우 또는 전제 조건이 없는 경우 이 규칙이 적용됩니다.

  6. 지금까지 패턴 규칙을 찾지 못했다면 더 열심히 시도해 보세요. 목록의 각 패턴 규칙에 대해:

    • 규칙이 터미널인 경우 무시하고 다음 규칙으로 이동합니다.

    • 전제 조건 이름을 이전과 같이 계산합니다.

    • 모든 전제 조건이 존재하는지 또는 존재해야 하는지 여부를 테스트합니다.

    • 존재하지 않는 각 전제 조건에 대해 이 알고리즘을 재귀적으로 따라 암시적 규칙에 의해 전제 조건이 만들어질 수 있는지 확인합니다.

    • 모든 전제 조건이 존재하거나 존재해야 하거나 암시적 규칙으로 만들 수 있는 경우 이 규칙이 적용됩니다.

  7. 묵시적 규칙이 적용되지 않으면 .DEFAULT(있는 경우)에 대한 규칙이 적용됩니다. 이 경우 .DEFAULT와 동일한 레시피를 제공합니다. 그렇지 않으면 t에 대한 레시피가 없습니다.

적용되는 규칙이 발견되면 t 또는 n과 일치하지 않는 규칙의 각 대상 패턴에 대해 패턴의 '%'가 s로 대체되고 결과 파일 이름은 레시피를 다시 만들 때까지 저장됩니다. 대상 파일 t가 실행됩니다. 레시피가 실행된 후 이러한 저장된 파일 이름 각각은 데이터베이스에 입력되고 업데이트된 것으로 표시되고 파일 t와 동일한 업데이트 상태를 갖습니다.

t에 대해 패턴 규칙의 레시피가 실행되면 대상 및 전제 조건에 따라 자동 변수가 설정됩니다. 자동 변수(Automatic Variables)를 참조하십시오.


11. Using make to Update Archive Files (make를 사용하여 아카이브 파일 업데이트)

아카이브 파일은 구성원(members)이라고 하는 명명된 하위 파일을 포함하는 파일입니다. 그것들은 ar 프로그램으로 유지되며 주요 용도는 링크를 위한 서브루틴 라이브러리입니다.

11.1 Archive Members as Targets (구성원을 대상으로 아카이브)

아카이브 파일의 개별 구성원은 make에서 대상 또는 전제조건으로 사용될 수 있습니다. 다음과 같이 아카이브 파일 archive에서 member라는 이름의 멤버를 지정합니다:

archive(member)

이 구성은 레시피가 아닌 대상 및 전제 조건에서만 사용할 수 있습니다! 레시피에서 사용할 수 있는 대부분의 프로그램은 이 구문을 지원하지 않으며 아카이브 구성원에 대해 직접 작동할 수 없습니다. 아카이브에서 작동하도록 특별히 설계된 ar 및 기타 프로그램만 그렇게 할 수 있습니다. 따라서 아카이브 구성원 대상을 업데이트하는 유효한 레시피는 아마도 ar를 사용해야 합니다. 예를 들어, 이 규칙은 hack.o 파일을 복사하여 아카이브 Foolib에 hack.o 멤버를 생성하도록 지시합니다:

foolib(hack.o) : hack.o
        ar cr foolib hack.o

사실 거의 모든 아카이브 구성원 대상이 이런 방식으로 업데이트되며 이를 수행하는 암시적 규칙이 있습니다. 참고: 아카이브 파일이 이미 존재하지 않는 경우 ar에 'c' 플래그가 필요합니다.

동일한 아카이브에 여러 구성원을 지정하려면 괄호 안에 모든 구성원 이름을 함께 쓸 수 있습니다. 예를 들어:

foolib(hack.o kludge.o)

는 다음과 같습니다:

foolib(hack.o) foolib(kludge.o)

아카이브 멤버 참조에서 셸 스타일 와일드카드를 사용할 수도 있습니다. 파일 이름에 와일드카드 문자 사용(Using Wildcard Characters in File Names)을 참조하십시오. 예를 들어, 'foolib(*.o)'는 이름이 '.o'로 끝나는 foolib 아카이브의 모든 기존 구성원으로 확장됩니다; 아마도 'foolib(hack.o) foolib(kludge.o)'.

11.2 Implicit Rule for Archive Member Targets (아카이브 구성원 대상에 대한 암시적 규칙)

a(m)처럼 보이는 대상은 아카이브 파일 a에서 m이라는 멤버를 나타냅니다.

make는 이러한 대상에 대한 암시적 규칙을 찾을 때 특수 기능으로 (m)과 일치하는 암시적 규칙과 실제 대상 a(m)과 일치하는 규칙을 고려합니다.

이로 인해 대상이 (%)인 하나의 특수 규칙이 일치합니다. 이 규칙은 파일 m을 아카이브에 복사하여 대상 a(m)를 업데이트합니다. 예를 들어, bar.o 파일을 아카이브 foo.a에 bar.o라는 이름의 멤버로 복사하여 아카이브 멤버 대상 foo.a(bar.o)를 업데이트합니다.

이 규칙이 다른 규칙과 연결될때 그 결과는 매우 강력합니다. 따라서 bar.c 파일이 있는 상태에서 'make "foo.a(bar.o)"' (따옴표는 '(' 및 ')'가 쉘에서 특별히 해석되지 않도록 보호하는 데 필요합니다)는 makefile 없이도 다음 레시피가 실행되도록 하기에 충분합니다.

cc -c bar.c -o bar.o
ar r foo.a bar.o
rm -f bar.o

여기서 make는 bar.o 파일을 중간 파일로 구상했습니다. 암시적 규칙 체인(Chains of Implicit Rules)을 참조하십시오.

이와 같은 암시적 규칙은 자동 변수 '$%'를 사용하여 작성됩니다. 자동 변수(Automatic Variables)를 참조하십시오.

아카이브의 아카이브 멤버 이름은 디렉토리 이름을 포함할 수 없지만 makefile에서 그렇게 하는 것이 유용할 수 있습니다. 아카이브 멤버 대상 foo.a(dir/file.o)를 작성하면 make는 다음 레시피로 자동 업데이트를 수행합니다:

ar r foo.a dir/file.o

이것은 파일 dir/file.o를 file.o라는 멤버에 복사하는 효과가 있습니다. 이러한 사용과 관련하여 자동 변수 %D 및 %F가 유용할 수 있습니다.

11.2.1 Updating Archive Symbol Directories (아카이브 심볼 디렉토리 업데이트)

라이브러리로 사용되는 아카이브 파일에는 일반적으로 다른 모든 구성원이 정의한 외부 기호 이름의 디렉토리를 포함하는 .SYMDEF라는 특수 구성원이 포함됩니다. 다른 구성원을 업데이트한 후에는 .SYMDEF를 업데이트하여 다른 구성원을 적절하게 요약해야 합니다. 이것은 ranlib 프로그램을 실행하여 수행됩니다:

ranlib archivefile

일반적으로 아카이브 파일에 대한 규칙에 이 명령을 넣고 아카이브 파일의 모든 구성원을 해당 규칙의 전제 조건으로 만듭니다. 예를 들어,

libfoo.a: libfoo.a(x.o) libfoo.a(y.o) ...
        ranlib libfoo.a

이것의 효과는 아카이브 구성원 x.o, y.o 등을 업데이트한 다음 ranlib를 실행하여 기호 디렉토리 구성원 __.SYMDEF를 업데이트하는 것입니다. 멤버 업데이트 규칙은 여기에 표시되지 않습니다. 이전 섹션에서 설명한 대로 파일을 아카이브에 복사하는 암시적 규칙을 사용하고 생략할 수 있습니다.

이것은 __.SYMDEF 멤버를 자동으로 업데이트하는 GNU ar 프로그램을 사용할 때 필요하지 않습니다.

11.3 Dangers When Using Archives (아카이브 사용시의 위험)

병렬 실행(-j 스위치, 병렬 실행(Parallel Execution) 참조) 및 아카이브를 사용할 때 주의하는 것이 중요합니다. 여러 ar 명령이 동일한 아카이브 파일에서 동시에 실행되면 서로에 대해 알지 못하고 파일이 손상될 수 있습니다.

아마도 미래 버전의 make는 동일한 아카이브 파일에서 작동하는 모든 레시피를 직렬화하여 이 문제를 우회하는 메커니즘을 제공할 것입니다. 그러나 당분간 이 문제를 피하기 위해 다른 방법으로 makefile을 작성하거나 -j를 사용하지 않아야 합니다.

11.4 Suffix Rules for Archive Files (아카이브 파일에 대한 접미사 규칙)

아카이브 파일을 처리하기 위한 특별한 종류의 접미사 규칙을 작성할 수 있습니다. 접미사 규칙에 대한 전체 설명은 접미사 규칙을 참조하십시오. 아카이브에 대한 패턴 규칙이 보다 일반적인 메커니즘이기 때문에 아카이브 접미사 규칙은 GNU make에서 더 이상 사용되지 않습니다(아카이브 업데이트(Archive Update) 참조). 그러나 다른 제조업체와의 호환성을 위해 유지됩니다.

아카이브에 대한 접미사 규칙을 작성하려면 대상 접미사 '.a' (아카이브 파일에 대한 일반적인 접미사)를 사용하여 접미사 규칙을 작성하기만 하면 됩니다. 예를 들어, 다음은 C 소스 파일에서 라이브러리 아카이브를 업데이트하는 구식 접미사 규칙입니다:

.c.a:
        $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
        $(AR) r $@ $*.o
        $(RM) $*.o

이것은 패턴 규칙을 작성한 것처럼 작동합니다:

(%.o): %.c
        $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
        $(AR) r $@ $*.o
        $(RM) $*.o

사실 이것은 make가 대상 접미사로 '.a'가 있는 접미사 규칙을 볼 때 수행하는 것입니다. 모든 이중 접미사 규칙 '.x.a'는 대상 패턴 '(%.o)' 및 전제 조건 패턴 '%.x'가 있는 패턴 규칙으로 변환됩니다.

다른 종류의 파일에 대한 접미사로 '.a'를 사용하고 싶을 수도 있으므로 make는 아카이브 접미사 규칙도 일반적인 방식으로 패턴 규칙으로 변환합니다(접미사 규칙(Suffix Rules) 참조). 따라서 이중 접미사 규칙 '.x.a'는 '(%.o): %.x' 및 '%.a: %.x'라는 두 가지 패턴 규칙을 생성합니다.


12. Extending GNU make (GNU make 확장)

GNU make는 많은 유용한 기능을 포함하여 많은 고급 기능을 제공합니다. 그러나 완전한 프로그래밍 언어가 포함되어 있지 않으므로 제한 사항이 있습니다. 때때로 이러한 제한은 비효율적일 수 있지만 별도의 프로그램을 호출하는 셸 기능을 사용하여 극복할 수 있습니다.

In cases where the built-in capabilities of GNU make are insufficient to your requirements there are two options for extending make. On systems where it's provided, you can utilize GNU Guile as an embedded scripting language (see GNU Guile Integration). On systems which support dynamically loadable objects, you can write your own extension in any language (which can be compiled into such an object) and load it to provide extended capabilities (see The load Directive).
GNU make의 내장 기능이 요구 사항에 충분하지 않은 경우 make 확장을 위한 두 가지 옵션이 있습니다. 제공되는 시스템에서 GNU Guile을 임베디드 스크립팅 언어로 활용할 수 있습니다(GNU Guile 통합(Guile Integration) 참조). 동적으로 로드할 수 있는 개체를 지원하는 시스템에서는 모든 언어로 자신의 확장을 작성하고(이러한 개체로 컴파일할 수 있음) 로드하여 확장된 기능을 제공할 수 있습니다(load 지시문(The load Directive) 참조).

12.1 GNU Guile Integration (GNU Guile 통합)

GNU make는 임베디드 확장 언어로 GNU Guile을 지원하여 빌드될 수 있습니다. Guile은 Scheme 언어를 구현합니다. GNU Guile과 Scheme 언어 및 그 기능에 대한 검토는 이 설명서의 범위를 벗어납니다. GNU Guile 및 Scheme에 대한 설명서를 참조하십시오.

.FEATURES 변수를 검사하여 make가 Guile에 대한 지원을 포함하는지 확인할 수 있습니다. Guile 지원을 사용할 수 있는 경우 guile이라는 단어가 포함됩니다.

Guile 통합은 하나의 새로운 make 기능인 guile을 제공합니다. guile 함수는 먼저 일반적인 방식으로 make에 의해 확장된 다음 GNU Guile 평가자에게 전달되는 하나의 인수를 취합니다. 평가자의 결과는 문자열로 변환되어 makefile에서 guile 함수의 확장으로 사용됩니다.

또한 GNU make는 Guile 스크립트에서 사용하기 위해 Guile 프로시저를 노출합니다.

12.1.1 Conversion of Guile Types (Guile 타입의 변환)

make에는 단 하나의 "데이터 유형"이 있습니다. 바로 문자열입니다. 반면 GNU Guile은 다양한 데이터 유형을 제공합니다. make와 GNU Guile 간의 인터페이스에서 중요한 측면은 Guile 데이터 유형을 make 문자열로 변환하는 것입니다.

이 변환은 두 곳에서 관련이 있습니다: makefile이 Guile 표현식을 평가하기 위해 guile 함수를 호출할 때 해당 평가 결과는 make가 추가로 평가할 수 있도록 make 문자열로 변환되어야 합니다. 두 번째로, Guile 스크립트가 프로시저에 제공된 make 인수가 내보낸 프로시저중 하나를 호출할 때 문자열로 변환되어야 합니다.

Guile 유형을 make 문자열로 변환하는 것은 다음과 같습니다:

  • #f

    False는 빈 문자열로 변환됩니다: make 조건문에서 빈 문자열은 false로 간주됩니다.

  • #t

    True는 문자열 '#t'로 변환됩니다: make 조건문에서 비어 있지 않은 문자열은 모두 true로 간주됩니다.

  • symbol

  • number

    기호 또는 숫자는 해당 기호 또는 숫자의 문자열 표현으로 변환됩니다.

  • character

    인쇄 가능한 문자는 동일한 문자로 변환됩니다.

  • string

    인쇄 가능한 문자만 포함하는 문자열은 동일한 문자열로 변환됩니다.

  • list

    목록은 위의 규칙에 따라 재귀적으로 변환됩니다. 이것은 모든 구조화된 목록이 평면화된다는 것을 의미합니다(즉, ''(a b (c d) e)'의 결과는 make 문자열 'a b c d e'로 변환됩니다.

  • other

    다른 모든 Guile 유형은 오류가 발생합니다. make의 차후 버전에서는 다른 Guile 유형이 변환될 수 있습니다.

'#f'(빈 문자열로) 및 '#t'(비어 있지 않은 문자열 '#t'로)의 번역은 부울 조건을 만들 때 Guile 부울 결과를 직접 사용할 수 있도록 설계되었습니다. 예를 들어:

$(if $(guile (access? "myfile" R_OK)),$(info myfile exists))

이러한 변환 규칙의 결과로 Guile 스크립트의 결과를 고려해야 합니다. 그 결과는 문자열로 변환되고 make에 의해 구문 분석되기 때문입니다. 스크립트에 대한 자연스러운 결과가 없는 경우(즉, 스크립트가 부작용만을 위해 존재하는 경우) makefile에서 구문 오류를 피하기 위해 '#f'를 최종 표현식으로 추가해야 합니다.

12.1.2 Interfaces from Guile to make (Guile에서 make로의 인터페이스)

makefile에서 사용할 수 있는 guile 기능 외에도 make는 Guile 스크립트에서 사용하기 위한 몇 가지 절차를 노출합니다. 시작시 make는 새로운 Guile 모듈인 gnu make를 생성하고 이러한 절차를 해당 모듈의 공개 인터페이스로 내보냅니다:

  • gmk-expand

    이 절차는 문자열로 변환되는 단일 인수를 사용합니다. 문자열은 일반적인 make 확장 규칙을 사용하여 make에 의해 확장됩니다. 확장 결과는 Guile 문자열로 변환되어 절차의 결과로 제공됩니다.

  • gmk-eval

    이 절차는 문자열로 변환되는 단일 인수를 사용합니다. 문자열은 마치 makefile인 것처럼 make에 의해 평가됩니다. 이것은 평가 기능을 통해 사용할 수 있는 동일한 기능입니다(Eval 함수(Eval Function) 참조). gmk-eval 절차의 결과는 항상 빈 문자열입니다.

    gmk-eval은 eval 함수와 함께 gmk-expand를 사용하는 것과 완전히 같지 않습니다. 후자의 경우 평가된 문자열이 두 번 확장됩니다. 먼저 gmk-expand에 의해, 그리고 다시 eval 함수에 의해.

12.1.3 Example Using Guile in make (make에서 Guile을 사용한 예)

다음은 GNU Guile을 사용하여 파일 쓰기를 관리하는 매우 간단한 예입니다. 이 Guile 프로시저는 단순히 파일을 열고 파일에 쓰기를 허용하고(한 줄에 하나의 문자열) 파일을 닫습니다. 우리는 make 변수에 Guile 포트와 같은 복잡한 값을 저장할 수 없기 때문에 포트를 Guile 인터프리터에서 전역 변수로 유지할 것입니다.

define/endef를 사용하여 Guile 함수를 쉽게 생성하여 Guile 스크립트를 생성한 다음 guile 함수를 사용하여 내부화할 수 있습니다:

define GUILEIO
;; A simple Guile IO library for GNU make

(define MKPORT #f)

(define (mkopen name mode)
  (set! MKPORT (open-file name mode))
  #f)

(define (mkwrite s)
  (display s MKPORT)
  (newline MKPORT)
  #f)

(define (mkclose)
  (close-port MKPORT)
  #f)

#f
endef

# Internalize the Guile IO functions
$(guile $(GUILEIO))

상당한 양의 Guile 지원 코드가 있는 경우 다른 파일(예: guileio.scm)에 보관한 다음 guile 함수를 사용하여 메이크파일에 로드하는 것을 고려할 수 있습니다:

$(guile (load "guileio.scm"))

이 방법의 장점은 guileio.scm를 편집할 때 편집자가 이 파일에 makefile 구문이 아닌 Scheme 구문이 포함되어 있다는 것을 이해할 수 있다는 것입니다.

이제 이러한 Guile 함수를 사용하여 파일을 만들 수 있습니다. 쉼표에 들어갈 수 없는 매우 큰 목록에서 작업해야 한다고 가정합니다.

prog: $(PREREQS)
        @$(guile (mkopen "tmp.out" "w")) \
         $(foreach X,$^,$(guile (mkwrite "$(X)"))) \
         $(guile (mkclose))
        $(LINK) < tmp.out

물론 보다 포괄적인 파일 조작 절차가 가능합니다. 예를 들어, 각각에 대한 기호를 선택하고 이를 해시 테이블의 키로 사용하여 여러 출력 파일을 동시에 유지 관리할 수 있습니다. 여기서 값은 포트입니다. 그런 다음 make 변수에 저장할 기호를 반환합니다.

12.2 Loading Dynamic Objects (동적 개체 로드)

경고: load 지시문 및 확장 기능은 이번 GNU make 릴리스에서 "기술 미리보기"로 간주됩니다. 이 기능을 실험해 볼 것을 권장하며 이에 대한 피드백을 보내주시면 감사하겠습니다. 그러나 다음 릴리스에서 이전 버전과의 호환성을 유지한다고 보장할 수는 없습니다. GNU make를 확장하는 대신 GNU Guile을 사용하는 것을 고려하십시오(guile 함수(The guile Function) 참조).

많은 운영 체제는 컴파일된 개체를 동적으로 로드하는 기능을 제공합니다. 당신의 시스템이 이 기능을 제공한다면, GNU make는 런타임에 동적 객체를 로드하기 위해 그것을 사용할 수 있으며, 당신의 makefile에 의해 호출될 수 있는 새로운 기능을 제공합니다.

load 지시자는 동적 개체를 로드하는 데 사용됩니다. 객체가 로드되면 객체가 스스로 초기화하고 GNU make에 새로운 기능을 등록할 수 있도록 "설정(setup)" 기능이 호출됩니다. 예를 들어 동적 객체에는 새로운 make 함수가 포함될 수 있으며 "설정" 함수는 이를 GNU make의 함수 처리 시스템에 등록합니다.

12.2.1 The load Directive (load 지시문)

load 지시문을 makefile에 배치하여 객체를 GNU make에 로드합니다. load 지시문의 구문은 다음과 같습니다:

load object-file ...

또는:

load object-file(symbol-name) ...

파일 object-file은 GNU make에 의해 동적으로 로드됩니다. 개체 파일에 디렉터리 경로가 포함되어 있지 않으면 현재 디렉터리에서 먼저 찾습니다. 거기에 없거나 디렉토리 경로가 포함되어 있으면 시스템별 경로가 검색됩니다. 어떤 이유로든 로드가 실패하면 make는 메시지를 출력하고 종료합니다.

로드가 성공하면 make는 초기화 기능을 호출합니다.

symbol-name이 제공되면 초기화 함수의 이름으로 사용됩니다.

기호 이름이 제공되지 않으면 초기화 함수 이름은 유효한 기호 이름 문자가 아닌 첫 번째 문자까지 object-file의 기본 파일 이름을 사용하여 생성됩니다(영숫자와 밑줄은 유효한 기호 이름 문자입니다). 이 접두사에 접미사 _gmk_setup이 추가됩니다.

하나 이상의 로드 지시문으로 둘 이상의 목적 파일을 로드할 수 있으며 두 가지 형식의 로드 인수를 동일한 지시문에서 사용할 수 있습니다.

초기화 함수에는 로드 작업 호출의 파일 이름과 줄 번호가 제공됩니다. int 유형의 값을 반환해야 합니다. 이 값은 실패 시 0이고 성공 시 0이 아니어야 합니다. 반환 값이 -1이면 GNU make는 개체 파일을 다시 작성하려고 시도하지 않습니다(로드된 개체가 다시 만들어지는 방법(How Loaded Objects Are Remade) 참조).

예를 들어:

load ../mk_funcs.so

동적 개체 ../mk_funcs.so를 로드합니다. 객체가 로드된후 make는 mk_funcs_gmk_setup 함수(공유 객체에 의해 정의된 것으로 가정)를 호출합니다.

반면에:

load ../mk_funcs.so(init_mk_func)

동적 개체 ../mk_funcs.so를 로드합니다. 객체가 로드된 후 make는 init_mk_func 함수를 호출합니다.

로드 지시문에 개체 파일이 몇 번 표시되는지에 관계없이 한 번만 로드되고 설정 함수만 호출됩니다.

개체가 성공적으로 로드되면 해당 파일 이름이 .LOADED 변수에 추가됩니다.

동적 객체 로드 실패가 오류로 보고되지 않도록 하려면 load 대신 -load 지시문을 사용할 수 있습니다. GNU make는 실패하지 않으며 개체 로드에 실패해도 메시지가 생성되지 않습니다. 실패한 개체는 .LOADED 변수에 추가되지 않으며 로드가 성공했는지 확인하기 위해 참조할 수 있습니다.

12.2.2 How Loaded Objects Are Remade (로드된 개체가 재생성되는 방법)

로드된 객체는 makefile과 동일한 re-make 절차를 거칩니다(Makefiles을 다시 만드는 방법(How Makefiles Are Remade) 참조). 로드된 개체가 다시 생성되면 make는 처음부터 시작하여 모든 makefile을 다시 읽고 개체 파일을 다시 로드합니다. 로드된 개체가 이를 지원하기 위해 특별한 작업을 수행할 필요는 없습니다.

로드된 객체를 다시 빌드하는데 필요한 규칙을 제공하는 것은 makefile 작성자에게 달려 있습니다.

12.2.3 Loaded Object Interface (로드된 개체 인터페이스)

경고: 이 기능이 유용하려면 확장 프로그램에서 GNU make 내부의 다양한 기능을 호출해야 합니다. 이 릴리스에서 제공되는 프로그래밍 인터페이스는 안정적인 것으로 간주되어서는 안 됩니다: 함수가 추가, 제거 또는 GNU make의 향후 버전에서 호출 서명 또는 구현을 변경할 수 있습니다.

유용하려면 로드된 객체가 GNU make와 상호 작용할 수 있어야 합니다. 이 상호 작용에는 로드된 개체가 makefile에 제공하는 인터페이스와 make의 작업을 조작하기 위해 로드된 개체에 제공하는 인터페이스가 모두 포함됩니다.

로드된 객체와 make 간의 인터페이스는 'gnumake.h' C 헤더 파일에 의해 정의됩니다. C로 작성된 모든 로드된 객체는 이 헤더 파일을 포함해야 합니다. C로 작성되지 않은 로드된 객체는 이 헤더 파일에 정의된 인터페이스를 구현해야 합니다.

일반적으로 로드된 객체는 설정 함수 내에서 gmk_add_function 루틴을 사용하여 하나 이상의 새로운 GNU make 함수를 등록합니다. 이러한 make 함수의 구현은 gmk_expand 및 gmk_eval 루틴을 사용하여 작업을 수행한 다음 선택적으로 함수 확장의 결과로 문자열을 반환할 수 있습니다.

Loaded Object Licensing (로드된 개체 라이선스)

모든 동적 확장은 GPL 호환 라이선스에 따라 라이선스가 부여되었음을 주장하기 위해 전역 기호 'plugin_is_GPL_compatible'을 정의해야 합니다. 이 기호가 존재하지 않으면 make는 치명적인 오류를 발생시키고 확장을 로드하려고 할 때 종료됩니다.

선언된 기호 유형은 int여야 합니다. 그러나 할당된 섹션에 있을 필요는 없습니다. 코드는 기호가 전역 범위에 존재한다고 주장할 뿐입니다. 다음과 같은 것으로 충분합니다:

int plugin_is_GPL_compatible;

Data Structures

  • gmk_floc

    이 구조는 파일 이름/위치 쌍을 나타냅니다. 항목을 정의할 때 제공되므로 필요한 경우 GNU make가 나중에 정의가 발생한 위치를 사용자에게 알릴 수 있습니다.

Registering Functions

현재 makefile이 로드된 객체가 제공하는 작업을 호출하는 한 가지 방법이 있습니다: make 함수 호출 인터페이스를 통해서입니다. 로드된 객체는 다른 함수와 동일한 방식으로 makefile 내에서 호출될 수 있는 하나 이상의 새 함수를 등록할 수 있습니다.

새 make 함수를 생성하려면 gmk_add_function을 사용하십시오. 그것의 인수들은 다음과 같습니다:

  • name

    함수 이름입니다. 이것은 makefile이 함수를 호출하는데 사용해야 하는 것입니다. 이름은 1~255자 사이여야 하며 영숫자, 마침표('.'), 대시('-') 및 밑줄('_') 문자만 포함할 수 있습니다. 마침표로 시작하지 않을 수 있습니다.

  • func_ptr

    make가 makefile에서 함수를 확장할때 호출할 함수에 대한 포인터입니다. 이 함수는 로드된 개체에 의해 정의되어야 합니다.

  • min_args

    함수가 허용할 최소 인수 수입니다. 0에서 255 사이여야 합니다. GNU make는 이것을 확인하고 함수가 너무 적은 인수로 호출된 경우 func_ptr을 호출하기 전에 실패합니다.

  • max_args

    함수가 허용할 최대 인수 수입니다. 0에서 255 사이여야 합니다. GNU make는 이것을 확인하고 함수가 너무 적은 인수로 호출된 경우 func_ptr을 호출하기 전에 실패합니다. 값이 0이면 원하는 수의 인수가 허용됩니다. 값이 0보다 크면 min_args보다 크거나 같아야 합니다.

  • flags

    이 기능이 작동하는 방식을 지정하는 플래그입니다. 원하는 플래그는 함께 OR해야 합니다. GMK_FUNC_NOEXPAND 플래그가 지정되면 함수가 호출되기 전에 함수 인수가 확장되지 않습니다. 그렇지 않으면 먼저 확장됩니다.

Registered Function Interface (등록된 기능 인터페이스)

make에 등록된 함수는 gmk_func_ptr 유형과 일치해야 합니다. name(함수의 이름), argc(함수에 대한 인수의 수) 및 argv(함수에 대한 인수에 대한 포인터 배열)의 세 가지 매개변수로 호출됩니다. 마지막 포인터(즉, argv[argc])는 널(0)이 됩니다.

함수의 반환 값은 함수를 확장한 결과입니다. 함수가 아무것도 확장하지 않으면 반환 값이 null일 수 있습니다. 그렇지 않으면 gmk_alloc으로 생성된 문자열에 대한 포인터여야 합니다. 함수가 반환되면 make는 이 문자열을 소유하고 적절할 때 해제합니다. 로드된 개체에서 액세스할 수 없습니다.

GNU make Facilities (GNU make 편의기능)

로드된 객체가 사용하기 위해 GNU make에서 내보낸 일부 기능이 있습니다. 일반적으로 이들은 설정 함수 및/또는 gmk_add_function을 통해 등록된 함수 내에서 실행되어 make가 작동하는 데이터를 검색하거나 수정합니다.

  • gmk_expand

    이 함수는 문자열을 받아서 make 확장 규칙을 사용하여 확장합니다. 확장 결과는 nil로 끝나는 문자열 버퍼에 반환됩니다. 호출자는 완료되면 반환된 버퍼에 대한 포인터로 gmk_free를 호출할 책임이 있습니다.

  • gmk_eval

    이 함수는 버퍼를 가져와 makefile 구문의 세그먼트로 평가합니다. 이 함수는 새 변수, 새 규칙 등을 정의하는 데 사용할 수 있습니다. make의 eval 함수를 사용하는 것과 같습니다.

    gmk_eval과 eval 함수를 사용하여 문자열로 gmk_expand를 호출하는것 사이에는 차이점이 있습니다. 후자의 경우 문자열은 두 번 확장됩니다. gmk_expand로 한번, eval 함수로 다시 한번. gmk_eval을 사용하면 버퍼가 최대 한번만 확장됩니다(make 파서가 읽을 때).

Memory Management (메모리 관리)

일부 시스템은 다른 메모리 관리 체계를 허용합니다. 따라서 make 함수에 직접 할당한 메모리를 전달해서는 안되며, make 함수에 의해 반환된 메모리를 직접 해제하려고 시도해서는 안됩니다. 대신 gmk_alloc 및 gmk_free 함수를 사용하십시오.

특히 gmk_add_function을 사용하여 등록한 함수에서 make에 반환된 문자열은 gmk_alloc을 사용하여 할당되어야 하고, make gmk_expand 함수에서 반환된 문자열은 gmk_free를 사용하여 (더 이상 필요하지 않은 경우) 해제되어야 합니다.

  • gmk_alloc

    새로 할당된 버퍼에 대한 포인터를 반환합니다. 이 함수는 항상 유효한 포인터를 반환합니다. 사용 가능한 메모리가 충분하지 않으면 make가 종료됩니다.

  • gmk_free

    make가 반환한 버퍼를 해제합니다. gmk_free 함수가 반환되면 문자열은 더 이상 유효하지 않습니다.

12.2.4 Example Loaded Object (로드된 객체의 예)

임시 파일을 만들고 그 이름을 반환하는 새로운 GNU make 함수를 작성하고 싶다고 가정해 봅시다. 함수가 접두사를 인수로 사용하기를 원합니다. 먼저 mk_temp.c 파일에 함수를 작성할 수 있습니다:

#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <gnumake.h>

int plugin_is_GPL_compatible;

char *
gen_tmpfile(const char *nm, int argc, char **argv)
{
  int fd;

  /* Compute the size of the filename and allocate space for it.  */
  int len = strlen (argv[0]) + 6 + 1;
  char *buf = gmk_alloc (len);

  strcpy (buf, argv[0]);
  strcat (buf, "XXXXXX");

  fd = mkstemp(buf);
  if (fd >= 0)
  {
    /* Don't leak the file descriptor.  */
    close (fd);
    return buf;
  }

  /* Failure.  */
  fprintf (stderr, "mkstemp(%s) failed: %s\n", buf, strerror (errno));
  gmk_free (buf);
  return NULL;
}

int
mk_temp_gmk_setup ()
{
  /* Register the function with make name "mk-temp".  */
  gmk_add_function ("mk-temp", gen_tmpfile, 1, 1, 1);
  return 1;
}

다음으로 이 공유 객체를 빌드하고 로드하고 사용할 수 있는 makefile을 작성합니다:

all:
        @echo Temporary file: $(mk-temp tmpfile.)

load mk_temp.so

mk_temp.so: mk_temp.c
        $(CC) -shared -fPIC -o $ $<

MS-Windows에서 공유 개체가 생성되는 방식의 특성으로 인해 컴파일러는 일반적으로 libgnumake-version.dll.a라고 하는 make 빌드시 생성된 가져오기 라이브러리를 스캔해야 합니다. 여기서 version은 로드 개체 API의 버전입니다. 따라서 공유 객체를 생성하는 레시피는 Windows에서 다음과 같이 표시됩니다 (API 버전이 1이라고 가정):

mk_temp.dll: mk_temp.c
        $(CC) -shared -o $ $< -lgnumake-1

이제 make를 실행하면 다음과 같은 내용이 표시됩니다:

$ make
cc -shared -fPIC -o mk_temp.so mk_temp.c
Temporary filename: tmpfile.A7JEwd

13. Integrating GNU make (GNU make 통합)

GNU make는 종종 통합 개발 환경, 컴파일러 도구 체인 등을 포함한 더 큰 도구 시스템의 한 구성 요소입니다. make의 역할은 명령을 시작하고 성공 여부를 결정하는 것입니다: 이를 수행하기 위해 특별한 통합이 필요하지 않습니다. 그러나 때로는 상위 수준 (make를 호출하는 도구)과 하위 수준 (호출을 만드는 도구) 모두 시스템의 다른 부분과 make를 더 긴밀하게 바인딩하는 것이 편리합니다.

13.1 Sharing Job Slots with GNU make (GNU make와 작업 슬롯 공유)

GNU make는 여러 레시피를 병렬로 실행할 수 있고(병렬 실행(Parallel Execution) 참조) make의 재귀 호출에서도 병렬 작업의 총 수를 제한할 수 있습니다 (Sub-make에 대한 옵션 통신(Communicating Options to a Sub-make) 참조). 다중 스레드 또는 다중 프로세스를 사용하여 병렬로 다중 작업을 실행할 수 있는 호출을 만드는 도구는 시스템에서 실행 중인 활성 스레드/프로세스의 총 수를 보장하기 위해 GNU make의 작업 관리 기능에 참여하도록 향상될 수 있습니다. GNU make에 제공된 최대 슬롯 수를 초과하지 마십시오.

GNU make는 재귀 호출에서 활성 작업의 수를 제어하기 위해 "jobserver"라는 방법을 사용합니다. jobserver의 실제 구현은 운영 체제에 따라 다르지만 몇 가지 기본적인 측면은 항상 true입니다.

먼저 make의 재귀 호출을 이해하는 명령줄 (MAKE 변수 작동 방식(How the MAKE Variable Works) 참조)만 jobserver에 액세스할 수 있습니다. makefile을 작성할때 명령을 재귀로 표시해야 합니다(가장 일반적으로 명령줄에 + 표시기를 접두어로 사용합니다(make의 재귀 사용(Recursive Use of make) 참조).

둘째, make는 MAKEFLAGS 환경 변수에서 환경을 통해 jobserver에 액세스하는데 필요한 정보를 자식에게 제공합니다. jobserver 프로토콜에 참여하려는 도구는 다음 섹션에 설명된 대로 이 환경 변수를 구문 분석해야 합니다.

셋째, 모든 명령 make가 시작하기 전에 하나의 암시적 작업 슬롯이 예약되어 있습니다. jobserver 프로토콜에 참여하려는 모든 도구는 jobserver에 전혀 연결하지 않고도 항상 하나의 작업을 실행할 수 있다고 가정해야 합니다.

마지막으로, jobserver 프로토콜에 참여하는 도구가 오류 조건에서도 종료되기 전에 jobserver에서 얻은 정확한 슬롯 수를 다시 jobserver로 반환하는 것이 중요합니다. 암시적 작업 슬롯이 jobserver에 반환되어서는 안 된다는 점을 기억하십시오! 너무 적은 슬롯을 반환하면 나머지 빌드 프로세스 동안 해당 슬롯이 손실됩니다. 너무 많은 슬롯을 반환하면 추가 슬롯을 사용할 수 있습니다. 최상위 make 명령은 jobserver에서 사용할 수 있는 슬롯의 잘못된 수를 감지하면 빌드 마지막에 오류 메시지를 인쇄합니다.

예를 들어 다중 스레드 작업을 제공하는 링커를 구현한다고 가정합니다. GNU에 의해 호출되는 경우 링크 중에 사용되는 스레드 수를 제어하기 위해 jobserver 프로토콜에 참여할 수 있도록 링커를 향상시키고 싶습니다. 먼저 MAKEFLAGS 환경 변수가 설정되었는지 확인하기 위해 링커를 수정해야 합니다. 다음으로 해당 변수의 값을 구문 분석하여 jobserver를 사용할 수 있는지 여부와 액세스 방법을 결정해야 합니다. 사용 가능한 경우 도구에 액세스하여 도구에서 사용할 수 있는 병렬 처리량을 제어하는 작업 슬롯을 얻을 수 있습니다. 완료되면 도구가 해당 작업 슬롯을 다시 jobserver로 반환해야 합니다.

13.1.1 POSIX Jobserver Interaction (POSIX jobserver 상호 작용)

POSIX 시스템에서 jobserver는 단순한 UNIX 파이프로 구현됩니다. 파이프는 사용 가능한 각 작업에 대해 하나의 단일 문자 토큰으로 미리 로드됩니다. 추가 슬롯을 얻으려면 jobserver 파이프에서 단일 문자를 읽어야 합니다. 슬롯을 해제하려면 jobserver 파이프에 단일 문자를 다시 작성해야 합니다. jobserver 파이프의 읽기 쪽은 "blocking" 모드로 설정되어 있습니다.

파이프에 액세스하려면 MAKEFLAGS 변수를 구문 분석하고 인수 문자열 --jobserver-auth=R,W를 찾아야 합니다. 여기서 'R' 및 'W'는 파일 설명자를 나타내는 음수가 아닌 정수입니다. 'R'은 읽기 파일 설명자입니다. 'W'는 쓰기 파일 설명자입니다.

작업 슬롯을 해제할때 해당 슬롯의 파이프에서 읽은 것과 동일한 문자를 다시 쓰는 것이 중요합니다. 모든 토큰이 동일한 문자라고 가정하지 마십시오. 다른 문자는 GNU make에 대해 다른 의미를 가질 수 있습니다. make는 작업이 어떤 순서로 완료될지 모르기 때문에 순서는 중요하지 않습니다.

강력한 구현을 위해 고려해야 하는 다양한 오류 조건이 있습니다:

  • 일반적으로 도구의 병렬 작업을 제어하는 명령줄 인수가 있습니다. 도구가 jobserver와 명령줄 인수가 모두 지정된 상황을 감지해야 하는지 여부와 대응 방법을 고려하십시오.

  • 도구가 MAKEFLAGS에서 --jobserver-auth 옵션을 사용할 수 있지만 지정된 파일 설명자가 닫혀 있다고 판단하는 경우 호출하는 make 프로세스가 도구가 재귀적 make 호출이라고 생각하지 않았음을 의미합니다 (예: 명령줄이 + 문자가 접두사로 붙지 않음). 이 상황을 사용자에게 알려야 합니다.

  • 또한 도구는 MAKEFLAGS 변수의 첫 번째 단어를 검사하고 문자 n을 찾아야 합니다. 이 문자가 있는 경우 make는 '-n' 옵션으로 호출되었으며 도구는 작업을 수행하지 않고 중지되어야 합니다.

  • 도구는 오류 조건에서도 읽은 토큰을 다시 기록해야 합니다. 여기에는 도구의 오류뿐만 아니라 인터럽트(SIGINT) 등과 같은 외부 영향도 포함됩니다. 이 쓰기 되돌림을 관리하기 위해 신호 처리기를 설치할 수 있습니다.

13.1.2 Windows Jobserver Interaction (Windows Jobserver 상호 작용)

Windows 시스템에서 작업 서버는 명명된 세마포어로 구현됩니다. 세마포어는 사용 가능한 슬롯 수와 동일한 초기 카운트로 설정됩니다. 슬롯을 얻으려면 세마포어에서 기다려야 합니다(시간 초과 여부에 관계없이). 슬롯을 해제하려면 세마포어를 해제하십시오.

세마포에 액세스하려면 MAKEFLAGS 변수를 구문 분석하고 인수 문자열 --jobserver-auth=NAME을 찾아야 합니다. 여기서 'NAME'은 명명된 세마포의 이름입니다. OpenSemaphore와 함께 이 이름을 사용하여 세마포어에 대한 핸들을 만듭니다.

강력한 구현을 위해 고려해야 하는 다양한 오류 조건이 있습니다:

  • 일반적으로 도구의 병렬 작업을 제어하는 명령줄 인수가 있습니다. 도구가 jobserver와 명령줄 인수가 모두 지정된 상황을 감지해야 하는지 여부와 대응 방법을 고려하십시오.

  • 도구는 오류 조건에서도 읽은 토큰에 대한 세마포어를 해제해야 합니다. 여기에는 도구의 오류뿐만 아니라 인터럽트(SIGINT) 등과 같은 외부 영향도 포함됩니다. 이 쓰기 되돌림을 관리하기 위해 신호 처리기를 설치할 수 있습니다.

13.2 Synchronized Terminal Output (동기 터미널 출력)

일반적으로 GNU make는 make가 시작된 것과 동일한 표준 및 오류 출력에 대한 액세스 권한이 있는 모든 명령을 호출합니다. 많은 도구가 출력이 터미널인지 아닌지를 감지하고 이 정보를 사용하여 출력 스타일을 변경합니다. 예를 들어 출력이 터미널로 가는 경우 도구는 색상을 설정하는 제어 문자를 추가하거나 커서 위치를 변경할 수도 있습니다. 출력이 터미널로 이동하지 않는 경우 이러한 특수 제어 문자는 로그 파일 등을 손상시키지 않도록 방출되지 않습니다.

--output-sync(병렬 출력중 출력(Output During Parallel Output) 참조) 옵션은 터미널 감지를 무효화합니다. 출력 동기화가 활성화되면 GNU make는 모든 명령 출력이 파일에 기록되도록 정렬하여 출력이 다른 명령의 간섭 없이 블록으로 기록될 수 있도록 합니다. 이것은 make에 의해 호출된 모든 도구가 출력이 터미널에 표시되지 않을 것이라고 믿는다는 것을 의미합니다(make가 명령이 완료된후 터미널에 표시되기 때문입니다).

출력을 터미널에 표시할지 여부를 결정하려는 도구를 용이하게 하기 위해 GNU make는 명령을 호출하기 전에 MAKE_TERMOUT 및 MAKE_TERMERR 환경 변수를 설정합니다. 표준 또는 오류 출력(각각)이 터미널에 표시되는지 여부를 결정하려는 도구는 이러한 환경 변수가 존재하고 비어 있지 않은 값을 포함하는지 확인하기 위해 이러한 환경 변수를 확인할 수 있습니다. 그렇다면 도구는 출력이 (결국) 터미널에 표시될 것이라고 가정할 수 있습니다. 변수가 설정되지 않았거나 값이 비어 있는 경우 도구는 출력이 터미널로 가는지 여부를 감지하는 일반적인 방법으로 폴백해야 합니다.

변수의 내용을 구문 분석하여 출력을 표시하는데 사용할 터미널 유형을 결정할 수 있습니다.

유사하게, make를 호출하고 출력을 캡처하여 최종적으로 터미널 (또는 터미널 제어 문자를 해석할 수 있는 일부 디스플레이)에 표시하려는 환경은 make를 호출하기 전에 이러한 변수를 설정할 수 있습니다. GNU make는 시작할때 이미 존재하는 환경 변수를 수정하지 않습니다.


14. Features of GNU make (GNU make의 기능)

다음은 make의 다른 버전과의 비교 및 신용을 위해 GNU make의 기능에 대한 요약입니다. 우리는 4.2 BSD 시스템의 make 기능을 베이스라인으로 고려합니다. 이식 가능한 makefile 작성에 관심이 있다면 여기에 나열된 make의 기능이나 Missing의 기능을 사용해서는 안 됩니다.

많은 기능이 System V의 make 버전에서 제공됩니다.

  • VPATH 변수와 그 특별한 의미. 전제 조건에 대한 디렉토리 검색(Searching Directories for Prerequisites)을 참조하십시오. 이 기능은 System V make에 존재하지만 문서화되지 않았습니다. 4.3 BSD make(System V의 VPATH 기능을 모방한다고 함)에 문서화되어 있습니다.

  • 포함된 메이크파일. 다른 Makefile 포함(Including Other Makefiles)을 참조하십시오. 단일 지시문에 여러 파일을 포함하는 것을 허용하는 것은 GNU 확장입니다.

  • 변수는 환경에서 읽고 환경을 통해 전달됩니다. 환경으로부터의 변수들(Variables from the Environment)를 참조하십시오.

  • make의 재귀 호출에 MAKEFLAGS 변수를 통해 전달된 옵션입니다. Sub-make에 옵션 통신(Communicating Options to a Sub-make)을 참조하십시오.

  • 자동 변수 $%는 아카이브 참조의 멤버 이름으로 설정됩니다. 자동 변수(Automatic Variables)를 참조하십시오.

  • 자동 변수 $@, $*, $<, $% 및 $? $(@F) 및 $(@D)와 같은 해당 형식이 있습니다. 우리는 이것을 명백한 확장으로 $^로 일반화했습니다. 자동 변수(Automatic Variables)를 참조하십시오.

  • 대체 변수 참조. 변수 참조의 기초(Basics of Variable References)를 참조하십시오.

  • 명령줄 옵션 '-b' 및 '-m'은 허용되고 무시됩니다. System V make에서 이러한 옵션은 실제로 무언가를 수행합니다.

  • '-n', '-q' 또는 '-t'가 지정되더라도 MAKE 변수를 통해 make를 실행하는 재귀 명령 실행. make의 재귀 사용(Recursive Use of make)을 참조하십시오.

  • 접미사 규칙에서 접미사 '.a' 지원. 아카이브 접미사 규칙(Archive Suffix Rules)을 참조하십시오. 이 기능은 GNU make에서 더 이상 사용되지 않습니다. 규칙 연결(암시적 규칙 연결(Chains of Implicit Rules) 참조)의 일반 기능을 통해 아카이브(아카이브 업데이트(Archive Update) 참조)에 구성원을 설치하는데 하나의 패턴 규칙으로 충분하기 때문입니다.

  • 래시피의 줄 및 백슬래시/줄 바꿈 조합의 배열은 래시피가 인쇄될때 유지되므로 초기 공백 제거를 제외하고 makefile에서와 같이 나타납니다.

다음 기능은 다양한 make 버전에서 영감을 받았습니다. 어떤 버전이 다른 버전에 영감을 줬는지 정확히 불분명한 경우도 있습니다.

  • '%'를 사용한 패턴 규칙. 이것은 make의 여러 버전에서 구현되었습니다. 누가 먼저 발명했는지는 확실하지 않지만 어느 정도 퍼졌습니다. 패턴 규칙 정의 및 재정의(Defining and Redefining Pattern Rules)를 참조하십시오.

  • 규칙 체인 및 암시적 중간 파일. 이것은 AT&T 8th 에디션 연구 Unix용 make 버전에서 Stu Feldman에 의해 구현되었고, 나중에 AT&T Bell 연구소의 Andrew Hume이 그의 mk 프로그램에서 구현했습니다 (여기서 "전이적 폐쇄"라고 함). 우리는 우리가 이것을 그들중 하나에게서 얻었는지 아니면 동시에 스스로 생각해 냈는지 정말로 모릅니다. 암시적 규칙 체인(Chains of Implicit Rules)을 참조하십시오.

  • 현재 대상의 모든 전제 조건 목록을 포함하는 자동 변수 $^. 우리는 이것을 발명하지 않았지만 누가 만들었는지 모릅니다. 자동 변수(Automatic Variables)를 참조하십시오. 자동 변수 $+는 $^의 간단한 확장입니다.

  • "what if" 플래그 (GNU make의 '-W')는 (우리가 아는 한) Andrew Hume이 mk에서 발명했습니다. 레시피 실행 대신(Instead of Executing Recipes)을 참조하십시오.

  • 한 번에 여러 작업을 수행한다는 개념(병렬화)은 System V 또는 BSD 구현에는 없지만 make 및 유사한 프로그램의 많은 화신에 존재합니다. 레시피 실행(Recipe Execution)을 참조하십시오.

  • 병렬 처리를 지원하는 다양한 빌드 도구도 출력 수집 및 단일 블록으로 표시하는 것을 지원합니다. 병렬 실행중 출력(Output During Parallel Execution)을 참조하십시오.

  • 패턴 대체를 사용하여 수정된 변수 참조는 SunOS 4에서 가져온 것입니다. 변수 참조의 기본(Basics of Variable References)을 참조하십시오. 이 기능은 SunOS 4와의 호환성을 위해 대체 구문이 구현되기 전에 patsubst 함수에 의해 GNU make에서 제공되었습니다. GNU make는 SunOS 4가 릴리스되기 전에 patsubst를 가지고 있었기 때문에 누가 누구에게 영감을 주었는지는 완전히 명확하지 않습니다.

  • IEEE 표준 1003.2-1992(POSIX.2)에 의해 레시피 행 앞에 오는 '+' 문자의 특별한 의미(레시피 실행 대신(Instead of Executing Recipes) 참조)가 지정됩니다.

  • 변수 값에 추가하는 '+=' 구문은 SunOS 4 make에서 가져온 것입니다. 변수에 더 많은 텍스트 추가(Appending More Text to Variables)를 참조하십시오.

  • 단일 아카이브 파일에 여러 멤버를 나열하는 'archive(mem1 mem2...)' 구문은 SunOS 4 make에서 가져온 것입니다. 아카이브 구성원(Archive Members)을 참조하십시오.

  • 존재하지 않는 파일에 대해 오류 없이 makefile을 포함하는 -include 지시문은 SunOS 4 make에서 제공됩니다. (그러나 SunOS 4 make는 하나의 -include 지시문에 여러 makefile을 지정하는 것을 허용하지 않습니다.) 동일한 기능이 SGI make 및 아마도 다른 이름에서 sinclude라는 이름으로 나타납니다.

  • != 셸 할당 연산자는 make의 많은 BSD에 존재하며 이러한 구현과 동일하게 동작하도록 여기에서 의도적으로 구현되었습니다.

  • Perl이나 Python과 같은 스크립팅 언어를 사용하여 다양한 빌드 관리 도구를 구현하므로 GNU make의 GNU Guile 통합과 유사한 자연스러운 임베디드 스크립팅 언어를 제공합니다.

나머지 기능은 GNU make의 새로운 발명품입니다:

  • 버전 및 저작권 정보를 인쇄하려면 '-v' 또는 '--version' 옵션을 사용하십시오.

  • '-h' 또는 '--help' 옵션을 사용하여 만들 옵션을 요약합니다.

  • 단순 확장 변수. 변수의 두 가지 특징(The Two Flavors of Variables)을 참조하십시오.

  • MAKE 변수를 통해 명령줄 변수 할당을 자동으로 전달하여 재귀적 make 호출에 전달합니다. make의 재귀 사용(Recursive Use of make)을 참조하십시오.

  • 디렉토리를 변경하려면 '-C' 또는 '--directory' 명령 옵션을 사용하십시오. 옵션 요약(Summary of Options)을 참조하십시오.

  • 정의를 사용하여 축약적인 변수 정의를 만드십시오. 여러 줄 변수 정의(Defining Multi-Line Variables)를 참조하십시오.

  • 특수 대상 .PHONY를 사용하여 가짜 대상을 선언합니다.
    AT&T Bell 연구소의 Andrew Hume은 mk 프로그램에서 다른 구문으로 유사한 기능을 구현했습니다. 이것은 병렬 발견의 경우인 것 같습니다. 가짜 대상(Phony Targets)을 참조하십시오.

  • 함수를 호출하여 텍스트를 조작합니다. 텍스트 변환 함수(Functions for Transforming Text)를 참조하십시오.

  • 파일의 수정 시간이 오래된 척하려면 '-o' 또는 '--old-file' 옵션을 사용하십시오. 일부 파일의 재컴파일 방지(Avoiding Recompilation of Some Files)를 참조하십시오.

  • 조건부 실행.
    이 기능은 make의 다양한 버전에서 여러번 구현되었습니다. C 전처리기 및 이와 유사한 매크로 언어의 기능에서 파생된 자연스러운 확장으로 보이며 혁신적인 개념이 아닙니다. Makefile의 조건부 부분(Conditional Parts of Makefiles)을 참조하십시오.

  • 포함된 메이크파일의 검색 경로를 지정합니다. 다른 Makefile 포함(Including Other Makefiles)을 참조하십시오.

  • 환경 변수로 읽을 추가 메이크파일을 지정합니다. 변수 MAKEFILES(The Variable MAKEFILES)를 참조하십시오.

  • 파일 이름에서 './'의 선행 시퀀스를 제거하여 ./file과 file이 동일한 파일로 간주되도록 합니다.

  • '-lname' 형식으로 작성된 라이브러리 전제조건에 대한 특수 검색 방법을 사용하십시오. 링크 라이브러리에 대한 디렉토리 검색(Directory Search for Link Libraries)을 참조하십시오.

  • 접미사 규칙에 대한 접미사를 허용합니다(구식 접미사 규칙(Old-Fashioned Suffix Rules) 참조). 다른 버전의 make에서는 '.'로 시작해야 하며 '/' 문자를 포함하지 않아야 합니다.

  • MAKELEVEL 변수를 사용하여 make 재귀의 현재 수준을 추적합니다. make의 재귀 사용(Recursive Use of make)을 참조하십시오.

  • MAKECMDGOALS 변수의 명령줄에 지정된 목표를 제공합니다. 목표를 지정하기 위한 인수(Arguments to Specify the Goals)를 참조하십시오.

  • 정적 패턴 규칙을 지정합니다. 정적 패턴 규칙(Static Pattern Rules)을 참조하십시오.

  • 선택적 vpath 검색을 제공합니다. 전제 조건에 대한 디렉토리 검색(Searching Directories for Prerequisites)을 참조하십시오.

  • 계산된 변수 참조를 제공합니다. 변수 참조의 기초(Basics of Variable References)를 참조하십시오.

  • 메이크파일을 업데이트합니다. Makefile을 다시 만드는 방법(How Makefiles Are Remade)을 참조하십시오. System V make는 SCCS 파일에서 makefile을 체크아웃한다는 점에서 이 기능의 매우 제한된 형태를 가지고 있습니다.

  • 다양한 새 내장 암시적 규칙. 기본 제공 규칙 카탈로그(Catalogue of Built-In Rules)를 참조하십시오.

  • make의 동작을 수정할 수 있는 동적 개체를 로드합니다. 동적 개체 로드(Loading Dynamic Objects)를 참조하십시오.


15. Incompatibilities and Missing Features (비호환성 및 누락된 기능)

다양한 다른 시스템의 make 프로그램은 GNU make에서 구현되지 않은 몇 가지 기능을 지원합니다. make를 지정하는 POSIX.2 표준(IEEE 표준 1003.2-1992)에는 이러한 기능이 필요하지 않습니다.

  • 'file((entry))' 형식의 대상은 아카이브 파일 파일의 구성원을 나타냅니다. 멤버는 이름이 아니라 링커 기호 항목을 정의하는 개체 파일로 선택됩니다.

    이 기능은 아카이브 파일 기호 테이블의 내부 형식을 만드는 데 지식을 넣는 비모듈성 때문에 GNU make에 포함되지 않았습니다. 아카이브 기호 디렉토리 업데이트(Updating Archive Symbol Directories)를 참조하십시오.

  • '~' 문자로 끝나는 접미사(접미사 규칙에 사용됨)는 System V make에 특별한 의미가 있습니다. 그들은 '~' 없이 얻을 수 있는 파일에 해당하는 SCCS 파일을 참조합니다. 예를 들어, 접미사 규칙 '.c~.o'는 SCCS 파일 s.n.c에서 파일 n.o를 만듭니다. 완전한 적용을 위해서는 이러한 접미사 규칙의 전체 시리즈가 필요합니다. 구식 접미사 규칙(Old-Fashioned Suffix Rules)을 참조하십시오.

    GNU make에서 이 일련의 전체 사례는 규칙 연결의 일반적인 기능과 함께 SCCS에서 추출하기 위한 두 가지 패턴 규칙에 의해 처리됩니다. 암시적 규칙 체인(Chains of Implicit Rules)을 참조하십시오.

  • System V 및 4.3 BSD make에서 VPATH 검색으로 찾은 파일(전제 조건에 대한 디렉토리 검색(Searching Directories for Prerequisites)) 참조)은 레시피 내에서 이름이 변경되었습니다. 우리는 항상 자동 변수를 사용하여 이 기능을 불필요하게 만드는 것이 훨씬 더 깨끗하다고 생각합니다.

  • 일부 유닉스 제조사에서 규칙의 전제 조건에 나타나는 자동 변수 $*는 해당 규칙의 대상의 전체 이름으로 확장되는 놀랍도록 이상한 "feature"를 가지고 있습니다. 우리는 Unix의 마음 속에서 무슨 일이 개발자들로 하여금 이것을 하도록 만들었는지 상상할 수 없습니다. $*의 일반적인 정의와 완전히 일치하지 않습니다.

  • 일부 Unix 제조사에서 암시적 규칙 검색(암시적 규칙 사용(Using Implicit Rules) 참조)은 레시피가 없는 대상뿐만 아니라 모든 대상에 대해 분명히 수행됩니다. 이는 다음을 수행할 수 있음을 의미합니다:

    foo.o:
            cc -c foo.c

    그리고 Unix make는 foo.o가 foo.c에 의존한다는 것을 직감할 것입니다.

    우리는 그러한 사용법이 깨졌다고 생각합니다. make의 전제 조건 속성은 잘 정의되어 있으며(적어도 GNU make의 경우) 그러한 작업을 수행하는 것은 단순히 모델에 적합하지 않습니다.

  • GNU make에는 EFL 프로그램을 컴파일하거나 사전 처리하기 위한 내장된 암시적 규칙이 포함되어 있지 않습니다. EFL을 사용하는 사람의 소식을 듣게 되면 기꺼이 추가하겠습니다.

  • SVR4 make에서는 레시피 없이 접미사 규칙을 지정할 수 있으며, 마치 빈 레시피가 있는 것처럼 처리됩니다(빈 레시피(Empty Recipes) 참조). 예를 들어:

    .c.a:

    내장된 .c.a 접미사 규칙을 무시합니다.

    우리는 레시피가 없는 규칙이 항상 대상에 대한 전제 조건 목록에 추가하는 것이 더 깨끗하다고 생각합니다. 위의 예는 GNU make에서 원하는 동작을 얻기 위해 쉽게 다시 작성할 수 있습니다:

    .c.a: ;
  • make의 일부 버전은 '-k'를 제외하고 '-e' 플래그로 쉘을 호출합니다(프로그램 컴파일 테스트(Testing the Compilation of a Program) 참조). '-e' 플래그는 실행 중인 프로그램이 0이 아닌 상태를 반환하는 즉시 종료하도록 쉘에 지시합니다. 우리는 레시피의 각 줄을 따로 작성하고 이 특별한 처리가 필요하지 않도록 작성하는 것이 더 깨끗하다고 생각합니다.


16. Makefile Conventions (메이크파일 규칙)

이것은 GNU 프로그램용 Makefile을 작성하기 위한 규칙을 설명합니다. Automake를 사용하면 이러한 규칙을 따르는 Makefile을 작성하는 데 도움이 됩니다. 이식 가능한 Makefile에 대한 자세한 내용은 Autoconf의 POSIX 및 이식 가능한 Make 프로그래밍(POSIX and Portable Make Programming in Autoconf)을 참조하십시오.

16.1 General Conventions for Makefiles (Makefile에 대한 일반 규칙)

모든 Makefile에는 다음 줄이 포함되어야 합니다:

SHELL = /bin/sh

SHELL 변수가 환경에서 상속될 수 있는 시스템에서 문제를 피하기 위해. (이것은 GNU make에서 결코 문제가 되지 않습니다.)

다른 make 프로그램에는 호환되지 않는 접미사 목록과 암시적 규칙이 있으며, 이로 인해 때때로 혼란이나 오작동이 발생합니다. 따라서 다음과 같이 특정 Makefile에 필요한 접미사만을 사용하여 명시적으로 접미사 목록을 설정하는 것이 좋습니다:

.SUFFIXES:
.SUFFIXES: .c .o

첫 번째 줄은 접미사 목록을 지우고 두 번째 줄은 이 Makefile에서 암시적 규칙의 적용을 받을 수 있는 모든 접미사를 소개합니다.

명령 실행 경로에 '.'가 있다고 가정하지 마십시오. make동안 패키지의 일부인 프로그램을 실행해야 할때 프로그램이 make의 일부로 빌드된 경우 ./를 사용하는지 확인하거나 파일이 소스 코드의 변경되지 않는 부분인 경우에는 $(srcdir)의 일부인지 확인하십시오. 이러한 접두사중 하나가 없으면 현재 검색 경로가 사용됩니다.

./(빌드 디렉토리)와 $(srcdir)/(소스 디렉토리)의 구분은 사용자가 '--srcdir' 옵션을 사용하여 별도의 디렉토리에 빌드할 수 있기 때문에 중요합니다. 그 형식의 규칙은:

foo.1 : foo.man sedscript
        sed -f sedscript foo.man > foo.1

foo.man과 sedscript가 소스 디렉토리에 있기 때문에 빌드 디렉토리가 소스 디렉토리가 아니면 실패합니다.

GNU make를 사용할 때 'VPATH'에 의존하여 소스 파일을 찾는 것은 단일 종속 파일이 있는 경우에 작동합니다. make 자동 변수 '$<'가 소스 파일이 어디에 있든 나타내기 때문입니다. (많은 make 버전이 암시적 규칙에서만 '$<'를 설정합니다.) 다음과 같은 Makefile 대상은

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o

다음과 같이 작성해야 합니다.

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@

'VPATH'는 이것이 올바르게 작동할 수 있도록 합니다. 대상에 여러 종속성이 있는 경우 명시적인 '$(srcdir)'을 사용하는 것이 규칙이 잘 작동하도록 하는 가장 쉬운 방법입니다. 예를 들어 위의 foo.1 대상은 다음과 같이 작성하는 것이 가장 좋습니다:

foo.1 : foo.man sedscript
        sed -f $(srcdir)/sedscript $(srcdir)/foo.man > $@

GNU 배포판에는 일반적으로 소스 파일이 아닌 일부 파일이 포함되어 있습니다 (예: Info 파일 및 Autoconf, Automake, Bison 또는 Flex의 출력). 이러한 파일은 일반적으로 소스 디렉터리에 나타나므로 항상 빌드 디렉터리가 아니라 소스 디렉터리에 나타나야 합니다. 따라서 업데이트하기 위한 Makefile 규칙은 업데이트된 파일을 소스 디렉토리에 넣어야 합니다.

그러나 파일이 배포판에 나타나지 않으면 Makefile은 이 파일을 소스 디렉터리에 두어서는 안 됩니다. 왜냐하면 일반적인 상황에서 프로그램을 빌드하는 것은 소스 디렉터리를 어떤 식으로든 수정해서는 안 되기 때문입니다.

빌드 및 설치 대상을 확인하여, 적어도(및 모든 하위 대상)이 병렬 make에서 올바르게 작동하도록 하십시오.

16.2 Utilities in Makefiles (Makefile의 유틸리티)

Makefile 명령(그리고 configure와 같은 모든 셸 스크립트)을 작성하여 csh가 아닌 sh(전통적인 Bourne 셸과 POSIX 셸 모두)에서 실행합니다. ksh나 bash의 특별한 기능이나 전통적인 Bourne sh에서 널리 지원되지 않는 POSIX 기능을 사용하지 마십시오.

configure 스크립트와 빌드 및 설치를 위한 Makefile 규칙은 다음을 제외하고 직접 유틸리티를 사용해서는 안 됩니다:

awk cat cmp cp diff echo egrep expr false grep install-info ln ls
mkdir mv printf pwd rm rmdir sed sleep sort tar test touch tr true

gzip과 같은 압축 프로그램을 dist 규칙에 사용할 수 있습니다.

일반적으로 이러한 프로그램의 널리 지원되는(일반적으로 POSIX 지정) 옵션과 기능을 고수하십시오. 예를 들어, 편리할 수 있습니다만 'mkdir -p'를 사용하지 마십시오. 왜냐하면, 일부 시스템에서는 이를 전혀 지원하지 않고 다른 시스템에서는 병렬 실행에 안전하지 않기 때문입니다. 알려진 비호환성 목록은 Autoconf의 'Portable Shell Programming'을 참조하십시오.

몇몇 파일 시스템은 심볼릭 링크를 지원하지 않기 때문에 메이크파일에 심볼릭 링크를 생성하지 않는 것이 좋습니다.

빌드 및 설치를 위한 Makefile 규칙도 컴파일러 및 관련 프로그램을 사용할 수 있지만 사용자가 대안을 대체할 수 있도록 make 변수를 통해 사용해야 합니다. 다음은 우리가 의미하는 프로그램 중 일부입니다:

ar bison cc flex install ld ldconfig lex
make makeinfo ranlib texi2dvi yacc

다음 make 변수를 사용하여 해당 프로그램을 실행합니다:

$(AR) $(BISON) $(CC) $(FLEX) $(INSTALL) $(LD) $(LDCONFIG) $(LEX)
$(MAKE) $(MAKEINFO) $(RANLIB) $(TEXI2DVI) $(YACC)

ranlib 또는 ldconfig를 사용할때 시스템에 문제의 프로그램이 없는 경우 나쁜 일이 발생하지 않는지 확인해야 합니다. 해당 명령의 오류를 무시하도록 배열하고 명령 앞에 메시지를 인쇄하여 이 명령의 실패가 문제를 의미하지 않는다는 것을 사용자에게 알립니다. (Autoconf 'AC_PROG_RANLIB' 매크로가 이에 도움이될 수 있습니다.)

심볼릭 링크를 사용하는 경우 심볼릭 링크가 없는 시스템에 대한 대체를 구현해야 합니다.

Make 변수를 통해 사용할 수 있는 추가 유틸리티는 다음과 같습니다:

chgrp chmod chown mknod

Makefile 부분(또는 스크립트)에서 다른 유틸리티가 존재하는 것을 알고 있는 특정 시스템용으로만 사용하는 것은 괜찮습니다.

16.3 Variables for Specifying Commands (명령 지정을 위한 변수)

Makefile은 특정 명령, 옵션 등을 재정의하기 위한 변수를 제공해야 합니다.

특히 대부분의 유틸리티 프로그램은 변수를 통해 실행해야 합니다. 따라서 Bison을 사용하는 경우 기본값이 'BISON = bison'으로 설정된 BISON이라는 변수를 가지고 Bison을 사용해야 할 때마다 $(BISON)으로 참조하십시오.

ln, rm, mv 등과 같은 파일 관리 유틸리티는 사용자가 다른 프로그램으로 교체할 필요가 없기 때문에 이러한 방식으로 변수를 통해 참조할 필요가 없습니다.

각 프로그램 이름 변수는 프로그램에 옵션을 제공하는데 사용되는 옵션 변수와 함께 제공되어야 합니다. 프로그램 이름 변수 이름에 'FLAGS'를 추가하여 옵션 변수 이름을 가져옵니다 (예: BISONFLAGS). (C 컴파일러의 경우 CFLAGS, yacc의 경우 YFLAGS, lex의 경우 LFLAGS라는 이름은 이 규칙의 예외이지만 표준이므로 그대로 유지합니다) 전처리기를 실행하는 모든 컴파일 명령에서 CPPFLAGS를 사용하고 ld의 직접 사용뿐만 아니라 링크를 수행하는 모든 컴파일 명령에서 LDFLAGS를 사용합니다.

특정 파일의 적절한 컴파일을 위해 사용해야 하는 C 컴파일러 옵션이 있는 경우 CFLAGS에 포함하지 마십시오. 사용자는 CFLAGS를 자유롭게 지정할 수 있기를 기대합니다. 대신, 다음과 같이 컴파일 명령에 명시적으로 작성하거나 암시적 규칙을 정의하여 CFLAGS와 독립적으로 필요한 옵션을 C 컴파일러에 전달하도록 정렬합니다:

CFLAGS = -g
ALL_CFLAGS = -I. $(CFLAGS)
.c.o:
        $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<

적절한 컴파일에 필요하지 않기 때문에 CFLAGS에 '-g' 옵션을 포함하십시오. 권장되는 기본값이라고 생각할 수 있습니다. 패키지가 기본적으로 GCC로 컴파일되도록 설정되어 있으면 CFLAGS의 기본값에도 '-O'를 포함할 수 있습니다.

사용자가 CFLAGS를 사용하여 다른 변수를 재정의할 수 있도록 CFLAGS를 컴파일 명령에서 컴파일러 옵션을 포함하는 다른 변수 다음에 마지막에 넣습니다.

CFLAGS는 컴파일을 수행하는 것과 링크를 수행하는 것 모두에서 C 컴파일러의 모든 호출에 사용해야 합니다.

모든 Makefile은 시스템에 파일을 설치하기 위한 기본 명령인 INSTALL 변수를 정의해야 합니다.

모든 Makefile은 INSTALL_PROGRAM 및 INSTALL_DATA 변수도 정의해야 합니다. (INSTALL_PROGRAM의 기본값은 $(INSTALL)이어야 하고, INSTALL_DATA의 기본값은 ${INSTALL} -m 644여야 합니다.) 그런 다음 실행 파일과 비실행 파일 각각에 대해 실제 설치를 위한 명령으로 해당 변수를 사용해야 합니다. 이러한 변수의 최소 사용은 다음과 같습니다:

$(INSTALL_PROGRAM) foo $(bindir)/foo
$(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a

그러나 다음 섹션에서 설명하는 것처럼 대상 파일에서 DESTDIR 접두사를 지원하는 것이 좋습니다.

다음과 같이 최종 인수가 디렉토리가 되는한 명령으로 여러 파일을 설치하는 것은 허용되지만 필수는 아닙니다:

$(INSTALL_PROGRAM) foo bar baz $(bindir)

16.4 DESTDIR: Support for Staged Installs (DESTDIR: 단계적 설치 지원)

DESTDIR은 다음과 같이 설치된 각 대상 파일 앞에 추가되는 변수입니다:

$(INSTALL_PROGRAM) foo $(DESTDIR)$(bindir)/foo
$(INSTALL_DATA) libfoo.a $(DESTDIR)$(libdir)/libfoo.a

DESTDIR 변수는 사용자가 make 명령줄에서 절대 파일 이름으로 지정합니다. 예를 들어:

make DESTDIR=/tmp/stage install

DESTDIR은 유용한 유일한 대상이므로 install 및 uninstall 대상에서만 지원되어야 합니다.

설치 단계에서 일반적으로 /usr/local/bin/foo 및 /usr/local/lib/libfoo.a를 설치하는 경우 위의 예와 같이 호출된 설치는 대신 /tmp/stage/usr/local/bin/foo 및 /tmp/stage/usr/local/lib/libfoo.a를 설치합니다.

이러한 방식으로 각 대상에 변수 DESTDIR을 추가하면 설치된 파일이 예상 위치에 직접 배치되지 않고 대신 임시 위치(DESTDIR)에 복사되는 단계적 설치가 제공됩니다. 그러나 설치된 파일은 상대 디렉토리 구조를 유지하며 포함된 파일 이름은 수정되지 않습니다.

Makefile에서 DESTDIR 값을 전혀 설정해서는 안 됩니다. 그러면 기본적으로 파일이 예상 위치에 설치됩니다. 또한 DESTDIR을 지정해도 소프트웨어의 작동이 변경되지 않아야 하므로 해당 값이 파일 내용에 포함되어서는 안 됩니다.

DESTDIR 지원은 일반적으로 패키지 생성에 사용됩니다. 또한 주어진 패키지가 어디에 설치되는지 이해하고, 일반적으로 보호 영역에 설치할 수 있는 권한이 없는 사용자가 해당 권한을 얻기 전에 빌드 및 설치할 수 있도록 하려는 사용자에게 유용합니다. 마지막으로 'stow'와 같은 도구에 유용할 수 있습니다. 코드는 한 곳에 설치되지만 심볼릭 링크나 특수 마운트 작업을 사용하여 다른 곳에 설치된 것처럼 보이게 합니다. 그래서 우리는 비록 그것이 절대적인 요구사항은 아니지만 GNU 패키지가 DESTDIR을 지원하는 것을 강력히 권장합니다.

16.5 Variables for Installation Directories (설치 디렉토리에 대한 변수)

설치 디렉토리는 항상 변수로 이름을 지어야 하므로 비표준 장소에 설치하기 쉽습니다. 이러한 변수의 표준 이름과 GNU 패키지에 있어야 하는 값은 아래에 설명되어 있습니다. 표준 파일 시스템 레이아웃을 기반으로 합니다. 그것의 변형은 GNU/Linux 및 기타 현대 운영 체제에서 사용됩니다.

설치 프로그램은 make(예: make prefix=/usr install) 또는 configure(예: configure --prefix=/usr)를 호출할 때 이 값을 재정의해야 합니다. GNU 패키지는 설치 중인 시스템에서 이러한 변수에 어떤 값이 적절해야 하는지 추측하려고 해서는 안 됩니다. 여기에 지정된 기본 설정을 사용하여 모든 GNU 패키지가 동일하게 작동하여 설치 프로그램이 원하는 레이아웃을 얻을 수 있도록 합니다.

모든 설치 디렉토리와 상위 디렉토리는 설치되기 전에 생성되어야 합니다(필요한 경우).

이 처음 두 변수는 설치 루트를 설정합니다. 다른 모든 설치 디렉토리는 이 두 디렉토리중 하나의 하위 디렉토리여야 하며 이 두 디렉토리에 직접 설치해서는 안 됩니다.

  • prefix

    아래 나열된 변수의 기본값을 구성하는데 사용되는 접두사입니다. 접두사의 기본값은 /usr/local 이어야 합니다. 완전한 GNU 시스템을 구축할때 접두사는 비어 있고 /usr은 /에 대한 심볼릭 링크가 됩니다. (Autoconf를 사용하는 경우 '@prefix@'로 작성하십시오.)

    Running 'make install' with a different value of prefix from the one used to build the program should not recompile the program.
    프로그램을 빌드하는 데 사용된 것과 다른 값의 접두사로 'make install'을 실행하면 프로그램을 다시 컴파일하지 않아야 합니다.

  • exec_prefix

    아래 나열된 일부 변수의 기본값을 구성하는데 사용되는 접두어입니다. exec_prefix의 기본값은 $(prefix)여야 합니다. (Autoconf를 사용하는 경우 '@exec_prefix@'로 작성하십시오.)

    일반적으로 $(exec_prefix)는 시스템 특정 파일(예: 실행 파일 및 서브루틴 라이브러리)이 포함된 디렉토리에 사용되는 반면 $(prefix)는 다른 디렉토리에 직접 사용됩니다.

    프로그램을 빌드할때 사용한 것과 다른 exec_prefix 값으로 'make install'을 실행하면 프로그램을 다시 컴파일하지 않아야 합니다.

실행 프로그램은 다음 디렉토리 중 하나에 설치됩니다.

  • bindir

    사용자가 실행할 수 있는 실행 프로그램을 설치하기 위한 디렉터리입니다. 이것은 일반적으로 /usr/local/bin 이어야 하지만 $(exec_prefix)/bin으로 작성합니다. (Autoconf를 사용하는 경우 '@bindir@'로 작성하십시오.)

  • sbindir

    쉘에서 실행할 수 있지만 일반적으로 시스템 관리자에게만 유용한 실행 프로그램을 설치하기 위한 디렉토리입니다. 이것은 일반적으로 /usr/local/sbin 이어야 하지만 $(exec_prefix)/sbin으로 작성합니다. (Autoconf를 사용하는 경우 '@sbindir@'로 작성하십시오.)

  • libexecdir

    사용자가 아닌 다른 프로그램이 실행할 실행 프로그램을 설치하기 위한 디렉터리입니다. 이 디렉토리는 일반적으로 /usr/local/libexec 이어야 하지만 $(exec_prefix)/libexec로 작성합니다. (Autoconf를 사용하는 경우 '@libexecdir@'로 작성하십시오.)

    'libexecdir'의 정의는 모든 패키지에서 동일하므로 해당 하위 디렉토리에 데이터를 설치해야 합니다. 대부분의 패키지는 $(libexecdir)/package-name/ 아래에 데이터를 설치합니다. 아마도 $(libexecdir)/package-name/machine/version과 같은 추가 하위 디렉토리에 있을 수 있습니다.

프로그램이 실행되는 동안 사용되는 데이터 파일은 두 가지 범주로 나뉩니다.

  • 일부 파일은 일반적으로 프로그램에 의해 수정됩니다. 다른 것들은 일반적으로 수정되지 않습니다(사용자가 이들 중 일부를 수정할 수 있음).

  • 일부 파일은 아키텍처에 독립적이며 사이트의 모든 시스템에서 공유할 수 있습니다. 일부는 아키텍처에 따라 다르며 동일한 종류 및 운영 체제의 시스템에서만 공유할 수 있습니다. 나머지는 두 시스템 간에 공유할 수 없습니다.

이것은 여섯 가지 다른 가능성을 만듭니다. 그러나 우리는 객체 파일과 라이브러리를 제외하고 아키텍처 종속 파일의 사용을 권장하지 않습니다. 다른 데이터 파일을 아키텍처에 독립적으로 만드는 것이 훨씬 깨끗하며 일반적으로 어렵지 않습니다.

다음은 Makefiles가 이러한 다양한 종류의 파일을 저장할 디렉토리를 지정하는 데 사용해야 하는 변수입니다:

  • 'datarootdir'

    읽기 전용 아키텍처 독립 데이터 파일에 대한 디렉토리 트리의 루트입니다. 이것은 일반적으로 /usr/local/share 여야 하지만 $(prefix)/share로 작성합니다. (Autoconf를 사용하는 경우 '@datarootdir@'로 작성하십시오.) 'datadir'의 기본값은 이 변수를 기반으로 합니다. 'infodir', 'mandir' 등도 마찬가지입니다.

  • 'datadir'

    이 프로그램에 대한 독특한 읽기 전용 아키텍처 독립 데이터 파일을 설치하기 위한 디렉토리입니다. 이것은 일반적으로 'datarootdir'과 같은 위치이지만 Info 파일, 매뉴얼 페이지 등의 위치를 변경하지 않고 이러한 프로그램별 파일을 이동할 수 있도록 두 개의 개별 변수를 사용합니다.

    이것은 일반적으로 /usr/local/share 이어야 하지만 $(datarootdir)로 작성합니다. (Autoconf를 사용하는 경우 '@datadir@'로 작성하십시오.)

    'datadir'의 정의는 모든 패키지에 대해 동일하므로 해당 하위 디렉토리에 데이터를 설치해야 합니다. 대부분의 패키지는 $(datadir)/package-name/ 아래에 데이터를 설치합니다.

  • 'sysconfdir'

    단일 시스템에 속하는 읽기 전용 데이터 파일, 즉 호스트를 구성하기 위한 파일을 설치하기 위한 디렉토리입니다. 메일러(Mailer) 및 네트워크 구성 파일, /etc/passwd 등이 여기에 속합니다. 이 디렉토리의 모든 파일은 일반 ASCII 텍스트 파일이어야 합니다. 이 디렉토리는 일반적으로 /usr/local/etc 여야 하지만 $(prefix)/etc로 작성합니다. (Autoconf를 사용하는 경우 '@sysconfdir@'로 작성하십시오.)

    이 디렉토리에 실행 파일을 설치하지 마십시오 (아마도 $(libexecdir) 또는 $(sbindir)에 속할 것입니다). 또한 정상적인 사용 과정에서 수정된 파일 (시스템 구성 변경을 목적으로하는 프로그램 제외)은 설치하지 마십시오. 그것들은 아마도 $(localstatedir)에 속할 것입니다.

  • 'sharedstatedir'

    프로그램이 실행되는 동안 수정하는 아키텍처 독립적인 데이터 파일을 설치하기 위한 디렉토리입니다. 이것은 일반적으로 /usr/local/com이어야 하지만 $(prefix)/com으로 작성합니다. (Autoconf를 사용하는 경우 '@sharedstatedir@'로 작성하십시오.)

  • 'localstatedir'

    프로그램이 실행되는 동안 수정하고 하나의 특정 시스템과 관련된 데이터 파일을 설치하기 위한 디렉토리입니다. 사용자는 패키지 작업을 구성하기 위해 이 디렉터리의 파일을 수정할 필요가 없습니다. 이러한 구성 정보를 $(datadir) 또는 $(sysconfdir)에 있는 별도의 파일에 넣으십시오. $(localstatedir)은 일반적으로 /usr/local/var 이어야 하지만 $(prefix)/var로 작성합니다. (Autoconf를 사용하는 경우 '@localstatedir@'로 작성하십시오.)

  • 'runstatedir'

    프로그램이 실행되는 동안 수정하는 데이터 파일을 설치하기 위한 디렉터리로, 하나의 특정 시스템과 관련이 있으며 프로그램 실행보다 오래 지속될 필요가 없습니다. 예를 들어 다음 재부팅 때까지 일반적으로 오래 지속됩니다. 시스템 데몬용 PID 파일이 일반적으로 사용됩니다. 또한 이 디렉토리는 재부팅시를 제외하고는 청소해서는 안되며, 일반 /tmp(TMPDIR)는 임의로 청소할 수 있습니다. 이것은 일반적으로 /var/run 이어야 하지만 $(localstatedir)/run으로 작성합니다. 별도의 변수로 사용하면 예를 들어 원하는 경우 /run을 사용할 수 있습니다. (Autoconf 2.70 이상을 사용하는 경우 '@runstatedir@'로 작성하십시오.)

이러한 변수는 프로그램에 특정 유형의 파일이 있는 경우 설치하기 위한 디렉토리를 지정합니다. 모든 GNU 패키지에는 Info 파일이 있어야 하므로 모든 프로그램에는 'infodir'이 필요하지만 모든 프로그램에 'libdir' 또는 'lispdir'이 필요한 것은 아닙니다.

  • 'includedir'

    C '#include' 전처리기 지시문을 사용하여 사용자 프로그램에 포함될 헤더 파일을 설치하기 위한 디렉토리입니다. 이것은 일반적으로 /usr/local/include 여야 하지만 $(prefix)/include로 작성합니다. (Autoconf를 사용하는 경우 '@includedir@'로 작성하십시오.)

    GCC 이외의 대부분의 컴파일러는 /usr/local/include 디렉토리에서 헤더 파일을 찾지 않습니다. 따라서 이 방법으로 헤더 파일을 설치하는 것은 GCC에서만 유용합니다. 일부 라이브러리는 실제로 GCC와 함께 작동하도록 의도되었기 때문에 때때로 이것은 문제가 되지 않습니다. 그러나 일부 라이브러리는 다른 컴파일러와 함께 작동하도록 되어 있습니다. 헤더 파일을 두 위치에 설치해야 합니다. 하나는 includedir로 지정하고 다른 하나는 oldincludedir로 지정해야 합니다.

  • 'oldincludedir'

    GCC 이외의 컴파일러와 함께 사용하기 위해 '#include' 헤더 파일을 설치하기 위한 디렉토리입니다. 이것은 일반적으로 /usr/include 여야 합니다. (Autoconf를 사용하는 경우 '@oldincludedir@'로 작성할 수 있습니다.)

    Makefile 명령은 oldincludedir 값이 비어 있는지 확인해야 합니다. 그렇다면 사용하려고 해서는 안 됩니다. 헤더 파일의 두 번째 설치를 취소해야 합니다.

    헤더가 동일한 패키지에서 온 것이 아니면 패키지가 이 디렉토리의 기존 헤더를 대체해서는 안 됩니다. 따라서 Foo 패키지가 헤더 파일 foo.h를 제공하는 경우 (1) 거기에 foo.h가 없거나 (2) foo 패키지로 부터 가져와 foo.h가 존재하는 경우 oldincludedir 디렉토리에 헤더 파일을 설치해야 합니다.

    foo.h가 Foo 패키지에서 왔는지 여부를 확인하려면 파일에 매직 문자열(주석의 일부)을 넣고 해당 문자열에 대해 grep하십시오.

  • 'docdir'

    이 패키지에 대한 문서 파일(Info 제외)을 설치하기 위한 디렉토리입니다. 기본적으로 /usr/local/share/doc/yourpkg 여야 하지만 $(datarootdir)/doc/yourpkg 로 작성해야 합니다. (Autoconf를 사용하는 경우 '@docdir@'로 작성하십시오.) 버전 번호를 포함할 수 있는 yourpkg 하위 디렉토리는 README와 같은 공통 이름을 가진 파일 간의 충돌을 방지합니다.

  • 'infodir'

    이 패키지에 대한 정보 파일을 설치하기 위한 디렉토리입니다. 기본적으로 /usr/local/share/info 여야 하지만 $(datarootdir)/info로 작성해야 합니다. (Autoconf를 사용하는 경우 '@infodir@'로 작성하십시오.) infodir은 기존 관행과의 호환성을 위해 docdir과 별개입니다.

  • 'htmldir'

  • 'dvidir'

  • 'pdfdir'

  • 'psdir'

    특정 형식의 문서 파일을 설치하기 위한 디렉터리입니다. 기본적으로 모두 $(docdir)로 설정되어야 합니다. (Autoconf를 사용하는 경우 '@htmldir@', '@dvidir@' 등으로 작성하십시오.) 문서의 여러 번역을 제공하는 패키지는 '$(htmldir)/'ll, '$(pdfdir)/'ll 등에 설치해야 합니다. 여기서 ll은 'en' 또는 'pt_BR'과 같은 로케일 약어입니다.

  • 'libdir'

    개체 파일 및 개체 코드 라이브러리의 디렉터리입니다. 여기에 실행 파일을 설치하지 마십시오. 대신 $(libexecdir)로 이동해야 합니다. libdir의 값은 일반적으로 /usr/local/lib 이어야 하지만 $(exec_prefix)/lib로 작성합니다. (Autoconf를 사용하는 경우 '@libdir@'로 작성하십시오.)

  • 'lispdir'

    이 패키지에 있는 Emacs Lisp 파일을 설치하기 위한 디렉토리입니다. 기본적으로 /usr/local/share/emacs/site-lisp 이어야 하지만 $(datarootdir)/emacs/site-lisp로 작성해야 합니다.

    Autoconf를 사용하는 경우 기본값을 '@lispdir@'로 작성합니다. '@lispdir@'이 작동하도록 하려면 configure.ac 파일에 다음 줄이 필요합니다:

    lispdir='${datarootdir}/emacs/site-lisp'
    AC_SUBST(lispdir)
  • 'localedir'

    이 패키지에 대한 로케일별 메시지 카탈로그를 설치하기 위한 디렉토리입니다. 기본적으로 /usr/local/share/locale 이어야 하지만 $(datarootdir)/locale로 작성해야 합니다. (Autoconf를 사용하는 경우 '@localedir@'로 작성하십시오.) 이 디렉토리는 일반적으로 로케일별로 하위 디렉토리가 있습니다.

Unix 스타일 매뉴얼 페이지는 다음 중 하나에 설치됩니다:

  • 'mandir'

    이 패키지의 매뉴얼 페이지(있는 경우)를 설치하기 위한 최상위 디렉토리입니다. 일반적으로 /usr/local/share/man 이지만 $(datarootdir)/man으로 작성해야 합니다. (Autoconf를 사용하는 경우 '@mandir@'로 작성하십시오.)

  • 'man1dir'

    섹션 1 매뉴얼 페이지를 설치하기 위한 디렉토리. $(mandir)/man1로 작성하십시오.

  • 'man2dir'

    섹션 2 매뉴얼 페이지를 설치하기 위한 디렉토리. $(mandir)/man2로 작성하십시오.

  • '...'

    GNU 소프트웨어의 기본 문서를 매뉴얼 페이지로 만들지 마십시오. 대신 Texinfo에 매뉴얼을 작성하십시오. 매뉴얼 페이지는 단지 보조 응용 프로그램인 Unix에서 GNU 소프트웨어를 실행하는 사람들을 위한 것입니다.

  • 'manext'

    설치된 매뉴얼 페이지의 파일 이름 확장명. 여기에는 마침표와 적절한 숫자가 포함되어야 합니다. 일반적으로 '.1'이어야 합니다.

  • 'man1ext'

    설치된 섹션 1 매뉴얼 페이지의 파일 이름 확장명.

  • 'man2ext'

    설치된 섹션 2 매뉴얼 페이지의 파일 이름 확장명.

  • '...'

    패키지가 매뉴얼의 둘 이상의 섹션에 매뉴얼 페이지를 설치해야 하는 경우 'manext' 대신 이 이름을 사용하십시오.

마지막으로 다음 변수를 설정해야 합니다:

  • 'srcdir'

    컴파일 중인 소스의 디렉터리입니다. 이 변수의 값은 일반적으로 configure 셸 스크립트에 의해 삽입됩니다. (Autoconf를 사용하는 경우 'srcdir = @srcdir@'을 사용합니다.)

예를 들어:

# Common prefix for installation directories.
# NOTE: This directory must exist when you start the install.
prefix = /usr/local
datarootdir = $(prefix)/share
datadir = $(datarootdir)
exec_prefix = $(prefix)
# Where to put the executable for the command 'gcc'.
bindir = $(exec_prefix)/bin
# Where to put the directories used by the compiler.
libexecdir = $(exec_prefix)/libexec
# Where to put the Info files.
infodir = $(datarootdir)/info

프로그램이 표준 사용자 지정 디렉토리중 하나에 많은 수의 파일을 설치하는 경우 해당 프로그램에 특정한 하위 디렉토리로 그룹화하는 것이 유용할 수 있습니다. 이렇게 하면 이러한 하위 디렉터리를 만들기 위한 설치 규칙을 작성해야 합니다.

사용자가 위에 나열된 변수 값에 하위 디렉토리 이름을 포함할 것으로 기대하지 마십시오. 설치 디렉토리에 대해 균일한 변수 이름 세트를 갖는 아이디어는 사용자가 여러 다른 GNU 패키지에 대해 정확히 동일한 값을 지정할 수 있도록 하는 것입니다. 이것이 유용하기 위해서는 모든 패키지가 사용자가 그렇게 할 때 현명하게 작동하도록 설계되어야 합니다.

때때로 이러한 변수 중 일부는 Autoconf 및/또는 Automake의 현재 릴리스에서 구현되지 않을 수 있습니다. 그러나 Autoconf 2.60에서 우리는 그들 모두가 그렇다고 믿습니다. 누락된 항목이 있는 경우 여기의 설명은 Autoconf가 구현할 항목에 대한 사양으로 사용됩니다. 프로그래머는 Autoconf의 개발 버전을 사용하거나, 이를 지원하는 안정적인 릴리스가 만들어질 때까지 이러한 변수를 사용하지 않을 수 있습니다.

16.6 Standard Targets for Users (사용자를 위한 표준 대상)

모든 GNU 프로그램은 Makefile에 다음 대상이 있어야 합니다:

  • 'all'

    전체 프로그램을 컴파일합니다. 이것은 기본 대상이어야 합니다. 이 대상은 문서 파일을 다시 빌드할 필요가 없습니다. 정보 파일은 일반적으로 배포판에 포함되어야 하며 DVI(및 기타 문서 형식) 파일은 명시적으로 요청할 때만 만들어야 합니다.

    기본적으로 Make 규칙은 컴파일되고 '-g'로 연결되어 실행 가능한 프로그램에 디버깅 기호가 있어야 합니다. 그렇지 않으면 충돌에 직면했을때 본질적으로 무력하고 새로운 빌드로 재현하기가 쉽지 않은 경우가 많습니다.

  • 'install'

    프로그램을 컴파일하고 실행 파일, 라이브러리 등을 실제 사용을 위해 상주해야 하는 파일 이름으로 복사합니다. 프로그램이 제대로 설치되었는지 확인하는 간단한 테스트가 있는 경우 이 대상에서 해당 테스트를 실행해야 합니다.

    실행 파일을 설치할때 제거하지 마십시오. 이것은 나중에 필요할 수 있는 궁극적인 디버깅에 도움이 되며 요즘에는 디스크 공간이 저렴하고 동적 로더는 일반적으로 정상적인 실행 중에 디버그 섹션이 로드되지 않도록 합니다. 제거된 바이너리가 필요한 사용자는 이를 수행하기 위해 install-strip 대상을 호출할 수 있습니다.

    가능하면 설치 대상 규칙을 작성하여 'make all'이 방금 완료된 경우 프로그램이 빌드된 디렉토리에서 아무 것도 수정하지 않도록 합니다. 이것은 한 사용자 이름으로 프로그램을 빌드하고 다른 사용자 이름으로 설치할때 편리합니다.

    명령은 파일이 설치될 모든 디렉토리를 생성해야 합니다(아직 존재하지 않는 경우). 여기에는 변수 prefix 및 exec_prefix의 값으로 지정된 디렉토리와 필요한 모든 하위 디렉토리가 포함됩니다. 이를 수행하는 한 가지 방법은 아래에 설명된 대로 installdirs 대상을 사용하는 것입니다.

    man 페이지를 설치하기 위한 명령 앞에 '-'를 사용하면 make가 모든 오류를 무시할 수 있습니다. Unix 매뉴얼 페이지 문서 시스템이 설치되지 않은 시스템이 있는 경우입니다.

    정보 파일을 설치하는 방법은 $(INSTALL_DATA)(명령 변수 참조)를 사용하여 $(infodir)에 복사한 다음 install-info 프로그램이 있으면 실행하는 것입니다. install-info는 Info dir 파일을 편집하여 주어진 Info 파일에 대한 메뉴 항목을 추가하거나 업데이트하는 프로그램입니다. Texinfo 패키지의 일부입니다.

    다음은 install-info가 존재하지 않는 것과 같은 일부 추가 상황을 처리하려고 시도하는 Info 파일을 설치하기 위한 샘플 규칙입니다.

    do-install-info: foo.info installdirs
            $(NORMAL_INSTALL)
    # Prefer an info file in . to one in srcdir.
            if test -f foo.info; then d=.; \
            else d="$(srcdir)"; fi; \
            $(INSTALL_DATA) $$d/foo.info \
              "$(DESTDIR)$(infodir)/foo.info"
    # Run install-info only if it exists.
    # Use 'if' instead of just prepending '-' to the
    # line so we notice real errors from install-info.
    # Use '$(SHELL) -c' because some shells do not
    # fail gracefully when there is an unknown command.
            $(POST_INSTALL)
            if $(SHELL) -c 'install-info --version' \
              >/dev/null 2>&1; then \
              install-info --dir-file="$(DESTDIR)$(infodir)/dir" \
                          "$(DESTDIR)$(infodir)/foo.info"; \
            else true; fi

    설치 대상을 작성할 때 모든 명령을 일반 명령, 사전 설치 명령 및 사후 설치 명령의 세 범주로 분류해야 합니다. 명령 범주 설치(Install Command Categories)를 참조하십시오.

  • 'install-html'

  • 'install-dvi'

  • 'install-pdf'

  • 'install-ps'

    이러한 대상은 Info 이외의 형식으로 문서를 설치합니다. 해당 형식이 필요한 경우 패키지를 설치하는 사람이 명시적으로 호출하도록 되어 있습니다. GNU는 Info 파일을 선호하므로 설치 대상에서 설치해야 합니다.

    설치할 문서 파일이 많은 경우 이러한 대상이 htmldir과 같은 적절한 설치 디렉토리의 하위 디렉토리에 설치되도록 배열하여 충돌과 혼란을 피하는 것이 좋습니다. 예를 들어, 패키지에 여러 설명서가 있고 많은 파일이 포함된 HTML 문서를 설치하려는 경우(예: makeinfo --html에 의한 "분할(split)" 모드 출력) 다른 설명서에 있는 같은 이름은 서로 덮어씁니다.

    예를 들어 형식을 종속성으로 만들어 이러한 설치 형식 대상이 형식 대상에 대한 명령을 호출하도록 하십시오.

  • 'uninstall'

    설치된 모든 파일('install' 및 'install-*' 대상이 생성하는 복사본)을 삭제합니다.

    이 규칙은 컴파일이 완료된 디렉터리를 수정하지 않고 파일이 설치된 디렉터리만 수정하면 안 됩니다.

    제거 명령은 설치 명령과 마찬가지로 세 가지 범주로 나뉩니다. 명령 범주 설치(Install Command Categories)를 참조하십시오.

  • 'install-strip'

    설치와 유사하지만 설치하는 동안 실행 파일을 제거합니다. 간단한 경우에 이 대상은 간단한 방법으로 설치 대상을 사용할 수 있습니다:

    install-strip:
            $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \
                    install

    그러나 패키지가 실제 실행 파일과 함께 스크립트를 설치하는 경우 install-strip 대상은 설치 대상을 참조할 수 없습니다. 스크립트가 아닌 실행 파일을 제거해야 합니다.

    install-strip은 설치를 위해 복사되는 빌드 디렉토리의 실행 파일을 제거해서는 안 됩니다. 설치된 복사본만 제거해야 합니다.

    일반적으로 프로그램에 버그가 없다고 확신하지 않는한 실행 파일을 제거하지 않는 것이 좋습니다. 그러나 버그가 있는 경우를 대비하여 제거되지 않은 실행 파일을 다른 곳에 저장하면서 실제 실행을 위해 제거된 실행 파일을 설치하는 것이 합리적일 수 있습니다.

  • 'clean'

    일반적으로 프로그램을 빌드하여 생성되는 현재 디렉터리의 모든 파일을 삭제합니다. 이 makefile에 의해 생성된 다른 디렉토리의 파일도 삭제하십시오. 그러나 구성을 기록하는 파일을 삭제하지 마십시오. 또한 빌드로 만들 수 있는 파일을 보존하지만 일반적으로 배포판에 포함되어 있기 때문에 그렇지 않습니다. 'mkdir -p'로 생성된 상위 디렉터리는 어쨌든 존재할 수 있으므로 삭제할 필요가 없습니다.

    배포에 포함되지 않은 .dvi 파일은 여기에서 삭제하십시오.

  • 'distclean'

    프로그램을 구성하거나 빌드하여 생성된 현재 디렉터리(또는 이 makefile에 의해 생성된)의 모든 파일을 삭제합니다. 소스의 압축을 풀고 다른 파일을 생성하지 않고 프로그램을 빌드했다면 'make distclean'은 배포판에 있던 파일만 남겨두어야 합니다. 그러나 'mkdir -p'로 생성된 상위 디렉터리는 어쨌든 존재할 수 있으므로 삭제할 필요가 없습니다.

  • 'mostlyclean'

    'clean'과 비슷하지만 일반적으로 사람들이 다시 컴파일하고 싶지 않은 몇 가지 파일을 삭제하지 않을 수 있습니다. 예를 들어, GCC의 '대부분 clean' 대상은 libgcc.a를 삭제하지 않습니다. 재컴파일이 거의 필요하지 않고 시간이 많이 걸리기 때문입니다.

  • 'maintainer-clean'

    이 Makefile로 재구성할 수 있는 거의 모든 것을 삭제하십시오. 여기에는 일반적으로 distclean에 의해 삭제된 모든 것 외에 Bison이 생성한 C 소스 파일, 태그 테이블, 정보 파일 등이 포함됩니다.

    우리가 "거의 모든 것"이라고 말하는 이유는 Makefile의 규칙을 사용하여 구성을 다시 작성할 수 있더라도 'make maintenanceer-clean' 명령을 실행하면 구성이 삭제되지 않아야 하기 때문입니다. 보다 일반적으로, 'make maintenanceer-clean'은 configure를 실행하고 프로그램 빌드를 시작하기 위해 존재해야 하는 어떤 것도 삭제해서는 안 됩니다. 또한 'mkdir -p'로 생성된 상위 디렉터리는 어쨌든 존재할 수 있으므로 삭제할 필요가 없습니다. 이것은 유일한 예외입니다. maintainer-clean은 다시 빌드할 수 있는 다른 모든 것을 삭제해야 합니다.

    'maintainer-clean' 대상은 일반 사용자가 아닌 패키지 관리자가 사용하도록 되어 있습니다. 'make maintainer-clean' 삭제하는 일부 파일을 재구성하려면 특별한 도구가 필요할 수 있습니다. 이러한 파일은 일반적으로 배포판에 포함되기 때문에 쉽게 재구성할 수 있도록 신경을 쓰지 않습니다. 전체 배포판의 압축을 다시 풀어야 하는 경우 저희를 비난하지 마십시오.

    사용자가 이를 알 수 있도록 하기 위해 특수 유지 관리 대상에 대한 명령은 다음 두 가지로 시작해야 합니다:

    @echo 'This command is intended for maintainers to use; it'
    @echo 'deletes files that may need special tools to rebuild.'
  • 'TAGS'

    이 프로그램에 대한 태그 테이블을 업데이트하십시오.

  • 'info'

    필요한 모든 정보 파일을 생성합니다. 규칙을 작성하는 가장 좋은 방법은 다음과 같습니다:

    info: foo.info
    
    foo.info: foo.texi chap1.texi chap2.texi
            $(MAKEINFO) $(srcdir)/foo.texi

    Makefile에서 MAKEINFO 변수를 정의해야 합니다. Texinfo 배포판의 일부인 makeinfo 프로그램을 실행해야 합니다.

    일반적으로 GNU 배포판은 Info 파일과 함께 제공되며, 이는 Info 파일이 소스 디렉토리에 있음을 의미합니다. 따라서 정보 파일에 대한 Make 규칙은 소스 디렉토리에서 이를 업데이트해야 합니다. 사용자가 패키지를 빌드할 때 일반적으로 Make는 Info 파일이 이미 최신 상태이기 때문에 업데이트하지 않습니다.

  • 'dvi'

  • 'html'

  • 'pdf'

  • 'ps'

    주어진 형식으로 문서 파일을 생성합니다. 이러한 대상은 항상 존재해야 하지만 지정된 출력 형식을 생성할 수 없는 경우 일부 또는 모두가 작동하지 않을 수 있습니다. 이러한 대상은 모든 대상의 종속성이 아니어야 합니다. 사용자는 수동으로 호출해야 합니다.

    다음은 Texinfo에서 DVI 파일을 생성하는 규칙의 예입니다:

    dvi: foo.dvi
    
    foo.dvi: foo.texi chap1.texi chap2.texi
            $(TEXI2DVI) $(srcdir)/foo.texi

    Makefile에서 변수 TEXI2DVI를 정의해야 합니다. Texinfo 배포판의 일부인 texi2dvi 프로그램을 실행해야 합니다. (texi2dvi는 실제 포맷 작업을 수행하기 위해 TeX를 사용합니다. TeX는 Texinfo와 함께 배포되지 않습니다.) 또는 종속성만 작성하고 GNU make가 명령을 제공하도록 허용하십시오.

    다음은 Texinfo에서 HTML을 생성하는 또 다른 예입니다:

    html: foo.html
    
    foo.html: foo.texi chap1.texi chap2.texi
            $(TEXI2HTML) $(srcdir)/foo.texi

    다시 말하지만, Makefile에서 변수 TEXI2HTML을 정의합니다. 예를 들어 makeinfo --no-split --html을 실행할 수 있습니다(makeinfo는 Texinfo 배포의 일부입니다).

  • 'dist'

    이 프로그램에 대한 배포 tar 파일을 만듭니다. tar 파일은 tar 파일의 파일 이름이 배포 대상 패키지의 이름인 하위 디렉토리 이름으로 시작하도록 설정해야 합니다. 이 이름에는 버전 번호가 포함될 수 있습니다.

    예를 들어, GCC 버전 1.40의 배포 tar 파일은 gcc-1.40이라는 하위 디렉토리에 압축을 풉니다.

    이를 수행하는 가장 쉬운 방법은 적절한 이름의 하위 디렉토리를 만들고 ln 또는 cp를 사용하여 적절한 파일을 설치한 다음 해당 하위 디렉토리를 tar하는 것입니다.

    tar 파일을 gzip으로 압축합니다. 예를 들어, GCC 버전 1.40의 실제 배포 파일은 gcc-1.40.tar.gz라고 합니다. 다른 무료 압축 형식도 지원하는 것이 좋습니다.

    dist 대상은 배포판에서 최신 상태인지 확인하기 위해 배포판에 있는 모든 비소스 파일에 명시적으로 의존해야 합니다. GNU 코딩 표준에서 릴리스 만들기를 참조하십시오.

  • 'check'

    자가 테스트를 수행합니다(있는 경우). 사용자는 테스트를 실행하기 전에 프로그램을 빌드해야 하지만 프로그램을 설치할 필요는 없습니다. 프로그램이 빌드되었지만 설치되지 않았을 때 작동하도록 자체 테스트를 작성해야 합니다.

다음 대상은 유용한 프로그램에 대해 일반적인 이름으로 제안됩니다.

  • installcheck

    설치 테스트를 수행합니다(있는 경우). 사용자는 테스트를 실행하기 전에 프로그램을 빌드하고 설치해야 합니다. $(bindir)이 검색 경로에 있다고 가정해서는 안됩니다.

  • installdirs

    파일이 설치된 디렉토리와 그 상위 디렉토리를 생성하기 위해 'installdirs'라는 대상을 추가하는 것이 유용합니다. 이에 편리한 mkinstalldirs라는 스크립트가 있습니다. Gnulib 패키지에서 찾을 수 있습니다. 다음과 같은 규칙을 사용할 수 있습니다.

    # Make sure all installation directories (e.g. $(bindir))
    # actually exist by making them if necessary.
    installdirs: mkinstalldirs
            $(srcdir)/mkinstalldirs $(bindir) $(datadir) \
                                    $(libdir) $(infodir) \
                                    $(mandir)

    또는 DESTDIR을 지원하려면(강력히 권장됨),

    # Make sure all installation directories (e.g. $(bindir))
    # actually exist by making them if necessary.
    installdirs: mkinstalldirs
            $(srcdir)/mkinstalldirs \
                $(DESTDIR)$(bindir) $(DESTDIR)$(datadir) \
                $(DESTDIR)$(libdir) $(DESTDIR)$(infodir) \
                $(DESTDIR)$(mandir)

    이 규칙은 컴파일이 완료된 디렉토리를 수정해서는 안 됩니다. 설치 디렉토리를 만드는 것 외에는 아무 작업도 수행하지 않아야 합니다.

16.7 Install Command Categories (설치 명령의 범주)

설치 대상을 작성할 때 모든 명령을 세 가지 범주로 분류해야 합니다: 일반 명령, 사전 설치 명령 및 사후 설치 명령.

일반 명령은 파일을 적절한 위치로 이동하고 해당 모드를 설정합니다. 그들은 그들이 속한 패키지에서 완전히 온 파일을 제외하고 어떤 파일도 변경할 수 없습니다.

사전 설치 및 사후 설치 명령은 다른 파일을 변경할 수 있습니다. 특히 전역 구성 파일이나 데이터베이스를 편집할 수 있습니다.

사전 설치 명령은 일반적으로 일반 명령보다 먼저 실행되고 사후 설치 명령은 일반적으로 일반 명령 뒤에 실행됩니다.

사후 설치 명령의 가장 일반적인 용도는 install-info를 실행하는 것입니다. 이것은 설치되고 있는 패키지에서 전적으로 그리고 단독으로 제공되지 않는 파일(Info 디렉토리)을 변경하기 때문에 일반 명령으로 수행할 수 없습니다. 패키지의 Info 파일을 설치하는 일반 명령 다음에 수행해야 하기 때문에 사후 설치 명령입니다.

대부분의 프로그램에는 사전 설치 명령이 필요하지 않지만 필요한 경우에 대비하여 기능이 있습니다.

설치 규칙의 명령을 이러한 세 가지 범주로 분류하려면 그 사이에 범주 행을 삽입하십시오. 범주 행은 다음에 오는 명령에 대한 범주를 지정합니다.

범주 행은 탭과 특수 Make 변수에 대한 참조, 그리고 끝에 선택적 주석으로 구성됩니다. 각 범주에 대해 하나씩 사용할 수 있는 세 가지 변수가 있습니다. 변수 이름은 범주를 지정합니다. 범주 행은 이 세 가지 Make 변수가 일반적으로 정의되지 않기 때문에 일반 실행에서는 작동하지 않습니다 (그리고 makefile에서 정의하면 안 됨).

다음은 의미를 설명하는 주석이 있는 세 가지 가능한 범주 행입니다:

        $(PRE_INSTALL)     # Pre-install commands follow.
        $(POST_INSTALL)    # Post-install commands follow.
        $(NORMAL_INSTALL)  # Normal commands follow.

설치 규칙의 시작 부분에 범주 행을 사용하지 않으면 첫 번째 범주 행까지 모든 명령이 정상으로 분류됩니다. 범주 행을 사용하지 않으면 모든 명령이 정상으로 분류됩니다.

제거를 위한 범주 행은 다음과 같습니다:

        $(PRE_UNINSTALL)     # Pre-uninstall commands follow.
        $(POST_UNINSTALL)    # Post-uninstall commands follow.
        $(NORMAL_UNINSTALL)  # Normal commands follow.

일반적으로 사전 제거 명령은 Info 디렉토리에서 항목을 삭제하는 데 사용됩니다.

설치 또는 제거 대상에 설치의 서브루틴 역할을 하는 종속성이 있는 경우 각 종속성의 명령을 범주 행으로 시작하고 기본 대상의 명령도 범주 행으로 시작해야 합니다. 이렇게 하면 실제로 실행되는 종속성에 관계없이 각 명령이 올바른 범주에 배치되도록 할 수 있습니다.

사전 설치 및 사후 설치 명령은 다음을 제외하고 어떤 프로그램도 실행해서는 안 됩니다:

[ basename bash cat chgrp chmod chown cmp cp dd diff echo
egrep expand expr false fgrep find getopt grep gunzip gzip
hostname install install-info kill ldconfig ln ls md5sum
mkdir mkfifo mknod mv printenv pwd rm rmdir sed sort tee
test touch true uname xargs yes

이렇게 명령어를 구분하는 이유는 바이너리 패키지를 만들기 위함입니다. 일반적으로 바이너리 패키지에는 설치해야 하는 모든 실행 파일과 기타 파일이 포함되어 있으며 자체 설치 방법이 있으므로 일반 설치 명령을 실행할 필요가 없습니다. 그러나 바이너리 패키지를 설치하려면 사전 설치 및 사후 설치 명령을 실행해야 합니다.

바이너리 패키지를 빌드하는 프로그램은 사전 설치 및 사후 설치 명령을 추출하여 작동합니다. 다음은 사전 설치 명령을 추출하는 한 가지 방법입니다 (하위 디렉토리 입력에 대한 메시지를 무음으로 설정하려면 -s 옵션을 만들어야 함):

make -s -n install -o all \
      PRE_INSTALL=pre-install \
      POST_INSTALL=post-install \
      NORMAL_INSTALL=normal-install \
  | gawk -f pre-install.awk

여기서 pre-install.awk 파일에는 다음이 포함될 수 있습니다:

$0 \~ /^(normal-install|post-install)[ \t]*$/ {on = 0}
on {print $0}
$0 \~ /^pre-install[ \t]*$/ {on = 1}

Appendix A. Quick Reference (빠른 참조)

이 부록은 GNU가 이해하는 지시어, 텍스트 조작 기능 및 특수 변수를 요약합니다. 기타 요약은 특별 목표(Special Targets), 기본 제공 규칙 카탈로그(Catalogue of Built-In Rules) 및 옵션 요약(Summary of Options)을 참조하십시오.

GNU Make 지시문 요약

다음은 GNU make가 인식하는 지시문을 요약한 것입니다:

  • define variable

  • define variable =

  • define variable :=

  • define variable ::=

  • define variable +=

  • define variable ?=

  • endef

    여러 줄 변수를 정의합니다. 다중 라인(Multi-Line)을 참조하십시오.

  • undefine variable

    정의되지 않은 변수. 정의되지 않은 지시문(Undefine Directive)을 참조하십시오.

  • ifdef variable

  • ifndef variable

  • ifeq (a,b)

  • ifeq "a" "b"

  • ifeq 'a' 'b'

  • ifneq (a,b)

  • ifneq "a" "b"

  • ifneq 'a' 'b'

  • else

  • endif

    makefile의 일부를 조건부로 평가합니다. 조건문(Conditionals)을 참조하십시오.

  • include file

  • -include file

  • sinclude file

    다른 메이크파일을 포함합니다. 다른 Makefile 포함(Including Other Makefiles)을 참조하십시오.

  • override variable-assignment

    변수를 정의하고 명령줄에 있는 모든 이전 정의를 재정의합니다. 재정의 지시문(The override Directive)을 참조하십시오.

  • export

    기본적으로 모든 변수를 자식 프로세스로 내보내도록 make에 지시하십시오. Sub-make에 변수 통신(Communicating Variables to a Sub-make)을 참조하십시오.

  • export variable

  • export variable-assignment

  • unexport variable

    이 변수 할당이 전제 조건에 의해 상속되도록 허용하지 마십시오. 상속 억제(Suppressing Inheritance)를 참조하십시오.

  • vpath pattern path

    '%' 패턴과 일치하는 파일의 검색 경로를 지정합니다. vpath 지시문(The vpath Directive)을 참조하십시오.

  • vpath pattern

    이전에 패턴에 대해 지정된 모든 검색 경로를 제거합니다.

  • vpath

    이전에 vpath 지시문에 지정된 모든 검색 경로를 제거합니다.

내장 함수 요약

다음은 내장 함수에 대한 요약입니다. 함수(Functions) 참조:

  • $(subst from,to,text)

    text에서 'from'을 'to'로 바꿉니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(patsubst pattern,replacement,text)

    text에서 pattern과 일치하는 단어들을 replacement로 바꿉니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(strip string)

    string에서 초과 공백 문자를 제거합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(findstring find,text)

    text에서 find를 찾습니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(filter pattern…,text)

    pattern 단어중 하나와 일치하는 단어들을 text에서 선택(필터링) 합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(filter-out pattern…,text)

    pattern 단어와 일치하지 않는 단어들을 text에서 선택(필터링) 합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(sort list)

    list의 단어를 사전순으로 정렬하여 중복을 제거합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(word n,text)

    text의 n번째 단어(one-origin)를 추출합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(words text)

    text의 단어 수를 계산합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(wordlist s,e,text)

    text의 단어 목록을 s에서 e까지 반환합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(firstword names…)

    names의 첫 단어를 추출합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(lastword names…)

    names의 마지막 단어를 추출합니다.

    문자열 대체 및 분석을 위한 함수(Functions for String Substitution and Analysis)를 참조하십시오

  • $(dir names…)

    names의 마지막 단어를 추출합니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(notdir names…)

    names 각 파일명의 디렉토리가 아닌 부분을 추출합니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(suffix names…)

    names 각 파일 이름의 접미사(마지막 '.' 및 다음 문자)를 추출합니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(basename names…)

    names 각 파일 이름의 기본 이름(접미사가 없는 이름)을 추출합니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(addsuffix suffix,names…)

    names의 각 단어에 suffix 접미사를 추가합니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(addprefix prefix,names…)

    names이름의 각 단어 앞에 prefix 접두사를 붙입니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(join list1,list2)

    두 개의 단어 목록을 결합합니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(wildcard pattern…)

    쉘 파일 이름 pattern과 일치하는 파일 이름을 찾습니다('%' 패턴이 아님).

    와일드카드 함수(The Function wildcard)를 참조하세요.

  • $(realpath names…)

    names의 각 파일명에 대해 '.', '..' 또는 심볼릭 링크를 포함하지 않는 절대 이름으로 확장합니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(abspath names…)

    names의 각 파일명에 대해 '.'나 '..'가 포함되지 않은 절대 이름으로 확장하지만 심볼릭 링크를 유지합니다.

    파일 이름에 대한 함수(Functions for File Names)를 참조하십시오.

  • $(error text…)

    make는 메시지 text와 함께 치명적인 오류를 생성합니다.

    Make를 제어하는 기능(Functions That Control Make)을 참조하십시오.

  • $(warning text…)

    make는 메시지 text와 함께 경고를 생성합니다.

    Make를 제어하는 기능(Functions That Control Make)을 참조하십시오.

  • $(shell command)

    셸 명령 command를 실행하고 출력을 반환합니다.

    쉘 함수(The shell Function)를 참조하십시오.

  • $(origin variable)

    make 변수 variable가 정의된 방법을 설명하는 문자열을 반환합니다.

    원점 함수(The origin Function)를 참조하십시오.

  • $(flavor variable)

    make 변수 variable의 특징을 설명하는 문자열을 반환합니다.

    특징 함수(The flavor Function)를 참조하십시오.

  • $(foreach var,words,text)

    words의 각 단어에 var로 바인딩된 text를 평가하고 결과를 연결합니다.

    foreach 함수(The foreach Function)를 참조하십시오.

  • $(if condition,then-part[,else-part])

    조건 condition을 평가해서 비어 있지 않은 경우 then-part의 확장을 대체하고 그렇지 않으면 else-part의 확장을 대체합니다.

    조건부 함수(Functions for Conditionals)를 참조하십시오.

  • $(or condition1[,condition2[,condition3…]])

    각 조건 conditionN을 한 번에 하나씩 평가해서 비어 있지 않은 첫 번째 확장을 대체합니다. 모든 확장이 비어 있으면 빈 문자열로 대체합니다.

    조건부 함수(Functions for Conditionals)를 참조하십시오.

  • $(and condition1[,condition2[,condition3…]])

    각 조건 conditionN을 한 번에 하나씩 평가해서 확장 결과 빈 문자열이 발생하면 빈 문자열로 대체합니다. 모든 확장으로 인해 비어 있지 않은 문자열이 생성되면 마지막 조건의 확장으로 대체합니다.

    조건부 함수(Functions for Conditionals)를 참조하십시오.

  • (callvar,param,)<br>(call var,param,…)<br>(1), $(2)에 대한 참조를 첫 번째, 두 번째 등의 param 값으로 바꾸는 변수 var를 평가합니다.

    call 함수(The call Function)를 참조하십시오.

  • $(eval text)

    text를 평가한 다음 결과를 makefile 명령으로 읽습니다. 빈 문자열로 확장합니다.

    eval 함수(The eval Function)를 참조하십시오.

  • $(file op filename,text)

    인수를 확장한 다음 모드 op를 사용하여 filename 파일을 열고 해당 파일에 text를 씁니다.

    file 함수(The file Function)를 참조하십시오.

  • $(value var)

    확장이 수행되지 않은 상태에서 변수 var의 내용을 평가합니다.

    value 함수(The value Function)를 참조하십시오.

자동 변수 요약

다음은 자동 변수에 대한 요약입니다. 전체 정보는 자동 변수(Automatic Variables)를 참조하십시오.

  • $@

    대상의 파일 이름입니다.

  • $%

    대상이 아카이브 구성원인 경우 대상 구성원 이름입니다.

  • $<

    첫 번째 전제 조건의 이름입니다.

  • $?

    대상보다 최신인 모든 필수 구성 요소의 이름(공백 포함). 아카이브 구성원인 전제 조건의 경우 명명된 구성원만 사용됩니다(아카이브(Archives) 참조).

  • $^

  • $+

    모든 필수 구성 요소의 이름(공백 포함). 아카이브 구성원인 전제 조건의 경우 명명된 구성원만 사용됩니다(아카이브(Archives) 참조). $^ 값은 중복 전제조건을 생략하는 반면 $+는 전제조건을 유지하고 순서를 유지합니다.

  • $*

    암시적 규칙이 일치하는 어간입니다(패턴 일치 방법(How Patterns Match) 참조).

  • $(@D)

  • $(@F)

    $@의 디렉토리 부분과 디렉토리 내 파일 부분.

  • $(*D)

  • $(F)

    $
    의 디렉토리 부분과 디렉토리 내 파일 부분.

  • $(%D)

  • $(%F)

    $%의 디렉토리 부분과 디렉토리 내 파일 부분.

  • $(<D)

  • $(<F)

    $<의 디렉토리 부분과 디렉토리 내 파일 부분.

  • $(^D)

  • $(^F)

    $^의 디렉토리 부분과 디렉토리 내 파일 부분.

  • $(+D)

  • $(+F)

    $+의 디렉토리 부분과 디렉토리 내 파일 부분.

  • $(?D)

  • $(?F)

    $?의 디렉토리 부분과 디렉토리 내 파일 부분.

GNU make에서 특별히 사용되는 변수들 요약

이 변수들은 GNU make에서 특별히 사용합니다:

  • MAKEFILES

    make를 호출할 때마다 읽을 Makefile.

    변수 MAKEFILES(The Variable MAKEFILES)를 참조하십시오.

  • VPATH

    현재 디렉토리에서 찾을 수 없는 파일의 디렉토리 검색 경로입니다.

    모든 전제 조건에 대한 VPATH 검색 경로( VPATH Search Path for All Prerequisites)를 참조하십시오.

  • SHELL

    시스템 기본 명령 인터프리터의 이름, 일반적으로 /bin/sh입니다. makefile에서 SHELL을 설정하여 레시피를 실행하는 데 사용되는 셸을 변경할 수 있습니다. 레시피 실행(Recipe Execution)을 참조하십시오. SHELL 변수는 환경에서 가져오고 환경으로 내보낼 때 특별히 처리됩니다. 쉘 선택(Choosing the Shell)을 참조하십시오.

  • MAKESHELL

    MS-DOS only, make가 사용할 명령 인터프리터의 이름입니다. 이 값은 SHELL 값보다 우선합니다. MAKESHELL 변수(MAKESHELL variable)를 참조하십시오.

  • MAKE

    make가 호출된 이름입니다. 레시피에서 이 변수를 사용하는 것은 특별한 의미가 있습니다. MAKE 변수 작동 방식(How the MAKE Variable Works)을 참조하십시오.

  • MAKE_VERSION

    내장 변수 'MAKE_VERSION'은 GNU make 프로그램의 버전 번호로 확장됩니다.

  • MAKE_HOST

    내장 변수 'MAKE_HOST'는 GNU make가 실행되도록 빌드된 호스트를 나타내는 문자열로 확장됩니다.

  • MAKELEVEL

    재귀(서브메이크) 수준의 수입니다. 변수/재귀(Variables/Recursion)를 참조하십시오.

  • MAKEFLAGS

    make를 위한 플래그입니다. 환경이나 makefile에서 이것을 설정하여 플래그를 설정할 수 있습니다. Sub-make에 옵션 통신(Communicating Options to a Sub-make)을 참조하십시오.

    MAKEFLAGS를 레시피 라인에서 직접 사용하는 것은 결코 적절하지 않습니다: 그 내용은 쉘에서 사용하기 위해 올바르게 인용되지 않을 수 있습니다. 재귀적 make가 부모로부터 환경을 통해 이러한 값을 얻을 수 있도록 항상 허용하십시오.

  • GNUMAKEFLAGS

    make에 의해 구문 분석되는 다른 플래그. 환경이나 makefile에서 이것을 설정하여 make 명령줄 플래그를 설정할 수 있습니다. GNU make는 이 변수 자체를 설정하지 않습니다. 이 변수는 POSIX 호환 makefile에서 GNU make-specific 플래그를 설정하려는 경우에만 필요합니다. 이 변수는 GNU make에서 볼 수 있고 다른 make 구현에서는 무시됩니다. GNU make만 사용하는 경우에는 필요하지 않습니다. MAKEFLAGS를 직접 사용하십시오. Sub-make에 옵션 통신(Communicating Options to a Sub-make)을 참조하십시오.

  • MAKECMDGOALS

    명령줄에서 만들기 위해 지정된 대상입니다. 이 변수를 설정해도 make 작업에는 영향을 주지 않습니다.

    목표를 지정하는 인수(Arguments to Specify the Goals)를 참조하십시오.

  • CURDIR

    현재 작업 디렉토리의 절대 경로 이름으로 설정합니다(있는 경우 모든 -C 옵션이 처리된 후). 이 변수를 설정해도 make 작업에는 영향을 주지 않습니다.

    make의 재귀 사용(Recursive Use of make)을 참조하십시오.

  • SUFFIXES

    make가 makefile들을 읽기 전의 기본 접미사 목록.

  • .LIBPATTERNS

    검색할 라이브러리의 이름과 순서를 정의합니다.

    링크 라이브러리에 대한 디렉토리 검색(Directory Search for Link Libraries)을 참조하십시오.


Appendix B. Errors Generated by Make (Make에서 생성한 오류)

다음은 make에 의해 생성되는 보다 일반적인 오류 목록과 그 의미와 수정 방법에 대한 정보입니다.

때때로 make 오류는 치명적이지 않습니다. 특히 레시피 줄에 - 접두사가 있거나 -k 명령줄 옵션이 있는 경우에 그렇습니다. 치명적인 오류에는 '***' 문자열이 접두사로 붙습니다.

오류 메시지에는 모두 프로그램 이름(보통 'make')이 접두사로 붙거나, 오류가 makefile에서 발견된 경우 문제가 포함된 파일 이름과 줄 번호가 붙습니다.

아래 표에서 이러한 공통 접두사는 생략되어 있습니다.

  • '[foo] Error NN'

  • '[foo] signal description'

    이러한 오류는 실제로 오류를 만드는 것이 아닙니다. 이는 make가 레시피의 일부로 호출된 프로그램이 0이 아닌 오류 코드('오류 NN')를 반환했으며, 이는 make가 실패로 해석하거나 다른 비정상적인 방식으로 종료되었음을 의미합니다 (일부 유형의 signal 포함). 레시피의 오류(Errors in Recipes)를 참조하십시오.

    메시지에 '***'가 첨부되지 않은 경우 하위 프로세스가 실패했지만 makefile의 규칙에 - 특수 문자가 접두어로 붙었기 때문에 make는 오류를 무시했습니다.

  • 'missing separator. Stop.'

  • 'missing separator (did you mean TAB instead of 8 spaces?). Stop.'

    이것은 make가 방금 읽은 makefile 행에 대해 많은 것을 이해할 수 없다는 것을 의미합니다. GNU make는 구문 분석 중인 행의 종류를 나타내기 위해 다양한 구분 기호 (:, =, 레시피 접두어 문자 등)를 찾습니다. 이 메시지는 유효한 메시지를 찾을 수 없음을 의미합니다.

    이 메시지가 표시되는 가장 일반적인 이유중 하나는 사용자 (또는 많은 MS-Windows 편집기의 경우처럼 유용한 편집기)가 탭 문자 대신 공백을 사용하여 레시피 행을 들여쓰려고 시도했기 때문입니다. 이 경우 make는 위의 오류의 두 번째 형식을 사용합니다. 레시피의 모든 라인은 탭 문자로 시작해야 함을 기억하십시오(.RECIPEPREFIX를 설정하지 않는 한; 특수 변수(Special Variables) 참조). 여덟 개의 공백은 계산되지 않습니다. 규칙 구문(Rule Syntax)을 참조하십시오.

  • 'recipe commences before first target. Stop.'

  • 'missing rule before recipe. Stop.'

    이것은 makefile의 첫 번째 항목이 레시피의 일부인 것처럼 보인다는 것을 의미합니다: 이는 레시피 접두어 문자로 시작하고 합법적인 make 지시문(예: 변수 할당)으로 보이지 않습니다. 레시피는 항상 대상과 연결되어야 합니다.

    행에 공백이 아닌 첫 번째 문자로 세미콜론이 있으면 두 번째 형식이 생성됩니다. make는 이것을 규칙의 "대상: 전제조건" 섹션을 생략했다는 의미로 해석합니다. 규칙 구문(Rule Syntax)을 참조하십시오.

  • 'No rule to make target `xxx'.'

  • 'No rule to make target xxx', needed by yyy'.'

    이것은 make가 타겟을 빌드할 필요가 있다고 결정했지만 명시적이든 암시적이든 (기본 규칙 데이터베이스 포함) makefile에서 이를 수행하는 방법에 대한 지침을 찾을 수 없음을 의미합니다.

    해당 파일을 빌드하려면 해당 대상을 빌드할 수 있는 방법을 설명하는 규칙을 makefile에 추가해야 합니다. 이 문제의 다른 가능한 원인은 makefile의 오타 (해당 파일 이름이 잘못된 경우) 또는 손상된 소스 트리 (해당 파일이 빌드되어야 하는 것이 아니라 전제 조건일 경우)입니다.

  • 'No targets specified and no makefile found. Stop.'

  • 'No targets. Stop.'

    전자는 명령줄에서 빌드할 대상을 제공하지 않았으며 make가 읽을 makefile을 찾을 수 없음을 의미합니다. 후자는 일부 makefile을 찾았지만 기본 목표를 포함하지 않았음을 의미합니다. 명령줄에 아무 것도 제공되지 않았습니다. GNU make는 이러한 상황에서 아무 일도 하지 않습니다. Makefile을 지정하는 인수(Arguments to Specify the Makefile)를 참조하십시오.

  • 'Makefile `xxx' was not found.'

  • 'Included makefile `xxx' was not found.'

    명령줄(첫 번째 형식)에 지정되었거나 포함된(두 번째 형식) 메이크파일을 찾을 수 없습니다.

  • 'warning: overriding recipe for target `xxx''

  • 'warning: ignoring old recipe for target `xxx''

    GNU make는 대상당 하나의 레시피만 지정하도록 허용합니다(이중 콜론 규칙 제외). 이미 정의된 대상에 대한 레시피를 제공하면 이 경고가 발생하고 두 번째 레시피가 첫 번째 레시피를 덮어씁니다. 하나의 대상에 대한 여러 규칙을 참조하십시오.

  • 'Circular xxx <- yyy dependency dropped.'

    이는 make가 종속성 그래프에서 루프를 감지했음을 의미합니다: 대상 xxx의 전제 조건 yyy 및 해당 전제 조건 등을 추적한 후 그 중 하나가 다시 xxx에 의존했습니다.

  • 'Recursive variable `xxx' references itself (eventually). Stop.'

    이것은 확장될 때 자신(xxx)을 참조하는 일반(재귀적) make 변수 xxx를 정의했음을 의미합니다. 이것은 허용되지 않습니다. 단순 확장 변수(':=' 또는 '::=')를 사용하거나 추가 연산자('+=')를 사용합니다. 변수 사용 방법(How to Use Variables)을 참조하십시오.

  • 'Unterminated variable reference. Stop.'

    이는 변수 또는 함수 참조에 적절한 닫는 괄호나 중괄호를 제공하는 것을 잊었다는 의미입니다.

  • 'insufficient arguments to function `xxx'. Stop.'

    이는 이 함수에 필요한 인수를 제공하지 않았음을 의미합니다. 인수에 대한 설명은 함수 설명서를 참조하십시오. 텍스트 변환 함수(Functions for Transforming Text)를 참조하십시오.

  • 'missing target pattern. Stop.'

  • 'multiple target patterns. Stop.'

  • 'target pattern contains no `%'. Stop.'

  • 'mixed implicit and static pattern rules. Stop.'

    이러한 오류는 형식이 잘못된 정적 패턴 규칙에 대해 생성됩니다(정적 패턴 규칙의 구문(Syntax of Static Pattern Rules) 참조). 첫 번째는 규칙의 대상 패턴 부분이 비어 있음을 의미합니다. 두 번째는 대상 패턴 부분에 여러 패턴 문자(%)가 있음을 의미합니다. 세 번째는 대상 패턴 부분에 패턴 문자가 없음을 의미합니다. 네 번째는 정적 패턴 규칙의 세 부분 모두에 패턴 문자(%)가 포함되어 있음을 의미합니다. 첫 번째 부분에는 패턴 문자가 포함되어서는 안 됩니다.

    이러한 오류가 표시되고 정적 패턴 규칙을 만들려고 하지않는 경우 대상 및 전제조건 목록의 변수 값을 확인하여 콜론이 포함되어 있지 않은지 확인하십시오.

  • 'warning: -jN forced in submake: disabling jobserver mode.'

    이 경고와 다음 경고는 make가 sub-make가 통신할 수 있는 시스템에서 병렬 처리와 관련된 오류 조건을 감지하면 생성됩니다(Sub-make에 대한 옵션 통신(Communicating Options to a Sub-make) 참조). 이 경고는 make 프로세스의 재귀 호출이 인수 목록에 강제로 '-jN'을 포함하는 경우 생성됩니다(여기서 N은 1보다 큼). 예를 들어, MAKE 환경 변수를 'make -j2'로 설정하면 이런 일이 발생할 수 있습니다. 이 경우, sub-make는 다른 make 프로세스와 통신하지 않으며 단순히 자체 작업이 두 개 있는 척합니다.

  • 'warning: jobserver unavailable: using -j1. Add `+' to parent make rule.'

    make 프로세스가 통신하기 위해 부모는 정보를 자식에게 전달합니다. 자식 프로세스가 실제로 make가 아닌 경우 문제가 발생할 수 있으므로 부모는 자식 프로세스가 make라고 생각하는 경우에만 이 작업을 수행합니다. 부모는 일반 알고리즘을 사용하여 이를 결정합니다(MAKE Variable 작동 방식(How the MAKE Variable Works) 참조). 부모가 자식이 make 프로세스라는 것을 모르도록 메이크 파일이 구성되면 자식은 필요한 정보의 일부만 받게 됩니다. 이 경우 자식은 이 경고 메시지를 생성하고 순차적으로 빌드를 진행합니다.

  • 'warning: ignoring prerequisites on suffix rule definition'

    POSIX에 따르면 접미사 규칙은 전제 조건을 포함할 수 없습니다. 접미사 규칙이 될 수 있는 규칙에 전제 조건이 있는 경우 대상 이름이 이상한 단순 명시적 규칙으로 해석됩니다. 이 요구 사항은 POSIX 준수 모드가 활성화된 경우 준수됩니다 (.POSIX 대상이 정의됨). 4.3 이전의 GNU make 버전에서는 경고가 발생하지 않고 접미사 규칙이 생성되었지만 모든 전제 조건이 무시되고 접미사 규칙의 일부가 아니었습니다. GNU make 4.3부터는 동작이 동일하며 추가로 이 경고가 생성됩니다. 향후 버전에서는 POSIX 준수 동작이 유일한 동작이 될 것입니다. 전제 조건이 있는 규칙은 접미사 규칙이 될 수 없으며 이 경고는 제거됩니다.

Appendix C. Complex Makefile Example (복잡한 Makefile 예제)

다음은 GNU tar 프로그램의 메이크파일입니다. 이것은 적당히 복잡한 makefile입니다. 첫 번째 줄은 #! makefile을 직접 실행할 수 있도록 설정합니다.

첫 번째 대상이기 때문에 기본 목표는 'all'입니다. 이 makefile의 흥미로운 기능은 testpad.h가 testpad.c에서 컴파일된 testpad 프로그램에 의해 자동으로 생성된 소스 파일이라는 것입니다.

'make' 또는 'make all'을 입력하면 make는 tar 실행 파일, 원격 테이프 액세스를 제공하는 rmt 데몬 및 tar.info 정보 파일을 만듭니다.

'make install'을 입력하면 make는 tar, rmt, tar.info를 생성할 뿐만 아니라 설치합니다.

'make clean'을 입력하면 make는 '.o' 파일과 tar, rmt, testpad, testpad.h 및 core 파일을 제거합니다.

'make distclean'을 입력하면 make는 'make clean'과 동일한 파일뿐만 아니라 TAGS, Makefile 및 config.status 파일도 제거합니다. (명백하지는 않지만 이 makefile(및 config.status)은 tar 배포판에서 제공되는 configure 프로그램을 사용하여 사용자에 의해 생성되지만 여기에는 표시되지 않습니다.)

'make realclean'을 입력하면 make는 'make distclean'과 동일한 파일을 제거하고 tar.texinfo에서 생성된 Info 파일도 제거합니다.

또한 배포 키트를 생성하는 대상 shar 및 dist가 있습니다.

#!/usr/bin/make -f
# Generated automatically from Makefile.in by configure.
# Un*x Makefile for GNU tar program.
# Copyright (C) 1991 Free Software Foundation, Inc.

# This program is free software; you can redistribute
# it and/or modify it under the terms of the GNU
# General Public License ...
...
...

SHELL = /bin/sh

#### Start of system configuration section. ####

srcdir = .

# If you use gcc, you should either run the
# fixincludes script that comes with it or else use
# gcc with the -traditional option.  Otherwise ioctl
# calls will be compiled incorrectly on some systems.
CC = gcc -O
YACC = bison -y
INSTALL = /usr/local/bin/install -c
INSTALLDATA = /usr/local/bin/install -c -m 644

# Things you might add to DEFS:
# -DSTDC_HEADERS        If you have ANSI C headers and
#                       libraries.
# -DPOSIX               If you have POSIX.1 headers and
#                       libraries.
# -DBSD42               If you have sys/dir.h (unless
#                       you use -DPOSIX), sys/file.h,
#                       and st_blocks in `struct stat'.
# -DUSG                 If you have System V/ANSI C
#                       string and memory functions
#                       and headers, sys/sysmacros.h,
#                       fcntl.h, getcwd, no valloc,
#                       and ndir.h (unless
#                       you use -DDIRENT).
# -DNO_MEMORY_H         If USG or STDC_HEADERS but do not
#                       include memory.h.
# -DDIRENT              If USG and you have dirent.h
#                       instead of ndir.h.
# -DSIGTYPE=int         If your signal handlers
#                       return int, not void.
# -DNO_MTIO             If you lack sys/mtio.h
#                       (magtape ioctls).
# -DNO_REMOTE           If you do not have a remote shell
#                       or rexec.
# -DUSE_REXEC           To use rexec for remote tape
#                       operations instead of
#                       forking rsh or remsh.
# -DVPRINTF_MISSING     If you lack vprintf function
#                       (but have _doprnt).
# -DDOPRNT_MISSING      If you lack _doprnt function.
#                       Also need to define
#                       -DVPRINTF_MISSING.
# -DFTIME_MISSING       If you lack ftime system call.
# -DSTRSTR_MISSING      If you lack strstr function.
# -DVALLOC_MISSING      If you lack valloc function.
# -DMKDIR_MISSING       If you lack mkdir and
#                       rmdir system calls.
# -DRENAME_MISSING      If you lack rename system call.
# -DFTRUNCATE_MISSING   If you lack ftruncate
#                       system call.
# -DV7                  On Version 7 Unix (not
#                       tested in a long time).
# -DEMUL_OPEN3          If you lack a 3-argument version
#                       of open, and want to emulate it
#                       with system calls you do have.
# -DNO_OPEN3            If you lack the 3-argument open
#                       and want to disable the tar -k
#                       option instead of emulating open.
# -DXENIX               If you have sys/inode.h
#                       and need it 94 to be included.

DEFS =  -DSIGTYPE=int -DDIRENT -DSTRSTR_MISSING \
        -DVPRINTF_MISSING -DBSD42
# Set this to rtapelib.o unless you defined NO_REMOTE,
# in which case make it empty.
RTAPELIB = rtapelib.o
LIBS =
DEF_AR_FILE = /dev/rmt8
DEFBLOCKING = 20

CDEBUG = -g
CFLAGS = $(CDEBUG) -I. -I$(srcdir) $(DEFS) \
        -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" \
        -DDEFBLOCKING=$(DEFBLOCKING)
LDFLAGS = -g

prefix = /usr/local
# Prefix for each installed program,
# normally empty or `g'.
binprefix =

# The directory to install tar in.
bindir = $(prefix)/bin

# The directory to install the info files in.
infodir = $(prefix)/info

#### End of system configuration section. ####

SRCS_C  = tar.c create.c extract.c buffer.c   \
          getoldopt.c update.c gnu.c mangle.c \
          version.c list.c names.c diffarch.c \
          port.c wildmat.c getopt.c getopt1.c \
          regex.c
SRCS_Y  = getdate.y
SRCS    = $(SRCS_C) $(SRCS_Y)
OBJS    = $(SRCS_C:.c=.o) $(SRCS_Y:.y=.o) $(RTAPELIB)
AUX =   README COPYING ChangeLog Makefile.in  \
        makefile.pc configure configure.in \
        tar.texinfo tar.info* texinfo.tex \
        tar.h port.h open3.h getopt.h regex.h \
        rmt.h rmt.c rtapelib.c alloca.c \
        msd_dir.h msd_dir.c tcexparg.c \
        level-0 level-1 backup-specs testpad.c

.PHONY: all
all:    tar rmt tar.info

tar:    $(OBJS)
        $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

rmt:    rmt.c
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ rmt.c

tar.info: tar.texinfo
        makeinfo tar.texinfo

.PHONY: install
install: all
        $(INSTALL) tar $(bindir)/$(binprefix)tar
        -test ! -f rmt || $(INSTALL) rmt /etc/rmt
        $(INSTALLDATA) $(srcdir)/tar.info* $(infodir)

$(OBJS): tar.h port.h testpad.h
regex.o buffer.o tar.o: regex.h
# getdate.y has 8 shift/reduce conflicts.

testpad.h: testpad
        ./testpad

testpad: testpad.o
        $(CC) -o $@ testpad.o

TAGS:   $(SRCS)
        etags $(SRCS)

.PHONY: clean
clean:
        rm -f *.o tar rmt testpad testpad.h core

.PHONY: distclean
distclean: clean
        rm -f TAGS Makefile config.status

.PHONY: realclean
realclean: distclean
        rm -f tar.info*

.PHONY: shar
shar: $(SRCS) $(AUX)
        shar $(SRCS) $(AUX) | compress \
          > tar-`sed -e '/version_string/!d' \
                     -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
                     -e q
                     version.c`.shar.Z

.PHONY: dist
dist: $(SRCS) $(AUX)
        echo tar-`sed \
             -e '/version_string/!d' \
             -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
             -e q
             version.c` > .fname
        -rm -rf `cat .fname`
        mkdir `cat .fname`
        ln $(SRCS) $(AUX) `cat .fname`
        tar chZf `cat .fname`.tar.Z `cat .fname`
        -rm -rf `cat .fname` .fname

tar.zoo: $(SRCS) $(AUX)
        -rm -rf tmp.dir
        -mkdir tmp.dir
        -rm tar.zoo
        for X in $(SRCS) $(AUX) ; do \
            echo $$X ; \
            sed 's/$$/^M/' $$X \
            > tmp.dir/$$X ; done
        cd tmp.dir ; zoo aM ../tar.zoo *
        -rm -rf tmp.dir
profile
Learns until die

0개의 댓글