[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Bug in $(shell ...) I can't understand
From: |
Paul Smith |
Subject: |
Bug in $(shell ...) I can't understand |
Date: |
Sun, 06 Feb 2022 11:23:03 -0500 |
User-agent: |
Evolution 3.42.3 (flatpak git) |
OK, someone posted a question to SO and that led me to an hour or more
of banging my head against a wall trying to understand what's
happening... and I can't.
The problem is that the user would like to invoke $(shell ...) and
capture errors, even errors that the program being run doesn't exist.
The shell function only captures stdout, not stderr. This simple idea
won't work of course:
out := $(shell bad-program 2>&1)
$(info out = $(out))
$ make
/bin/sh: bad-program: not found
out =
because this redirects the output of the bad-program, but it's the
shell printing the error not the program. So I suggested this:
out := $(shell $(SHELL) -c 'bad-program' 2>&1)
$(info out = $(out))
This SHOULD work: the outer shell is invoking a sub-shell with the sub-
shell's stderr redirected to its stdout, then the subshell will print
the not found error to its stderr (redirected to stdout).
But it DOES NOT WORK!
$ make
/bin/sh: bad-program: not found
out =
What is happening here?!?! I wrote a little C program to verify my
thinking:
/* ----- */
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char** argv)
{
char *args[4] = {"/bin/sh", "-c",
"/bin/sh -c bad-program 2>&1", NULL};
int pid = fork();
if (pid == 0) {
execv(args[0], args);
} else {
int st;
waitpid(pid, &st, 0);
}
return 0;
}
/* ----- */
But, this works as expected. Something make is doing is causing
problems here. I tried building both with and without posix_spawn and
both behave the same so it's nothing like that.
If you force the sub-shell to create its own subshell, then it works!
This works:
out := $(shell $(SHELL) -c 'bad-program | cat' 2>&1)
$(info out = $(out))
$ make
out = /bin/sh: bad-program: not found
- Bug in $(shell ...) I can't understand,
Paul Smith <=