Running case commands with the shell function?

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

Running case commands with the shell function?

Sébastien Hinderer
Dear all,

I'd like to be able to write something like this:

flags := \
  $(shell \
    case "$(TARGET)" in \
      i386-*-openbsd5.[5-9]*|i386-*-openbsd[6-9].*) \
        echo "-ccopt -nopie";; \
      *);; \
    esac \
  )

Of course this does not work because the first closing parenthesis is
interpreted as ending the call to the shell function.

Is there a way to actually achieve this, please?

Thanks!

Sébastien.

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

Re: Running case commands with the shell function?

Paul Smith-20
On Thu, 2017-09-14 at 13:52 +0200, Sébastien Hinderer wrote:
> Of course this does not work because the first closing parenthesis is
> interpreted as ending the call to the shell function.
>
> Is there a way to actually achieve this, please?

You have at least three choices:

First, use the matched parenthesis form of case; this is valid POSIX
shell syntax (and I prefer it even in normal shell scripts as it makes
editor matching etc. simpler):

  case "$target" in
      (i386-*-) echo foo ;;
      (*) ;;
  esac

Make will count the open/close parens properly.

Or second, you could use the curly-brace form of variable/function
invocation instead, like:

  ${shell ... }

so make will ignore mismatched parentheses.

Or third, you can assign a variable to the close-paren and use that
instead:

  CP := )

  $(shell ... *$(CP) ;; ...)

Make always parses to the end of the variable or function first, before
it tries to expand what's inside.

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

Re: Running case commands with the shell function?

David Boyce
Fourth, you don't really need the case statement any more though you might
still have a cosmetic preference. At one time "case" was necessary with
patterns because "if" didn't handle them, but in the POSIX shell they take
the same pattern constructs so you could say "if [[ $$target =  i386-*- ]];
then ... else ... fi".

Fifth, of course, wrap the logic in a standalone shell script which is
arguably better practice anyway. Certainly easier to read and test.

On Thu, Sep 14, 2017 at 5:04 AM, Paul Smith <[hidden email]> wrote:

> On Thu, 2017-09-14 at 13:52 +0200, Sébastien Hinderer wrote:
> > Of course this does not work because the first closing parenthesis is
> > interpreted as ending the call to the shell function.
> >
> > Is there a way to actually achieve this, please?
>
> You have at least three choices:
>
> First, use the matched parenthesis form of case; this is valid POSIX
> shell syntax (and I prefer it even in normal shell scripts as it makes
> editor matching etc. simpler):
>
>   case "$target" in
>       (i386-*-) echo foo ;;
>       (*) ;;
>   esac
>
> Make will count the open/close parens properly.
>
> Or second, you could use the curly-brace form of variable/function
> invocation instead, like:
>
>   ${shell ... }
>
> so make will ignore mismatched parentheses.
>
> Or third, you can assign a variable to the close-paren and use that
> instead:
>
>   CP := )
>
>   $(shell ... *$(CP) ;; ...)
>
> Make always parses to the end of the variable or function first, before
> it tries to expand what's inside.
>
> _______________________________________________
> Help-make mailing list
> [hidden email]
> https://lists.gnu.org/mailman/listinfo/help-make
>
_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Running case commands with the shell function?

Sébastien Hinderer
In reply to this post by Paul Smith-20
Many thanks, Paul, for all your help!

I'll probably use the first solution but the three ones are really great
to know. I really appreciate your responses which are always so prompt,
clear and detailed!

Best wishes,

Sébastien.

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

Re: Running case commands with the shell function?

Sébastien Hinderer
In reply to this post by David Boyce
Many thanks for your contribution, David, also very helpful!

I thought about using an external script but was then reluctant to do so
because I wanted everything to be self-contained. But you are right that
it is going to be more readable.

I was not aware of the [[ ]] trick to use patterns in ifs! Awesome! So I
guess I'll actually write an external script that uses this syntax.

