Записать содержимое переменной makefile (> 131000 символов) в файл? - PullRequest
6 голосов
/ 30 августа 2011

Как я могу записать содержимое переменной makefile в файл, не вызывая команду оболочки? Проблема заключается в том, что содержимое переменной возможно дольше, чем оболочка допускает команду (т. Е. Дольше, чем символы MAX_ARG_STRLEN (131072)).

В частности, в make-файле у меня есть переменная, содержащая длинный список имен файлов для обработки (включая их абсолютные пути для сборок вне исходного кода). Теперь мне нужно записать эти имена файлов во (временный) файл, который затем я могу передать другой команде.

До сих пор у нас было такое правило ($COLLATED_FILES - это переменная, содержащая пути):

$(outdir)/collated-files.tely: $(COLLATED_FILES)
    $(LYS_TO_TELY) --name=$(outdir)/collated-files.tely --title="$(TITLE)" \
    --author="$(AUTHOR)" $^

Это ломается, если COLLATED_FILES длиннее, чем около 130000 символов, мы получаем сообщение об ошибке:

make[2]: execvp: /bin/sh: Argument list too long

В качестве решения мы сейчас пытаемся записать содержимое переменной в файл и использовать этот файл в команде $(LYS_TO_TELY). К сожалению, я еще не нашел способ сделать это без вызова оболочки. Мои попытки включают в себя:

$(outdir)/collated-files.list: $(COLLATED_FILES)
    echo "" > $@
    $(foreach f,$^,echo $f >> $@;)

Но это также вызывает сразу все echo команды в оболочке, поэтому команда оболочки такая же длинная.

Есть ли способ записать содержимое $(COLLATED_FILES) в файл на диске, не передавая его в командной строке команде оболочки?

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

Ответы [ 4 ]

5 голосов
/ 18 августа 2014

Если вы используете GNU Make, есть функция file!

https://www.gnu.org/software/make/manual/html_node/File-Function.html

$(file op filename,text)

, где op - это либо >, либо >>.

Для этого требуется GNU Make 4.0 +

2 голосов
/ 31 августа 2011

Вы можете переместить любой код make-файла, который вы используете для создания значения COLLATED_FILES, в тривиальный вспомогательный make-файл, а затем вызывать make рекурсивно из вашего исходного make-файла и использовать тривиальное перенаправление оболочки для захвата stdout рекурсивного вызова make - в этом контексте в основном используется make как элементарный инструмент для обработки текста. Например, создайте make-файл с именем get_collated_files.mk со следующим содержимым:

COLLATED_FILES=abc
COLLATED_FILES+=def
COLLATED_FILES+=ghi
# ... etc ...

# Use $(info) to print the list to stdout.  If you want each filename on a 
# separate line, use this instead:
#
# $(foreach name,$(COLLATED_FILES),$(info $(name)))

$(info $(COLLATED_FILES))

all: ;@#shell no-op to quell make complaints

Затем в вашем исходном make-файле:

collated-files.list:
        $(MAKE) -f get_collated_files.mk > $@

$(outdir)/collated-files.tely: collated-files.list
    $(LYS_TO_TELY) --name=$(outdir)/collated-files.tely --title="$(TITLE)" \
    --author="$(AUTHOR)" --filelist=collated-files.list

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

РЕДАКТИРОВАТЬ : один последний вариант, если вы действительно хотите, чтобы каждое имя файла находилось на отдельной строке, и у вас есть большой контроль над тем, как определяется COLLATED_FILES:

define NL


endef
COLLATED_FILES=abc
COLLATED_FILES+=$(NL)def
COLLATED_FILES+=$(NL)ghi
$(info $(COLLATED_FILES))
all: ;@#no-op

Этот подход позволяет вам снова использовать только один вызов $(info), если это важно для вас по какой-то причине.

2 голосов
/ 28 января 2012

Вот патч для gnu make, который позволяет напрямую записывать переменную в файл. Он создает новую функцию 'writefile', аналогичную существующей функции 'info', за исключением того, что он принимает аргумент имени файла и записывает в файл:

https://savannah.gnu.org/bugs/?35384

1 голос
/ 30 августа 2011

Мне кажется, что вы должны переосмыслить свой дизайн сборки - несомненно, есть лучший способ, чем позволить переменной получить такой большой размер.Но вот способ сделать это:

# Make sure this doesn't collide with any of your other targets.    
NAMES_TO_WRITE = $(addprefix write_,$(COLLATED_FILES)) 

collated-files.list: $(NAMES_TO_WRITE)

write_blank:
        echo "" > collated-files.list

.PHONY: $(NAMES_TO_WRITE)
$(NAMES_TO_WRITE) : write_% : write_blank
        echo $* >> collated-files.list
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...