Я знаю, что уже немного поздно, но я хотел бы дать более подробный ответ, почему это происходит и как именно помогают другие решения.
Рабочим решением будет: вы используете либо b.depends += a
как вы делали раньше или CONFIG += ordered
и добавьте PRE_TARGETDEPS += ...
к b
.(Примечание: заказывать не рекомендуется, так как это может значительно замедлить ваши сборки и обычно считается плохой практикой)
TL; DR: Причина, по которой необходима эта специальная комбинация:app.depends = lib_mylib
в проекте subdirs гарантирует, что библиотека всегда собирается перед запуском сборки приложения, а PRE_TARGETDEPS
гарантирует, что приложение фактически перестраивается при каждом изменении библиотеки.
Длинное объяснение:
Чтобы понять, почему это работает, нам нужно понять, как qmake обрабатывает подкаталоги.qmake является генератором Makefile, что означает, что он будет создавать только make-файлы.Таким образом, все упорядочение зависимостей должно выполняться с использованием методов make prodives.Чтобы понять, что происходит, мы должны сначала понять, как работает make.
В make зависимости относительно просты:
some_target: dep1 dep2 dep3
some_command
означает, что если вы хотите создать some_target
, make будетсначала создайте dep1
, dep2
и dep3
в неопределенном порядке .После того как все 3 будут выполнены, будет выполнено some_command
.
Тем не менее, make оптимизирует это для файлов.Учитывая следующее:
hello.txt:
echo "creating hello"
echo "hello" > hello.txt
hello2.txt: hello.txt
echo "creating hello2"
echo "hello2" > hello2.txt
Запуск make создаст оба файла и напечатает оба сообщения.Запуск его во второй раз ничего не даст.Причина в том, что make отслеживает уже созданные файлы и их изменения.Поскольку hello.txt
уже существует, он не создается снова.И поскольку hello.txt
не изменился, нет необходимости создавать hello2.txt
снова.Если вы теперь внешне измените содержимое hello.txt
и запустите make снова, hello2.txt
будет создан заново, и вы увидите сообщение.
Теперь с проектами subdirs это становится немного сложнее, так как мытеперь нужны зависимости между несколькими разными make-файлами!Обычно это решается с помощью рекурсивных вызовов.Для вашего примера qmake создает следующий код (упрощенно):
lib_mylib: FORCE
$(MAKE) lib_mylib/Makefile
app: lib_mylib FORCE
$(MAKE) app/Makefile
Этот код, как и ожидалось, сначала создаст lib_mylib
(блокировка, т.е. lib_mylib
завершится только после того, как вся библиотекабыл построен) и после этого создать app
.Зависимость FORCE
гарантирует, что эта команда всегда выполняется, даже если цель уже существует.
С учетом этих основ мы можем теперь восстановить то, что происходит с qmake.Использование b.depends += a
сгенерирует код, как указано выше - это гарантирует, что все зависимости построены в правильном порядке, но не более того!Использование упорядоченного конфига просто автоматически создает эти зависимые правила, поэтому нет логической разницы в том, как они работают.
Однако этого недостаточно для фактического перестроения app
при изменении lib_mylib
.Это только гарантирует, что lib_mylib
будет собран до того, как make начнет сборку app
.
. Чтобы перестроить app
, мы используем PRE_TARGETDEPS
- это добавляет зависимость, как показано ранее, к цели make вmake-файл приложения
app.exe: mylib.lib:
#linker code
Это означает, что при каждом изменении lib_mylib
app
теперь также перестраивается.Однако использование этого без упорядоченного конфига может привести к сбою, так как возможно, что make сначала попытается собрать app
(который либо ничего не делает, так как lib не изменился, либо завершится ошибкой, если lib еще не существует) и после этого перестроитьlib_mylib
.Выполнение make во второй раз также приведет к перестройке app
, но это довольно неудобно.
Итак, поэтому нам нужно объединить эти два.Нам нужно контролировать порядок выполнения различных make-файлов и ссылаться на созданные артефакты из другого make-файла - и это именно то, что делают эти команды.