Best wishes,

Sébastien.

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

Re: Running case commands with the shell function?

Quinn Grier
In reply to this post by David Boyce
On 2017-09-14 05:54, David Boyce wrote:
> At one time "case" was necessary with
> patterns because "if" didn't handle them, but in the POSIX shell they take
> the same pattern constructs so you could say "if [[ $$target =  i386-*- ]];
> then ... else ... fi".

Is this true? I can only find POSIX saying otherwise:

     The following words may be recognized as reserved words on
     some implementations (when none of the characters are quoted),
     causing unspecified results:

          [[          ]]          function          select


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

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Running case commands with the shell function?

David Boyce
I was working from memory there. It's at *least* true of bash and ksh, and
the POSIX shell was based on ksh originally so I'd have expected it to be
in POSIX too. But I don't see it in dash which was intended to be a
bare-bones POSIX shell so it looks like I was wrong about POSIX.

David

On Thu, Sep 14, 2017 at 10:22 AM, Quinn Grier <[hidden email]> wrote:

> On 2017-09-14 05:54, David Boyce wrote:
> > At one time "case" was necessary with
> > patterns because "if" didn't handle them, but in the POSIX shell they
> take
> > the same pattern constructs so you could say "if [[ $$target =  i386-*-
> ]];
> > then ... else ... fi".
>
> Is this true? I can only find POSIX saying otherwise:
>
>      The following words may be recognized as reserved words on
>      some implementations (when none of the characters are quoted),
>      causing unspecified results:
>
>           [[          ]]          function          select
>
>
_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Running case commands with the shell function?

John Calcote-2
In reply to this post by Sébastien Hinderer
$ cat Makefile

TARGET := i386-x-openbsd5.5y
iflags := \
    case "$(TARGET)" in \
      i386-*-openbsd5.[5-9]*|i386-*-openbsd[6-9].*)\
        echo "-ccopt -nopie";; \
      *);; \
    esac

flags := $(shell $(iflags))

all:
echo $(flags)

$ make
echo -ccopt -nopie
-ccopt -nopie

If you can't get make to parse a macro properly due to embedded special
chars, I've found that often embedding the bad stuff in an internal macro
and then calling the internal macro from the outer macro works wonders.

Regards,
John


On Thu, Sep 14, 2017 at 5:52 AM, Sébastien Hinderer <
[hidden email]> wrote:

> Dear all,
>
> I'd like to be able to write something like this:
>
> flags := \
>   $(shell \
>     case "$(TARGET)" in \
>       i386-*-openbsd5.[5-9]*|i386-*-openbsd[6-9].*) \
>         echo "-ccopt -nopie";; \
>       *);; \
>     esac \
>   )
>
> Of course this does not work because the first closing parenthesis is
> interpreted as ending the call to the shell function.
>
> Is there a way to actually achieve this, please?
>
> Thanks!
>
> Sébastien.
>
> _______________________________________________
> Help-make mailing list
> [hidden email]
> https://lists.gnu.org/mailman/listinfo/help-make
>
_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Running case commands with the shell function?

Sébastien Hinderer
Hi John,

John Calcote (2017/09/14 12:26 -0600):
> If you can't get make to parse a macro properly due to embedded special
> chars, I've found that often embedding the bad stuff in an internal macro
> and then calling the internal macro from the outer macro works
> wonders.

That's a great trick! Thanks!

Sébastien.

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

Re: Running case commands with the shell function?

Rakesh Sharma-6
In reply to this post by Sébastien Hinderer

Hi Sebstien,


You could also choose to make do with the GNU-make's builtins and avoid forking to the shell.


TARGET := i386-XXXX-openbsd5.8YYYY

