학습자료(~2017)/리눅스

[makefile] 정리

단세포소년 2012. 1. 25. 16:45
반응형
makefile 찾는 이름, 순서
 `GNUmakefile', `makefile' 그리고`Makefile'.
// MakeFile 을 추천
//명시적으로 찾고 싶다면 -f , --file 사용 // `-f name'`--file=name'

다른 makefile 삽입
 include filenames...
// filename 은 쉘 패턴 사용 가능
예) include foo *.mk $(bar)
//만약 filenames 에 존재하지 않는 파일은 무시하고 싶다면 '-include filenames...'를 사용하라. \
//존재하지 않는 파일은 에러경고 없이 무시한다. \
// '-include' 는 또다른 이름으로 'sinclude' 를 사용한다.



가짜 목적물
 .PHONY
//가짜 목적물을 사용하는 이유 : 동일한 이름의 파일과 충돌 피하기, 퍼포먼스 개선(목적물 검색 패스)
.PHONY : clean
clean :
       rm ~~~~
혹시라도 clean 이라는 파일이 생긴다면 clean 은 동작하지 않을것이다. (무조건 최신일것이기 때)

//.PHONY 를 사용하지 않는 방법으로는
clean: FORCE
        rm $(objects)
FORCE :
//위의 예제는 FORCE라는 종속물이 만들어 지지 않기 때문에 .PHONY를 사용한 것과 같은 효과가 있다.




주석
#comment
//한 라인이 주석으로 처리된다.



문법 규칙
 targets : dependencies
        command
        ...

또는 다음과 같이 생겼다:

targets : dependencies ; command
        command
        ...
//targets 는 공백으로 분리된 파일이름들, 와일드카드 문자 사용가능 , 아카이브 파일 사용시 a(m) 는 a 아카이브파일 안의 멤버 m을 표


$$란?
'$' 문자를 표현

\* 란?
와일드카드 문자 *의 기능을 끌 수 있다.


와일드카드 *
변수에서는 기능하지않고 target이나 denpencies에서 기능한다.
//objects := $(wildcard *.o) 이렇게 해야 변수에서 와일드카드가 기능한다.


와일드카드
 $(wildcard pattern...)

//예) $(wildcard *.c)
//우리는 C 소스 파일들의 리스트를 `.c' 접미사를 `.o'로 변경해서 오브젝트 파일들의 리스트로 변경할 수 있다. 다음과 같이:
//$(patsubst %.c,%.o,$(wildcard *.c))



모든 종속물에 대한 검색 경로지정
 VPATH = src:../headers
//이것은 make가 이 순서로 검색하는, 두 디렉토리들, `src'`../headers', 을 담고 있는 경로를 지정하고 있다
//타켓이나 종속물로 포함된 어떤 파일이 현재 디렉토리에 존재하지 않는다면 VPATH 에 지정된 경로를 찾아볼것이다.


특정 종속물에 대한 검색 경로 지정
 vpath pattern directories
    이것은 pattern와 매치되는 파일 이름들에 대한 검색 경로 directories를 지정한다. directories라는 검색 경로는 검색될 디렉토리들의 리스트이며, VPATH 변수에서 사용된 검색 경로와 비슷하게, 콜론(MS-DOS와 MS-Windows에 대해서는 세미-콜론)과 공백들에 의해서 구분된다.
vpath pattern
    이것은 pattern에 연결된 검색 경로를 청소하다.
vpath
    이것은 vpath 지시어로 이전에 지정된바 있던 모든 검색 경로들을 삭제한다.
//예) vpath %.h ../headers
//이것은 make가 `.h'로 끝나는 이름의 종속물이 현재 디렉토리에 없으면 `../headers' 디렉토리에서 찾도록 말한다.
//vpath 는 다수가 존재 가능하다.
vpath %.c foo
vpath %   blish
vpath %.c bar
// .c 파일을 순서적으로 foo, blish, bar 에서 찾을것임
or

vpath %.c foo:bar
vpath %   blish
// .c 파일을 순서적으로 foo, bar, blish


종속물에 -lname
 target : -lname
// -lname 은 링커에게 libname.a 으로 통한다. 종속물에 -lname이 존재한다면 libname.a 를 현재 디렉토리에서 우선 찾게되고 그다음 vpath , VPATH, /lib , /usr/lib ,  prefix/lib (일반적으로 prefix 는 /usr/local/) 에서 찾게 된다.
//예)  foo : foo.c -lcurses
        cc $^ -o $@
