aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-09-12 14:03:26 +0100
committerRon Yorston <rmy@pobox.com>2023-09-12 15:01:06 +0100
commit504f373c8d4447a4801a74887f99f0dfa809f53e (patch)
treeb96d61abd47657a60f8e1a194e31b1019f2a2be4
parentfaf0d38e40e099eebccac4013ab2692e545f612e (diff)
downloadbusybox-w32-504f373c8d4447a4801a74887f99f0dfa809f53e.tar.gz
busybox-w32-504f373c8d4447a4801a74887f99f0dfa809f53e.tar.bz2
busybox-w32-504f373c8d4447a4801a74887f99f0dfa809f53e.zip
make: return non-zero exit status when a command fails
When a build command returned a non-zero exit status 'make' reported a warning and returned an exit code of zero. This was due to the misuse of the status returned by system(3). As the man page says: the return value is a "wait status" that can be examined using the macros described in waitpid(2). (i.e., WIFEXITED(), WEXITSTATUS(), and so on). Use the error() function to correctly report the problem on stderr and return an exit status of 2. Some additional changes in the same area: - When a target is removed report the diagnostic on stderr, as required by POSIX. - When a build command receives a signal GNU make removes the target. bmake doesn't and it isn't required by POSIX. Implement this as an extension. - Expand the error message when a build command fails so it includes the exit status or signal number, as obtained from the value returned by system(3). - Alter the WIN32 implementation of system(3) to handle exit codes which represent termination as if by a signal. Adds 200-240 bytes. (GitHub issue #354)
-rw-r--r--miscutils/make.c45
-rwxr-xr-xtestsuite/make.tests8
-rw-r--r--win32/system.c5
3 files changed, 48 insertions, 10 deletions
diff --git a/miscutils/make.c b/miscutils/make.c
index d554a5f7f..8feec1202 100644
--- a/miscutils/make.c
+++ b/miscutils/make.c
@@ -293,6 +293,19 @@ vwarning(FILE *stream, const char *msg, va_list list)
293} 293}
294 294
295/* 295/*
296 * Diagnostic handler. Print message to standard error.
297 */
298static void
299diagnostic(const char *msg, ...)
300{
301 va_list list;
302
303 va_start(list, msg);
304 vwarning(stderr, msg, list);
305 va_end(list);
306}
307
308/*
296 * Error handler. Print message and exit. 309 * Error handler. Print message and exit.
297 */ 310 */
298static void error(const char *msg, ...) NORETURN; 311static void error(const char *msg, ...) NORETURN;
@@ -2111,7 +2124,7 @@ remove_target(void)
2111 if (!dryrun && !print && !precious && 2124 if (!dryrun && !print && !precious &&
2112 target && !(target->n_flag & (N_PRECIOUS | N_PHONY)) && 2125 target && !(target->n_flag & (N_PRECIOUS | N_PHONY)) &&
2113 unlink(target->n_name) == 0) { 2126 unlink(target->n_name) == 0) {
2114 warning("'%s' removed", target->n_name); 2127 diagnostic("'%s' removed", target->n_name);
2115 } 2128 }
2116} 2129}
2117 2130
@@ -2164,23 +2177,35 @@ docmds(struct name *np, struct cmd *cp)
2164 2177
2165 target = np; 2178 target = np;
2166 status = system(cmd); 2179 status = system(cmd);
2167 target = NULL;
2168 // If this command was being run to create an include file 2180 // If this command was being run to create an include file
2169 // or bring it up-to-date errors should be ignored and a 2181 // or bring it up-to-date errors should be ignored and a
2170 // failure status returned. 2182 // failure status returned.
2171 if (status == -1 && !doinclude) { 2183 if (status == -1 && !doinclude) {
2172 error("couldn't execute '%s'", q); 2184 error("couldn't execute '%s'", q);
2173 } else if (status != 0 && !signore) { 2185 } else if (status != 0 && !signore) {
2174 if (!doinclude) 2186 if (!posix && WIFSIGNALED(status))
2175 warning("failed to build '%s'", np->n_name);
2176#if !ENABLE_PLATFORM_MINGW32
2177 if (status == SIGINT || status == SIGQUIT)
2178#endif
2179 remove_target(); 2187 remove_target();
2180 if (errcont || doinclude) 2188 if (errcont || doinclude) {
2189 warning("failed to build '%s'", np->n_name);
2181 estat |= MAKE_FAILURE; 2190 estat |= MAKE_FAILURE;
2182 else 2191 } else {
2183 exit(status); 2192 const char *err_type = NULL;
2193 int err_value;
2194
2195 if (WIFEXITED(status)) {
2196 err_type = "exit";
2197 err_value = WEXITSTATUS(status);
2198 } else if (WIFSIGNALED(status)) {
2199 err_type = "signal";
2200 err_value = WTERMSIG(status);
2201 }
2202
2203 if (err_type)
2204 error("failed to build '%s' %s %d", np->n_name,
2205 err_type, err_value);
2206 else
2207 error("failed to build '%s'", np->n_name);
2208 }
2184 } 2209 }
2185 } 2210 }
2186 if (sdomake || dryrun || dotouch) 2211 if (sdomake || dryrun || dotouch)
diff --git a/testsuite/make.tests b/testsuite/make.tests
index b53b4a2ea..60bb78406 100755
--- a/testsuite/make.tests
+++ b/testsuite/make.tests
@@ -86,6 +86,14 @@ test.k:
86' 86'
87cd .. || exit 1; rm -rf make.tempdir 2>/dev/null 87cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
88 88
89# There was a bug where the failure of a build command didn't result
90# in make returning a non-zero exit status.
91testing "make return error if command fails" \
92 "make -f - >/dev/null 2>&1; echo \$?" "2\n" "" '
93target:
94 @exit 42
95'
96
89# A macro created using ::= remembers it's of type immediate-expansion. 97# A macro created using ::= remembers it's of type immediate-expansion.
90# Immediate expansion also occurs when += is used to append to such a macro. 98# Immediate expansion also occurs when += is used to append to such a macro.
91testing "make appending to immediate-expansion macro" \ 99testing "make appending to immediate-expansion macro" \
diff --git a/win32/system.c b/win32/system.c
index 44a47f861..00b594242 100644
--- a/win32/system.c
+++ b/win32/system.c
@@ -6,6 +6,7 @@ int mingw_system(const char *cmd)
6 intptr_t proc; 6 intptr_t proc;
7 HANDLE h; 7 HANDLE h;
8 DWORD ret = 0; 8 DWORD ret = 0;
9 int sig;
9 10
10 if (cmd == NULL) 11 if (cmd == NULL)
11 return 1; 12 return 1;
@@ -18,5 +19,9 @@ int mingw_system(const char *cmd)
18 GetExitCodeProcess(h, &ret); 19 GetExitCodeProcess(h, &ret);
19 CloseHandle(h); 20 CloseHandle(h);
20 21
22 // Was process terminated as if by a signal?
23 sig = ret >> 24;
24 if (sig != 0 && ret == sig << 24 && is_valid_signal(sig))
25 return sig;
21 return ret << 8; 26 return ret << 8;
22} 27}