1-9 := 1 2 3 4 5 6 7 8 9
flags := \
   $(strip \
      $(if $(subst i386,,$(firstword $(subst -, ,$(TARGET)))),,\
         $(if $(strip \
               $(foreach i,\
                  $(addprefix -openbsd,\
                     $(addprefix 5.,$(wordlist 5,9,$(1-9)))\
                                    $(wordlist 6,9,$(1-9))),\
                  $(findstring $i,$(TARGET)))),-ccopt -nopie)))

$(info $(flags))

--Rakesh


________________________________
From: Help-make <help-make-bounces+sharma__r=[hidden email]> on behalf of Sébastien Hinderer <[hidden email]>
Sent: Thursday, September 14, 2017 4:52 AM
To: [hidden email]
Subject: Running case commands with the shell function?

Dear all,

I'd like to be able to write something like this:

flags := \
  $(shell \
    case "$(TARGET)" in \
      i386-*-openbsd5.[5-9]*|i386-*-openbsd[6-9].*) \
        echo "-ccopt -nopie";; \
      *);; \
    esac \
  )

Of course this does not work because the first closing parenthesis is
interpreted as ending the call to the shell function.

Is there a way to actually achieve this, please?

Thanks!

Sébastien.

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Help-make -- Users list for the GNU implementation of make<https://lists.gnu.org/mailman/listinfo/help-make>
lists.gnu.org
This list is for users and installers of GNU make to ask for help. Please send bug reports to [hidden email] instead of posting them here. To see the collection of ...



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

Re: Running case commands with the shell function?

Rakesh Sharma-6
In reply to this post by Sébastien Hinderer

There was a slight error in the previous version as it was not testing the dot "." after the

openbsd versions 6,7,8, & 9.


TARGET := i386-$(rand)-openbsd8.$(rand)

1-9 := 1 2 3 4 5 6 7 8 9
flags := \
   $(strip \
      $(if $(patsubst i386-%,,$(TARGET)),,\
         $(if $(strip \
               $(foreach i,\
                  $(addprefix -openbsd,\
                     $(addprefix 5.,$(wordlist 5,9,$(1-9)))\
                     $(addsuffix .,$(wordlist 6,9,$(1-9)))),\
                  $(findstring $i,$(TARGET)))),-ccopt -nopie)))

$(info $(flags))


________________________________
From: Help-make <help-make-bounces+sharma__r=[hidden email]> on behalf of Sébastien Hinderer <[hidden email]>
Sent: Thursday, September 14, 2017 4:52 AM
To: [hidden email]
Subject: Running case commands with the shell function?

Dear all,

I'd like to be able to write something like this:

flags := \
  $(shell \
    case "$(TARGET)" in \
      i386-*-openbsd5.[5-9]*|i386-*-openbsd[6-9].*) \
        echo "-ccopt -nopie";; \
      *);; \
    esac \
  )

Of course this does not work because the first closing parenthesis is
interpreted as ending the call to the shell function.

Is there a way to actually achieve this, please?

Thanks!

Sébastien.

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Help-make -- Users list for the GNU implementation of make<https://lists.gnu.org/mailman/listinfo/help-make>
lists.gnu.org
This list is for users and installers of GNU make to ask for help. Please send bug reports to [hidden email] instead of posting them here. To see the collection of ...



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

Re: Running case commands with the shell function?

Sébastien Hinderer
Dear Rakesh,

Many thanks for your two e-mails and for the nice makefile-only solution
you propose.

I definitely find it elegant and also interesting from a "cultural" or
"theoretical" point of view to know that there _is_ a Makefile-only
solution to this.

That being said, I must also take maintainability and readability by
others into account, so I went for the external shell script solution.

Best wishes and thanks to all for your enlightening contributions,

Sébastien.

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

Re: Running case commands with the shell function?

Rakesh Sharma-6
Hi Sebastien,

If you prefer sticking to the more maintainable, shell-based version then I would suggest  that you change the double quotes around the $(TARGET) in the case structure, as this would hinder the shell from working if there were to be dollar signs $ , double quotes " , or back quotes `  present in the make variable $(TARGET)

