2009-02-26 6 views
11

У меня есть немного хак Makefile для выполнения тестов:Почему GNU сделать удалить файл

### Run the tests 

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

test: $(tests) 

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

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

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

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

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

ответ

14

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


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

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


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

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

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

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

и:

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

11

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

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

test: $(tests) runtests 

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

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

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

+1

+1 за то, что это единственный ответ, указывающий на то, что поведение было вызвано багги-файлом, который объединял создание тестовой программы и запуск ее в одно правило. –

+0

IMO это лучшее решение: более чистые и более «make-like». Хотя, детали могут быть обработаны более чисто. Сначала автор makefile должен решить: хотите ли вы выполнить _allways_ тесты или выполнить тесты только в том случае, если тестовый файл был перестроен (последний - это то, что сделал исходный пример). – MadScientist

6

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

Смежные вопросы