Spec-Zone.ru › GNU Make

Вторичное расширение

Ранее мы узнали, что GNU make работает в двух отдельных фазах: фазе чтения и фазе обновления цели (см. Как make читает Makefile). GNU make также может включить вторичное расширение предварительных зависимостей (только) для некоторых или всех целей, определенных в Makefile. Для того, чтобы это вторичное расширение произошло, специальная цель .SECONDEXPANSION должна быть определена перед первым списком предварительных зависимостей, использующим эту функцию.

Если .SECONDEXPANSION определена, то когда GNU make нужно проверить предварительные зависимости цели, предварительные зависимости расширяются второй раз. В большинстве случаев это вторичное расширение не окажет никакого влияния, так как все ссылки на переменные и функции будут расширены во время начальной обработки Makefile. Для того, чтобы воспользоваться фазой вторичного расширения анализатора, необходимо экранировать ссылку на переменную или функцию в Makefile. В этом случае первое расширение просто снимает экранирование ссылки, но не расширяет ее, а расширение оставляется для фазы вторичного расширения. Например, рассмотрим этот Makefile:

.SECONDEXPANSION:
ONEVAR = onefile
TWOVAR = twofile
myfile: $(ONEVAR) $$(TWOVAR)

После первой фазы расширения список предварительных зависимостей цели myfile будет onefile и $(TWOVAR); первая (неэкранированная) ссылка на переменную ONEVAR расширяется, а вторая (экранированная) ссылка просто снимает экранирование, не распознавая ее как ссылку на переменную. Теперь во время вторичного расширения первое слово расширяется снова, но поскольку оно не содержит ссылок на переменные или функции, оно остается со значением onefile, а второе слово теперь является обычной ссылкой на переменную TWOVAR, которая расширяется до значения twofile. Результатом является две предварительные зависимости: onefile и twofile.

Очевидно, это не очень интересный случай, так как тот же результат можно было бы более легко получить, просто указав обе переменные, без экранирования, в списке предварительных зависимостей. Разница становится заметной, если переменные сброшены; рассмотрим этот пример:

.SECONDEXPANSION:
AVAR = top
onefile: $(AVAR)
twofile: $$(AVAR)
AVAR = bottom

Здесь предварительная зависимость onefile будет расширена немедленно и примет значение top, а предварительная зависимость twofile не будет полностью расширена до вторичного расширения и даст значение bottom.

Это немного интереснее, но истинную мощь этой функции можно оценить только тогда, когда вы обнаружите, что вторичные расширения всегда происходят в рамках области автоматических переменных для этой цели. Это означает, что вы можете использовать такие переменные, как $@, $*, и т.д. во время второго расширения, и они будут иметь свои ожидаемые значения, точно так же, как и в рецепте. Всё, что вам нужно сделать, это отложить расширение, экранировав $. Кроме того, вторичное расширение происходит как для явных, так и для неявных (шаблонных) правил. Зная это, возможные применения этой функции значительно возрастают. Например:

.SECONDEXPANSION:
main_OBJS := main.o try.o test.o
lib_OBJS := lib.o api.o

main lib: $$($$@_OBJS)

Здесь после начального расширения предварительные зависимости как цели main, так и lib будут $($@_OBJS). Во время вторичного расширения переменная $@ устанавливается в имя цели, поэтому расширение для цели main даст $(main_OBJS), или main.o try.o test.o, а вторичное расширение для цели lib даст $(lib_OBJS), или lib.o api.o.

Вы также можете смешивать здесь функции, если они должным образом экранированы:

main_SRCS := main.c try.c test.c
lib_SRCS := lib.c api.c

.SECONDEXPANSION:
main lib: $$(patsubst %.c,%.o,$$($$@_SRCS))

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

Вычисление автоматических переменных во время фазы вторичного расширения, особенно переменной имени цели $$@, ведет себя аналогично вычислению внутри рецептов. Однако есть некоторые тонкие различия и «исключительные случаи», которые вступают в силу для различных типов определений правил, которые make понимает. Тонкости использования различных автоматических переменных описаны ниже.

Вторичное расширение явных правил

Во время вторичного расширения явных правил $$@ и $$% соответственно вычисляются как имя файла цели и, когда цель является членом архива, имя члена цели. Переменная $$< вычисляется как первая предварительная зависимость в первом правиле для этой цели. $$^ и $$+ вычисляются как список всех предварительных зависимостей правил, которые уже появились для той же цели ($$+ с повторениями и $$^ без повторений). Следующий пример поможет проиллюстрировать эти особенности:

.SECONDEXPANSION:

foo: foo.1 bar.1 $$< $$^ $$+    # line #1

foo: foo.2 bar.2 $$< $$^ $$+    # line #2

foo: foo.3 bar.3 $$< $$^ $$+    # line #3

В первом списке предварительных зависимостей все три переменные ($$<, $$^, и $$+) расширяются до пустой строки. Во втором списке они будут иметь значения foo.1, foo.1 bar.1, и foo.1 bar.1 соответственно. В третьем списке они будут иметь значения foo.1, foo.1 bar.1 foo.2 bar.2, и foo.1 bar.1 foo.2 bar.2 foo.1 foo.1 bar.1 foo.1 bar.1 соответственно.

Правила проходят вторичное расширение в порядке Makefile, за исключением того, что правило с рецептом всегда оценивается последним.

Переменные $$? и $$* недоступны и расширяются до пустой строки.

Вторичное расширение статических шаблонных правил

Правила для вторичного расширения статических шаблонных правил идентичны правилам для явных правил, выше, за исключением одного случая: для статических шаблонных правил переменная $$* устанавливается в шаблонную основу. Как и в явных правилах, $$? недоступна и расширяется до пустой строки.

Вторичное расширение неявных правил

Поскольку make ищет неявное правило, оно заменяет основу и затем выполняет вторичное расширение для каждого правила с соответствующим шаблоном цели. Значение автоматических переменных определяется аналогично статическим шаблонным правилам. Например:

.SECONDEXPANSION:

foo: bar

foo foz: fo%: bo%

%oo: $$< $$^ $$+ $$*

Когда неявное правило пробуется для цели foo, $$< расширяется до bar, $$^ расширяется до bar boo, $$+ также расширяется до bar boo, и $$* расширяется до f.

Обратите внимание, что префикс каталога (D), как описано в Алгоритме поиска неявных правил, добавляется (после расширения) ко всем шаблонам в списке предварительных зависимостей. Например:

.SECONDEXPANSION:

/tmp/foo.o:

%.o: $$(addsuffix /%.c,foo bar) foo.h
        @echo $^

Список предварительных зависимостей, напечатанный после вторичного расширения и восстановления префикса каталога, будет /tmp/foo/foo.c /tmp/bar/foo.c foo.h. Если вы не заинтересованы в этом восстановлении, вы можете использовать $$* вместо % в списке предварительных зависимостей.

Copyright © 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Free Software Foundation, Inc.
Licensed under the GNU Free Documentation License.
https://www.gnu.org/software/make/manual/html_node/Secondary-Expansion.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API