GNU Make: Как вызвать $ (подстановочный знак) в пределах $ (eval) - PullRequest
8 голосов
/ 11 марта 2010

Я пытаюсь создать универсальный шаблон сборки для моих Makefiles, что-то вроде того, что они обсуждают в eval документации .

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

SRC_DIR = ./src/

PROG_NAME = test

define PROGRAM_template
  $(1)_SRC_DIR = $(join $(SRC_DIR), $(1)/)
  $(1)_SRC_FILES = $(wildcard $$($(1)_SRC_DIR)*.c)
endef

$(eval $(call PROGRAM_template, $(PROG_NAME)))

all:
    @echo $(test_SRC_DIR)
    @echo $(test_SRC_FILES)
    @echo $(wildcard $(wildcard $(test_SRC_DIR)*.c)

Когда я запускаю make с этим, вывод

./src/test

[correct list of all .c files in ./src/test/]

По сути, подстановочный вызов в PROGRAM_template не является eval'd, как я ожидал. В результате вызова появляется пустой список.
Хотя вызов соединения eval'd правильно.

Итак, что я делаю не так? Я думаю, что

$$($(1)_SRC_DIR) 

не правильно, но я не могу найти правильный способ сделать это.

EDIT Как только это было решено, мне не потребовалось много времени, чтобы решить другую проблему с помощью eval. Я отправил это как новый вопрос в Обходной путь для GNU Make 3.80: ошибка eval

1 Ответ

10 голосов
/ 11 марта 2010

Вам необходимо дважды экранировать практически все функции и переменные, когда вы используете eval. В большинстве случаев единственные вещи, которые не должны быть дважды экранированы, - это аргументы функции (поскольку функция call полностью их расширит). В этом случае вам технически не нужно ни дважды избегать join, ни SRC_DIR, но это упростит вам жизнь, если вы просто всегда будете дважды экранировать все переменные и функции при использовании eval.

Причина, по которой вам нужны двойные побеги, заключается в том, что расширение происходит дважды при использовании eval. Функция eval сама выполняет расширение, а затем расширение выполняется снова , когда блок, наконец, анализируется как синтаксис make-файла (т.е. когда он фактически вычисляется).

Как вы написали, wildcard вызывается для строкового литерала $( test_SRC_DIR)*.c. Если вы хотите, вы можете убедиться в этом сами, заменив wildcard на info в вашей версии и посмотрите, что произойдет.

Вам нужно отложить фактический вызов wildcard до второго раскрытия, чтобы его аргумент был результатом расширения $(test_SRC_DIR).

Попробуйте это:

SRC_DIR = ./src/

PROG_NAME = test

define PROGRAM_template
  $(1)_SRC_DIR = $$(join $$(SRC_DIR),$(1)/)
  $(1)_SRC_FILES = $$(wildcard $$($(1)_SRC_DIR)*.c)
endef

$(eval $(call PROGRAM_template,$(PROG_NAME)))

all:
    @echo $(test_SRC_DIR)
    @echo $(test_SRC_FILES)
    @echo $(wildcard $(test_SRC_DIR)*.c)

EDIT : После публикации я подумал, что лучше проверить его, чтобы убедиться, что он действительно работает. При этом я обнаружил еще одну проблему. Вы должны избегать ставить пробелы между запятой и аргументом при вызове функций. Это приводит к тому, что буквенный символ пробела предшествует аргументу, который передается функции, и приводит к непредвиденным результатам. Я удалил пробелы после запятых в вызовах функций в моей версии (хотя это не проблема для вызова join, я удалил пробелы и там только потому, что это хорошая привычка, в которую можно попасть).

...