Нужно разобраться, как писать циклы, обрабатывающие длинные переменные makefile.
Длинная переменная
для тестирования нужно как-нибудь создать длинную переменную, содержащую много слов.
возьмём словарь и добавим слова из него в переменную
DISTFILES := $(shell sed ':a;N;$!ba;s/\n/ /g' /usr/share/dict/words)
https://www.gnu.org/software/make/manual/html_node/Shell-Function.html
функция shell сама превращает переводы строки в пробелы, достаточно такого кода (новый код проще объяснять, не нужно знать sed)
DISTFILES := $(shell cat /usr/share/dict/words)
обработать слова циклом
DISTFILES := $(shell cat /usr/share/dict/words)
.PHONY: default_target
define my_macros
@echo ${1}
endef
default_target:
$(foreach w,$(DISTFILES),$(call my_macros,${w})${EOL})
https://www.gnu.org/software/make/manual/html_node/Foreach-Function.html
$(foreach var,list,text)
1) The first two arguments, var and list, are expanded before anything else is done;
2) piece of text is used repeatedly, each time with a different substitution performed on it
text is expanded as many times as there are whitespace-separated words in list.
for each word of the expanded value of list, the variable named by the expanded value of var is set to that word, and text is expanded.
Presumably text contains references to that variable, so its expansion will be different each time.
3) The multiple expansions of text are concatenated, with spaces between them, to make the result of foreach.
можно было бы провести замены функций $(subst from,to,list)
но это более трудное для понимания изменение, лучше будем вызывать sed как в исходном коде, такое преобразование вызовет меньше вопросов
сгруппировать слова
Пробуем сгруппировать слова для команды echo небольшими группами
DISTFILES := $(shell cat /usr/share/dict/words)
define EOL
endef
define run_shell_command
EDITED_DISTFILES+=$(shell echo ${1}|sed 's/./\L&/g'|sed 's-b-B-g')
endef
define split_to_groups
$(eval _args:=)
$(foreach obj,$1,$(eval _args+=$(obj))$(if $(word $2,$(_args)),$(call run_shell_command,$(_args))$(EOL)$(eval _args:=)))
$(if $(_args),$(call run_shell_command,$(_args)))
endef
EDITED_DISTFILES:=
$(eval $(call split_to_groups,${DISTFILES},10000))
.PHONY: default_target
define my_macros
@echo ${1}
endef
default_target:
$(foreach w,$(EDITED_DISTFILES),$(call my_macros,${w})${EOL})
Если задать слишком много слов за раз, будет выдано сообщение:
make: execvp: echo: Argument list too long
Makefile:37: recipe for target 'default_target' failed
make: *** [default_target] Error 127
тут не очень ясно, как отлаживать. Может вывести при помощи $(info ...)?
или заменить пробелы на подчёркивания, затем выполнить печать по строкам (переводы строк не будут заменены и останутся разделителями слов, так как они являются whitespace),
а потом подчёркивания заменить обратно на пробелы (надо подумать насчёт escape-инга подчёркиваний, иначе при обратной замене пострадают исходные подчёркивания)
есть вообще
$(subst from,to,text)
Performs a textual replacement on the text text: each occurrence of from is replaced by to