Makefile recipe with a here-document redirection Makefile recipe with a here-document redirection shell shell

Makefile recipe with a here-document redirection


Using the line .ONESHELL: somewhere in your Makefile will send all recipe lines to a single shell invocation, you should find your original Makefile works as expected.


When make sees a multi-line block in a recipe(i.e., a block of lines all ending in \, apart from the last),it passes that block un-modifed to the shell.This generally works in bash,apart from here docs.

One way around this is to strip any trailing \s,then pass the resulting string to bash's eval.You do this in make by playing with ${.SHELLFLAGS} and ${SHELL}.You can use both of these in target-specific form if you only want it to kick in for a few targets.

.PHONY: heredocheredoc: .SHELLFLAGS = -c evalheredoc: SHELL = bash -c 'eval "$${@//\\\\/}"'heredoc:    @echo First    @cat <<-there \        here line1 \        here anotherline \    there    @echo Last

giving

$ makeFirsthere line1here anotherlineLast

Careful with that quoting, Eugene.Note the cheat here:I am removing all backslashes,not just the ones at the ends of the line.YMMV.


With GNU make, you can combine multi-line variables with the export directive to use a multi-line command without having to turn on .ONESHELL globally:

export define scriptcat <<'EOF'here document in multi-line shell snippetcalled from the "$@" targetEOFendefrun:; @ eval "$$script"

will give

here document in multi-line shell snippetcalled from the "run" target

You can also combine it with the value function to prevent its value from being expanded by make:

define _scriptcat <<EOFSHELL var expanded by the shell to $SHELL, pid is $$EOFendefexport script = $(value _script)run:; @ eval "$$script"

will give

SHELL var expanded by the shell to /bin/sh, pid is 12712