Makefile: функция оболочки в ленивой переменной не ленива - PullRequest
0 голосов
/ 04 апреля 2019

Рассмотрим следующий Makefile.

$(shell touch /tmp/example.txt)
FILE := /tmp/example.txt
CONTENTS = $(shell cat $(FILE); bash -c 'echo [debugging id: $$RANDOM]')

.PHONY: all
all:
    @cat $(FILE)
    @echo '$$(CONTENTS):' $(CONTENTS)
    bash -c 'echo file-contents-$$RANDOM' > $(FILE)
    @cat $(FILE)
    @echo '$$(CONTENTS):' $(CONTENTS) # This line outputs the old contents. Why?

Он печатает содержимое файла, перезаписывает новое содержимое и снова печатает содержимое. Показывается как (после второго выстрела make):

file-contents-1543
$(CONTENTS): file-contents-1543 [debugging id: 15172]
bash -c 'echo file-contents-$RANDOM' > /tmp/example.txt
file-contents-22441
$(CONTENTS): file-contents-1543 [debugging id: 151]

Старое содержимое - file-contents-1543, новое - file-contents-22441 (числа случайные), но последняя строка echo $(CONTENTS) не печатает новое содержимое. Я думаю, что команда фактически вызывается дважды, как показывают идентификаторы отладки, но функция оболочки в переменной lazy, кажется, выполняется перед записью нового содержимого в файл.

Я ожидаю, что ленивая переменная в Makefile оценивается каждый раз, когда на нее ссылаются, команда echo $(CONTENTS) всегда печатает самое последнее содержимое файла. В чем я не прав?

Кстати, я обнаружил, что использование CONTENTS = $$(cat $(FILE)) работает, как я ожидал. Я буду использовать это вместо функции оболочки, но это нормально?

1 Ответ

2 голосов
/ 04 апреля 2019

Я ожидаю, что ленивая переменная в Makefile вычисляется при каждом обращении к ней, команда echo $ (CONTENTS) всегда печатает самое последнее содержимое файла.В чем я не прав?

Прежде всего, в сленге make эти переменные называются recursive , а не lazy.И, да, они получают расширенный (т. Е. Рекурсивно замещенный) каждый раз, когда им присваивается $(CONTENTS).Учитывая, что $(eval...) и $(shell...) (так же, как и $(...)) также проходили одну и ту же (рекурсивную) процедуру расширения (хотя и с некоторыми "побочными эффектами"), каждое расширение такой переменной также может привести кв некотором роде «вычисления» или «выполнения».

Далее, порядок раскрытия в make немного специфичен.В частности, рецепты (т. Е. Строки, начинающиеся с [tab]) раскрываются после весь make-файл был (предварительно) обработан, но за до первая строка рецепта выполняетсяоболочкойЯ полагаю, что это основной источник вашей путаницы.

Я обнаружил, что использование CONTENTS = $$ (cat $ (FILE)) работает так, как я ожидаю

$$ - это способ получить один литерал $ после процедуры расширения.Таким образом, $$(cat $(FILE)) при расширении становится $(cat /tmp/example.txt), что является допустимым синтаксисом для подстановки команд в bash.Это означает, что он будет работать только как часть команды bash (строка рецепта).Если это то, что вы хотите, тогда все в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...