1

In bash I can use src/{foo/{one,two},bar/{three,four}}.o to describe the files:

src/foo/one.o
src/foo/two.o
src/bar/three.o
src/bar/four.o

I would like to describe the prerequisites of a makefile target in a similar manner. Is there a way to accomplish this in GNU Make?

This is what I have:

SHELL:=/bin/bash

all: src/{foo/{one,two},bar/{three,four}}.o
    @echo "$(^)"

And I get:

make: *** No rule to make target 'src/{foo/{one,two},bar/{three,four}}.o', needed by 'all'.  Stop.

I came across this and this questions that suggest to add SHELL=/usr/bin/bash to the makefile. But I still cannot get it to work.

Thanks.

onlycparra
  • 607
  • 4
  • 22
  • make uses its own language. It's not shell. Read the documentation for your version to see if there's something that can be used. – Shawn Jul 10 '21 at 01:42
  • 3
    thanks for sending me to read the manual, How didn't I think about that? – onlycparra Jul 10 '21 at 01:47
  • The links you've referenced mention adding `SHELL=/usr/bin/bash` to the makefile, or adding to the OS-level call via `make SHELL=/bin/bash`; in your example you've added an extra `:` between `SHELL` and `=`; can you try removing the `:` from your code and see if that works? obviously verify you've got the right path to your local `bash`, and it wouldn't hurt to verify `bash --version` returns a message that it really is `bash` ... "Duh, Mark!" ? – markp-fuso Jul 10 '21 at 02:02
  • @markp-fuso, thanks for the input, I appreciate your time. the bash is effectively in /bin/bash. and := is almost equivalent to =. For this case, there is no difference. Moreover, I came up with an answer to the problem, I just posted in hope somebody else in the future finds it useful. – onlycparra Jul 10 '21 at 02:08
  • so if you remove the `:` it still does not work? and you still have to make the `$(shell ...)` call? – markp-fuso Jul 10 '21 at 02:09
  • 1
    @markp-fuso, Your approach seems much less cumbersome than mine. However, I just replaced the `:=` for `=` and the behavior is the same. Am I missing something? – onlycparra Jul 10 '21 at 02:14
  • Make does not use the shell to expand prerequisite globbing. Make uses the standard C runtime functions glob(3). See the POSIX definition of this here: https://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html and you'll see it does not support brace expansion. If you run the `$(shell ...)` function then make will invoke whatever shell you have set in the `SHELL` variable but that doesn't impact how _make_ expands globbing expressions. – MadScientist Jul 10 '21 at 02:31

1 Answers1

1

Ok, so GNU make has this shell command that alone is not much relevant here because the brace expansion is a bash thing, and make uses Bourne shell (/bin/sh). But, together with the recommendation of the cited questions, I can do something like this:

SHELL:=/bin/bash

all: $(shell echo src/{foo/{one,two},bar/{three,four}}.o)
    @echo "$(^)"

With this, the braces are correctly expanded.

onlycparra
  • 607
  • 4
  • 22
  • 1
    Good answer. While not as succinct as brace notation, if you're going to be using GNU Make anyhow, one can also use the `addprefix` function. For example, `$(addprefix foo, d l t bar)` expands to *food fool foot foobar*. – hackerb9 Sep 12 '22 at 07:19