2013-10-10 2 views
9

У меня есть следующий упрощенный make-файл, и я пытаюсь установить разные пути на основе разных целей. К сожалению, я не получаю ожидаемых результатов. Это сделано с версией 3.81.Почему эта целевая переменная target make не расширяется, как ожидалось?

.SECONDEXPANSION: 
all: Debug32 

# Object directory set by target 
Debug32: OBJDIR = objdir32 
#OBJDIR = wrongdirectory 

# ObjDir is empty here. :(
OBJS = $(addprefix $(OBJDIR)/,DirUtil.o) 

$(OBJDIR)/%.o : %.cpp 
      echo Compile: [email protected] 

Debug32: $(OBJS) 

$(OBJS): | $(OBJDIR) 

$(OBJDIR): 
      echo mkdir $(OBJDIR) - [email protected] 

Результаты таковы, без установки OBJDIR:

echo Compile: /DirUtil.o 

Если я раскомментировать строку «OBJDIR = wrongdirectory», я получить следующие результаты, которые сбивают с толку, так как я вижу, оба значения переменной, где я думаю, что я должен видеть только один:

echo mkdir objdir32 - wrongdirectory - 
echo Compile: wrongdirectory/DirUtil.o 

Я предполагаю, что переменные не расширяются, когда я думаю, что они должны, но я не могу понять, как изменить этот Бех Avior.

ответ

11

Из информации ГНУ ручной

Переменные и функции во всех частях 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 

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

+0

Это работает, но кажется, что я должен указать каталог объектов дважды и каждый .o-файл дважды, включая правило шаблона для исходного файла.Неужели я все это делаю неправильно? Слишком сложно создать простой общий файл makefile для двух или более целей. – Jeff

+0

Я добавил способ охватить все объектные файлы. Я ожидаю, что это возможно, без перечисления их всех (что-то вроде '% .o: $$ (basename%). Cpp | $$ (dir $$ @)'), но у меня пока нет его работы. –

+0

Я добавил простую в использовании версию и примечания о том, что нужно указывать каталоги. Метод Марка Галека для создания каталогов выглядит, как будто это может быть лучше. –

3

хороший способ справиться с

%/obj.o: | % 
    touch [email protected] 

OBJDIRS = objdir32 wrongdirectory anotherdirectory 
$(OBJDIRS): 
    mkdir [email protected] 

является:

%/.: 
    mkdir -p [email protected] 

.SECONDEXPANSION: 

потом вы можете просто написать, для любой цели, которые могут нуждаться в каталог

target: prerequisites | $$(@D)/. 
    normal recipe for target 
Смежные вопросы