Получение make для удаления дополнительных файлов при ошибке - PullRequest
7 голосов
/ 12 марта 2009

В последнее время мы обсуждаем способ обработки файлов .d для зависимостей в процессе сборки на основе make. Была поднята проблема, что иногда .d файлы могут быть повреждены при прерывании сборки.

Мы используем цель .DELETE_ON_ERROR, чтобы гарантировать, что в случае прерывания или сбоя сборки удаляются объектные файлы, которые были в процессе генерации. Однако мы также используем GCC для генерации файлов .d во время компиляции, которые также необходимо удалить. Кажется, нет простого способа сказать об этом.

Таким образом, вопрос заключается в том, можно ли каким-либо образом уговорить нас удалить наш объект и наши файлы зависимостей в случае ошибки? Есть ли какой-нибудь способ, которым мы можем настроить правила, чтобы он знал, что файлы .d и .o генерируются одновременно и должны быть удалены в случае ошибки?

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

Ответы [ 2 ]

6 голосов
/ 12 марта 2009

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

.DELETE_ON_ERROR:

all: foo.o

%.o %.d: %.c
    @touch $*.d
    @touch $*.o
    @exit 1

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

В качестве альтернативы, общая парадигма в этом случае такая же, как вы предложили: GCC генерирует файл .d во временное имя файла и перемещает его на место только после успешного выполнения команды GCC. Обычно это достигается с помощью хитрости оболочки:

all: foo.o

%.o: %.c
    gcc -o $@ -MMD -MF $(basename $@).d.tmp -c $< \
        && mv $(basename $@).d.tmp $(basename $@).d

Здесь «магический трюк» - это использование флагов GCC -MMD, который генерирует файл зависимостей как побочный эффект компиляции, и -MF, который позволяет указать имя вывода для файла зависимостей; и использование синтаксиса оболочки cmd1 && cmd2, который заставляет оболочку выполнять cmd2, только если cmd1 успешно завершается.

0 голосов
/ 19 апреля 2011

Ни один из примеров Эрика не работает должным образом. GCC (версия 4.4) ничего не компилирует, когда вы передаете ключ -MM, поэтому не похоже, что вы можете скомпилировать и написать .d за один раз. Вот что я сделал:

%.o: %.c
    @rm -f $@ $(patsubst %.o,%.d,$@)
    gcc -c $< -o $@
    @$(CXX) -MM -MG > $(patsubst %.o,%.d,$@)

Он начинается с удаления существующего файла .d, третья строка, генерирующая новый, выполняется только в том случае, если вторая команда, фактический шаг компиляции, выполнена успешно (трюк Eric && не нужен, make делает это автоматически) , По какой-то причине я не понимаю, существующий файл .o не удаляется автоматически, если компиляция не удалась, но это было легко решить, добавив $@ к первому rm.

...