In a makefile, I have
@echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@
The problem is that $(CLEAN_FILES)
is quite large, so when I run make, I get
make: execvp: /bin/sh: Argument list too long
I'm on Xubuntu 18.10.
Edit: I should provide a little more context. What I am working on is a make rule (I'm using GNU make) to automatically generate the .hgignore
file. Here is the make rule in its entirety:
.hgignore : .hgignore_extra
@echo "Making $@"
@rm -f $@
@echo "# Automatically generated by Make. Edit .hgignore_extra instead." > $@
@tail -n +2 $< >> $@
@echo "" >> $@
@echo "# The following files come from the Makefile." >> $@
@echo "syntax: glob" >> $@
@echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@
@chmod a-w $@
.PHONY : .hgignore
Edit 2: At @mosvy 's suggestion, I have also tried
.hgignore : .hgignore_extra
@echo "Making $@"
@rm -f $@
@echo "# Automatically generated by Make. Edit .hgignore_extra instead." > $@
@tail -n +2 $< >> $@
@echo "" >> $@
@echo "# The following files come from the Makefile." >> $@
@echo "syntax: glob" >> $@
$(file >$@) $(foreach V,$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES),$(file >>$@,$V))
@true
@chmod a-w $@
.PHONY : .hgignore
Running make .hgignore
with this, I no longer get the "Argument list too long" error, but the generated .hgignore file only contains output up to the syntax: glob
line, and then nothing after that.
Best Answer
As @schily has already explained, this is not a shell problem, and cannot be worked around with
xargs
, quoting, splitting into more echo's with;
, etc. All the text from a make action is passed as argument/s to a singleexecve(2)
, and it can't be longer than the maximum size allowed by the operating system.If you're using GNU make (the default on linux), you can use its
file
andforeach
functions:This will print all words from
$(TEST)
separated by newlines into the file named in$@
. It's based on a similar example from make's manual.Your Makefile could probably be reworked into something more manageable, that doesn't require fancy GNU features, but it's hard to tell how from the snippets you posted.
Update:
For the exact snippet from the question, something like this could do:
I've changed it a little, so it first writes into
.hgignore.new
, and if everything goes well, only then move.hgignore.new
to.hgignore
. You'll have to change back the indenting spaces to tabs, because this dumb interface is mangling whitespaces.