Иногда необходимо, чтобы некоторые команды выполнялись всегда, при любом запуске make, в самом начале или в самом конце работы.
Чтобы наша цель выполнялась в нужное время, нужно как-то привязаться с к цели, которая первой выполняется при запуске make. Это обеспечит то, что наша команда выполнится. Далее, нужно привязяться таким образом, чтобы наша цель выполнялась до (или после) всех целей, от которых зависит первая цель.
Выполнение Makefile по умолчанию начинается с первой цели по порядку. qmake первыми целями генерирует следующее:
first: all all: Makefile $(DESTDIR_TARGET)
1 2 3 4 |
Глядя на эти правила, придумать цель, которая всегда будет выполняться, и будет выполняться в самом конце, несложно. Эту цель можно сделать зависимой от all (значит, она выполнится после all), и сделать first зависимой от нее (а значит, она выполнится).
Правило для команды, всегда выполняемой в самом конце - qmake
QMAKE_EXTRA_TARGETS += after_build firsthook firsthook.target = first firsthook.depends = after_build after_build.depends = all after_build.CONFIG = phony after_build.commands = @echo after_build && @echo ============
1 2 3 4 5 6 7 8 9 10 |
QMAKE_EXTRA_TARGETS += after_build firsthook firsthook.depends = after_build after_build.commands = @echo after_build && @echo ============ |
Результирующий Makefile:
Правило для команды, всегда выполняемой в самом конце - Makefile
first: all all: Makefile $(DESTDIR_TARGET) after_build: all FORCE @echo after_build && @echo ============ first: after_build
1 2 3 4 5 6 7 8 9 |
all: Makefile $(DESTDIR_TARGET) |
Конечно, все поломается, если make будет вызван как make all, но Qt Creator по умолчанию запускает make без параметров. Так что меня такой способ устраивает.
Да, еще – до последних команд дело не дойдет, если make завершится с ошибкой в каком-либо правиле посередине. Нюанс, с которым ничего поделать нельзя.
Если с командой, выполняемой в конце, все достаточно просто, то с командой, выполняемой в начале выполнения make, дела обстоят сложнее. Во-первых, для того, чтобы такая цель гарантированно выполнилась до выполнения всего остального, Makefile и $(DESTDIR_TARGET) должны от нее зависеть. Далее, эта цель не может быть phony, потому как в противном случае у Makefile и $(DESTDIR_TARGET) будет необновленная зависимость, что приведет к запуску команд одного из этих правил (скорее всего, Makefile, и значит, произойдет вызов qmake). Раз цель не может быть phony, то должен существовать одноименный файл. И этот файл должен быть старым, иначе qmake запустится. И, наконец, чтобы команды выполнялись всегда, цель должна быть зависимой от FORCE.
Правило для команды, всегда выполняемой в самом начале - qmake
# создаем файл-заглушку !exists($$OUT_PWD/.beforebuild) { system(@echo aaa > $$system_path($${OUT_PWD}/.beforebuild)) } QMAKE_EXTRA_TARGETS += before_build makefilehook makefilehook.target = $(MAKEFILE) makefilehook.depends = .beforebuild POST_TARGETDEPS += .beforebuild before_build.target = .beforebuild before_build.depends = FORCE before_build.commands = @echo our command
В Makefile получается следующее:
Правило для команды, всегда выполняемой в самом начале - Makefile
$(DESTDIR_TARGET): $(OBJECTS) .beforebuild $(LINKER) $(LFLAGS) -o $(DESTDIR_TARGET) $(OBJECTS) $(LIBS) .beforebuild: FORCE @echo our command $(MAKEFILE): .beforebuild
1 2 3 4 5 6 7 8 9 |
$(DESTDIR_TARGET): $(OBJECTS) .beforebuild |
И не забывайте – файл .beforebuild существует, и он всегда старше Makefile!