From 05ce3863bf4072b21c85f9e322eee924368e7fa9 Mon Sep 17 00:00:00 2001 From: psmith Date: Tue, 6 Jul 2010 06:37:42 +0000 Subject: [PATCH] - Enhance .POSIX to set -e when invoking shells, as demanded by a backward-incompatible change in the 2008 POSIX specification. - Add the .SHELLFLAGS variable so people can choose their own shell flags. - Add tests for this. - Add documentation for this. --- ChangeLog | 10 ++++++++++ NEWS | 20 ++++++++++++++++++-- doc/make.texi | 24 ++++++++++++++++++++++-- job.c | 43 ++++++++++++++++++++++++++----------------- main.c | 21 +++++++++++---------- read.c | 5 ++++- tests/ChangeLog | 7 +++++++ tests/scripts/targets/POSIX | 26 ++++++++++++++++++++++++++ tests/scripts/variables/SHELL | 14 ++++++++++++++ 9 files changed, 138 insertions(+), 32 deletions(-) create mode 100644 tests/scripts/targets/POSIX diff --git a/ChangeLog b/ChangeLog index 7b9711b..f77391c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2010-07-06 Paul Smith + + * main.c (main): Set a default value of "-c" for .SHELLFLAGS. + * NEWS: Mention the new behavior of .POSIX and the new .SHELLFLAGS + variable. + * job.c (construct_command_argv): Retrieve the .SHELLFLAGS value + and pass it to construct_command_argv_internal(). + (construct_command_argv_internal): If .SHELLFLAGS is non-standard + use the slow path. Use that value instead of hard-coded "-c". + 2010-07-05 Paul Smith * implicit.c (pattern_search): lastslash can be const. diff --git a/NEWS b/NEWS index f452686..b9577c9 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,15 @@ Version 3.81.90 standard runtime library. * WARNING: Backward-incompatibility! + The POSIX standard for make was changed in the 2008 version in a + fundamentally incompatible way: make is required to invoke the shell as if + the '-e' flag were provided. Because this would break many makefiles that + have been written to conform to the original text of the standard, the + default behavior of GNU make remains to invoke the shell with simply '-c'. + However, any makefile specifying the .POSIX special target will follow the + new POSIX standard and pass '-e' to the shell. See also .SHELLFLAGS below. + +* WARNING: Backward-incompatibility! The '$?' variable now contains all prerequisites that caused the target to be considered out of date, even if they do not exist (previously only existing targets were provided in $?). @@ -58,6 +67,10 @@ Version 3.81.90 set and reset at will; recipes will use the value active when they were first parsed. To detect this feature check the value of $(.RECIPEPREFIX). +* New special variable: .SHELLFLAGS allows you to change the options passed to + the shell when it invokes recipes. By default the value will be "-c" (or + "-ec" if .POSIX is set). + * New variable modifier 'private': prefixing a variable assignment with the modifier 'private' suppresses inheritance of that variable by prerequisites. This is most useful for target- and pattern-specific @@ -66,13 +79,17 @@ Version 3.81.90 * New make directive: 'undefine' allows you to undefine a variable so that it appears as if it was never set. Both $(flavor) and $(origin) functions will return 'undefined' for such a variable. To detect this - feature search for 'undefine in the .FEATURES special variable. + feature search for 'undefine' in the .FEATURES special variable. * The parser for variable assignments has been enhanced to allow multiple modifiers ('export', 'override', 'private') on the same line as variables, including define/endef variables, and in any order. Also, it is possible to create variables and targets named as these modifiers. +* The 'define' make directive now allows a variable assignment operator after + the variable name, to allow for simple, conditional, or appending multi-line + variable assignment. + Version 3.81 @@ -109,7 +126,6 @@ Version 3.81 of this SysV feature you will need to update them. * WARNING: Backward-incompatibility! - In order to comply with POSIX, the way in which GNU make processes backslash-newline sequences in recipes has changed. If your makefiles use backslash-newline sequences inside of single-quoted strings in diff --git a/doc/make.texi b/doc/make.texi index 03212d5..81d3d26 100644 --- a/doc/make.texi +++ b/doc/make.texi @@ -4,7 +4,7 @@ @include version.texi @set EDITION 0.70 -@set RCSID $Id: make.texi,v 1.64 2009/11/12 16:42:36 bosk Exp $ +@set RCSID $Id: make.texi,v 1.65 2010/07/06 06:37:42 psmith Exp $ @settitle GNU @code{make} @setchapternewpage odd @@ -2873,6 +2873,21 @@ of @code{make} will be run serially, even if the @samp{-j} option is given. Any recursively invoked @code{make} command will still run recipes in parallel (unless its makefile also contains this target). Any prerequisites on this target are ignored. + +@findex .POSIX +@item .POSIX +@cindex POSIX-conforming mode, setting + +If @code{.POSIX} is mentioned as a target, then the makefile will be +parsed and run in POSIX-conforming mode. This does @emph{not} mean +that only POSIX-conforming makefiles will be accepted: all advanced +GNU @code{make} features are still available. Rather, this target +causes @code{make} to behave as required by POSIX in those areas +where @code{make}'s default behavior differs. + +In particular, if this target is mentioned then recipes will be +invoked as if the shell had been passed the @code{-e} flag: the first +failing command in a recipe will cause the recipe to fail immediately. @end table Any defined implicit rule suffix also counts as a special target if it @@ -3713,11 +3728,16 @@ truncated, at least). @subsection Choosing the Shell @cindex shell, choosing the @cindex @code{SHELL}, value of +@cindex @code{.SHELLFLAGS}, value of @vindex SHELL +@vindex .SHELLFLAGS The program used as the shell is taken from the variable @code{SHELL}. If this variable is not set in your makefile, the program -@file{/bin/sh} is used as the shell. +@file{/bin/sh} is used as the shell. The argument(s) passed to the +shell are taken from the variable @code{.SHELLFLAGS}. The default +value of @code{.SHELLFLAGS} is @code{-c} normally, or @code{-ec} in +POSIX-conforming mode. @cindex environment, @code{SHELL} in Unlike most variables, the variable @code{SHELL} is never set from the diff --git a/job.c b/job.c index 03d8a83..8e83a47 100644 --- a/job.c +++ b/job.c @@ -2228,7 +2228,7 @@ void clean_tmp (void) static char ** construct_command_argv_internal (char *line, char **restp, char *shell, - char *ifs, int flags, + char *shellflags, char *ifs, int flags, char **batch_filename_ptr) { #ifdef __MSDOS__ @@ -2436,6 +2436,12 @@ construct_command_argv_internal (char *line, char **restp, char *shell, if (*ap != ' ' && *ap != '\t' && *ap != '\n') goto slow; + if (shellflags != 0) + if (shellflags[0] != '-' + || ((shellflags[1] != 'c' || shellflags[2] != '\0') + && (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0'))) + goto slow; + i = strlen (line) + 1; /* More than 1 arg per character is impossible. */ @@ -2717,34 +2723,33 @@ construct_command_argv_internal (char *line, char **restp, char *shell, if (*line == '\0') return 0; #endif /* WINDOWS32 */ + { /* SHELL may be a multi-word command. Construct a command line - "SHELL -c LINE", with all special chars in LINE escaped. + "$(SHELL) $(.SHELLFLAGS) LINE", with all special chars in LINE escaped. Then recurse, expanding this command line to get the final argument list. */ unsigned int shell_len = strlen (shell); -#ifndef VMS - static char minus_c[] = " -c "; -#else - static char minus_c[] = ""; -#endif unsigned int line_len = strlen (line); + unsigned int sflags_len = strlen (shellflags); - char *new_line = alloca (shell_len + (sizeof (minus_c)-1) + char *new_line = alloca (shell_len + 1 + sflags_len + 1 + (line_len*2) + 1); char *command_ptr = NULL; /* used for batch_mode_shell mode */ # ifdef __EMX__ /* is this necessary? */ if (!unixy_shell) - minus_c[1] = '/'; /* " /c " */ + shellflags[0] = '/'; /* "/c" */ # endif ap = new_line; memcpy (ap, shell, shell_len); ap += shell_len; - memcpy (ap, minus_c, sizeof (minus_c) - 1); - ap += sizeof (minus_c) - 1; + *(ap++) = ' '; + memcpy (ap, shellflags, sflags_len); + ap += sflags_len; + *(ap++) = ' '; command_ptr = ap; for (p = line; *p != '\0'; ++p) { @@ -2794,7 +2799,7 @@ construct_command_argv_internal (char *line, char **restp, char *shell, #endif *ap++ = *p; } - if (ap == new_line + shell_len + sizeof (minus_c) - 1) + if (ap == new_line + shell_len + sflags_len + 2) /* Line was empty. */ return 0; *ap = '\0'; @@ -2846,8 +2851,10 @@ construct_command_argv_internal (char *line, char **restp, char *shell, new_argv[2] = NULL; } else #endif /* WINDOWS32 */ + if (unixy_shell) - new_argv = construct_command_argv_internal (new_line, 0, 0, 0, flags, 0); + new_argv = construct_command_argv_internal (new_line, 0, 0, 0, 0, flags, 0); + #ifdef __EMX__ else if (!unixy_shell) { @@ -2923,10 +2930,10 @@ construct_command_argv_internal (char *line, char **restp, char *shell, instead of recursively calling ourselves, because we cannot backslash-escape the special characters (see above). */ new_argv = xmalloc (sizeof (char *)); - line_len = strlen (new_line) - shell_len - sizeof (minus_c) + 1; + line_len = strlen (new_line) - shell_len - sflags_len - 2; new_argv[0] = xmalloc (line_len + 1); strncpy (new_argv[0], - new_line + shell_len + sizeof (minus_c) - 1, line_len); + new_line + shell_len + sflags_len + 2, line_len); new_argv[0][line_len] = '\0'; } #else @@ -2958,7 +2965,7 @@ char ** construct_command_argv (char *line, char **restp, struct file *file, int cmd_flags, char **batch_filename_ptr) { - char *shell, *ifs; + char *shell, *ifs, *shellflags; char **argv; #ifdef VMS @@ -3063,15 +3070,17 @@ construct_command_argv (char *line, char **restp, struct file *file, } #endif /* __EMX__ */ + shellflags = allocated_variable_expand_for_file ("$(.SHELLFLAGS)", file); ifs = allocated_variable_expand_for_file ("$(IFS)", file); warn_undefined_variables_flag = save; } - argv = construct_command_argv_internal (line, restp, shell, ifs, + argv = construct_command_argv_internal (line, restp, shell, shellflags, ifs, cmd_flags, batch_filename_ptr); free (shell); + free (shellflags); free (ifs); #endif /* !VMS */ return argv; diff --git a/main.c b/main.c index 20b445a..c972e65 100644 --- a/main.c +++ b/main.c @@ -1123,26 +1123,27 @@ main (int argc, char **argv, char **envp) define_variable_cname (".VARIABLES", "", o_default, 0)->special = 1; /* define_variable_cname (".TARGETS", "", o_default, 0)->special = 1; */ define_variable_cname (".RECIPEPREFIX", "", o_default, 0)->special = 1; + define_variable_cname (".SHELLFLAGS", "-c", o_default, 0); /* Set up .FEATURES We must do this in multiple calls because define_variable_cname() is a macro and some compilers (MSVC) don't like conditionals in macros. */ - define_variable_cname (".FEATURES", - "target-specific order-only second-expansion else-if" - " shortest-stem undefine", - o_default, 0); + { + const char *features = "target-specific order-only second-expansion" + " else-if shortest-stem undefine" #ifndef NO_ARCHIVES - do_variable_definition (NILF, ".FEATURES", "archives", - o_default, f_append, 0); + " archives" #endif #ifdef MAKE_JOBSERVER - do_variable_definition (NILF, ".FEATURES", "jobserver", - o_default, f_append, 0); + " jobserver" #endif #ifdef MAKE_SYMLINKS - do_variable_definition (NILF, ".FEATURES", "check-symlink", - o_default, f_append, 0); + " check-symlink" #endif + ; + + define_variable_cname (".FEATURES", features, o_default, 0); + } /* Read in variables from the environment. It is important that this be done before $(MAKE) is figured out so its definitions will not be diff --git a/read.c b/read.c index 591f1f3..1e8d2f3 100644 --- a/read.c +++ b/read.c @@ -1958,7 +1958,10 @@ record_files (struct nameseq *filenames, const char *pattern, /* Check for special targets. Do it here instead of, say, snap_deps() so that we can immediately use the value. */ if (streq (name, ".POSIX")) - posix_pedantic = 1; + { + posix_pedantic = 1; + define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0); + } else if (streq (name, ".SECONDEXPANSION")) second_expansion = 1; diff --git a/tests/ChangeLog b/tests/ChangeLog index c8f3aab..a611422 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,10 @@ +2010-07-06 Paul Smith + + * scripts/variables/SHELL: Test the new .SHELLFLAGS variable. + + * scripts/targets/POSIX: New file. Test the .POSIX special target. + Verify that enabling .POSIX changes the shell flags to set -e. + 2010-07-01 Paul Smith * scripts/features/recursion: Add a space to separate command-line diff --git a/tests/scripts/targets/POSIX b/tests/scripts/targets/POSIX new file mode 100644 index 0000000..662c16d --- /dev/null +++ b/tests/scripts/targets/POSIX @@ -0,0 +1,26 @@ +# -*-perl-*- + +$description = "Test the behaviour of the .PHONY target."; + +$details = ""; + + +# Ensure turning on .POSIX enables the -e flag for the shell + +run_make_test(q! +.POSIX: +all: ; @false; true +!, + '', "#MAKE#: *** [all] Error 1\n", 512); + +# User settings must override .POSIX + +run_make_test(q! +.SHELLFLAGS = -xc +.POSIX: +all: ; @false; true +!, + '', "+ false\n+ true\n"); + +# This tells the test driver that the perl test script executed properly. +1; diff --git a/tests/scripts/variables/SHELL b/tests/scripts/variables/SHELL index a303540..69871d2 100644 --- a/tests/scripts/variables/SHELL +++ b/tests/scripts/variables/SHELL @@ -56,4 +56,18 @@ two: export SHELL := /./$mshell\n".' one two:;@echo "$@: $(SHELL) $$SHELL" ', '', "two: /./$mshell /./$mshell\none: /././$mshell $mshell\n"); +# Test .SHELLFLAGS + +run_make_test(q! +.SHELLFLAGS = -xc +all: ; @true +!, + '', "+ true\n"); + +run_make_test(q! +.SHELLFLAGS = -xec +all: ; @true; false; true +!, + '', "+ true\n+ false\n#MAKE#: *** [all] Error 1\n", 512); + 1; -- 2.11.4.GIT