On Tue, Jan 18, 2022 at 4:51 PM Hongyi Zhao <hongyi.z...@gmail.com> wrote: > > On Wed, Jan 19, 2022 at 2:56 AM Paul Smith <psm...@gnu.org> wrote: > > > > On Tue, 2022-01-18 at 10:14 +0800, Hongyi Zhao wrote: > > > But it seems that the `$?' used above can't obtain the exit status of > > > the code block in @(...) when used from outside the @() structure > > > [2]. So, I want to know if I can reliably obtain the exit status of > > > the code block in @(...) from outside the @() structure. Any hints > > > will be greatly appreciated. > > > > First, of course you must use $$? not $?, because $? is a shell > > variable not a make variable so you must escape it from make. > > > > Second, there's nothing magical about (). > > So, I would like to know when I should use () to group some commands > and when not. > > > All versions of make, including GNU make, invoke each logical line of > > the recipe in a separate shell. There is no interaction between two > > different shells: the exit code of one shell cannot be accessed by a > > sibling shell. > > > > A rule like this: > > > > foo: > > (exit 1) > > echo $$? > > > > causes make to invoke two different shells: > > > > /bin/sh -c '(exit 1)' > > /bin/sh -c 'echo $?' > > > > The exit code of the first shell is not put into the $? variable of the > > second shell. > > > > If you want to access the exit code of a previous command you must put > > them both into the same shell, which means they both need to be in the > > same logical line of the recipe. So, this rule: > > > > foo: > > (exit 1) ; \ > > echo $$? > > > > invokes a single shell command: > > > > /bin/sh -c '(exit 1) ; echo $?' > > > > now it will work as you expect. > > But see the following testings: > > werner@X10DAi-00:~$ /bin/sh -c '(exit 1); echo $?' > 1 > werner@X10DAi-00:~$ /bin/sh -c 'exit 1; echo $?' > werner@X10DAi-00:~$ > > Why must I use () here, otherwise, the exit code will not be captured?
In the first case a subshell is started (via () syntax)) and immediately exits with exit code 1; the subsequent echo $? prints the exit code of that subshell. In the second case exit 1 is performed first from the same shell that was intended to execute the echo, and the echo never happens. Britton > > > > So, in your makefile rule, you just need to make sure that you add > > semicolons and backslashes to ensure that the recipe is treated as one > > logical line; change: > > > > echo "*** located here $(2)" ; \ > > exit 1 ; fi ; fi ; fi) > > if test $? -eq 0 -a ! -e ../$(3); then \ > > > > to add the semicolon / backslash: > > > > echo "*** located here $(2)" ; \ > > exit 1 ; fi ; fi ; fi) ; \ > > if test $$? -eq 0 -a ! -e ../$(3); then \ > > Thank you for your correction. > > HZ >