는 `cc foo.c /usr/lib/libcurses.a -o foo'가, `foo'가 `foo.c'보다 또는 `/usr/lib/libcurses.a'보다 더 오래된 것이라면, 실행되도록 한다.




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

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




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

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

@echo About to make distribution files

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

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

//묶여진 명령 에코 없애기
frob.out: frob.in
    @$(frobnicate)



명령 실행
 make 는 명령을 실행할때 각 라인마다 새로운 쉘을 생성하여 실행한다.
// 같은 쉘에서 명령을 실행하고 싶다면 ';' 을 사용하자
예) foo : bar/lose
        cd bar; gobble lose > ../foo
//기본적으로 /bin/sh 을 사용한다.
//SHELL 변수를 이용하여 쉘을 찾는다. (MS-DOS는 SHELL변수가 등록되지 않았다면 COMSPEC 변수를 이용)



패러럴 실행(병렬실행)
//MS-DOS 는 지원안함
 -j [정수]  혹은 --jobs
//GNU make는 여러 명령들을 동시에 실행하는 방법을 알고 있다. 일반적으로 make는 한번에 하나의 명령만을 실행하고 다음의 것을 실행하기전에 그것이 종료될 때까지 기다린다. 그러나 `-j' 또는 `--jobs' 옵션은 make 에게 많은 명령들을 동시에 실행하도록 한다.
MS-DOS에서 `-j' 옵션은 효과가 없다. 왜냐면 그 시스템은 멀티-프로세싱을 지원하지 않기 때문이다.
`-j' 옵션 뒤에 정수가 붙으면 이것은 한 번에 수행할 명령들의 개수를 말한다; 이것은 작업 슬롯(job slots) 의 개수라고 불린다. `-j' 옵션 뒤에 정수로 보이는 것이 없다면 작업 슬롯의 개수에 제한이 없어진다. 작업 슬롯의 디폴트 개수는 1이다. 이것은 순차적인 실행(한번에 하나씩)을 의미한다.
//시스템의 부하가 아주 클때 여러분은 아마도 부하가 적을 때보다 더 적은 작업들을 실행하고자 할 것이다. 여러분은 `-l' 옵션을 써서 make에게 한번에 실행할 작업들의 개수를, 평균 부하에 기초해서 제한하도록 지시할 수 있다. `-l' 또는 `--max-load' 옵션은 그 뒤에 부동-소숫점 숫자가 붙는다. 예를 들어서,
-l 2.5
이것은 make가, 평균 부하가 2.5보다 크면 한 작업보다 더 많은 작업을 시작하지 못하도록 할 것이다. 뒤에 숫자가 없는 `-l' 옵션은, 이전에 `-l' 옵션으로 지정된 것이 있다면, 부하 제한을 제거한다.
좀 더 정확하게, make가 하나의 작업을 시작할 때, 그리고 적어도 하나의 실행중인 작업을 가지고 있을 때, 이것은 현재 평균 부하를 측정한다; `-l'로 주어진 제한보다 더 낮지 않다면 make 는 평균 부하가 그 제한보다 낮아질 때까지 혹은 모든 다른 작업들이 종료될 때까지 기다린다.
디폴트로 부하 제한은 없다.



명령에서 에러
 -명령
// '-' 는 명령 실행의 반환값을 무시한다.
//각 쉘 명령이 리턴한 후, make는 그것의 종료 상태값을 조사한다. 그 명령이 성공적으로 종료하면 다음 명령 라인이 새로운 쉘에서 실행된다; 마지막 명령 라인이 종료된 후 그 규칙은 종료한다. 에러가 있으면(종료 상태값이 0이 아니면), make는 현재 규칙을 그리고 아마도 모든 규칙들을, 포기한다.



MAKE의 재귀적 사용
 subsystem:
        cd subdir && $(MAKE)


subsystem:
        $(MAKE) -C subdir
//MAKE 파일이 다른 곳에 존재하는 또다른 MAKE 파일을 실행해야 할 때 사용된다.




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

export variable ...

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

unexport variable ...

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

export variable = value

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

variable = value
export variable

그리고

export variable := value

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

variable := value
export variable

비슷하게

export variable += value

는 다음과 동일하다:

variable += value
export variable




명령들을 묶어서 정의하기
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

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




빈 명령
 target : ;
//타켓은 있고 종속물이 없다.
//타켓의 실 파일이 생긴다면 문제가 될수 있기 때문에 가짜목적물 .PHONY 을 이용하라.
.PHONY : target



변수 사용 방법 (매크로 macro 라고도 함)
변수 이름은 ':' , '#' , '=' 또는 시작이나 끝에 공백문자를 담고 있지 않는 문자들의 임의의 시퀀스이다.
변수 이름은 대소문자를 구분한다.




변수 참조의 기본
 변수 값을 사용하기 위해서는
$(foo) 또는 ${foo} 이다.
// $$ : '$' 표시를 하고 싶을때
// 변수 참조는 타겟, 종속물, 명령, 대부분의 지시어, 그리고 새로운 변수 값 안에서 사용된다.
예)
objects = program.o foo.o utils.o
program : $(objects)
      cc -o program $(objects)

$(objects) : defs.h




변수의 두 취향
 recursively expanded 변수
예)
foo = $(bar)
bar = $(ugh)
ugh = Huh?

all : ;echo $(foo)
$(foo) 는 $(bar) 로 확장. $(bar) 는 $(ugh)로 확장. $(ugh)는 Hug? 로 확장.

// 무한 루프 조심 예) CFLAGS = $(CFLAGS) -o
// 무한 루프는 검출하여 에러 보고함


simply expanded 변수
- 단순하게 확장되는 변수의 값은 변수가 정의될 때 다른 변수들과 함수들에 대한 참조를 확장하면서 단 한번만 스캔된다.
정의된 변수가 보이면 바로바로 넣는다.
예)
x := foo
y := $(x) bar
x := later
//equals
y := foo bar
x := later
//단순하게 확장된 변수가 참조될 때 그것은 값은 있는 그대로 대입

다음은 shell 함수와 := 를 결합하여 사용한 좀 더 복잡한 예제이다.
ifeq (0,${MAKELEVEL})
cur-dir   := $(shell pwd)
whoami    := $(shell whoami)
host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
endif


선두 공백문자를 변수 값들로 채용하기
nullstring :=
space := $(nullstring) # end of the line

//주의
dir := /foo/bar    # directory to put the frobs in
여기서 dir 변수의 값은 '/foo/bar ' 이다 의도치 않은 스페이스가 포함된다.

다음은 ?=  할당연산자이다. 이것은 조건 변수 할당 연산자라고 불린다. 이유는 그 변수가 아직 정의되지 않았을 경우에만 효력을 가지기 때문이다.
FOO ?= bar
//equal
ifeq ($(origin FOO), undefined)
   FOO = bar
endif




변수 참조의 고급 기능
대입참조
 한변수의 값을 지정하는 다른 대체값으로 대입한다.
$(var:a=b) 혹은 ${var:a=b} 혹은 $(patsubst a,b,$(var))

변수 var의 값을 취해서 한 단어의 뒤에있는 각 a를 그 값안에 있는 b로 교체하고 결과 문자열을 대입한다는 것
예)
foo := a.o b.o c.o
bar := $(foo:.o=.c)
bar는 결국 a.c b.c c.c 로 설정된다.
//대입 참조는 실제로 patsubst 확장 함수의 축소판이다. 다른 버젼의 make 구현물과의 호환성을 위해서 patsubst과 함께 제공한다.
예)
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
bar는 결국 a.c b.c c.c 로 설정된다.



계산된 변수 이름
 x := $($(y))

//주의 : 중첩된 변수 참조의 유일한 제한은 호출될 함수의 이름에 사용할수 없다는 것이다.(아래 예제 있음)
// 중첩된 변수 참조는 심각한 결과를 만들어 낼 수 있으니 사용을 자제한다.
예)
x = y
y = z
a := $($(x))
결과는 a는 결국 z 이다.

예)
x = y
y = z
z = u
a := $($($(x)))
결과는 a는 결국 u 이다.

예)
x = $(y)
y = z
z = Hello
a := $($(x))
결과는 a는 Hello 이다.

예)
x = variable1
variable2 := Hello
y = $(subst 1,2,$(x))
z = y
a := $($($(z)))
결과는 a 는 결국 Hello 이다. subst은 $(subst a,b,c) 라 하면 c의 문자열의 포함된 a를 b로 치환한다.

예)
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))

결과는 dirs 는 use_a 와 use_dirs 의 설정값에 따라 a_dirs , 1_dirs, 1_files, a_files 가 될 수 있다.
//makefile 에서 모든 값은 그냥 문자열로 생각하라.

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

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

이것은 sources를,  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'를 정의한다.
변수 할당의 왼쪽편에서나 define 지시어 안에서 변수 참조가 쓰일수 있다.




변수가 값을 얻는 방법
 1. make를 실행 할 때 값을 지정하거나 오버라이드 할 수 있다.
 2. 할당 또는 축어적 정의 등으로 makefile안에서 값을 지정 할 수 있다.
 3. 환경변수들이 make 변수들이 될수 있다.
 4. 몇가지 자동 변수들이 각 규칙에 대해서 새로운 값들을 받는다.
 5. 몇가지 변수들이 상수 초기값들을 가진다.



변수 설정
 = , := , ?= 를 통해 변수를 설정할 수 있다.
 =  는 재귀적 확장된 변수
 :=  는 단순 확장된 변수
 ?=  어떤 변수가 앞서 설정되지 않았을 경우에만 어떤 값을 설정하는 변수
 += 는 어떤 변수에 텍스를 덧붙일때 사용한다.

 변수 이름에 값을 설정하지 않는다면 빈 문자열을 가진다.
 값이 길다면 역슬래쉬 - 개행문자를 넣어서 쪼갤수 있다.
//값이 길다면 역슬래쉬 - 개행문자를 넣어서 쪼갤수 있다.
예) foo = a b c d e f g\
h i j k\
l m n

//변수 이름에 값을 설정하지 않는다면 빈 문자열을 가진다.
foo :=




변수에 텍스를 덧붙이기
 이미 정의된 변수의 값에다 텍스트를 추가하는 것은 종종 유용하다.
 += 을 통해 이를 행할수 있다.
 
 변수가 이전에 정의된 것이 아니라면 += 은 = 인 것처럼 동작한다.
 만약 이전에 정의된 것이라면 += 은 원래 정의한 변수의 취향이 무엇이었는가에 따라서 달라진다.
 이전에 = (재귀적 확장 변수) 였다면 += 은 = 으로 동작하고
 이전에 := (단순 확장 변수) 였다면 += 은 := 으로 동작한다.
예)
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


예) 이전에 := (단순 확장 변수) 였다면 += 은 := 으로 동작한다.
variable := value
variable += more
//equal
variable := value
variable := $(variable) more

예) 문제가 발생할 수 있는 예
CFLAGS = $(includes) -O
...
CFLAGS += -pg # enable profiling
//이 상태에서 우리는 += 을 사용하지 않고 CFLAGS 의 값에다 무엇을 덧 붙이려고 한다면 우리는 다음과 같이 할지모른다.

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

이렇게 된다면 CFLAGS 는 나중에 나올 includes 정의는 아무런 효력을 발휘하지 못하고 CFLAGS 는 '-O -pg' 만을 가질 것이다.



override 지시어
 override variable = value 또는 override variable := value 또는 override variable += value

override 가 설정되었다면 makefile 안의 일반 할당은 무시된다. 명령 매개변수로 설정된 바 있더라도 그 변수를 makefile 안에서 설정하고자 한다면 override 지시어를 사용할 수 있다.

//override 지시어는 makefile 과 명령 매개변수들 간의 전쟁에서 자동 조절을 위해서 고안된 것이 아니다. 예를 들어 c 컴파일러를 실행할 때 언제나 '-g' 스위치를 원하지만 사용자에게 보통처럼 명령 매개변수들로 다른 스위치를 지정하는 것을 허락하고자 한다고 가정하자. 그러면 다음과 같이 override 지시어를 사용할 수 있다.
예) override CFLAGS += -g
//아래는 위의 예와 비슷하게 작동할 것임
override define foo
bar
endef



축어 변수 정의
define variable
~~
~~
endef

이 지시어는 개행 문자들이 그 값에 포함되는 것을 허용한다. 이렇게 하는 것은 명령들의 묶인 시퀀스를 정의할 때 편리
define 은 = 와 비슷하게 작동한다. 이것은 재귀적 확장 즉, 이것이 사용되는 실제 변수 이름을 찾기 위해서 지시어가 읽힐 때 확장된다.
//예)
define two-lines
echo foo
echo $(bar)
endef

//일반 할당에서의 값은 개행을 가지지 못한다. 그러나 define 안의 값들의 라인을 나누는 개행들은 그 변수의 값이 된다.(endef 앞의 개행문자는 제외)
위의 예는 two-lines = echo foo; echo $(bar) 와 기능적으로 동일하다. 그러나 분리된 라인들은 사용시에는 독립된 서브셀에서 실행된다는 것을 주목하자

//define 으로 만들어진 변수 정의들이 명령행 변수 정의들보다 우선순위가 더 높기를 바란다면 define 과 함께 override 지시어를 사용하자.
예)
override define two-lines
foo
$(bar)
endef



환경변수로부터의 변수들
 make 가 시작 할 때 모든 환경변수들은 make 변수로 동일한 이름과 동일한 값을 가진채 변환된다. 그러나 makefile에서의 명시적 할당이나, 명령 매개변수를 사용한 명시적 할당은 환경을 오버라이드한다. (-e 플래그가 지정되면 환경으로부터의 값들이 makefile 에 있는 할당들을 오버라이드한다.)

그래서 CFAGS 라는 변수를 환경에서 설정하면 이런 컴파일러 스위치들을 대부분의 makefile에 있는 모든 c컴파일이 사용하도록 할 수 있다.

make 가 재귀적으로 호출될때 외부 호출에서 정의된 변수들은 내부 호출로, 환경을 통해서 전달될수 있다. 디폴트로 환경으로부터 또는 명령행으로부터 온 변수들만이 재귀적 호출에 전달된다.
export 지시어를 사용해서 다른 변수들을 익스포트 할 수 있다.

// 환경으로부터의 변수들을 다르게 사용하는 것은 권장하지 않는다. makefile들이 그들의 기능을 그들의 제어 바깥에서 설정된 환경변수들에 의존한다는 것은 별로 현명한 것이 아니다.
그런문제들로인해 SHELL 이라는 변수는 무시한다.




타겟-종속적인 변수 값
make 에 있는 변수값들은 보통 전역적이다. 한가지 예외는 자동 변수들의 경우이다.

target ... : variable-assignment
또는
target ... : override variable-assignment

다수의 target 값들은 타겟 리스트의 각 멤버에 대해서 타겟-종속적인 값을 개별적으로 생성한다.
variable-assignment 는 할당의 유효한 형태 =, := , +=, ?= 면된다.

//타겟-종속적인 변수들은 다른 makefile변수와 동일한 우선순위를 가진다. 명령행에서 주어진 변수(-e 옵션이 주어진)가 우선권을 갖는다면 override 를 지정하는 것은 타겟-종속 변수값이 더 선호되도록한다.

//타겟-종속적인 변수는 전역 변수와 별도로 구분이 된다. 

//예)
prog : CFLAGS = -g
prog : prog.o foo.o bar.o




패턴-종속적인 변수 값
 패턴에 종속적인 변수값을 지원한다. 패턴으로 지정된 타겟에서 종속적인 변수들이다.
pattern ... : variable-assignment
 또는
pattern ... : variable-assignment
예)
%.c : CFLAGS = -o




Makefile의 조건 부분
조건의 예
 다음 조건의 예제는 make에게 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 : 지시어는 조건을 종료한다.

//위의 예와 같음
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)



조건의 문법
conditional-directive
text-if-true
endif

conditional-directive
text-if-true
else
text-if-false
endif

ifeq : 두 변수가 같으면 true
ifneq : 두 변수가 다르면 true
ifdef : 변수가 정의 되있다면 true
ifndef : 변수가 정의 안되어있다면 true
// 같은 기능 다른 문법 예)
ifeq (arg1, arg2)
ifeq 'arg1' 'arg2'
ifeq "arg1" "arg2"
ifeq "arg1" 'arg2'
ifeq 'arg1' "arg2"
//arg1 과 arg2 가 확장이 일어난 뒤에 비교한다.

// 어떤 변수가 빈것 인지 아닌지 판단해야할때가 많다. 빈것으로 생각한 확장이 실제로 공백문자들을 담고 있어서 빈것으로 보이지 않을 수도 있다. 이때는 strip 함수를 사용하라.
ifeq ($(strip $(foo)),)
text-if-true
endif

//ifdef 사용예이다. ifdef 은 하나의 변수가 정의 되었다면 true 반환
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif
// frobozz 를 yes 로 설정
반면
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif
//이것은 frobozz 를 no 로 설정

//조건 테스트 안에서 자동 변수들을 사용할 수 없다. 왜냐면 그들은 명령들이 실행되기 전에는 정의되지 않기 때문이다.




플래그 검사 조건
 -t 와 같은 make 명령 플래그들은 변수 MAKEFLAGS 와 findstring 함수를 사용함으로써 검사하는 조건을 작성할수 있다.
예)
archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

//'+' 프리픽스는 이런 명령 라인들이 재귀적이어서 그들이 -t 플래그에도 불구하고 실행될 것이라는것을 표시한다.






텍스트변환을 위한 함수
함수는 여러분이 makefile 안에서 작업할 파일들을 알아내거나 아니면 사용할 명령들을 알아낼 수 있도록, 텍스트를 처리하는 것이다. 함수는 dfn{함수호출(function call)} 안에서 사용한다. 여기에서 함수의 이름과 함수가 작업할 텍스트수를 제공한다.

함수 호출 문법
 $(function arguments)  또는  ${function arguments}

function : 함수 이름
arguments : 함수에 쓰일 매개변수 갯수에 따라 ',' 을 붙인다.
// 스페이스를 콤머로 변경하고 결과를 대입하기
comma := ,
empty :=
space := $(empty) $(empty)
foo := a b c
bar := $(subst $(space),$(comma),$(foo))
#bar is now 'a,b,c'
//subst 함수는 세번째 인자의 문자열의 첫번째 인자를 두번째 인자로 바꾼다.





문자 대입과 분석을 위한 함수들
 $(subst from,to,text) : text의 문자열 중 from 이 나오면 to로 대치한다.
 $(patsubst pattern,replacement,text) : text의 문자열안에서 공백문자로 분리된 단어들 중 pattern 과 매치되는 단어를 찾아서 그것들을 replacement 로 변경한다. 여기서 pattern 은 와일드 역활을 하는 % 를 가질수 있는데, 이것은 어떤 단어 내에 있는 임의 개수의 어떤 문자들과도 매치된다. % 를 문자 그대로 표현하고 싶다면 역슬래쉬(\) 를 앞에 붙인다.
the\%weird\\%pattern\\ 은 the%weird\%pattern\\ 로 표현된다.
 $(strip string) : 이함수는 string 의 앞뒤에 있는 공백문자들을 제거하고 내부에 있는 하나 이상의 공백문자들을 단일 스페이스로 교체한다.
 $(findstring find,in) : 이함수는 in에서 find를 찾는다. 있다면 그 값은 find가 된다. 그렇지 않다면 그 값은 빈것이 된다.이 함수를 이용하여 특정 문자열안에 특정 문자열의 존재 여부를 검사할 수 있다.
 $(filter pattern...,text) : 이함수는 pattern 단어들 중의 임의의 것과 일치하지 않는 text 내의 공백문자로 분리된 단어들을 모두 제거하고 일치하는 단어들만 리턴한다.
 $(filter-out pattern...,text) : 이 함수는 text에서 pattern 단어들과 일치하는 공백문자들로 분리된 단어들을 모두 제거하고 일치하지 않는 단어들만을 리턴한다. filter 함수의 정확한 반대이다.
//예)
$(patsubst %.c,%.o,x.c.c bar.c) 는 x.c.o bar.o
$(var:pattern=replacement) 은 $(patsubst pattern,replacement,$(var))와 같다.
$(var:suffix=replacement) 은 $(patsubst %suffix,%replacement,$(var)) 와 같다.
objects = foo.o bar.o baz.o
$(objects:.o=.c)
$(patsubst %.o,%.c,$(objects))


//filter 예)
sources := foo.c bar.c baz.c ugh.h
foo : $(source)
      cc $(filter %.c %.s,$(sources)) -o foo
는 여기서 ugh.h 는 맞는 패턴이 없으므로 버려진다.


//filter-out 예)
objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
$(filter-out $(mains),$(obejcts))
objects 에서 mains 에 있는 오브젝트는 모두 없앤다.


//subst 와 patsubst 을 사용한 현실적인 예제이다.
   VPATH 변수를 사용하여 make 가 종속파일들을 검색해야 할 디렉토리 리스트를 지정한다고 가정하자.
   이 예제는 C 컴파일러에게 동일한 디렉토리 리스트에서 헤더 파일들을 찾는 방법을 말하는 방법을 보여준다.

  VPATH 의 값은 'src:../headers' 와 같이 콜론으로 분리되는 디렉토리 리스트이다. 첫번째 subst 함수는 콜론들을 스페이스들로 변경하는데 사용된다.
$(subst :, ,$(VPATH))
 이것은 'src ../headers'를 만든다 그리고 나서 patsubst는 각 디렉토리 이름을 '-I' 플래그로 변경하는데 사용된다. 이것은 변수 CFLAGS의 값에 더해질 수 있다.
override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))
  이것은  효과는 텍스트 '-Isrc -I../headers' 를 CFAGS에게 사전에 주어졌던 값에 덧붙이는 것이다. override 지시어는 CFLAGS의 이전의 값이 명령 매개변수로 주어졌다 하더라도 새로운 값이 할당되도록 하는데 사용된다.




파일 이름들을 위한 함수
 $(dir names...) : 이것은 names 에 있는 각 파일 이름에서 디렉토리-파트를 추출한다. 파일 이름의 디렉토리-파트는 그안에 있는 마지막 슬래쉬까지를 포함한다. 그 파일 이름이 슬래쉬가 없으면 디렉토리 파트는 문자열 './' 이 된다.
 $(notdir names...) : 이 함수는 names 에 있는 각 파일 이름의 디렉토리 부분을 제외한 모든것을 추출한다. 파일 이름에 슬래쉬가 없으면 변환되지 않는다. 그렇지 않을 경우 마지막 슬래쉬까지 모든것이 그것으로 부터 제거된다. 슬래쉬로 끝나는 파일 이름은 빈 문자열이 될 것이다. 이렇게 되는 것은 불행하다. 왜냐면 이렇게 되는것은 그 결과가 항상 매개변수가 가지는 것과 동일하지 않은 개수의 공백으로 분리된 파일 이름들을 가진다는 것을 의미하기 때문이다.
 $(suffix names...) : 이 함수는 names 에 있는 각 파일 이름의 접미사를 추출한다. 파일 이름이 소숫점을 갖고 있다면 접미사는 마지막 소숫점부터 시작한 모든 것이다. 그렇지 않다면 점미사는 빈 문자열이다. 
 $(basename names...) : 이 함수는 names 에 있는 각 파일 이름의 접미사를 제외한 모든 것을 추출한다. 파일 이름이 소숫점을 갖고 있다면 basename은 처음부터 마지막 소수점까지의(소수점은 포함하지 않음) 모든 것이 된다. 디렉토리 부분에 있는 소숫점들은 모두 무시된다. 소숫점이 없으면 전체 파일 이름이 된다.
 $(addsuffix suffix,names...) : 매개변수 names 는 공백문자들로 분리된, 일단의 이름들로 취급된다. suffix는 유닛으로써 사용된다. suffix의 값은 각 개별 이름의 끝에 더해지고 그들 사이에 단일 스페이스들을 추가한 더 큰 이름들이 그결과이다.
 $(addprefix prefix,names...) : 매개변수 names는 공백문자들로 구분된 일단의 이름들이며 prefix는 유닛으로써 사용된다. prefix의 값은 각 개별 이름의 앞에 붙고 그들 사이에 단일 스페이스들로 채워 연결된 더 커다란 이름들이 결과이다.
 $(join list1,list2) : 이것은 두 매개변수들을 단어 단위로 연결한다. 연결된 두개의 첫 단어들이 결과의 첫번째 단어를 구성하고 두개의 두번째 단어들이 결과의 두번째 단어를 구성한다. n번 단어는 각 매개변수의 n번 단어들에 의해 구성된다.
 $(word n,text) : 이것은 text의 n번째 단어를 리턴한다. n의 합법적인 값은 1부터 시작한다. n이 text에 있는 단어들 개수보다 더 크다면 그 값은 빈것이 된다.
 $(wordlist s,e,text) : 이것은 s로 시작하고 e로 끝나는 text안의 단어들 리스트를 리턴한다. s와 e는 합법적으로 1부터 시작한다. s가 text에 있는 단어들 개수보다 크다면 빈값을 반환 e가 text에 있는 단어들 개수보다 크다면 text의 끝까지의 단어들이 리턴 s가 e보다 더 크다면 make는 그들을 서로 맞바꾼다.
 $(words text) : 이것은 text에 있는 단어들 개수를 리턴. 그래서 text의 마지막 단어는 $(word $(words text),text)로 표현가능
 $(firstword names...) : names 매개변수는 공백으로 분리된, 일단의 이름들이다. 결과 값은 이 단어들중 첫번째이다.
 $(wildcard pattern) : pattern 매개변수는 파일 이름 패턴이다. 전형적으로 와일드 카드 문자들이다.(쉘 파일 이름 패턴과 동일) wildcard 함수의 결과는 패턴과 일치하는 현존하는 파일들의 이름들을 스페이스로 분리한 리스트이다.
// dir 예)
$(dir src/foo.c hacks) 는 'src/ ./' 라는 결과를 만든다.

// notdir 예)
 $(notdir src/foo.c hacks) 는 'foo.c hacks' 라는 결과를 만든다.

// suffix 예)
 $(suffix src/foo.c src-1.0/bar.c hacks) 는 '.c .c'라는 결과를 만든다.

// basename 예)
 $(basename src/foo.c src-1.0/bar hacks) 는 'src/foo src1.0/bar hacks' 라는 결과를 만든다.

// addsuffix 예)
 $(addsuffix .c,foo bar) 는 'foo.c bar.c'라는 결과를 만들어낸다.

// addprefix 예)
 $(addprefix src/,foo bar) 는 'src/foo src/bar' 라는 결과를 만든다.

// join 예)
 $(join a b,.c .o) 는 'a.c b.o' 라는 결과를 만든다.

// word 예)
 $(word 2,foo bar baz) 는 'bar' 를 리턴한다.

// wordlist 예)
 $(wordlist 2,3,foo bar baz) 는 'bar baz' 를 리턴한다.

// words 예)
 $(word $(words text),text) 는 text의 마지막 단어를 리턴한다.

// firstword 예)
 $(firstword foo bar) 는 foo 를 리턴한다. 이는 $(word 1,foo bar) 와 같다. 단순성 때문에 남아있다.



foreach 함수
 $(foreach var,list.text)
 var와 list는 다른것이 수행되기전에 확장된다. text는 동일한 시간에 확장 되지 않는다. 그리고 나서 list 의 확장된 각 단어에 대해서 var의 확장된 값을 가지는 변수는 이 단어로 설정되고 그다음에 text가 확장된다. 아마 text는 그 변수에 대한 참조를 담고 있을 것이다. 그래서 그것의 확장은 매번 다르다.
결과적으로 text는 list에 있는 공백으로 분리된 단어들 개수만큼 확장된다. text의 여러 확장들이 그들 사이에 스페이스들을 넣어서 연결되어 foreach의 결과를 만든다.

foreach 함수는 다른 함수들과 아주 다르다. 이것은 텍스트의 한 조각이 반복적으로 사용되도록 한다. 이때 매번 그것에 대해서 다른 대입이 수행된다. 이것은 쉘 의 for 명령 rmflrh c쉘 csh의 foreach 명령과 닮았다.
예)
dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
// text는 $(wildcard $(dir)/*) 이다. 첫번째 반복은 dir에 대해서 값 'a' 을 찾아 넣고서 $(wildcard a/*) 와 동일한 결과를 생산한다. 두번째 반복은 $(wildcard b/*) 이라는 결과를 생성한다. 세번째는 $(wildcard c/*)
이예제는
files := $(wildcard a/* b/* c/* d/*) 와 동일한 결과를 가진다.

text가 복잡할 때는 추가의 변수로 그것에 이름을 주어서 가독성을 증진할 수 있다.

fild_files = $(wildcard $(dir)/*)
dirs := a b c d
files := $(foreach dir,$(dirs),$(find_files))
//위에서는 find_files 을 재귀적 확장을 사용했다. 단순 확장 변수는 foreach의 제어하에서 확장되지 않고 즉시 확장되지 때문이다.



origin 함수
 $(origin variable)

variable은 질의하고 있는 변수의 이름이다. 그 변수에 대해서 참조하는 것이 아니다. 그러므로 그것을 쓸때 $ 나 괄호들을 일반적인 경우처럼 쓰지 않을 것이다.

이함수의 결과는 그변수 variable이 정의된 방법을 말하는 문자열이다.

undefind : 변수 variable 이 전혀 정의된 바가 없다면 이 값을 가진다.
default : 변수 variable 이 CC 나 기타 등등처럼 일반적인 디폴트 정의를 갖고 있다면 이값을 가진다. 디폴트 변수를 재정의한것이라면 origin 함수는 추후 정의의 원천을 리턴할 것이다.
environment : variable 이 환경 변수로써 정의된 것이고 -e 옵션이 켜진 것이 아니라면 이 값을 가진다.
environment override : variable 이 환경 변수로 정의되었고 -e 옵션이 켜졌다면 이값을 가진다.
file : variable 이 makefile에서 정의된 것이라면 이 값을 가진다.
command line : variable 이 명령행에서 정의도니 것이라면 이값을 가진다.
override : variable 이 override 지시어로 makefile에서 정의된 것이라면 이 값을 가진다.
automatic : variable 이 각 규칙의 명령들의 실행에 대해서 정의된 자동 변수라면 이 값을 가진다.

이 정보는 주로 어떤 변수의 값을 믿고자 하는가 안하는가를 결정할때 유용하다.
ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc
endif
endif
// bletch 가 환경으로부터 정의되었다면 이것은 그것을 재정의 할 것이다.


bletch의 이전 정의를 override 하고자 하고 이것이 환경으로부터 온 것이라면, -e 하에서조차 여러분은 다음과 같이 쓸수 있다.
ifneq "$(findstring environment,$(origin bletch))" ""
bletch = barf, gag, etc
endif
//여기에서 $(origin bletch)가 environment 또는 environment override 를 리턴한다면 재정의가 일어난다.




shell 함수
 shell

shell 함수는 wildcard 함수를 제외하고 이것이 make의 바깥 세상과 통신한다는 점에서 다른 함수들과 다르다.

shell함수는 대부분의 쉘에서 역홑따옴표( ` )가 수행하는 기능과 동일한 기능을 수행한다. 이것은 command expansion 을 한다. 이것은 쉘 명령인 매개변수를 취하고 명령의 결과를 리턴한다는 것을 의미한다. make가 이 결과에 대해서 주변 텍스트로 이것을 대입하기 전에 하는 유일한 처리는 각 개행이나 캐리지리턴 / 개행 쌍을 단일 공백으로 변환하는 것이다. 이것은 또한 끝에 달린 개행을 이것이 결과의 마지막이라면 제거한다.

