Qmake pre-build step перед ЛЮБОЙ компиляцией
Есть несколько вопросов о том, как создать шаг предварительной сборки для qmake
, я могу сделать это с этим в файле .pro
:
versionTarget.target = ../VersionData/versioning.h
versionTarget.depends = FORCE
win32: versionTarget.commands = cd $$PWD; python.exe ./version_getter.py -p $$TARGET
else: versionTarget.commands = cd $$PWD; python ./version_getter.py -p $$TARGET
PRE_TARGETDEPS += ../VersionData/versioning.h
QMAKE_EXTRA_TARGETS += versionTarget
Теперь проблема заключается в том, что этот подход не является самим положением сборки, а просто другой целью сборки, поэтому, если у меня есть флаг -j
, настроенный для make
, он запускает мой script параллельно с другой сборкой рабочие места. Это очень плохо, потому что мой script создает/обновляет заголовочный файл - если он меняет часть пути, компиляция неприемлема.
Итак, все-таки я могу запустить этот script до того, как будет запущена какая-либо компиляция? Я знаю, что могу создать еще один script и последовательно вызывать version_getter.py
и qmake
, но это нежелательно, поскольку мне пришлось бы компилироваться из командной строки, а не из Qt Creator.
Update
Полный .pri
файл, который включен в каждый из моих подпроектов, находится ниже:
CONFIG += thread
QT += core \
gui
versionTarget.target = ../VersionData/versioning.h
versionTarget.depends = FORCE
win32: versionTarget.commands = cd $$PWD; python.exe ./version_getter.py -p $$TARGET
else: versionTarget.commands = cd $$PWD; python ./version_getter.py -p $$TARGET
PRE_TARGETDEPS += ../VersionData/versioning.h
QMAKE_EXTRA_TARGETS += versionTarget
DEPENDPATH += ../VersionData
INCLUDEPATH += ../VersionData
HEADERS += ../VersionData/versioning.h
UI_HEADERS_DIR = $${_PRO_FILE_PWD_}/include/Qui
DESTDIR = $(SYREN_PATH)
!win32-msvc {
QMAKE_CXXFLAGS += -std=c++0x
}
Но это все равно приводит к такому же параллельному поведению. Я думал, что это возможно из-за моего использования ccache
, но отключение его не имело никакого значения (кроме, конечно, гораздо медленнее).
Ответы
Ответ 1
Другой вариант - начать с фрагмента файла проекта в исходном вопросе, а также убедиться, что qmake знает, что versioning.h
является зависимостью для других целей сборки в файле проекта -
- Добавьте полный путь к
versioning.h
в вашу переменную HEADERS
.
- Добавьте папку, в которой
versioning.h
находится в вашей переменной DEPENDPATH
.
(Предостережение: если вы запустите qmake, когда versioning.h
не существует, он выдаст "WARNING: Failure find: versioning.h" - единственный обходной путь для этого предупреждения заключается в использовании команды system()
, как я описал в своем другом ответе.)
Пример
Создать test.pro
, содержащий следующее:
versionTarget.target = ../versioning.h
versionTarget.depends = FORCE
versionTarget.commands = sleep 5s ; touch ../versioning.h
PRE_TARGETDEPS += ../versioning.h
QMAKE_EXTRA_TARGETS += versionTarget
SOURCES = test.c
HEADERS = ../versioning.h
DEPENDPATH = ..
Создайте test.c
, содержащий следующее:
#include "../versioning.h"
Запустите qmake
. Он выведет WARNING: Failure to find: ../versioning.h
.
Запустите make -j9
. Он запустит versionTarget.commands
(который спит в течение 5 секунд, чтобы преувеличивать любые проблемы многопроцессорности), а после этого запустите команду для компиляции test.c
.
(И если вы просмотрите сгенерированный Makefile
, вы увидите, что test.o
зависит как от test.c
, так и от ../versioning.h
, поэтому Make должен правильно понять, что он не может выполнить команду для компиляции test.c
перед командой для создания/обновления ../versioning.h
.)
Ответ 2
Используйте команду system()
qmake - она запускается при запуске qmake
, что происходит до make
как make
запускает любые команды сборки.
win32: PYTHON=python.exe
else: PYTHON=python
system(cd $$PWD; $$PYTHON ./version_getter.py -p ../VersionData/versioning.h)
Ответ 3
Я заметил, что если вы проверяете Makefile, созданный qmake, всегда есть первое правило Makefile с именем "first", которое зависит от другого правила отладки (или выпуска), содержащего инструкции для сборки. То есть что-то вроде этого:
...
MAKEFILE = Makefile
first: debug
...
Чтобы создать шаг перед сборкой, мы должны взломать это правило, чтобы оно зависело от другого с более высоким приоритетом.
Что-то вроде
...
MAKEFILE = Makefile
first: prebuild debug
prebuild:
do_your_instructions
...
На самом деле это будет что-то вроде этого:
...
MAKEFILE = Makefile
first: debug
...
first: prebuild
prebuild:
do_your_instructions
...
который можно легко взломать в проекте qmake, выполнив:
# $$PWD/test_prebuild is a batch with the instructions to execute before every build
!build_pass:prebuild.commands = $$PWD/test_prebuild
!build_pass:first.depends = prebuild
QMAKE_EXTRA_TARGETS += prebuild first
Обратите внимание, что "! build_pass:" гарантирует, что вы пишете это правило предварительной сборки только в Makefile (а не в Makefile.Debug или Makefile.Release), предотвращая многократное выполнение test_prebuild.
Обратите внимание, что это возможно, потому что "first" не зарезервирован (хотя это и есть примитив qmake.
В моем случае это работало нормально: я надеюсь, что этот трюк может помочь и другим.