Добавление пользовательских команд в существующие объекты в qmake

Есть ли способ указать в файле .pro дополнительные команды, которые будут добавлены к стандартной цели в Makefile, который генерирует qmake? Например, рассмотрите distclean, дополнительные команды могут быть желательны:

  • Удалить * ~ файлы.
  • Очистить выходные файлы сгенерированных из исходного дерева.
  • Etc.

Я хочу использовать обычную цель, а не настраиваемую цель, потому что я хочу, чтобы это было полностью прозрачно в моем рабочем процессе. То есть (опять-таки используя distclean в качестве примера), я не хочу...

  • ... требуют знания в многопроектной настройке, что определенные Make файлы используют настраиваемое правило вместо distclean.
  • ... настраивать пользовательские правила даже для автономных проектов, поскольку distclean уже известный и интуитивно понятный .

Я нашел Как добавить пользовательские цели в созданный qmake Makefile?, но это описывает добавление пользовательских целей (которое уже документировано, даже назад в 4.6) вместо добавления правил к существующим целям. Хотя в нем содержатся некоторые подсказки, все они требуют добавления новых пользовательских целей, поскольку указание одной и той же цели более одного раза в Makefile заменяет (не добавляет) команды из предыдущей цели.

Единственное, что я действительно мог попробовать, это добавить target.commands += new commands в .pro файл как дикое предположение (например, distclean.commands += rm \"*~\"). Это не влияет.

Как я могу прозрачно добавлять пользовательские команды к существующим целям с помощью qmake?


Для примера distclean: хотя maintainer-clean также находится в этом списке "стандартных целей", на практике я нашел его редко используемым и в любом случае qmake не генерирует его по умолчанию; Я считаю это непригодным.

Ответ 1

Есть два простых способа выполнить это, в зависимости от того, насколько автономным/переносным вы хотите, чтобы ваше решение было и насколько мягким вы хотите быть с порядком выполнения команды.


Вариант 1

Первый вариант - создать пользовательскую цель в файле .pro для новых команд, а затем добавить эту цель в качестве предпосылки для стандартной цели, которую вы изменяете. Вернемся к примеру distclean, скажем, вы хотите добавить команду для удаления всех * ~ файлов:

  • Создайте пользовательскую цель в вашем файле .pro. Обратите внимание, что вам нужно избежать кавычек и слэшей в файлах .pro. Например, добавьте:

    extraclean.commands = find . -name \"*~\" -exec rm -v {} \\;
    
  • Добавьте эту цель в зависимость от цели, которую вы изменяете:

    distclean.depends = extraclean
    

    На самом деле это правило не будет изменять правило distclean, так как этот метод не может использоваться для изменения существующих правил. Однако...

  • Добавьте как новую цель, так и цель, которую вы модифицируете как дополнительные цели:

    QMAKE_EXTRA_TARGETS += distclean extraclean
    

    Это добавит вторую спецификацию distclean к Makefile, но это работает, потому что вы можете добавлять зависимости к существующим целям в make в отдельные правила, даже если вы не можете добавлять команды таким образом. Если вы также должны указать distclean.commands в вашем .pro файле, вы бы сломали существующий distclean, заменив его по умолчанию.

Итак, все это вместе, в файле .pro:

extraclean.commands = find . -name \"*~\" -exec rm -v {} \\;
distclean.depends = extraclean
QMAKE_EXTRA_TARGETS += distclean extraclean

Где extraclean - это некоторая настраиваемая цель с командами, которые вы хотите добавить, а distclean - это существующая цель, которую вы хотите изменить.

Плюсы:

  • Полностью автономный файл .pro.
  • Как переносимый, вы можете получить фактический синтаксис Makefile и генерировать до qmake.

Минусы:

  • Ваши новые команды не добавляются к существующему рецепту. Скорее, они происходят после того, как все предварительные цели выполнены, но до существующего рецепта. В примере distclean с версией qmake, которую я использую, это ставит команды после того, как исходное дерево очищено, но до того, как сам Makefile будет удален (что является единственным действием, которое принимает по умолчанию рецепт). Это не проблема для этого примера, но может быть проблемой для вас.

Вариант 2

Второй вариант - изменить имя файла Makefile, который генерирует qmake, и создать собственный пользовательский Makefile, который отсылает к сгенерированному, а не включает в себя + переопределяет его. Это также простой вариант; хотя он не является самодостаточным как вариант 1, он дает вам возможность выполнять команды как до, так и после рецепта, созданного по умолчанию.

Вы не хотите включать + переопределять существующий Makefile, потому что вы не хотите заменять стандартные рецепты. Если вы это сделаете, вам придется повторно реализовать значение по умолчанию, но это может быть проблемой, поскольку это значение по умолчанию может измениться (и вам нужно идти в ногу с изменениями). Лучше всего позволить qmake делать как можно больше работы, а не повторять свою работу.

Для этого:

  • Сначала измените имя файла, который генерирует qmake. Это можно сделать, добавив строку в файл .pro:

    MAKEFILE = RealMakefile
    

    Это приведет к тому, что qmake выведет RealMakefile вместо Makefile.

  • Следующим шагом будет создание собственного Makefile с вашими пользовательскими командами. Однако здесь есть некоторые оговорки. Во-первых, полный пример, снова используя distclean. В файле с именем Makefile:

    .DEFAULT_GOAL := all
    
    %:
        @$(MAKE) -f RealMakefile [email protected]
    
    distclean:
        @$(MAKE) -f RealMakefile [email protected] 
        @find . -name "*~" -exec rm -v {} \;
    

    Некоторые примечания об этом:

    • Мы устанавливаем .DEFAULT_GOAL, потому что иначе distclean будет по умолчанию. Альтернативой этому, если вам не удобно с .DEFAULT_GOAL, является указание правила all с использованием @$(MAKE) -f RealMakefile [email protected] в качестве рецепта.
    • Цель % соответствует любой цели, которая иначе не определена в этом Makefile. Он просто делегирует обработку в RealMakefile.
    • Цель distclean заключается в добавлении наших команд. Нам по-прежнему необходимо делегировать RealMakefile, но дополнительные команды могут быть добавлены как до, так и после этого.

Плюсы:

  • Больше контроля над порядком команд. Команды могут быть добавлены как до, так и после рецепта по умолчанию.

Минусы:

  • Не является самодостаточным в .pro.
  • Не так, как переносимо: он не оставляет все генерацию Makefile до qmake, а также я не уверен, какие части являются специфическими для GNU make здесь (комментарии приветствуются).

Итак, хотя этот ответ может быть немного длинным, оба этих метода очень просты. Я бы предпочел вариант 1, если проблема с исполнением команды не является проблемой.