shell 함수에 대한 호출에 의해서 실행된 명령은 함수 호출이 확장될 때 실행된다.
예)
contents := $(shell cat foo)
이것은 contents 를 foo 파일의 내용으로 설정한다.(개행은 공백으로 처리)

files := $(shell echo *.c)
이것은 files를 *.c 의 확장으로 설정한다. make가 아주 이상한 쉘을 사용하고 있지 않다면 이것은 $(wildcard *.c) 와 동일한 결과를 얻는다.





make 실행 방법
 make 종료 코드는 다음 세가지이다.

0 : make가 성공
2 : 어떤 에러를 만났다면 종료 코드는 2다 이것은 특정 에러를 설명하는 메시지들을 출력할 것이다.
1 : -q 플래그를 사용하였고 make 가 어떤 타겟이 아직 up to date 가 아니라고 판단하면 종료코드는 1이다.



Makefile을 지정하는 매개변수
 -f  혹은  --file 
옵션을 사용하여 makefile을 지정한다.

-f altmake 라면 altmake 를 makefile로 사용하라는 말이다.

-f 플래그를 여러번 사용하였다면 각각의 -f 뒤에 매개변수가 따른다면 모든 지정된 파일들은 서로 묶여서 makefile로 사용

-f   혹은   --file을 사용하지 않는다면 GNUmakefile, makefile, Makefile 이 순서대로 있나 없나 검사해서 실행한다.




