make: One Shell

1 
1 5.3.1 Using One Shell
1 ---------------------
1 
1 Sometimes you would prefer that all the lines in the recipe be passed to
1 a single invocation of the shell.  There are generally two situations
1 where this is useful: first, it can improve performance in makefiles
1 where recipes consist of many command lines, by avoiding extra
1 processes.  Second, you might want newlines to be included in your
1 recipe command (for example perhaps you are using a very different
1 interpreter as your 'SHELL').  If the '.ONESHELL' special target appears
1 anywhere in the makefile then _all_ recipe lines for each target will be
1 provided to a single invocation of the shell.  Newlines between recipe
1 lines will be preserved.  For example:
1 
1      .ONESHELL:
1      foo : bar/lose
1              cd $(@D)
1              gobble $(@F) > ../$@
1 
1 would now work as expected even though the commands are on different
1 recipe lines.
1 
1    If '.ONESHELL' is provided, then only the first line of the recipe
1 will be checked for the special prefix characters ('@', '-', and '+').
1 Subsequent lines will include the special characters in the recipe line
1 when the 'SHELL' is invoked.  If you want your recipe to start with one
1 of these special characters you'll need to arrange for them to not be
1 the first characters on the first line, perhaps by adding a comment or
1 similar.  For example, this would be a syntax error in Perl because the
1 first '@' is removed by make:
1 
1      .ONESHELL:
1      SHELL = /usr/bin/perl
1      .SHELLFLAGS = -e
1      show :
1              @f = qw(a b c);
1              print "@f\n";
1 
1 However, either of these alternatives would work properly:
1 
1      .ONESHELL:
1      SHELL = /usr/bin/perl
1      .SHELLFLAGS = -e
1      show :
1              # Make sure "@" is not the first character on the first line
1              @f = qw(a b c);
1              print "@f\n";
1 
1 or
1 
1      .ONESHELL:
1      SHELL = /usr/bin/perl
1      .SHELLFLAGS = -e
1      show :
1              my @f = qw(a b c);
1              print "@f\n";
1 
1    As a special feature, if 'SHELL' is determined to be a POSIX-style
1 shell, the special prefix characters in "internal" recipe lines will
1 _removed_ before the recipe is processed.  This feature is intended to
1 allow existing makefiles to add the '.ONESHELL' special target and still
1 run properly without extensive modifications.  Since the special prefix
1 characters are not legal at the beginning of a line in a POSIX shell
1 script this is not a loss in functionality.  For example, this works as
1 expected:
1 
1      .ONESHELL:
1      foo : bar/lose
1              @cd $(@D)
1              @gobble $(@F) > ../$@
1 
1    Even with this special feature, however, makefiles with '.ONESHELL'
1 will behave differently in ways that could be noticeable.  For example,
1 normally if any line in the recipe fails, that causes the rule to fail
1 and no more recipe lines are processed.  Under '.ONESHELL' a failure of
1 any but the final recipe line will not be noticed by 'make'.  You can
1 modify '.SHELLFLAGS' to add the '-e' option to the shell which will
1 cause any failure anywhere in the command line to cause the shell to
1 fail, but this could itself cause your recipe to behave differently.
1 Ultimately you may need to harden your recipe lines to allow them to
1 work with '.ONESHELL'.
1