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 (). 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. 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 \