makefile에는 다음과 같은 몇 가지 규칙이 있습니다.
out.txt: foo.sh input.txt
./foo.sh -i input.txt > out.txt
foo.sh
실패 하면 out.txt
크기 0의 파일이 생성됩니다. 내가 달리면만들다out.txt
이번에도 파일이 성공적으로 생성되었다고 잘못 판단하여 규칙을 다시 실행하지 않습니다.
이 상황을 처리하는 올바른 방법은 무엇입니까?
답변1
규칙이 실패하면 다음을 정의하여 대상 파일 제거를 요청할 수 있습니다.특별한 목표명명 된.DELETE_ON_ERROR
. 아무것도 할 필요가 없고 종속성이 필요하지 않으므로 makefile에 추가하기만 하면 됩니다.
.DELETE_ON_ERROR:
그러면 다음을 얻게 됩니다:
$ cat Makefile
.DELETE_ON_ERROR:
foo:
false > foo
$ make
false > foo
make: *** [foo] Error 1
make: *** Deleting file `foo'
zsh: exit 2 make
$ stat foo
stat: cannot stat `foo': No such file or directory
~에서레시피의 오류:
일반적으로 레시피 라인이 실패할 때 대상 파일이 전혀 변경되면 파일이 손상되어 사용할 수 없거나 적어도 완전히 업데이트되지 않습니다. 그러나 파일의 타임스탬프는 현재 최신 상태임을 나타내므로 다음에
make
파일을 실행할 때 파일 업데이트를 시도하지 않습니다. 이 상황은 신호에 의해 쉘이 종료되는 경우와 동일합니다.방해하다. 따라서 파일 변경을 시작한 후 레시피가 실패하면 일반적으로 올바른 방법은 대상 파일을 삭제하는 것입니다. 이 작업은 대상으로 존재하는 경우make
수행됩니다 ..DELETE_ON_ERROR
이는 거의 항상 수행하려는 작업이지만make
역사적 관행이 아니므로 호환성을 위해 명시적으로 요청해야 합니다.
답변2
가능할 때마다 makefile 규칙은 먼저 임시 이름으로 대상을 생성한 다음 이를 제자리로 이동해야 합니다. 이렇게 하면 어떤 이유로든 빌드 프로세스가 중단되더라도 절반만 작성된 대상 파일과 완전히 작성된 파일을 구별할 수 없는 상황이 발생하지 않습니다.
out.txt: foo.sh input.txt
./foo.sh -i input.txt >[email protected]
mv -f [email protected] $@
mv -f [email protected] $@
이것은 일반적인 메이크파일 관용어입니다.
줄리아노의 답변동적으로 생성된 임시 파일 이름의 변형이 표시됩니다. 동일한 대상을 생성하는 프로세스가 여러 개 있거나 다른 사용자가 디렉터리에 쓸 수 있는 경우 동적 이름 생성이 필요합니다. 빌드 트리의 경우 이런 일이 거의 발생하지 않으므로(이러한 문제가 발생하면 일반적인 makefile에서 발생하는 많은 작업이 손상될 수 있음) 일반적으로 추가 복잡성이 필요하지 않습니다.
답변3
이것은 귀하가 작성한 것(또는 귀하가 작성한 것에 의해 생성된 것)인 것처럼 보이므로 출력 파일 이름을 사용하는 플래그를 추가하는 것을 foo.sh
고려해 보겠습니다 . -o
그러면 기본 I/O 리디렉션 동작에 의존할 필요가 없습니다. 스크립트는 출력 파일의 일부를 정리할 수 있으며 오류를 조기에 감지할 수 있으면 처음부터 파일 생성을 피할 수도 있습니다.
답변4
foo.sh
오류가 발생하면 0이 아닌 값을 올바르게 반환한다고 생각합니다 . 그런 다음 임시 작업을 수행하고 성공할 경우에만 출력을 덮어써야 합니다.
tmp=$$(mktemp) && ./foo.sh input.txt > $$tmp && mv $$tmp $@ || rm -f $$tmp && false