Bug 205176

Summary: Handling of errors in shell cycle in make(1) depends on the subsequent commands (this shouldn't happen)
Product: Base System Reporter: Yuri Victorovich <yuri>
Component: binAssignee: Jilles Tjoelker <jilles>
Status: Closed Works As Intended    
Severity: Affects Only Me CC: jilles, ports-bugs
Priority: ---    
Version: 10.0-STABLE   
Hardware: Any   
OS: Any   

Description Yuri Victorovich freebsd_committer freebsd_triage 2015-12-10 03:10:53 UTC
Consider this Makefile:

> cycle1:
>              @for i in a b c; do \
>                (echo $$i && false); \
>              done;
> cycle2:
>              @for i in a b c; do \
>                (echo $$i && false); \
>              done && \
>              echo "past that!";

All iterations always fail. But the cycle behavior depends if it is followed by other commands.

Only the first iteration is executed when the cycle is the last:

> # make cycle1
> a
> *** Error code 1
> 
> Stop.
> make: stopped in /usr/ports/yuri

Every iteration is still executed when the cycle is followed by some other command:

> # make cycle2
> a
> b
> c
> *** Error code 1
> 
> Stop.
> make: stopped in /usr/ports/yuri

The behavior of the cycle should not depend on what follows it.
The first case, when any iteration failure causes the cycle failure is the correct behavior.

10.2 STABLE
Comment 1 Yuri Victorovich freebsd_committer freebsd_triage 2015-12-10 04:32:55 UTC
Actually the second case corresponds to the regular shell behavior.
Comment 2 Mathieu Arnold freebsd_committer freebsd_triage 2015-12-10 08:14:31 UTC
This does not look like a ports framework problem, but a make(1) problem.
Comment 3 Jilles Tjoelker freebsd_committer freebsd_triage 2015-12-10 22:58:38 UTC
Although this may be confusing, I see no way to fix it.

To avoid major compatibility problems, make must continue to use sh's -e option. Unfortunately, the shell language and environment do not really permit a proper "abort on error" mechanism, and therefore and for historical reasons, -e has various confusing properties. To avoid making things even more confusing and becoming incompatible with other shells, this will not change.

The confusing property that is biting you here is that the left command of a && control operator is considered "tested", so its failure does not cause the shell to exit. This includes everything nested within the left command.

Replacing the && after done in cycle2 with a ; will fix your problem.

As an exception, a subshell's non-zero exit status may cause the shell to exit even if that exit status was caused by a "tested" command within the subshell. Therefore, the part (echo $$i && false) does not cause this kind of problem.

See also the commit message for r291605: Say it with me, "I will not chain commands with && in Makefiles". This should be fine if the command is in a sub-shell such as: (cmd1 && cmd2)
Comment 4 Kubilay Kocak freebsd_committer freebsd_triage 2015-12-11 07:51:06 UTC
Assign to resolver