Подтвердить что ты не робот

Make правило, которое несколько раз вызывает другое правило с разными значениями для переменной

У меня есть правило something, которое работает с переменной VAR. У меня также есть другое правило something-all, которому нужно запустить something, с VAR, установленным для каждого значения в vars.

vars = hello world

something:
    echo $(VAR)

something-all:
    $(foreach VAR,$(vars),something)

Это не работает, я получаю

[email protected]:~/Desktop$ make something-all
something something
make: something: No such file or directory
make: *** [something-all] Error 1

Вероятно, он должен напечатать hello\nworld.

Я использовал это с помощью подстановочных правил, извлекая VAR из %, но понял, что это неправильный способ сделать это. Это выглядело так:

vars = hello world

all: $(foreach VAR,$(vars),something-$(VAR))

something-%:
    echo $*
4b9b3361

Ответ 1

TL; DR: Если вы хотите запрограммировать make, отмените GNU Make в пользу BSD Make.

Это персональная рекомендация. В то время как BSD Make кажется более ограниченным, чем GNU Make, поскольку он предлагает меньше программных возможностей, намного проще программировать и имеет несколько уникальных функций убийцы. Вот почему я предлагаю решение с GNU Make и другое решение для BSD Make:

Выполнение этого в GNU Make

Используя GNU Make, вы можете написать макрос для определения цели. Канонический способ определения последовательности в Makefile состоит в том, чтобы добавить этапы последовательности как зависимости к цели, как показано ниже:

vars= hello world

define something_t =
something: something-$(1)
something-$(1):
    @echo $(1)
endef

$(foreach _,$(vars),$(eval $(call something_t,$_)))

Рекомендуется использовать эту организацию (а не определять только одну цель), потому что вы можете работать над ней, чтобы сделать задачу легко возобновленной, если прервать последовательность. Makefile описывает работу, продвижение которой полностью описывается состоянием файловой системы. Затем задача легко возобновляется, если каждый шаг связан с файлом, обычно объектом компиляции, но иногда также и пустым файлом, который используется для указания того, что важные контрольные точки переданы.

Использование вспомогательного макроса - это гибкое решение, которое может быть адаптировано к более сложным задачам, чем просто повторение имени. Обратите внимание, что это работает с новейшими версиями GNU Make (4.1). В GNU Make 3.81 вы должны удалить знак равенства из определения макроса.

Адаптация вашего примера для BSD Make

Если это вариант для вас, я рекомендую отказаться от использования GNU Make и заменить его на BSD Make, который прост в программировании: it имеет короткую и точную документацию, в то время как документация GNU Make очень многословна и несколько неясна, BSD Make имеет примеры промышленной прочности сложных наборов правил (система сборки FreeBSD или BSD Owl) и он имеет простой и предсказуемый макроязык.

vars= hello world

something:
.for _var in ${vars}
    echo ${_var}
.endfor

Это может эволюционировать для поддержки более сложных задач, просто заменив echo на адаптированные команды или используя промежуточные шаги.

Разрешить пользователю переопределять некоторые задачи, а также в BSD Make

В этом чуть более расширенном варианте мы разрешаем пользователю переопределять наши собственные рецепты для создания целей something-hello и something-world. Для каждого элемента в нашем списке цель something-* создается, если она еще не существует, и добавляется к зависимостям something. Вся операция определения этих целей происходит только в том случае, если something осталось undefined. Поэтому пользователи этих макросов могут:

  • Переопределить рецепты для something-hello и something-world
  • Отмените полную процедуру, связанную с something.

Реализация таких возможностей настройки является обязательной, если мы хотим написать полезные, многоразовые макросы для Make. К несчастью, настройка этого вида почти невозможна в GNU Make.

vars = hello world

.if!target(depend)
.for _var in ${vars}
.if!target(something-${_var})
something-${_var}:
    echo ${_var}
.endif
something: something-${_var}
.endfor
.endif

Ответ 2

Вот один из способов сделать это:

VARS := hello world
THINGS := $(addprefix something-, $(VARS))

allthings: $(THINGS)

something-%:
    echo $*

Ответ 3

Ниже следует исправить вашу проблему.

Использование foreach (Пробовал на GNU Делать 3,80 на sparc-solaris 2.8 и windows)

vars = hello world

something:
    echo $(VAR)

something-all:
    $(foreach i, $(vars), $(MAKE) something VAR=$i || exit 1;)

Использование оболочки для цикла (Прочитано на GNU Сделайте 3,80 и cc на sparc-solaris 2.8)

vars = hello world

something:
    echo $(VAR)

something-all:
    for i in $(vars); do $(MAKE) something VAR=$$i || exit 1; done

Ответ 4

Неудивительно, что

vars := hello world
something-all:
    $(foreach VAR,$(vars),something)

пытается запустить something something. То, что расширяет foreach, поскольку вы не ссылаетесь на VAR в третьем выражении.

Все, что вам нужно сделать, это ссылка VAR и использовать команду, например echo:

vars := hello world
something-all:
    $(foreach VAR,$(vars),echo $(VAR);)

$ make
echo hello; echo world;
hello
world

Обратите внимание на то, как цепочка команд с точкой с запятой позволяет развернуть несколько оболочек или - GASP! - рекурсивные make вызовы. Это не будет более результативным, чем это.

В качестве альтернативы, если ваша команда принимает несколько аргументов в качестве аргументов,

vars := hello world
something-all:
    echo $(foreach VAR,$(vars),$(VAR))

$ make
echo hello world
hello world

Но это эквивалентно суперпростой echo $(vars). Так что это может окупиться, чтобы думать вне коробки, пытаясь изменить ваши требования, чтобы сделать это простое решение.