'Capture standard error of shell in makefile
I have a problem with the shell function in makefiles. Doing this:
var := $(shell some-command)
Allows me to capture the stdout of some-command.
Doing this:
var := $(shell some-command 2>&1)
Allows me to capture the stdout and the stderr of some-command.
How do I capture the stderr of the shell itself?
This makefile ilustrates the problem:
var1 := $(shell date 2>&1)
var2 := $(shell ls aaa 2>&1)
var3 := $(shell a-command-which-does-not-exist 2>&1)
show-me:
@echo var1: \"$(var1)\"
@echo var2: \"$(var2)\"
@echo var3: \"$(var3)\"
It will produce:
/bin/sh: 1: a-command-which-does-not-exist: not found
var1: "So 6. Feb 00:37:05 CET 2022"
var2: "ls: cannot access aaa: No such file or directory"
var3: ""
I would like to capture /bin/sh: 1: a-command-which-does-not-exist: not found into var3. Is this possible?
Solution 1:[1]
You have to run it in a subshell:
var3 := $(shell $(SHELL) -c 'a-command-which-does-not-exist' 2>&1)
There's no other way unfortunately.
ETA OK, I figured it out. The problem is that if the shell invoked by the $(shell ...) function exits with an error code of 127 (which is the shell's exit code for when it can't find a program to run), then GNU make will explicitly write its output to stderr rather than capture it (if you examine the function.c:func_shell_base() function you'll see this).
Any change to the shell that you invoke that ensures it doesn't exit with the 127 exit code will "fix" the problem:
$ cat Makefile
out := $(shell bad-program 2>&1 || exit 1)
$(info out = $out)
$ make
out = /bin/sh: 1: bad-program: not found
make: *** No targets. Stop.
This might be a bug in GNU make. I'll need to consider it.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