goal 을 지정하는 매개변수
 goals 은 make가 궁극적으로 업데이트하려고 할 타겟들이다. 다른 타겟들은 그들이 goal의 종속물이나 goals 의 종속물의 종속물 등으로 나타난다면 엡데이트된다.

디폴트로 goal 은 makefile의 첫번째 타겟이다.(점으로 시작하는 타겟은 뺀다.)  그러므로 makefile들은 보통 첫번째 타겟이 전체 프로그램을 컴파일하기 위한 것이나 그들이 설명하는 프로그램들을 컴파일하기 위한 것이다.

makefile에 있는 임의의 타겟은 goal로 지정될 수 있다.(그것이 '-' 로 시작하거나 '=' 을 담고 있지 않다면 말이다. 이런 경우 일반적인 옵션인 swich나 변수 정의로 가각 생각되어진다.) make가 그것들을 만드는 방법을 말한 묵시적 규칙들을 찾을수만 있다면, makefile에 없는 타겟들도 지정될 수 있다.

make 는 특수변수 MAKECMDGOALS 를 명령 라인에서 여러분이 지정한 goal들의 리스트로 지정할 것이다. 명령라인에 어떤 goal 도 지정되지 않았다면 이 변수는 빈것이된다.

아래는 GNU 소프트웨어 팩키지들이 사용하는 표준 타겟 이름들이다. 전형적인 .PHONY 및 빈 타겟 이름들이다.

