Makefile recipe with a here-document redirection
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