views:

310

answers:

1

I'm trying to create a generic build template for my Makefiles, kind of like they discuss in the eval documentation.

I can't seem to get the wildcard function to work within an eval. The basic code I'm having issues with looks like this.

SRC_DIR = ./src/

PROG_NAME = test

define PROGRAM_template
  $(1)_SRC_DIR = $(join $(SRC_DIR), $(1)/)
  $(1)_SRC_FILES = $(wildcard $$($(1)_SRC_DIR)*.c)
endef

$(eval $(call PROGRAM_template, $(PROG_NAME)))

all:
    @echo $(test_SRC_DIR)
    @echo $(test_SRC_FILES)
    @echo $(wildcard $(wildcard $(test_SRC_DIR)*.c)

When I run make with this, the output is

./src/test

[correct list of all .c files in ./src/test/]

Basically, the wildcard call within PROGRAM_template is not being eval'd as I expect it. The call results in an empty list.
The join call is being eval'd correctly though.

So, what am I doing wrong? My guess is that

$$($(1)_SRC_DIR) 

is not correct, but I can't figure out the right way to do it.

EDIT Once this was solved, it didn't take long for me to hit another issue with eval. I posted it as a new question at http://stackoverflow.com/questions/2428506/workaround-for-gnu-make-3-80-eval-bug

+2  A: 

You need to double escape virtually all of the functions and variables when you use eval. In most cases, the only things that don't need to be double-escaped are function arguments (because the call function will fully expand them). In this case, you technically don't need to double-escape join or SRC_DIR either, but it will simplify your life if you just always double-escape all variables and functions when using eval.

The reason you need the double escapes is that expansion happens twice when using eval. The eval function itself performs expansion, and then expansion is done again when the block is finally parsed as makefile syntax (i.e. when it is actually evaluated).

The way you've got it written, wildcard is invoked on the string literal $( test_SRC_DIR)*.c. If you want, you can see this for yourself by replacing wildcard with info in your version and see what happens.

You need to hold off on actually invoking wildcard until the second expansion, so that it's argument is the result of the expansion of $(test_SRC_DIR).

Try this:

SRC_DIR = ./src/

PROG_NAME = test

define PROGRAM_template
  $(1)_SRC_DIR = $$(join $$(SRC_DIR),$(1)/)
  $(1)_SRC_FILES = $$(wildcard $$($(1)_SRC_DIR)*.c)
endef

$(eval $(call PROGRAM_template,$(PROG_NAME)))

all:
    @echo $(test_SRC_DIR)
    @echo $(test_SRC_FILES)
    @echo $(wildcard $(test_SRC_DIR)*.c)

EDIT: After posting this, I thought I'd better test it out to make sure it actually works. In doing so, I discovered another problem. You should avoid putting spaces between the comma and argument when calling functions. It causes a literal space character to be prepended to the argument that is passed to the function and leads to unintended results. I've removed the spaces after the commas in the function calls in my version (while this isn't a problem for the call to join, I removed the space there as well just because it's a good habit to get into).

Dan Moulding
Thank you!I was about to comment that it didn't work, then I came back and saw your edit.It seems like the line $(1)_SRC_DIR = $$(join $$(SRC_DIR),$(1)/)also works the way I had it, but for the $(wildcard) line, you need the $$.
bengineerd
@bengineerd: Yes, I've since clarified my answer a bit. You don't need the double escapes on `join` and `SRC_DIR` because those get *fully* expanded after just one expansion. But, like I say, it makes life easier to just always use the double-escapes. They won't harm anything when they're not needed.
Dan Moulding