all : 이것은 makefile 이 알고 있는 톱-레벨 타겟들 모두를 make한다.
clean : 일반적으로 make를 실행함으로써 생성되는 모든 파일들을 삭제한다.
mostlyclean : 이것은 clean 과 비슷하지만 사람들이 일반적으로 재컴파일하고자 원하지 않는 몇가지 파일들을 지우지 않을 것이다. 예를 들어서 GCC를 위한 mostlyclean 타겟은 libgcc.a 를 지우지 않는다. 이것은 재컴파일하는 것이 거의 필요없기 때문이다.
distclean , realclean, clobber : 이 세개의 타겟들은 clean 이 하는 것보다 더 많은 파일들을 지우기 위해서 정의될 것이다.
 예를 들어 컴파일을 준비하기 위해서 생성한 링크들이나 설정 파일들을 지울것이다.
install : 이것은 실행 파일을 사용자가 전형적으로 명령들에 대해서 찾는 위치의 디렉토리에다 복사한다. 실행 파일들이 사용하는 보조 파일들도 이들을 찾을 위치의 디렉토리들에 복사한다.
print : 변경된 소스 파일들의 리스트를 인쇄
tar : 소스 파일들의 tar 파일을 생성한다.
shar : 이것은 소스 파일들의 쉘 아카이브을 생성한다.
dist : 이것은 소스 파일들의 배포 파일을 생성한다. 이것은 아마도 tar파일이거나 shar파일이거나 위의 것들 중 하나의 압축된 버전이거나 일것이다.
TAGS : 이 프로그램에 대한 태그 테이블을 업데이트한다.
check , test : 이 둘은 makefile 이 빌드하는 프로그램에 대해서 자체 테스트를 수행한다.




명령 실행 대신에
 makefile은 make에게 타겟이 up to date인가 아닌가 어떻게 판단할 것인가 그리고 각 타겟을 어떻게 업데이트 할 것인가를 지정한다. 그러나 타겟을 업데이트하는 것은 항상 여러분이 원하는 것이 아닐수 있다.

-n , --just-print , --dry-run , --recon : no-op 어떤 명령들이 타겟들을 업데이트하기 위해서 사용될 것인가를 출력
-t , --touch : 그것을 실제로 변경하지 않고서 타겟들을 마치 업데이트 된 것처럼 마킹한다.
-q , --question : 조용히 어떤 타겟들이 이미 업데이트되었는지 아닌지 찾는다. 컴파일도 안하고 출력도 없다.
-W file , --what-if=file , --assume-new=file , --new-file=file : 각 플래그는 파일 이름이 뒤따른다. 주어진 파일들의 변경 시간들은 make에 의해서 현재 시간으로 기록되는 반면 실제 변경 시간은 동일하게 남는다. -W 플래그와 -n 플래그를 사용해서 여러분이 특정 파일을 변경한다면 어떤 일이 벌어지는지 확인할 수 있다.
-n : make는 실제 그들을 실행하지 않지만 일반적인 실행 때와 동일한 명령들을 인쇄한다.
-t : make는 규칙들에 있는 명령들을 무시하고 다시 만들어져야 할 각 타겟에 대해서 touch 라는 명령을 사용한다. -s 나 .SILENT 가 사용되지 않으면 touch 명령 또한 인쇄 된다. 속도를 위해서 make는 실제로 프로그램 touch를 호출하지 않을것이다. 이것은 직접 작업한다.
-q : make는 아무것도 출력하지 않고 아무런 명령도 실행하지 않지만 종료 상태 코드는 타겟이 이미 갱신된 것이라고 생각되어질 때에만 0이된다. 종료 상태가 1이면 어떤 갱신이 필요하다는 것을 의미, make 가 에러를 만나면 종료 상태는 2이다. 그래서 에러를 타겟이 갱신 안되었다는 것과 구분할 수 있다.

-n , -t 그리고 -q 옵션들은 + 문자들로 시작하는 명령 라인들이나 $(MAKE) sk ${MAKE} 문자열들을 담고 있는 명령 라인들에 영향을 미치지 않는다. + 문자나 문자열 $(MAKE) 또는 ${MAKE} 를 담고 있는 라인들만이 이런 옵션들에 상관없이 실행된다.

