이 명령에 관한 책을 읽고 있는데 make
그 안에 다음과 같은 단락이 있습니다.
전제조건에 연관된 규칙이 있는 경우 먼저 해당 규칙을 업데이트해 보십시오. 다음으로 대상 파일을 고려하십시오. 전제조건이 대상보다 최신인 경우 명령을 실행하여 대상을 다시 생성하십시오. 각 명령줄은 셸로 전달되어 자체 하위 셸에서 실행됩니다.
거기에서 사용되는 서브쉘의 개념과 그러한 서브쉘을 사용해야 하는 이유를 설명할 수 있습니까?
답변1
make(1)
쉘 명령 자체를 실행하는 방법을 모릅니다. 이런 방식으로 수행할 수도 있지만 Unix 방식은 우려 사항을 훌륭하게 분리하는 것입니다. 즉, make(1)
수행해야 할 작업을 결정하기 위해 종속성 그래프를 작성하는 방법을 알고 sh(1)
명령을 실행하는 방법을 알아야 합니다.
작성자가 말하려는 요점은 파일 시스템을 통하는 경우를 제외하고 후자의 명령줄이 이전 명령줄에 종속되도록 명령줄을 작성할 수 없다는 것입니다. 예를 들어 다음은 작동하지 않습니다.
sometarget: some.x list.y of-dependencies.z
foo=`run-some-command-here`
run-some-other-command $$foo
이것이 두 줄로 구성된 쉘 스크립트라면 첫 번째 명령의 출력이 두 번째 명령의 인수로 전달됩니다. 그러나 각 명령은 별도의 서브쉘에서 실행되기 때문에 $foo
첫 번째 서브쉘이 존재하면 변수의 값이 손실되므로 첫 번째 서브쉘로 전달할 것이 없습니다.
위에서 암시했듯이 이 문제를 해결하는 한 가지 방법은 파일 시스템을 사용하는 것입니다.
TMPDIR=/tmp
TMPFILE=$(TMPDIR)/example.tmp
sometarget: some.x list.y of-dependencies.z
run-some-command-here > $(TMPFILE)
run-some-other-command `cat $(TMPFILE)`
두 번째 명령이 값을 로드할 수 있도록 첫 번째 명령의 출력을 영구 위치에 저장합니다.
때때로 초보자를 혼란스럽게 하는 또 다른 점 make(1)
은 쉘 스크립트에서 가독성을 위해 일반적으로 여러 줄로 분할되는 구성이 한 줄에 작성되어야 한다는 것입니다. 또는 Makefile
.loop에 있는 경우 이에 대한 좋은 예는 작동하지 않습니다. :
someutilitytarget:
for f in *.c
do
munch-on $f
done
모든 것을 한 줄에 넣으려면 세미콜론을 사용해야 합니다.
someutilitytarget:
for f in *.c ; do munch-on $f ; done
나 자신의 경우 이 작업을 수행하여 명령줄이 약 80자를 초과할 때마다 이를 읽을 수 있도록 외부 쉘 스크립트로 옮깁니다.
답변2
Make 자체는 쉘이 아니므로 쉘에서 실행해야 합니다. make 자체가 (아마도) 쉘에서 실행되기 때문에 이 책에서는 이를 "서브쉘"이라고 부릅니다. 책에서 실제로 전달하려는 것은 각 명령에 자체 쉘이 있으므로 한 줄에서 변수를 내보내고 다음 줄(또는 다른 후속 줄)에서 사용하려는 경우 작동하지 않는다는 것입니다 export
( 사용하는 쉘은 별도의 쉘에서 실행되는 다음 줄로 끝납니다.
답변3
오래된 질문이지만 셸에서 명령을 실행하고 출력을 얻을 수도 있습니다.
http://electric-cloud.com/blog/2009/03/makefile-performance-shell/
OUTPUT = $(shell pwd)
some-target:
@echo $(OUTPUT)
답변4
즉, 규칙의 각 명령줄은 자체 쉘 프로세스에서 호출됩니다. 그 이유는 make가 하나의 명령줄을 실행한 후 다음 명령줄을 호출하기 전에 이를 확인하려고 하기 때문입니다.
명령을 호출하는 다른 방법을 생각할 수 있지만 이것이 방법입니다.만들다그 당시에 디자인된 것입니다.
틀림없이만들다그냥 할 수 있어포크()/exec()명령을 사용하지만 쉘 하위 프로세스를 사용하면 사용자가 쉘 기능을 사용할 수도 있습니다.