g.b.
g.b.

Reputation: 209

Defining custom GNU make functions

What is the problem with the dep2 function in the sample code below?

dep1 = $(eval makefile_list_$1 := $(MAKEFILE_LIST))$(eval -include $1.mk)$(eval MAKEFILE_LIST := $(makefile_list_$1))

define dep2
$(eval makefile_list_$1 := $(MAKEFILE_LIST))
$(eval -include $1.mk)
$(eval MAKEFILE_LIST := $(makefile_list_$1))
endef

$(call dep1,test)
$(call dep2,test)

.DEFAULT_TARGET: all
.PHONY: all
all:
    @echo $@

GNU make 3.81 and 3.82 produce Makefile:10: *** missing separator. Stop. which points to the dep2 call, dep1 is run without errors. The only difference between the two variants is the newlines in dep2 (and the whole point why I'd like to use define).

Upvotes: 20

Views: 25647

Answers (4)

Bill Zhao
Bill Zhao

Reputation: 11

You can do as the below line to kill the error:

FOO := $(call dep2, test)

I guess the reason is the early version of gcc (3.8.1/2) can only accept nothing as the return of expression.

eg $(info string) returns nothing, but $(call dep2, test) returns 2 newlines charaters.

Upvotes: 0

Louis
Louis

Reputation: 151401

I would move the $(eval ...) calls outside of dep2. By doing it this way, there's no need for semicolons in dep2. This means doubling the $ signs of some expansions to avoid expansion being done too early. So:

define dep2
makefile_list_$1 := $$(MAKEFILE_LIST)
-include $1.mk
MAKEFILE_LIST := $$(makefile_list_$1)
endef

$(eval $(call dep2,test))

# Quick checks for testing, to be removed from the final code...
$(info $(makefile_list_test))
$(info $(MAKEFILE_LIST))

.DEFAULT_TARGET: all
.PHONY: all
all:
    @echo $@

I've tested the code above and it works with Gnu Make 4.0. I would expect it to work back to Gnu Make 3.8x. The $(eval $(call ...)) pattern is what I always do to execute my custom functions, and I've used it for quite a while now.

Upvotes: 3

doctor Make
doctor Make

Reputation: 1

There is much that can be improved in what you are doing. For one thing you really want to factor the eval calls to a single call at the top.

Your particular problem, however, stems from not understanding that the multiline recursive string the make's define command uses never includes the lady new line. The most natural convention for writing evalable functions is

define Foo Line1 Line2

endef

You can look at the string eval is seeing and see what this does via the info command, e.g. $(info $(call Foo,x) $(call Foo,y)).

Upvotes: -1

Beta
Beta

Reputation: 99094

You forgot the =:
define dep2 =

EDIT:
Put a semicolon at the end of each line. I've tested this and it works (in GNUMake 3.81).

define dep2
$(eval makefile_list_$1 := $(MAKEFILE_LIST));
$(eval -include $1.mk);
$(eval MAKEFILE_LIST := $(makefile_list_$1));
endef

Why these semicolons are necessary I don't know, but in the documentation define seems to be used for multi-line "variables" only when defining sequences of shell commands to be used in recipes, not Make commands, so maybe the rules are a little different.

Upvotes: 11

Related Questions