-W 플래그는 다음과 같은 두 기능을 제공한다.
  -n 나 -q 플래그와 같이 사용하면 어떤 파일들을 변경했을 때 make 가 어떻게 할 것인가를 볼 수 있다.
  -n 나 -q 플래그 없이는 make 가 실제로 명령들을 실행할때 -W 플래그는 make가 어떤파일들이 변경된 것처럼 실제로 파일들을 변경하지 않고 작동한다.
 




어떤 파일들을 재컴파일하는 것을 피하기
 1. 명령 make 를 사용해서 실제로 재 컴파일 필요한 소스 파일들을 재컴파일한다.
 2. 헤더 파일들을 변경한다.
 3. 명령 make -t 를 사용해서 모든 오브젝트 파일들이 갱신된 것처럼 마킹한다. 다음번에 make를 실행하면 헤더 파일의 변화는 어떤 재컴파일도 일으키지 않을 것이다.

어떤 파일들이 재컴파일이 필요한 때에 변경하였다면 너무 느린 것이어서 위와 같이 할수 없다. 대신에 -o file 을 사용하자.
이것은 특정 파일을 구닥다리(old)로 마킹한다. 이것은 그파일 자체가 다시 만들어지지 않을 것이며 다른 어떤 것도 이것을 위해서 다시 만들어지지 않을 것이다.
1. 특정 파일과 무관한 이유 때문에 컴파일이 필요한 소스 파일들을 make -o headfile 를 가지고 재컴파일한다. 몇가지 헤더 파일들이 포함되어 있다면 독립된 -o 옵션을 각 헤더 파일에 사용한다.
2. 모든 오브젝트 파일들을 make -t 로 터치한다.




변수 겹쳐쓰기
 override variable = value

make 안에서 정의된 변수가 make variable=value 로 인해 사라지는 것을 방지 하기 위해 사용된다. override 지시어는 이 변수의 우선순위를 높여 명령행으로 전달된 동일한 이름의 변수에 의해 사라지는 것을 방지한다.

CFLAGS=-g
cc -c $(CFLAGS) foo.c 이라면 make 실행시 cc -c -g foo.c 로 실행될 것이다.
그러나 make CFLAGS='-g -O' 라고 make 를 실행했다면 make 내에서 정의한 CFAGS는 무시되고 cc -c -g -O foo.c 로 실행될것이다.
override 로 변수를 정의한다면 이런 상황에서 make 내에 정의된 변수값을 실행될 것이다.(cc -c -g foo.c)




프로그램의 컴파일 테스트
 일반적으로 쉘 명령을 실행할때 에러가 발생하면 make 는 즉각 포기하여 0이 아닌 상태값을 리턴한다.
하지만 우리는 멈추지 않고 얼마나 많은 컴파일 에러가 나오는지 확인하고 싶을 때

-k 나 --keep-going

플래그를 사용해야한다. 이는 make가 실행중 타겟의 다른 종속물들이 컴파일 에러가 나도 이를 무시하고 다른 오브젝트 파일들을 계속 컴파일 할 것이다.make -k 는 타겟이나 종속 파일들을 만드는 방법을 모른다는 사실을 알아도 가능한 계속한다. 실패의 원인을 찾고 교정하기 위해서 이 명령은 필요하다.





옵션들의 요약
 -b , -m , -C dir , --directory=dir : makefile을 읽기전에 디렉토리를 변경한다. 다수의 -C 옵션들이 지정되면 각가가은 이전의 것과 상대적인 것으로 해석된다. 그래서 -C / -C etc 는 -C /etc 와 동일한다.
-d , --debug : 일반적인 처리에 덧붙여 디버깅 정보를 출력. 디버깅 정보는 어떤 파일들이 다시 만들어져야 하는것으로 생각되고 있지는 어떤 파일-시간들이 어떤 결과들과 비교되고 있는지 그리고 어떤 묵시적 규칙들이 생각되고 있는지와 어떤 것이 적용되는지에 대해서 말해준다.
-e, --environment-overrides : 이것은 환경변수로 부터 취해진 변수들이 makefile의 변수들보다 더 우선하도록한다.
-f file , --file=file , --makefile=file : file을 makefile로 읽는다.
-h , --help : make 가 이해하는 옵션들을 보요주고 종료
-i , --ignore-errors : 파일들을 다시 만들기 위해서 실행되는 명령들에서 모든 에러들을 무시한다.
-I , --include-dir=dir : 포함된 makefile들을 찾기 위해서 dir 디렉토리를 지정한다. 몇개의 -I 옵션들이 있다면 순차적으로 검색한다.
-j [jobs] --jobs=[jobs] : 동시에 실행하는 작업들의 개수를 지정한다. 병렬처리한다.(MS-DOS 에서 무시된다.)
-k , --keep-going : 에러 이후에도 가능한 한 계속하도록한다. 실패한 타겟, 이것에 의존하는 타겟들등이 다시 만들어질수 없는 반면 이런 타겟들의 다른 종속물들은 동일하게 처리될수 있다.
-l [load] , --load-average[=load] , --max-load[=load] : 다른 작업들이 있고 평균 부하가 적어도 load(부동소숫점) 이라면 어떤 새로운 작업들도 시작되지 않도록 한다. 매개변수가 없으면 이전의 부하 제한을 제거한다. 패러럴 실행시..
-n , --just-print , --dry-run , --recon : 실행될 명령들을 인쇄하지만 그들을 실행하지는 않는다.
-o file , --old-file=file , --assume-old=file : file 라는 파일이 그것의 종속물들보다 더 오래된 것이라도 다시 만들지 않으며 file 의 변경이 있더라도 아무것도 다시 만들지 않도록한다. 기본적으로 이파일은 아주 오래된 것으로 취급되며 그것의 규칙은 무시된다.
-p , --print-data-base : makefile들을 읽은 결과의 데이터베이스(규칙들과 변수값)을 인쇄한다. 그리고 나서 보통때처럼 실행하거나 지정된 것처럼 한다. 이것은 또한 -v 스위치에 의해서 주어진 버전 정보를 출력한다. 어떤 파일들도 다시 만들려고 노력하지 않고서 데이터베이스를 출력하려면 make -p -f /dev/null 을 사용한다.
-q , --question : 질문 모드 어떤 명령도 실행하지 않고 어떤 것도 출력하지 않도록한다. 단지 종료 상태값만 리턴한다. 지정된 타겟이 이미 갱신되었다면 0리턴, 리메이크가 필요하다면 1 리턴 에러를 만났다면 2 리턴
-r , --no-builtin-rules : 내장 묵시적 규칙들의 사용을 제거한다. 여러분 자신만의 것을 패턴 규칙들을 작성함으로서 정의할수 있다. -r 옵션은 또한 접미사 규칙들에 대한 디폴트 점미사 리스트를 완전히 청소한다. 그러나 .SUFFIXES 에 대한 규칙으로 자신만의 접미사들을 정의할 수 있고 자신만의 접미사 규칙들을 정의할 수 있다. 단지 -r 옵션에 의해서 영향을 받는다. 디폴트 변수들은 그대로 효력이 있다.
-s , --silent , --quiet : 조용한 작업 그들이 실행될 때 명령들이 인쇄되지 않는다.
-S , --no-keep-going , --stop : -k 옵션의 효력을 취소. 이것은 톱레벨 make로부터 MAKEFLAGS를 통해서 -k 가 승계된 재귀적인 make 외에는 절대 필요 없다. 아니면 환경의 MAKEFLAGS 에다 -k를 설정하였을 때
-t , --touch : 명령들을 실행하지 않고 파일들을 touch(실제로 ㄱ들을 변경하지 않고서 날짜 시간만 현재 시간으로 마크) 이것은 make 의 추후 실행을 속이기 위해서 그 명령이 실행된 것처럼 만든다.
-v , --version : make 프로그램의 버전과 저작권, 개발자 리스트, 그리고 어떤 보증도 없다는 알림을 보여주고 종료
-w , --print-directory : makefile을 실행하기 전과 후에 작업디렉토리를 담고 있는 메시지 출력, 이것은 복잡하게 포개진 재귀적인 make 명령들로부터 에러를 추적하는데 유용할 수 있다.
--no-print-directory : -w 하에서 작업 디렉토리를 출력하는것을 금지함. 이 옵션은 -w가 자동으로 켜질때만 유용
-W file , --what-if=file , --new-file=file , --assume-new=file : 타겟 file 이 방금 변경된 것처럼 가장 -n 플래그와 함께 사용될 때, 이것은 그 파일을 변경한 다면 무슨일이 일어나는가를 보여준다. -n 없이 쓰면 이것은 make 를 실행하기전에 주어진 파일에 touch 명령을 실행하는 것과 거의 유사. 단 변경 시간이 make안에서 상상으로만 변경
--warn-undefined-variables : make가 정의도지 않은 변수에 대한 참조를 볼 때 마다 경고 메시지를 발행. 이것은 변수들을 복잡하게 사용하는 makefile을 디버그 하려고 할 때 유용





