mirror of
https://github.com/mirror/make.git
synced 2025-03-25 01:00:30 +08:00
[SV 28092] Preserve the exit status of the $(shell...) function.
Add a new variable .SHELLSTATUS which holds the exit status of the last-invoked shell function or != assignment. * NEWS, doc/make.texi: Document the change. * function.c (shell_completed, msdos_openpipe, func_shell_base): Add shell_completed() to handle the completion of the shell, by setting .SHELLSTATUS. Call it where needed. * job.c (child_handler): Call shell_completed(). * tests/scripts/functions/shell: Add tests for .SHELLSTATUS.
This commit is contained in:
parent
c18b23f7b2
commit
43181f1f82
9
NEWS
9
NEWS
@ -1,6 +1,6 @@
|
||||
GNU make NEWS -*-indented-text-*-
|
||||
History of user-visible changes.
|
||||
05 Oct 2014
|
||||
12 Jul 2015
|
||||
|
||||
See the end of this file for copyrights and conditions.
|
||||
|
||||
@ -9,12 +9,17 @@ manual, which is contained in this distribution as the file doc/make.texi.
|
||||
See the README file and the GNU make manual for instructions for
|
||||
reporting bugs.
|
||||
|
||||
Version 4.1.90 (05 Oct 2014)
|
||||
Version 4.1.90 (12 Jul 2015)
|
||||
|
||||
A complete list of bugs fixed in this version is available here:
|
||||
|
||||
http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=106&set=custom
|
||||
|
||||
* New variable: $(.SHELLSTATUS) is set to the exit status of the last != or
|
||||
$(shell ...) function invoked in this instance of make. This will be "0" if
|
||||
successful or not "0" if not successful. The variable value is unset if no
|
||||
!= or $(shell ...) function has been invoked.
|
||||
|
||||
* VMS-specific changes:
|
||||
|
||||
* Perl test harness now works.
|
||||
|
@ -5669,7 +5669,7 @@ endif
|
||||
@end example
|
||||
|
||||
The shell assignment operator @samp{!=} can be used to execute a
|
||||
program and set a variable to its output. This operator first
|
||||
shell script and set a variable to its output. This operator first
|
||||
evaluates the right-hand side, then passes that result to the shell
|
||||
for execution. If the result of the execution ends in a newline, that
|
||||
one newline is removed; all other newlines are replaced by spaces.
|
||||
@ -5694,6 +5694,9 @@ hash := $(shell printf '\043')
|
||||
var := $(shell find . -name "*.c")
|
||||
@end example
|
||||
|
||||
As with the @code{shell} function, the exit status of the just-invoked
|
||||
shell script is stored in the @code{.SHELLSTATUS} variable.
|
||||
|
||||
|
||||
@node Appending, Override Directive, Setting, Using Variables
|
||||
@section Appending More Text to Variables
|
||||
@ -8024,6 +8027,10 @@ implications of using the @code{shell} function within recursively
|
||||
expanded variables vs.@: simply expanded variables (@pxref{Flavors, ,The
|
||||
Two Flavors of Variables}).
|
||||
|
||||
@vindex .SHELLSTATUS
|
||||
After the @code{shell} function or @samp{!=} assignment operator is
|
||||
used, its exit status is placed in the @code{.SHELLSTATUS} variable.
|
||||
|
||||
Here are some examples of the use of the @code{shell} function:
|
||||
|
||||
@example
|
||||
|
37
function.c
37
function.c
@ -1450,7 +1450,22 @@ fold_newlines (char *buffer, unsigned int *length, int trim_newlines)
|
||||
}
|
||||
|
||||
pid_t shell_function_pid = 0;
|
||||
int shell_function_completed;
|
||||
static int shell_function_completed;
|
||||
|
||||
void
|
||||
shell_completed (int exit_code, int exit_sig)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
shell_function_pid = 0;
|
||||
if (exit_sig == 0 && exit_code == 127)
|
||||
shell_function_completed = -1;
|
||||
else
|
||||
shell_function_completed = 1;
|
||||
|
||||
sprintf (buf, "%d", exit_code);
|
||||
define_variable_cname (".SHELLSTATUS", buf, o_override, 0);
|
||||
}
|
||||
|
||||
#ifdef WINDOWS32
|
||||
/*untested*/
|
||||
@ -1630,14 +1645,15 @@ msdos_openpipe (int* pipedes, int *pidp, char *text)
|
||||
errno = EINTR;
|
||||
else if (errno == 0)
|
||||
errno = ENOMEM;
|
||||
shell_function_completed = -1;
|
||||
if (fpipe)
|
||||
pclose (fpipe);
|
||||
shell_completed (127, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pipedes[0] = fileno (fpipe);
|
||||
*pidp = 42; /* Yes, the Meaning of Life, the Universe, and Everything! */
|
||||
errno = e;
|
||||
shell_function_completed = 1;
|
||||
}
|
||||
return fpipe;
|
||||
}
|
||||
@ -1696,7 +1712,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
#endif
|
||||
return o;
|
||||
}
|
||||
#endif
|
||||
#endif /* !__MSDOS__ */
|
||||
|
||||
/* Using a target environment for 'shell' loses in cases like:
|
||||
export var = $(shell echo foobie)
|
||||
@ -1743,7 +1759,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
if (pipedes[0] < 0)
|
||||
{
|
||||
/* Open of the pipe failed, mark as failed execution. */
|
||||
shell_function_completed = -1;
|
||||
shell_completed (127, 0);
|
||||
perror_with_name (error_prefix, "pipe");
|
||||
return o;
|
||||
}
|
||||
@ -1824,7 +1840,10 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
/* Close the read side of the pipe. */
|
||||
#ifdef __MSDOS__
|
||||
if (fpipe)
|
||||
(void) pclose (fpipe);
|
||||
{
|
||||
int st = pclose (fpipe);
|
||||
shell_completed (st, 0);
|
||||
}
|
||||
#else
|
||||
(void) close (pipedes[0]);
|
||||
#endif
|
||||
@ -1843,9 +1862,9 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
}
|
||||
shell_function_pid = 0;
|
||||
|
||||
/* The child_handler function will set shell_function_completed
|
||||
to 1 when the child dies normally, or to -1 if it
|
||||
dies with status 127, which is most likely an exec fail. */
|
||||
/* shell_completed() will set shell_function_completed to 1 when the
|
||||
child dies normally, or to -1 if it dies with status 127, which is
|
||||
most likely an exec fail. */
|
||||
|
||||
if (shell_function_completed == -1)
|
||||
{
|
||||
|
7
job.c
7
job.c
@ -558,7 +558,6 @@ child_handler (int sig UNUSED)
|
||||
}
|
||||
|
||||
extern pid_t shell_function_pid;
|
||||
extern int shell_function_completed;
|
||||
|
||||
/* Reap all dead children, storing the returned status and the new command
|
||||
state ('cs_finished') in the 'file' member of the 'struct child' for the
|
||||
@ -816,11 +815,7 @@ reap_children (int block, int err)
|
||||
/* Check if this is the child of the 'shell' function. */
|
||||
if (!remote && pid == shell_function_pid)
|
||||
{
|
||||
/* It is. Leave an indicator for the 'shell' function. */
|
||||
if (exit_sig == 0 && exit_code == 127)
|
||||
shell_function_completed = -1;
|
||||
else
|
||||
shell_function_completed = 1;
|
||||
shell_completed (exit_code, exit_sig);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,26 @@ $description = 'Test the $(shell ...) function.';
|
||||
|
||||
$details = '';
|
||||
|
||||
# Test standard shell
|
||||
run_make_test('.PHONY: all
|
||||
OUT := $(shell echo hi)
|
||||
all: ; @echo $(OUT)
|
||||
','','hi');
|
||||
|
||||
# Test shells inside rules.
|
||||
run_make_test('.PHONY: all
|
||||
all: ; @echo $(shell echo hi)
|
||||
','','hi');
|
||||
','','hi');
|
||||
|
||||
# Verify .SHELLSTATUS
|
||||
run_make_test('.PHONY: all
|
||||
PRE := $(.SHELLSTATUS)
|
||||
$(shell exit 0)
|
||||
OK := $(.SHELLSTATUS)
|
||||
$(shell exit 1)
|
||||
BAD := $(.SHELLSTATUS)
|
||||
all: ; @echo PRE=$(PRE) OK=$(OK) BAD=$(BAD)
|
||||
','','PRE= OK=0 BAD=1');
|
||||
|
||||
|
||||
# Test unescaped comment characters in shells. Savannah bug #20513
|
||||
@ -27,6 +42,6 @@ run_make_test('
|
||||
export HI = $(shell echo hi)
|
||||
.PHONY: all
|
||||
all: ; @echo $$HI
|
||||
','','hi');
|
||||
','','hi');
|
||||
|
||||
1;
|
||||
|
@ -134,7 +134,7 @@ char *patsubst_expand_pat (char *o, const char *text, const char *pattern,
|
||||
const char *replace_percent);
|
||||
char *patsubst_expand (char *o, const char *text, char *pattern, char *replace);
|
||||
char *func_shell_base (char *o, char **argv, int trim_newlines);
|
||||
|
||||
void shell_completed (int exit_code, int exit_sig);
|
||||
|
||||
/* expand.c */
|
||||
char *recursively_expand_for_file (struct variable *v, struct file *file);
|
||||
|
Loading…
Reference in New Issue
Block a user