Although that possibility no doubt is remote, but since as this is from a maintenance standpoint , you don't want a fully-functional and verified Makefile to suddenly blow up at the customer's end ! That is why it's never a good idea to provide the shell with unknown inputs when those  are to be interpreted as instructions. (my 2 francs)

######################

TARGET := i386-'foo'-openbsd5.6y
iflags := \
    case '$(subst ','\'',$(TARGET))' in \
      i386-*-openbsd5.[5-9]*|i386-*-openbsd[6-9].*)\
        echo "-ccopt -nopie";; \
      *) :;; \
    esac

######################

Thanks,
/Rakesh

________________________________
From: Help-make <help-make-bounces+sharma__r=[hidden email]> on behalf of Sébastien Hinderer <[hidden email]>
Sent: Monday, September 18, 2017 1:17 AM
To: [hidden email]
Subject: Re: Running case commands with the shell function?

Dear Rakesh,

Many thanks for your two e-mails and for the nice makefile-only solution
you propose.

I definitely find it elegant and also interesting from a "cultural" or
"theoretical" point of view to know that there _is_ a Makefile-only
solution to this.

That being said, I must also take maintainability and readability by
others into account, so I went for the external shell script solution.

Best wishes and thanks to all for your enlightening contributions,

Sébastien.

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Help-make -- Users list for the GNU implementation of make<https://lists.gnu.org/mailman/listinfo/help-make>
lists.gnu.org
This list is for users and installers of GNU make to ask for help. Please send bug reports to [hidden email] instead of posting them here. To see the collection of ...



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

Re: Running case commands with the shell function?

Sébastien Hinderer
Thanks a lot, Rakesh, will take this other remark into account.

Best wishes,

Sébastien.

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

Re: Running case commands with the shell function?

Mark Piffer
Am Do., 21. Sep. 2017 um 09:36 Uhr schrieb Sébastien Hinderer <
[hidden email]>:

> Thanks a lot, Rakesh, will take this other remark into account.
>
> Best wishes,
>
> Sébastien.
>
> _______________________________________________
> Help-make mailing list
> [hidden email]
> https://lists.gnu.org/mailman/listinfo/help-make



Sorry for dropping in so late - had a lot to do lately.
If you want, you can use the GNUmake table toolkit at
https://github.com/markpiffer/gmtt which is now
implementing more than only tables. Your code can be glob-matched this way
(I hope you get the idea):

----------------------------------------------
include gmtt/gmtt.mk

# lags := \
#   $(shell \
#     case "$(TARGET)" in \
#       i386-*-openbsd5.[5-9]*|i386-*-openbsd[6-9].*) \
#         echo "-ccopt -nopie";; \
#       *);; \
#     esac \
#   )


$(info $(call
glob-match,i386-whatever-openbsd5.7.8-experimental,i386-*-openbsd5.[5-9]*))
$(info $(call
glob-match,i386-whatever-openbsd5.4.8-experimental,i386-*-openbsd5.[5-9]*))

TARGET := i386-whatever-openbsd5.7.8-experimental
$(info $(TARGET): $(if $(or $(call
glob-match,$(TARGET),i386-*-openbsd5.[5-9]*),\
                            $(call
glob-match,$(TARGET),i386-*-openbsd[6-9].*)),   -ccopt -nopie, nothing!))

TARGET := i386-whatever-openbsd5.4.8-experimental
$(info $(TARGET): $(if $(or $(call
glob-match,$(TARGET),i386-*-openbsd5.[5-9]*),\
                            $(call
glob-match,$(TARGET),i386-*-openbsd[6-9].*)),   -ccopt -nopie, nothing!))
------------------------------------------

glob-match doesn't support '|' in the expression yet - I will be grateful
if someone can point me to
a glob syntax which is generally accepted and standard, maybe the missing
operators could be
implemented in finite time.

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