Как заставить make всегда перестраивать файл

У меня есть файл version.c в моем проекте, который содержит текущую ревизию проекта и некоторые другие вещи, которые передаются как определение (опция компилятора CN00) из makefile.

Я знаю, что заставить make компилировать version.c всегда независимо от даты модификации, я могу touch version.c.

Есть ли способ makefile только для этого? Если я пишу .PHONY: version.o объектный файл вообще не .PHONY: version.o.

EDIT: Вот мой makefile:

export CC = gcc


export MODULES = $(sort \
     sys \
     cim \
     version \
)

export FILES = $(sort \
             main.c \
             cim.c \
             version.c \
)

VPATH = $(MODULES)

OBJS = $(FILES:.c=.o)

INCLUDES = $(addprefix -I,$(MODULES))

all:$(OBJS)
    $(CC) $(INCLUDES) $(OBJS) -o main.exe


clean:
    rm -rf *.o *.exe

cim.o: cim.c
main.o: main.c cim.o
version.o: version.c

.PHONY: version.o

.c.o :
    $(CC) $(CFLAGS) $(INCLUDES) -c $<

Ответ 1

Классический способ сделать это:

version.o:   .FORCE

.FORCE:

(и вы можете добавить .PHONY:.FORCE). Предполагается, что файл ".FORCE" не существует, поэтому он всегда "создан", поэтому version.o всегда устаревает, поэтому version.o всегда компилируется.

Я не уверен, что сделать version.o в фальшивый файл правильным; это фактически настоящий файл, а не фальшивый.

Ответ 2

Если вы хотите сделать это с помощью механизма FORCE, правильное решение будет выглядеть так:

version.o: FORCE

.PHONY: FORCE
FORCE:

.SECONDARY: образом объявляя FORCE ложным, мы убеждаемся, что все будет работать правильно, даже если используется .SECONDARY: (.SECONDARY: приведет к тому, что FORCE будет считаться промежуточным файлом, и make не будет перестраивать промежуточные файлы, если у них нет предпосылок, более новых, чем конечная цель, и FORCE не имеет каких-либо предварительных условий, поэтому .PHONY: FORCE требуется).

Другое решение (с использованием $(shell touch version.c)) также имеет проблему: это может привести к тому, что ваш редактор подумает, что версия version.c обновлена и запрашивает перезагрузку файла, что может оказаться разрушительным, если вы "Редактирование файлового буфера, но еще не сохранено. Если вы не против этого, это можно сделать еще проще, заметив, что touch команда молчит, так что назначение на hack фиктивной переменной не требуется:

$(shell touch version.c)  # This is enough, but will likely confuse your editor

"ХОРОШИЙ" трюк, о котором упоминается в комментариях к вопросу, как правило, НЕ работает. Это может выглядеть так, потому что это заставит relink iff version.o уже существовать, но фактический объектный файл не будет восстановлен, если правило файла .o является неявным правилом (которое обычно есть). Проблема в том, что make не выполняет неявный поиск правил для явно фальшивых целей. В этом файле отображается ошибка:

fooprog: test.o
        cp $< [email protected]

%.o: %.c
        cp $< [email protected]

.PHONY: test.o # WRONG

clean:
        rm test.o fooprog

Если вместо неявного правила используется правило статического шаблона, трюк .PHONY: version.o будет работать. В общем случае использование правил статических шаблонов вместо неявных правил отсеивает большинство более запутывающих моделей поведения. Но большинство файлов используют неявные правила.

Ответ 3

Не способ makefile, но проще, чем прикосновение:

make -B

"-B" - всегда

Рассмотрите все цели устаревшие. GNU переходит к рассмотрению целей и их предпосылок с использованием обычных алгоритмов; однако все цели, которые считаются, всегда переделываются независимо от статуса их предпосылок. Чтобы избежать бесконечной рекурсии, если MAKE_RESTARTS (см. Другие специальные переменные) задано числом больше 0, эта опция отключается при рассмотрении вопроса о том, нужно ли переделывать make файлы (см. Раздел "Как make файлы").

Ответ 4

Быстрая версия взлома, когда вам просто нужно ее работать, и вы не хотите играть в игры Make:

# Hack to get main.c rebuilt
hack := $(shell touch main.c)

В основном просто сделайте Make run touch для вас.