Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GNU Make: How to call $(wildcard) within $(eval)

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 Workaround for GNU Make 3.80 eval bug

like image 379
bengineerd Avatar asked Mar 10 '10 23:03

bengineerd


1 Answers

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).

like image 95
Dan Moulding Avatar answered Oct 13 '22 19:10

Dan Moulding