Удалить цели с рецептами не удалось в Makefile - PullRequest
0 голосов
/ 17 января 2019

Я пытался использовать .DELETE_ON_ERROR target в make-файле, чтобы удалить оба $(OBJ) и executable файлы, если рецепт не удался, но он не работает. Если я помещаю ошибку в любой объектный файл, то во время компиляции правила шаблона возникает ошибка, и она останавливается. Старый объектный файл все еще на своем месте, но я ожидаю, что .DELETE_ON_ERROR удалит его.

Может кто-нибудь проверить код? Может ли -include $(DEP) или флаг -DDBG влиять? Цель состоит в том, чтобы удалить как файл .o, который не удалось, так и executable.

OUTPUT = executable
CPP := $(shell find $(SRC) -type f -name "*.cpp")
OBJ := $(CPP:.cpp=.o)
DEP := $(OBJ:.o=.d)

CXX := g++
CXXFLAGS =-MMD -MP -DDBG
INCLUDES = -I.

.DELETE_ON_ERROR :

$(OUTPUT): $(OBJ)
    $(CXX) $^ -o $@

%.o: %.cpp
    $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@

-include $(DEP)

.PHONY : clean
clean:
    rm -rf $(OBJ) $(DEP) 

РЕДАКТИРОВАТЬ: В соответствии с решением Ondrej K., чтобы исправить эту проблему, вам нужно добавить команду @touch перед компилятором, чтобы изменить объектные файлы (документы читают ", удаляя цель правила, если она изменилось ".). Итак, код должен выглядеть так:

%.o: %.cpp
    @touch $@
    $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@

1 Ответ

0 голосов
/ 17 января 2019

Не знаю, какую неудачу вы видите, но я боюсь, что для вас это не самый лучший способ. Файлы .o и исполняемый файл ($(OUTPUT)) являются отдельными правилами. Если последнее не помогает, первое уже не рассматривается. См. документацию :

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

Другими словами, если ваша цель, создающая двоичный объект, потерпела неудачу после того, как .o сама цель была обновлена, make удалил измененный файл. Но если ваш исполняемый файл не связывался, он не вернется и не удалит объектные файлы.

Не уверен, что это было бы неплохо, но если бы вам действительно это было нужно, вы, вероятно, могли бы добиться этого путем рефакторинга вашего make-файла, чтобы в основном иметь прямое exec + objs из правила исходных условий с одним рецептом. Очевидный недостаток: такое правило будет означать, что изменение файла .c приведет к перекомпиляции всех файлов (что в основном сводит на нет существенные преимущества использования make).


РЕДАКТИРОВАТЬ: Я немного расширю комментарий, чтобы уточнить. Похоже, что вам нужно: если поврежденный файл .c завершился неудачно, удалите старый файл .o. Это совершенно не совсем так, как работает .DELETE_ON_ERROR. Если файл .o уже обновлен, а затем правило не выполнено, он удалит его ( "удалит цель правила, если оно изменилось" ), но в случае упомянутой синтаксической проблемы, компилятор потерпит неудачу, прежде чем он создаст файл .o.

Итак, если, например, вы обновили правило (шаблон) для компиляции, чтобы оно сначала touch es (эффективно обновляет временную метку) в файле .o, а затем попыталось скомпилировать. После сбоя вызова компилятора и правила make сочтет, что цель поврежденного корня была обновлена, и удалит ее. В качестве альтернативы вы также можете изменить правило, чтобы сначала попытаться rm ожидаемый файл '.o', в этом случае вам на самом деле не нужно будет использовать .DELETE_ON_ERROR (и если в соответствующих источниках нет изменений, правило делает не привыкать, так что на самом деле это не так страшно, как кажется). В любом случае это не совсем чисто, но ведет к поведению, которое, как я понимаю, вы описываете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...