묵시적 규칙
묵시적 규칙 사용
 만약
foo.o : foo.p  라고 했을때 .p 파일이 없어도 묵시적규칙에 의해 foo.c 가 있다면 c 소스 파일로부터 오브젝트 파일을 만들것이다.



묵시적 규칙들의 카달로그
 명시적으로 오버라이드하거나 취소하지 않았다면 makefile은 이들을 항상 사용할 것이다. 이런 사용이 가능한 사전에 정의된 묵시적 규칙들을 카탈로그로 준다.

-r 이나 --no-builtin-rules 옵션은 모든 사전에 정의된 규칙들을 취소한다

접미사 .out , .a, .ln, .o, .o, .c, .cc, .C, .p, .f, .F, .r, .y, .l, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch, .web, .sh, .elc, .el. 는 이미 정의된 묵시적 접미사 규칙이다.

C프로그램 컴파일 : n.o 는 n.c 로부터 $(CC) -c $(CPPFLAGS) $(CFLAGS) 형태의 명령에 의해서 자동으로 만들어짐

C++ 컴파일 : n.o 는 n.cc 나 n.C 로부터 $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) 형태의 명령에 의해서 자동으로 만들어짐( C++ 소스는 .c 보다는 .cc 접미사를 사용하기를 권한다.)

파스칼 프로그램 컴파일 : n.o 는 n.p 로부터 $(PC) -c $(PFLAGS) 라는 명령을 사용해서 자동으로 만들어짐

포트란과 Ratfor 컴파일 : n.o 는 n.r, n.F 또는 n.f 로부터 자동으로 만들어진다.
   .f : $(FC) -c $(FFLAGS)
   .F : $(FC) -c $(FFLAGS) $(CPPFLAGS)
   .r : $(FC) -c $(FFLAGS) $(RFLAGS)

포트란과 Ratfor 프로그램 사전처리 : n.f 는 n.r 또는 file{n.F} 로 부터 자동으로 만들어진다.
   .F : $(FC) -F $(CPPFLAGS) $(FFLAGS)
   .r : $(FC) -F $(FFLAGS) $(RFLAGS)

Modula-2 컴파일 : n.sym 는 n.def 로부터 $(M2C) $(M2FLAGS) $(DEFFLAGS) 로 만들어진다.
   n.o 는 n.mod 로부터 $(M2C) $(M2FLAGS) $(MODFLAGS) 로 만들어진다.

어셈블러 프로그램을 어셈블링하고 사전처리하기
   n.o 는 n.s 로부터 어셈블러 as 를 실행함으로써 자동으로 만들어진다. $(AS) $(ASFLAGS)
   n.s 는 C 선행 처리기 cpp를 실행함으로써 n.S 파일로부터 자동으로 만들어진다. $(CPP) $(CPPFLAGS)

단일 오브젝트 파일을 링크 : n 은 n.o 로부터 C 컴파일러를 경유해서 링커(ld)를 실행함으로써 자동으로 만들어진다. 정확한 명령은 $(CC) $(LDFLAGS) n.o $(LOADLIBES) 이 규칙은 단일 소스 파일을 가지는 단순한 프로그램에 대해서 정확하고 다수의 오브젝트 파일들이 있더라도 정확할 것임
예) 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

C 프로그램을 Yacc(Yacc for C programs) : n.c 는 n.y 로 버터 $(YACC) $(YFLAGS) 명령으로 자동으로 만들어진다.

C 프로그램 Lex(Lex for C programs) : n.c 는 n.l 로부터 $(LEX) $(LFAGS) 명령으로 자동으로 만들어진다.

Ratfor 프로그램을 LEX : n.r는 lex 는 Lex를 실행하여 n.l로부터 자동으로 만들어지며 $(LEX) $(LFAGS)  동일한 접미사 .l 을 모든 Lex 파일들에 대해서 사용하는 관례는 그들이 Ratfor 코드나 C 코드들 중에 어떤 것을 만들던지 상관없이 make 가 특별한 경우에 이 두 언어들 중의 어떤 것을 사용중인지 자동으로 결정하는 것을 불가능하게 만든다. .l 파일로부터 오브젝트 파일을 다시 만들기 위해서 make 가 호출되었다면 이거은 어떤 컴파일러를 사용할 것인가를 반드시 추측해내야 한다. C 컴파일러라고 추측해낼 수 도 있을것이다.  왜냐면 이것이 가장 일반적이기 때문이다. Ratfor 를 사용하고 있다면 make 가 이것을 알도록 n.r 을 makefile안에 언급해야 한다. 또는 Ratfor를 C 파일들 없이 배타적으로 사용하고 있다면 다음과 같이 묵시적 규칙 접미사 리스트로부터 .c를 제거
.SUFFIXES:
.SUFFIXES: .o .r .f .l ...

OUTPUT_OPTION 변수 : 이 변수는 VPATH와 비슷하다. 만들어진 오브젝트 파일을 어디에 둘지 정의한다.
예) OUTPUT_OPTION = ; mv $*.o $@





묵시적 규칙에 의해 사용되는 변수
묵시적으로 사용되는 변수 테이블
 
AR : 디폴트 'ar'  - 아카이브관리 프로그램
AS : 디폴트 'as' - 어셈블리 수행 프로그램
CC : 디폴트 'cc' - C 프로그램을 컴파일하는 프로그램
CXX : 디폴트 'g++' - C++ 프로그램들을 컴파일하는 프로그램
CO : 디폴트 'co' - RCS 로부터 파일을 추출하는 프로그램
CPP : 디폴트 'samp{$(CC) -E}' - 결과는 표준출력으로 내는 C 선행처리기
FC : 디폴트 'f77' - 포트란과 Ratfor 프로그램 컴파일, 선행처리하는 프로그램
GET : 디폴트 'get' - SCCS 로부터 파일을 추출하는 프로그램
LEX : 디폴트 'lex' - Lex 문법들을 C 프로그램이나 Ratfor 프로그램들로 변환하는데 사용되는 프로그램
PC : 디폴트 'pc' - 파스칼 컴파일 프로그램
YACC : 디폴트 'yacc' - YACC 문법들을 C 프로그램들로 변환하는 프로그램
RM : 디폴트 'rm -f'  -파일을 제거하는 명령


묵시적 플래그 변수 테이블

ARFLAGS : 디폴트 'rv' -아카이브관리프로그램에 주어지는 플래그
ASFLAGS : 어셈블러에 주어지는 여분의 플래그
CFLAGS : C 컴파일러에게 주어지는 여분의 플래그
CXXFLAGS : C++ 컴파일러에게 주어지는 여분의 플래그
COFLAGS : RCS co 프로그램에게 주어지는 여분의 플래그
CPPFLAGS : C 선행처리기와 이것을 사용하는 프로그램(C, 포트란)에게 주어지는 여분의 플래그
FFLAGS : 포트란에게 주어지는 여분의 플래그
GFLAGS : SCCS get 프로그램에 주어지는 여분의 플래그
LDFLAGS : 링커 ld 를 호출할 것으로 추정되는 컴파일러에게 주어지는 여분의 플래그
LFLAGS : Lex 에게 주어지는 여분의 플래그
PFLAGS : 파스칼 컴파일러에게 주어지는 여분의 플래그
RFLAGS : Ratfor 프로그램들에 대해서 포트란 컴파일러에게 주어지는 여분의 플래그
YFLAGS : Yacc 에게 주어지는 여분의 플래그




묵시적 규칙의 연쇄 - 중간 파일
 예를 들어서 n.o 라는 파일은 cc를 실행해서 n.y 로 부터 만들어 질수 있다.
n :  라고 했을때 n.c 가 존재한다면 n.c 가 n.o 가 되고 n.o 가 n 이 될것이다.
이렇게 중간에 생기는 파일을 중간 파일이라고 하고 중간 파일은 자동 삭제 된다.

YACC 는 yacc 언어로 된 n.y 파일을 n.c 로 만들어준다.

n.o 를 만들기 위해 n.y 가 존재할때 중간에 필요한 n.c는 중간 파일이다.
중간파일은 다음과 같이 두가지방식으로 다르게 취급된다.

