foreach with error in loop continues

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

foreach with error in loop continues

Emmanuel Mayssat
Hello,

I am running a make with the $(foreach directive.
What I noticed is that if the loop fails ($? != 0), foreach still
continues.

Here is the code:

define create_role_targets
$(1):
    -$(MAKE) -e IAM_ROLE_NAME=$(1) _iam_create_role
    $(foreach P, $(call get_role_policies_R,$(1)), \
        $(MAKE) -e IAM_POLICY_NAME=\$(P) -e IAM_ROLE_NAME=$(1) _iam_validate_policy_document _iam_put_role_policies; \
    )
endef
$(eval $(foreach R, $(_CONFIG_ROLE_NAMES), $(call create_role_targets,$(R))))



I agree the code is somewhat convoluted, but the MAKE in the foreach loop
occasionally fails and if it does, it continues. No only that is not
desirable, but it is not expected.
Is there a way to fail the foreach loop if its inner command fails?

Regards,

--
Emmanuel
Menlo Security, Inc.
Menlo Park, CA


_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: foreach with error in loop continues

Paul Smith-20
On Mon, 2016-10-10 at 13:50 -0700, Emmanuel Mayssat wrote:
> What I noticed is that if the loop fails ($? != 0), foreach still
> continues.

The loop body of a foreach loop cannot fail.  The foreach function (like
most functions in GNU make) doesn't actually run any commands: it
performs text substitution only.

For example the make invocation of:

  $(foreach x,a b c d e f,$x)

expands "$x" for each element in the loop, giving "a b c d e f".  It
doesn't try to "run" "$x" (whatever that might mean) and so there can be
no error code.

Likewise in your example:

> Here is the code:
>
> define create_role_targets
> $(1):
>     -$(MAKE) -e IAM_ROLE_NAME=$(1) _iam_create_role
>     $(foreach P, $(call get_role_policies_R,$(1)), \
>         $(MAKE) -e IAM_POLICY_NAME=\$(P) -e IAM_ROLE_NAME=$(1) _iam_validate_policy_document _iam_put_role_policies; \
>     )
> endef

This foreach loop _expands_ the text of its body completely, then the
results are passed to the shell, all at once.

Also, I don't know why you're passing the "-e" flag multiple times.  It
seems like you are under the impression you need to use it before every
variable assignment on the command line but that's not what -e means.

Also you don't escape dollar signs with backslashes inside make, you
escape them by writing two dollar signs "$$".

Let's look at a simpler example:

  POL = foo bar

  target:
          $(foreach P, $(POL), $(MAKE) X=y P=$(P) biz)

When make decides to build target it will first EXPAND the recipe, which
means the foreach loop.  The result of expansion will be this:

    make X=y P=foo biz make X=y P=bar biz

You can see immediately that is not what you want since it's just one
command, not multiple commands.  Also you can see that make isn't
running these commands during the foreach looping, so there's no chance
it can stop after the first one.

You can write your makefile like this:

  target:
          $(foreach P, $(POL), $(MAKE) X=y P=$(P) biz && ) true

Note how I added the "&&" to separate the commands.  The expansion of this which is passed to the shell will now be:

  make X=y P=foo biz && make X=y P=bar biz && true

This ensures that as soon as one of those make commands fails, the shell will exit immediately.

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: foreach with error in loop continues

Emmanuel Mayssat
On 22:19 Mon 10 Oct     , Paul Smith wrote:
> Also, I don't know why you're passing the "-e" flag multiple times. �It
> seems like you are under the impression you need to use it before every
> variable assignment on the command line but that's not what -e means.

I read the man page and indeed this is not what -e means!

> Also you don't escape dollar signs with backslashes inside make, you
> escape them by writing two dollar signs "$$".

It turns out I was trying to escape the $(P) and $$(P) did not expend to
anything (but \$(P) did!). After a few attempt, it turns out that the
foreach is executed before the call to eval and therefore $(P) doesn't need
to be escaped!


> � target:
> � � � � � $(foreach P, $(POL), $(MAKE) X=y P=$(P) biz && ) true
>

Neat trick! I was using ';' as a separator and that lead to symptoms I
described. Now it works as expected!

--
Emmanuel
Menlo Security, Inc.
Menlo Park, CA


_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: foreach with error in loop continues

Paul Smith-20
On Mon, 2016-10-10 at 20:45 -0700, Emmanuel Mayssat wrote:
> > Also you don't escape dollar signs with backslashes inside make,
> you
> > escape them by writing two dollar signs "$$".
>
> It turns out I was trying to escape the $(P) and $$(P) did not expend
> to anything

Right, because $$(P) expands to the static string '$(P)' not a
reference to a variable, so that is what would be passed to the shell.

>  (but \$(P) did!).

It will expand to the static string '\x' where "x" is each value in the
loop.  However the shell will ignore that backslash since it doesn't
escape any interesting characters, so it's essentially a no-op in this
case (but it could cause problems in other situations if used
incorrectly).

It's helpful to look very carefully at the output command line that
make prints.  That's what it's sending to the shell, so if that doesn't
look right then you'll need to figure out why.

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make