Подтвердить что ты не робот

Почему GNU удаляет файл

У меня есть немного хакерский makefile для запуска тестов:

### Run the tests

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

test: $(tests)

$(tests): %: %.c
    gcc -o [email protected] $(testflags) $<
    [email protected]

Он работает, но делает 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 удаляет скомпилированный тест?

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

4b9b3361

Ответ 1

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


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

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


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

$(tests): %: %.c
    gcc -o [email protected] $(testflags) $<
    [email protected]

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

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

и

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

Ответ 2

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

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

test: $(tests) runtests

$(tests): %: %.c
    gcc -o [email protected] $(testflags) $<

runtests: %.out: %
    $< | tee [email protected]

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

Ответ 3

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