몇 줄의 bash 명령을 통해 프로젝트를 컴파일하는 매우 편안한 방법이 있습니다. 하지만 이제는 makefile을 통해 컴파일해야합니다. 모든 명령이 자체 셸에서 실행된다는 것을 고려할 때 내 질문은 makefile에서 서로 의존하는 여러 줄 bash 명령을 실행하는 가장 좋은 방법 은 무엇입니까?
예를 들면 다음과 같습니다.
for i in `find`
do
all="$all $i"
done
gcc $all
또한 누군가가 한 줄 명령조차도 bash -c 'a=3; echo $a > file'
터미널에서 올바르게 작동하지만 메이크 파일의 경우 빈 파일을 만드는 이유를 설명 할 수 있습니까?
답변
줄 연속에 백 슬래시를 사용할 수 있습니다. 그러나 쉘은 한 줄로 연결된 전체 명령을 수신하므로 세미콜론으로 일부 줄을 종료해야합니다.
foo:
for i in `find`; \
do \
all="$$all $$i"; \
done; \
gcc $$all
그러나 find
호출에서 반환 된 전체 목록을 가져 와서에 전달하려는 경우 gcc
실제로 여러 줄 명령이 필요하지는 않습니다.
foo:
gcc `find`
또는 좀 더 셸 전통적인 $(command)
접근 방식을 사용합니다 ( $
이스케이프에 주의하십시오 ).
foo:
gcc $$(find)
답변
질문에서 알 수 있듯이 모든 하위 명령은 자체 쉘에서 실행됩니다 . 이것은 사소하지 않은 쉘 스크립트를 작성하는 것을 약간 지저분 하게 만듭니다.하지만 가능합니다! 해결책은 make가 단일 하위 명령 (단일 행)을 고려하는 것으로 스크립트를 통합하는 것입니다.
메이크 파일 내에서 쉘 스크립트 작성을위한 팁 :
- 다음
$
으로 대체 하여 스크립트의 사용 을 피하십시오.$$
;
명령 사이 에 삽입하여 스크립트를 한 줄로 작동하도록 변환- 여러 줄에 스크립트를 작성하려면 다음을 사용하여 줄 끝을 이스케이프하십시오.
\
- 선택적
set -e
으로 하위 명령 실패시 중단하도록 make의 프로비저닝과 일치하도록 시작 - 이것은 전적으로 선택 사항이지만 스크립트를 대괄호 로 묶
()
거나{}
여러 줄 시퀀스의 응집성을 강조 할 수 있습니다. 이는 일반적인 메이크 파일 명령 시퀀스가 아닙니다.
다음은 OP에서 영감을 얻은 예입니다.
mytarget:
{ \
set -e ;\
msg="header:" ;\
for i in $$(seq 1 3) ; do msg="$$msg pre_$${i}_post" ; done ;\
msg="$$msg :footer" ;\
echo msg=$$msg ;\
}
답변
명령을 호출하는 데있어 문제점은 무엇입니까?
foo:
echo line1
echo line2
....
그리고 두 번째 질문에 대해, 당신은 탈출 할 필요가 $
사용하여 $$
즉, 대신 bash -c '... echo $$a ...'
.
편집 : 다음과 같이 한 줄 스크립트로 예제를 다시 작성할 수 있습니다.
gcc $(for i in `find`; do echo $i; done)
답변
물론 Makefile을 작성하는 올바른 방법은 실제로 어떤 타겟이 어떤 소스에 의존하는지 문서화하는 것입니다. 사소한 경우에는 제안 된 솔루션이 foo
자체적으로 의존 하게 되지만 물론make
순환 의존성을 떨어 뜨릴만큼 똑똑합니다. 그러나 디렉토리에 임시 파일을 추가하면 “마법처럼”종속성 체인의 일부가됩니다. 아마도 스크립트를 통해 명시적인 종속성 목록을 한 번에 생성하는 것이 좋습니다.
GNU make는 및 파일 gcc
세트에서 실행 파일을 생성하기 위해 실행하는 방법을 알고 있으므로 실제로 필요한 모든 것은.c
.h
foo: $(wildcard *.h) $(wildcard *.c)
답변
ONESHELL 지시문을 사용하면 동일한 쉘 호출에서 실행할 여러 줄 레시피를 작성할 수 있습니다.
SOURCE_FILES = $(shell find . -name '*.c')
.ONESHELL:
foo: ${SOURCE_FILES}
for F in $^; do
gcc -c $$F
done
하지만 단점이 있습니다. 특수 접두어 문자 ( ‘@’, ‘-‘및 ‘+’)는 다르게 해석됩니다.
https://www.gnu.org/software/make/manual/html_node/One-Shell.html