Из информации ГНУ ручной
Переменные и функции во всех частях Makefile расширяются когда читать, потому что в рецептах, то правые части переменных определений с помощью «=» за исключением, и тела переменных определений с использованием директивы 'define'.
Целевая переменная применяется только в рецептах. В
$(OBJS): | $(OBJDIR)
и
$(OBJDIR):
она становится глобальной переменной.
Так что, работая над тем, что происходит при запуске make Debug32
, он видит содержимое OBJS
как необходимое условие, которое приводит к первому правилу выше. $(OBJDIR)
уже заменен глобальным значением, и это совпадает с именем-мишенью во втором правиле, которое также было заменено таким же образом.
Однако, когда мы перейдем к рецепту:
echo mkdir $(OBJDIR) - [email protected]
$(OBJDIR)
не был заменен еще, так что он получает значение переменной целевой конкретной.
рабочая версия
.SECONDEXPANSION:
all: Debug32
# Object directory set by target
Debug32: OBJDIR = objdir32
OBJDIR = wrongdirectory
Debug32: OBJS = $(addprefix $(OBJDIR)/,obj.o)
OBJS = wrongobjs
Debug32: $$(OBJS)
echo OBJS are $(OBJS)
echo OBJDIR is $(OBJDIR)
%/obj.o: | %
touch [email protected]
OBJDIRS = objdir32 wrongdirectory anotherdirectory
$(OBJDIRS):
# mkdir $(OBJDIR)
mkdir [email protected]
Основное изменение использует $$
в этой строке:
Debug32: $$(OBJS)
С только одной $
, я получаю сообщение об ошибке
make: *** No rule to make target `wrongobjs', needed by `Debug32'. Stop.
Однако, с $$
, я получаю
echo OBJS are objdir32/obj.o
OBJS are objdir32/obj.o
echo OBJDIR is objdir32
OBJDIR is objdir32
Использование вторичного расширения позволило получить доступ к переменной целевой специфичные в предпосылок.
Другое изменение состоит в том, что я сделал OBJS
целевую переменную (потому что она). Для того, чтобы иметь правила, чтобы построить OBJS
независимо от его значения, я должен был использовать шаблонное правило:
%/obj.o: | %
Чтобы избежать необходимости отдельной строкой для каждого объектного файла, вы можете сделать следующее вместо:
OBJ_BASENAMES=obj.o obj2.o obj3.o
$(addprefix %/,$(OBJ_BASENAMES)): | %
touch [email protected] # Replace with the proper recipe
строка, содержащая addprefix
макрос для
%/obj.o %/obj2.o %/obj3.o: | %
Затем выполняется make anotherdirectory/obj2.o
создает каталог с именем «anotherdirectory» пихта st и создает в нем файл с именем obj2.o.
Примечание: все возможные каталоги должны быть указаны в OBJDIRS
. Невозможно собрать все специфичные для правила значения OBJDIR, поэтому их перечисление - лучший выбор. Альтернативой является правило % :
для создания любой директории, которая будет способна сопоставлять и строить любую цель, что может быть рискованным. (Если вы откажетесь от использования целевых переменных, существует другой способ получить список каталогов, которые можно было бы построить: вместо этого используйте переменные с предсказуемыми именами, например Debug32_OBJDIR
, и сгенерируйте список их значений с помощью функций make.)
в качестве альтернативы, общее правило, которое не требует перечислений объектных файлов:
SOURCE=$(basename $(notdir [email protected])).cpp
DIR=$(patsubst %/,%,$(dir [email protected]))
%.o: $$(SOURCE) | $$(DIR)
touch [email protected] # Replace with proper recipe
Там нет особенности читать правила в контексте каждой цели, подставляя в целевом конкретном переменных и приобретает новое правило для каждой цели. Общие правила не могут быть записаны таким образом, используя переменные, специфичные для конкретной цели.
Это работает, но кажется, что я должен указать каталог объектов дважды и каждый .o-файл дважды, включая правило шаблона для исходного файла.Неужели я все это делаю неправильно? Слишком сложно создать простой общий файл makefile для двух или более целей. – Jeff
Я добавил способ охватить все объектные файлы. Я ожидаю, что это возможно, без перечисления их всех (что-то вроде '% .o: $$ (basename%). Cpp | $$ (dir $$ @)'), но у меня пока нет его работы. –
Я добавил простую в использовании версию и примечания о том, что нужно указывать каталоги. Метод Марка Галека для создания каталогов выглядит, как будто это может быть лучше. –