2012-03-16 2 views
0

У меня есть файл makefile, который запускает двоичный файл для генерации файлов cpp. Затем я компилирую файлы cpp и создаю файлы .o для каждого файла cpp.Как заставить переоценку переменных в make-файле

Проблема заключается в том, когда Makefile сначала вызывается, папка пуста, потому что двоичный файл еще не испробованы и

CPP_FILES=$(wildcard $(MY_DIR)/inc/output/*.cpp) 

будет пустой переменной.

Так что я изменил строку

CPPFILES=$$(wildcard $(MY_DIR)/inc/output/*.cpp) 
OBJFILES=$$(patsubst $(MY_DIR)/*.cpp,$(MY_DIR)/*.o,$(CPPFILES)) 

и

// запускал бинарный для создания CPP файлов

.SECONDEXPANSION: 
libEXP.so:$(CPPFILES),$(OBJFILES) 
     $(CC) $(CFLAGS) -I(INC) -L(LIBS) -shared -o $(OBJFILES) [email protected] 

вторичного расширение неудачно говоря оболочку не может найти команду подстановки.
Что я делаю неправильно?

ответ

3

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

Итак, когда make расширяет значение $(OBJFILES), даже если вы задерживаете его с помощью второе расширение, все равно, что .cpp-файлы еще не созданы.

Вы должны объяснить, что существует правило, которое может сгенерировать файл .cpp. Как только make поймет, что это вызовет ваше правило для вас. Вы не сможете использовать подстановочный знак для определения файлов .cpp, которые должны быть созданы, если вы не хотите делать что-то вроде первой сборки всех .cpp-файлов, а затем рекурсивно вызывать make.

Edit:

Вы спросили, почему второе расширение не работает. Я упомянул об этом в своем первом абзаце, но, вероятно, не был достаточно ясен. Make проходит через две стадии обработки. Сначала он читает make-файлы, во-вторых, он проходит через правила и строит вещи. Шаг вторичного расширения задерживает разрешение до второго шага ... но это не поможет вам в этом случае.

Вы просите make построить libEXP.so. Для этого ему необходимо расширить предварительные условия libEXP.so, чтобы он знал, от чего зависит цель. ЭТО - это когда выполняется второе расширение, но здесь мы еще не создали никаких файлов .cpp, потому что мы не знаем, что они нам нужны, поэтому подстановочный знак расширяется до нуля. Make не будет создавать эти .cpp-файлы, пока он не узнает, что он им нужен, и он не может знать, что он им нужен, пока он уже не имеет их, чтобы он мог генерировать список.o файлы для предпосылок libEXP.so. Очевидно, что это не сработает :)

+0

Привет MadScientist, спасибо за объяснение, но вот почему я использовал scendexpansion, в чем смысл, если он не переоценивает значение и не придерживается его первоначального значения. Интересно, если я заменил подстановочную строку в определении CPPFILES, командой оболочки «find $ MY_DIR -name» * .cpp «-type f», вернет мне список правильно, но у меня все еще есть проблема с командой patsubst. Если secondexapnsion работает только с функциями оболочки, мне интересно, как сделать документацию по secondexpansion, говорит, что она может использоваться с patsubst. – learningtocode

+0

Я предполагаю, что я действительно спрашиваю, есть ли способ, которым я могу использовать функцию wildacrd, не жалуясь, что командный шаблон не найден. Кроме того, может ли рекурсивный решить эту проблему, я думал, что переменные в списке предварительных условий считываются из всех включенных make-файлов на этапе чтения? – learningtocode

+0

На самом деле Мэдсиенист был прав. Я поместил правило, чтобы развить файлы cpp в одном файле makefile и переместил строку, чтобы разделить файл .o и библиотеку на другой make-файл. Я вызвал второй make-файл рекурсивно из первого, и вуаля это сработало! Я почти отказался от этого. Но я до сих пор не понимаю, как должен работать этот пример в gnu make документации. В любом случае. Большое вам спасибо MadScientist и Eldar! – learningtocode

0

Оставить CPPFILES и OBJFILES как обычные рекурсивные переменные:

CPPFILES = $(wildcard $(MY_DIR)/inc/output/*.cpp) 
OBJFILES = $(CPPFILES:%.cpp=%.o) 

И отложить расширение этого использовать двойные доллары следующим образом:

.SECONDEXPANSION: 
libEXP.so: $$(OBJFILES) 
    $(CC) $(CFLAGS) -I(INC) -L(LIBS) -shared -o $(OBJFILES) [email protected] 

Но я думаю, что проблема заключается в том, что расширение возникает перед запуском генератора файлов cpp. Как вы его вызываете? Это правило или что-то еще?

+0

Eldar, Спасибо за ответ: Пожалуйста, посмотрите на эту ссылку: http://www.gnu.org/software/make/manual /html_node/Secondary-Expansion.html. Я последовал примеру patsubst, который использует второе расширение так, как я его использовал. Что касается вызова правила для запуска двоичного файла, у меня есть правило с именем exp, которое определяется как «exp: genCPP libEXP.so» – learningtocode

+0

@learning, ах, я вижу, но он имеет почти такой же эффект, как и код, который я предложил. Также обратите внимание, что 'exp: genCPP libEXP.so' может не работать должным образом при использовании с использованием параметра Параметр Make (' -j'). Ну, на самом деле, MadScientist объяснил причину проблемы. –

1

Чтобы сделать его явным: вы не должны использовать $(wildcard) для сгенерированных файлов. Если вам нужен «список всех сгенерированных файлов», $(wildcard) предоставит вам этот список только удачей (если все файлы уже сгенерированы).

Если между файлом генератора и сгенерированным файлом существует соответствие 1 к 1, вы можете использовать $(wildcard) в файлах генератора и преобразовать результат.

Использование буферов протокола Google в качестве примера (он может генерировать .cc файлы из .proto файлов)

PROTOSS := $(wildcard *.proto) 
GENERATED_SOURCES := ${PROTOSS:.proto=.cc} 
GENERATED_HEADERS := ${PROTOSS:.proto=.h} 
0

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

0

Другой вариант заключается в использовании для цикла в Баш:

target: prereqs 
    for file in files/*; do \ 
     ... \ 
    done 
Смежные вопросы