포니 타겟은 실제 파일의 이름이 아닌 타겟이다.
포니 타겟의 사용 목적은 두 가지이다. 1) 같은 이름의 파일과 충돌을 막기 위해 2) 퍼포먼스 향상을 위해
만약 실제 타겟 파일을 생성하지 않는 규칙을 만든다면, 이 규칙은 make시 항상 실행하게 된다.
clean :
rm *.o temp
왜냐하면 rm 명령어는 clean이라는 이름의 파일을 생성하지 않는다. 따라서 rm 명령어는 'make clean'을 할 때마다 항상 실행된다.
만약 clean이라는 파일을 이 디렉토리에 만들면, clean 타겟은 제대로 동작하지 않는다. clean은 필요 항목이 없기 때문에, clean은 언제나 최신 파일로 고려되고 위 규칙은 수행하지 않는다. 이러한 문제를 막기위해 PHONY 타겟이라고 명시적으로 선언한다.
.PHONY: clean
clean:
rm *.o temp
위와 같이 명시해두면, make clean은 clean이라는 파일의 존재 여부와 관계없이 언제나 실행된다.
또한 포니 타겟은 make의 재귀적 호출에서도 유용하게 사용된다. makefile은 종종 하위 디렉토리의 리스트들을 가지고 있는다. 이러한 리스트를 다루는 단순한 방법은 하위 디렉토리의 루프를 도는 규칙을 선언하는 것이다.
SUBDIRS = foo bar baz
subdirs :
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
그러나 이 방법에는 몇 가지 문제가 있다.
첫 번째는 submake에서 발견된 에러는 규칙에 의해 무시된다. 따라서 하나가 실패하더라도 나머지 디렉토리들을 계속해서 빌드할 것이다. 이러한 문제는 error를 기록하고 exit하는 명령어를 추가하면 극복할 수 있다. 그러나 make가 -k 옵션으로 실행된다면 에러 핸들링 명령어를 추가했음에도 불가하고 계속 수행할 것이다.
두 번째는 타겟을 병렬 빌드하는 make의 이점을 활용하지 못한다.
하위 디렉토리를 포니타겟으로 선언하면 위와 같은 문제들을 해결할 수 있다.
SUBDIRS = foo bar baz
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
foo: baz
foo 서브 디렉토리는 baz 서브디렉토리가 끝날 때까지 빌드할 수 없다. 이와 같은 관계 선언은 병렬 빌드를 시도할 때 중요하다.
포니 타겟은 실제 타겟파일의 필요항목이 되면 안된다. 만약 필요항목이 되면, make를 할 때마다 포니타겟 파일을 업데이트하기위해 항상 실행된다. 포니타겟이 실제파일의 필요항목이 되지 않는한, 포니타겟은 오직 구체적인 목적이 있을 때만 실행된다.
포니타겟은 필요항목을 가질 수 있다. 하나의 디렉토리가 다수개의 프로그램을 가지고 있을 때, 포니를 사용하는게 가장 편리한 방법이다.
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
출처 : https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html