1. 중간 파일이 존재하지 않을 때 일어난는 것이다. 일반 파일 b가 존재하지 않고 make가 b에 종속적인 타겟을 생각한다면 이것은 항상 b를 생성한 다음 b로 부터 그 타겟을 갱신한다. 그러나 b가 중간 파일이라면 make는 그대로 둘 수도 있다 이것은 b 또는 궁극적인 타겟을 b의 어떤 종속물도 타겟보다 더 새로운 것이 아니거나 그 타겟을 갱신할 어떤 다른 이유가 없다면 갱신하려고 하지 않는다.

2. make가 어떤 다른것을 갱신하기 위해서 b를 생성한다면 이것이 더이상 필요없을때 b를 지운다. 그러므로 make이전에 존재하지 않던 중간 파일은 make 이후에도 존재하지 않는다. 이런 자동삭제는 rm -f 명령을 인쇄함으로써 그 삭제 사실을 우리에게 보고한다.

일반적으로 makefile에서 타겟이나 종속물로 언급된다면 중간 파일이 될수 없다. 그러나 특수 타겟
.INTERMEDIATE 의 종속물 리스트에 넣어서 어떤 파일을 명시적으로 중간 파일로 지정할 수 있다.

중간 파일의 자동 삭제는 그 파일을 이차파일로 지정함으로서 막을수 있다. 이것은 특수 타겟
.SECONDARY 의 종속물 리스트에 넣으면 된다. 어떤 파일이 이차이라면 make는 그 파일이 사전에 존재하지 않는다는 이유 하나만으로 생성하지는 않을 것이다. 그러나 make 는 그 파일을 자동으로 지우지 않는다. 어떤 파일을 이차로 지정하는 것은 그것을 또한 중간 파일로 지정하는 것이다.

묵시적 규칙의  타겟 패턴을 특수 타겟 .PRECIOUS 의 종속물로 지정해서 타겟 패턴이 그 파일의 이름과 일치하는 묵시적 규칙들에 의해서 만들어진 중간 파일들을 보존할 수 있다.

하나의 연쇄가 두개보다 많을 수는 있으나 동일한 묵시적 규칙이 연쇄에서 두번 이상 불리지 않는다.





패턴 규칙에 대한 소개
 패턴 규칙은 타겟 안에 % 문자를 담고 있다. 그렇지 않으면 이것은 일반 규칙과 완전히 똑같이 보일 것이다.
타겟은 파일이름들과 일치하는 패턴이다. %는 임의의 빈것이 아닌 부분문자열과 일치하고 다른 문자들은 그들 자신들과 일치한다.

예를 들어서 패턴으로써 %.c 는 .c로 끝나는 임의의 파일 이름과 일치
패턴으로써 s.%.c 는 s.로 시작하고 .c로 끝나며 적어도 다섯개의 문자 이상으로 이루어진 임의의 파일 이름과 일치한다.
%와 일치하는 부분문자열은 줄기라고 불린다.

패턴 규칙의 종속물 안에 있는 %는 타겟에서 %와 일치한 것과 동일한 줄기를 나타낸다. 패턴 규칙이 적용되기 위해서 그것의 타겟 패턴은 그 파일 이름과 반드시 일치해야하며 그것의 종속물 패턴은 반드시 존재하거나 만들어질 수 있는 파일들의 이름을 갖고 있어야한다.

문법
%.o : %.c ; command...

n.o 를 n.c 파일이 존재하거나 만들어 질 수 있다면 종속물 n.c파일을 가지고 만드는 방법을 지정
%를 사용하지 않는 종속물들이 있을 수 있다. 그런 종속물은 이런 패턴 규칙에 의해서 만들어진 모든 파일들에 첨부된다.
이것은 종종 유용하다.

패턴 규칙은 % 를 담고 있는 종속물들을 반드시 가질 필요가 없다. 실제로 종속물을 안가져도 된다. 그런 규칙은 효율적으로 일반 와일드 카드가 된다. 이것은 타겟 패턴과 일치하는 임의의 파일을 만드는 방법을 제공한다.




패턴 규칙
 패턴 규칙들이 makefile 에서 나타나는 순서는 아주 중요하다 왜냐면 이것이 바로 그들이 생각되어지는 순서이다. 단지 맨 처음 찾아진 패턴 규칙만을 사용한다.

패턴 예제
%.o : %.c
       $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

% :: RCS/%,v
      $(CC) $(COFLAGS) $<
이것은 서브디렉토리 RCS에서 대응하는 파일 x,v 로부터 x 파일을 만들 수 있는 규칙을 정의한다. 타겟이 %이기 때문에 이 규칙은 적절한 종속 파일이 존재한다면 임의의 파일 무엇에나 적용될 것이다. 더블 콜론 :: 은 이 규칙을 terminal로 만든다.
terminal 이란 그것의 종속물이 중간 파일이 아니어야 한다는 것





자동 변수들
 $@ : 규칙에 있는 타겟의 파일 이름. 타겟이 아카이브 멤버이면 $@ 는 아카이브 파일의 이름이다. 
 $% : 타겟이 아카이브 멤버 일때 타겟 멤버 이름 예를 들어서 타겟이 foo.a(bar.o) 이면 $%는 bar.o 이고 $@는 foo.a 이다.
        타겟이 아카이브 멤버가 아니면 $%는 빈것이다.
 %< : 첫번째 종속물의 이름이다. 타겟이 묵시적 규칙으로부터 그의 명령들을 얻었다면 이것은 묵시적 규칙에 의해서 추가된 첫번째 종속물이 될것이다.
 %? : 타겟보다 더 새로운 모든 종속물들의 이름들. 이들 사이에는 스페이스들이 들어간다. 아카이브 멤버들인 종속물들에 대해서 이름이 있는 멤버만이 사용된다.
 %^ : 모든 종속물들의 이름. 이들 사이에는 스페이스들이 들어간다. 아카이브 멤버인 종속물들에 대해서 이름있는 멤버만이 사용된다. 타겟은 이것이 의존하는 다른 각 파일들에 대해서 각 파일이 종속물 리스트에서 몇번이나 나왔는가에 상관없이 딱 한번만 사용한다. 그래서 어떤 타겟을 위해서 한번 이상 종속물을 사용한다면 $^의 값은 그 이름을 딱 한번 담고 있는 형태가 된다.
 $+ : 이것은 $^와 비슷하다. 그러나 종속물들이 makefile에서 리스트된 순서와 나타난 대로 중복되었다고 해도 한번 이상 리스트된다. 이것은 특별한 순서로 라이브러리 파일 이름들을 반복하는 것이 의미가 있는 링크 명령들 안에서 주로 유용하다.
 $* : 묵시적 규칙이 일치하는 대상 줄기(패턴). 타겟이 dir/a.foo.b 이고 타겟 패턴이 a.%.b 이라면 줄기는 /dir/foo 이다. 줄기는 관련된 파일들의 이름을 만들때 유용하다. 정적 패턴 규칙에서 줄기는 타겟 패턴에서 % 와 일치한 파일 이름의 일부분을 말한다. 명시적 규칙에서는 줄기가 없다. 그래서 $* 는 그런식으로 결정될 수 없다. 대신에 타겟 이름이 인식된 접미사로 끝난다면 $* 는 타겟 이름 빼기 접미사로 설정된다. 예를 들어서 타겟 이름이 foo.c 이라면 $* 는 foo 로 설정된다. 왜냐면 .c 가 접미사이기 때문이다. GNU make는 다른 make 구현물과 호환성을 위해서만 이런 괴기스런일을 한다. 일반적으로 묵시적 규칙들이나 정적 패턴 규칙들을 제외하고는 $* 를 쓰지 않도록 해야한다. 명시적 규칙 안의 타겟 이름이 인식된 접미사로 끝나지 않는다면 $* 은 그 규칙에 대해서 빈 문자열로 설정된다.

사용 사례 : $?
lib 라는 이름의 아카이브가 몇개의 오브젝트 파일들의 복사물들을 담고 있다고 가정하면
lib : foo.o bar.o lose.o win.o
      ar r lib $?





패턴 비교 방법
줄기
접두사와 접미사 사이에 하나의 %를 가진다. 어떤 파일 이름이 중복없이 접두사로 시작하고 접미어로 끝나면 패턴이 일치하는 것이다. 접두사와 접미사 사이의 텍스트는 줄기()라고 불린다. 그래서 패턴 %.o 가 test.o 와 일치하면 줄기는 test이다.

타겟 패턴이 슬래쉬를 갖지 않으면 파일 이름에서 디렉토리 이르들은 그 파일 이름에서 타겟 접두사와 접미사와 비교되기전에 제거된다. 파일 이름을 타겟 패턴과 비교한 후 디렉토리 이름들은 이들 마지막에 있는 슬래쉬와 함께 패턴 규칙의 종속물 패턴들과 그 파일 이름으로부터 만들어지는 종속물 파일에 더해진다. 디렉토리


반응형