2013-03-21 2 views
0

У меня есть куча файлов C в разных каталогах, и я получаю ошибку make: nothing to be done for 'all' с моим рекурсивным Makefile; однако, если я изменю зависимости, я могу заставить его работать ... но я не понимаю, зачем это нужно.рекурсивный makefile not building

Вот мой оригинальный Makefile:

APP_DIRS=rescoco ressys resvm 

.PHONY: all 

all: $(APP_DIRS) 

$(APP_DIRS): 
    $(MAKE) --directory [email protected] 

clean: 
    $(RM) *~ 

Теперь, если я изменю свою линию: .PHONY к .PHONY: all $(APP_DIRS) он строит отлично.

Другая возможность, если я изменю линию: $(APP_DIRS): до $(APP_DIRS): clean он строит отлично.

(Примечание: удаление цели .PHONY не меняет ничего)


Так что же здесь происходит? Является ли Makefile попыткой сказать мне, что я не перечислял зависимости правильно? Я думал make бы сделать что-то вроде:

  • построить .PHONY я сначала построить all
  • построить all я сначала построить $(APP_DIRS)
  • $(APP_DIRS) уже не PreReqs так не выполнить команду для этого (что приведет к тому, что рекурсивные команды будут выполняться).

Очевидно, что я ошибаюсь; но почему?


FYI, если это важно мои файлы структурированы что-то вроде этого:

Makefile  #top level makefile as seen above 
/rescoco 
    rescoco.c 
    Makefile #builds rescoco src and moves archive to ../lib directory 
/ressys 
    ressys.c 
    Makefile #same as above but for ressys 
/resvm 
    resvm.c 
    Makefile #same as above but for resvm 
/lib 

и моя команда сборки просто make. Когда я бегу с make -n или make -n all я не получаю никакого вывода вообще:

:~/proj$ make -n all 
make: Nothing to be done for 'all'. 
:~/proj$ 
+0

какая команда вы используете? сделать все? – 75inchpianist

+0

Запустите make -n, чтобы точно увидеть, что происходит. Я также использую печать переменных, чтобы убедиться, что все работает так, как должно. – stdcall

+0

@ 75inchpianist - просто 'make', но' make all' дает те же результаты. (см. править) – Mike

ответ

2

Вещи первых, вы должны знать:

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

Так что ваш Makefile esentially только говорит это:

  • Чтобы построить цель all, мне нужно построить $(APP_DIRS). Поскольку all является объектом PHONY, я всегда буду исполнять рецепт для all.
  • $(APP_DIRS) не является целью PHONY и не имеет каких-либо зависимостей. Итак, * только если$(APP_DIRS) еще не существует (например, файла или каталога), я собираюсь выполнить рецепт, иначе я ничего не делаю для этой цели.
  • clean не имеет обязательных условий, а не PHONY, поэтому я ожидаю выполнение этого правила только при явном вызове make (из командной строки или другого Makefile). Также clean не PHONY, поэтому я ожидаю, что рецепт, чтобы создать файл с именем clean после выполнения (что неверно для вашего случая)

Следовательно, изменяя .PHONY линию:

.PHONY: all $(APP_DIRS) 

делает Makefile идет и выполняет рецепт для $ (APP_DIRS) всегда.

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

Для конкретной потребительной случае, я думаю, что это Makefile вы должны использовать:

APP_DIRS=rescoco ressys resvm 

.PHONY: all clean $(APP_DIRS) 

all: $(APP_DIRS) 

$(APP_DIRS): 
    $(MAKE) --directory [email protected] 

clean: 
    $(RM) *~ 

БОНУС:

  • Изменение $(APP_DIRS): к $(APP_DIRS): clean означает, что $(APP_DIRS) зависит от clean цель.
  • Хотя clean не отмечен PHONY, make не видит файл с именем clean в текущем каталоге. Поэтому он идет вперед и пытается выполнить рецепт для clean.
  • Поскольку была создана зависимость $ (APP_DIRS) (т. Е. clean), это делает Makefile исполнением рецепта для построения $ (APP_DIRS).

Это подводит нас к интересному наблюдению: - Любая цель, которая зависит от фиктивной цели всегда будет получать перестроены (то есть рецепт будет выполняться).

Возьмите эту простую Makefile:

all: target1 

target1: target2 
    @echo "[email protected]" 
    @touch [email protected] 

target2: target3 
    @echo "[email protected]" 
    @touch [email protected] 

target3: 
    @echo "[email protected]" 

.PHONY: all target3 

В первый раз я бегу make, я вижу этот вывод:

target3 
target2 
target1 

После этого файлы target1 и target2 созданы. Даже тогда, если я снова запустить make, я хотел бы видеть выход:

target3 
target2 
target1 

Как вы можете видеть, PHONY зависимости получить распространяющуюся вверх, а не другой путь вниз. target2 получает перестроенный только потому, что target3 является PHONY, а target1 получает перестроенный только потому, что target2 получил перестроенный.

+0

+1 ОК, это имеет большой смысл. Я знал, что если что-то было указано как «.PHONY», оно всегда было бы построено, я думал *, то есть, если бы я перечислил «все» как «.PHONY», он и все его зависимости всегда строились ... но это не распространяется. Верный? – Mike

+0

@Mike - зависимые зависимости PHONY распространяются по цепочке зависимостей, а не наоборот. Посмотрите на мой пример, который я добавил в конце. – Tuxdude

0

Вы определяете переменную с именем «APP_DIRS» со списком каталогов. Это нормально.

Вы затем сделать

$(APP_DIRS): make blah blah,, которая по существу эквивалентна rescoco ressys resvm: make blah blah

, который, очевидно, разве действует.

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

, говорит, что, думаю, почему .PHONY: все $ (APP_DIRS) работает