При объявлении правила шаблона как PHONY он не запускается

У меня есть следующий рекурсивный make файл:

.PHONY: all clean

%.subdir:
    $(MAKE) -C src $*
    $(MAKE) -C dict $*

all: all.subdir

clean: clean.subdir

и он отлично работает:

$ make all
make -C src all
make[1]: Entering directory `/or-1.3.6-fix/src'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/or-1.3.6-fix/src'
make -C dict all
make[1]: Entering directory `/or-1.3.6-fix/dict'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/or-1.3.6-fix/dict'

Но было бы логичнее определять правила %.subdir как фальшивые:

.PHONY: all clean all.subdir clean.subdir

и теперь делайте остановки, как я хочу:

$ make all
make: Nothing to be done for `all'.
$ make -d all
...
Updating goal targets....
Considering target file `all'.
 File `all' does not exist.
  Considering target file `all.subdir'.
   File `all.subdir' does not exist.
   Finished prerequisites of target file `all.subdir'.
  Must remake target `all.subdir'.
  Successfully remade target file `all.subdir'.
 Finished prerequisites of target file `all'.
Must remake target `all'.
Successfully remade target file `all'.
make: Nothing to be done for `all'.

Может кто-нибудь объяснить мне, почему (или даже лучше указать мне на документацию)?

Ответ 1

Вы правы, было бы разумнее определить правила subdir как PHONY. Но Make не рассматривает неявные правила для целей PHONY, поэтому вам придется переписать это правило. Я предлагаю следующее:

SUBDIR_TARGETS = all.subdir clean.subdir
.PHONY: all clean $(SUBDIR_TARGETS) 

$(SUBDIR_TARGETS): %.subdir:
    $(MAKE) -C src $*
    $(MAKE) -C dict $*

all: all.subdir
clean: clean.subdir

Ответ 2

Если вы используете GNU make, см. официальное руководство пользователя

Make не делает ничего, потому что он не видит никаких файлов (так как они все фальшивые). Убедитесь, что ваша неявная цель default не является фальшивой, так что make имеет что-то для сборки.

Обновление: Из в этом разделе руководства по установке:

Поскольку он знает, что фальшивые цели не указывать фактические файлы, которые могут быть переделать из других файлов, пропустить неявный поиск правил для фальшивых цели.

Поэтому ваши неявные цели никогда не ищутся, потому что они фальшивые.

Вы можете достичь того, что вы пытаетесь сделать другим путем. Попробуйте следующее:

SUBDIRS := all clean
.PHONY: $(SUBDIRS)

$(SUBDIRS):
    echo $(MAKE) -C src [email protected]
    echo $(MAKE) -C dict [email protected]

Ответ 3

То, что GNU делает требуемые цели, объявленные как .PHONY явными, уже было указано в других ответах, что также предоставило некоторое средство для этого.

В этом дополнительном ответе я хотел бы добавить альтернативу, которая, как я тестировал, объединяет "фальшивое" поведение, то есть, эти цели запускаются каждый раз независимо от того, существуют ли файлы с тем же именем (они игнорируются). Альтернатива выглядит следующим образом:

.PHONY: phony_explicit

phony_explicit: 

%.subdir: phony_explicit
    $(MAKE) -C src $*
    $(MAKE) -C dict $*

Это работает на предпосылке, что, хотя только явные цели могут быть установлены как .PHONY, независимо от того, какая явная фальшивая цель, сама наследует многие (насколько мне известно) фальшивые атрибуты. Неявная, то есть цель сопоставления с шаблоном, такая как %.subdir выше, точно так же, как если бы она была добавлена ​​к .PHONY (что невозможно, потому что оно не является явным явным), но все же становится фальшивым посредством своего предрешительного фальшивого phony_explicit.

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

Действительно, в документации GNU упоминается FORCE target, который в некоторых версиях GNU, которые не предлагают .PHONY цель эмулирует частично поведение .PHONY. В представленной здесь альтернативе используется этот целевой подход FORCE, но поскольку используется GNU make, он также устанавливает цель FORCE как .PHONY, избегая потенциальных конфликтов с реально существующими файлами с тем же именем.

При этом решении даже a

touch clean.subir; make clean.subdir

даст искомый вызов

make -C src clean
make -C dist clean

Что может быть потенциальной про-точкой этой альтернативы, так это то, что она не нуждается в явном объявлении clean.subdir и all.subdir, но действительно использует неявное сопоставление шаблонов %.subdir.