[bash] 메이크 파일의 여러 줄 bash 명령

몇 줄의 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가 단일 하위 명령 (단일 행)을 고려하는 것으로 스크립트를 통합하는 것입니다.

메이크 파일 내에서 쉘 스크립트 작성을위한 팁 :

  1. 다음 $으로 대체 하여 스크립트의 사용 을 피하십시오.$$
  2. ;명령 사이 에 삽입하여 스크립트를 한 줄로 작동하도록 변환
  3. 여러 줄에 스크립트를 작성하려면 다음을 사용하여 줄 끝을 이스케이프하십시오. \
  4. 선택적 set -e으로 하위 명령 실패시 중단하도록 make의 프로비저닝과 일치하도록 시작
  5. 이것은 전적으로 선택 사항이지만 스크립트를 대괄호 로 묶 ()거나 {}여러 줄 시퀀스의 응집성을 강조 할 수 있습니다. 이는 일반적인 메이크 파일 명령 시퀀스가 ​​아닙니다.

다음은 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


답변