Почему GNU заставляет удалить файл - PullRequest
12 голосов
/ 26 февраля 2009

У меня есть слегка взломанный make-файл для запуска тестов:

### Run the tests

tests := tests/test1 tests/test2 ...

test: $(tests)

$(tests): %: %.c
    gcc -o $@ $(testflags) $<
    $@

Это работает, но заставляет Make делать то, что я никогда раньше не видел. Мой тест в настоящее время не работает и вызывает ошибку шины. Make дает следующий вывод:

gcc -o tests/test1 [flags blah blah] tests/test1.c
tests/test1
make: *** [tests/test1] Bus error
make: *** Deleting file `tests/test1'

Мне любопытно насчет последней строки. Я никогда не видел, чтобы Make делал это раньше. Почему Make удаляет скомпилированный тест?

Примечание. Я довольно сильно отредактировал этот пример, чтобы упростить его. Я мог бы внести некоторые ошибки.

Ответы [ 3 ]

14 голосов
/ 26 февраля 2009

Потому что цель может быть построена неправильно. В следующий раз, когда вы make проект, он попытается восстановить цель. Если файл не был удален, make не сможет узнать, что что-то пошло не так. make не может знать, что сбой произошел из-за теста, а не процесса, который строит цель.


Желательно ли это поведение в вашем случае, зависит от характера тестов. Если вы планируете исправить тест, чтобы он не вызывал Bus error, удаление цели не имеет большого значения. Если вы хотите использовать цель для отладки позже, вам нужно внести изменения в процесс make.

Один из способов не удалять цели - использовать цель .PRECIOUS.


Другое может быть:

$(tests): %: %.c
    gcc -o $@ $(testflags) $<
    -$@

Не проверено, но документация указывает, что цель не будет удалена:

Когда происходит ошибка, о которой make не было сказано игнорировать, это означает, что текущая цель не может быть корректно переделана, как и любая другая, которая зависит от нее прямо или косвенно. Для этих целей дальнейшие команды не будут выполняться, поскольку их предварительные условия не были достигнуты.

и

Обычно при сбое команды, если она вообще изменила целевой файл, файл поврежден и не может быть использован или, по крайней мере, не полностью обновлен. Тем не менее, отметка времени файла говорит о том, что он обновлен, поэтому при следующем запуске make не будет пытаться обновить этот файл. Ситуация такая же, как когда команда убита сигналом; см. Прерывания. Таким образом, в общем случае правильное решение - удалить целевой файл, если после начала изменения файла не удается выполнить команду. make сделает это, если в качестве цели появится .DELETE_ON_ERROR. Это почти всегда то, что вы хотите сделать, но это не историческая практика; поэтому для совместимости вы должны явно запросить его.

11 голосов
/ 26 февраля 2009

Один из способов избежать такого поведения - разделить сборку и выполнение теста на два этапа:

tests := tests/test1 tests/test2 ...

test: $(tests) runtests

$(tests): %: %.c
    gcc -o $@ $(testflags) $<

runtests: %.out: %
    $< | tee $@

(Возможно, в моем синтаксисе make есть ошибки, каждый может его исправить.) Основная идея состоит в том, чтобы при выполнении теста генерировался выходной файл, что облегчает make запуск каждого теста по отдельности.

6 голосов
/ 26 февраля 2009

Это стандартное поведение make. Когда команда возвращает код ошибки (например, ненулевой возврат), тогда цель создания удаляется. Директивы make-файла .PRECIOUS и .IGNORE могут изменить это поведение.

...